[
  {
    "path": ".gitignore",
    "content": ".vs\n.vscode\nbuild/*\noutput/*\nloader/payload_00.h\nloader/payload_01.h\ntools/bin2c/bin2c\ntools/bin2c/bin2c.exe\ntools/lz/lz77\ntools/lz/lz77.exe\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.,\n 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Lesser General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n                            NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.\n"
  },
  {
    "path": "Makefile",
    "content": "ifeq ($(strip $(DEVKITARM)),)\n$(error \"Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM\")\nendif\n\ninclude $(DEVKITARM)/base_rules\n\n################################################################################\n\nIPL_LOAD_ADDR := 0x40008000\nIPL_MAGIC := 0x43544349 #\"ICTC\"\ninclude ./Versions.inc\n\n################################################################################\n\nTARGET := hekate\nBUILDDIR := build\nBUILDTDIR := build/$(TARGET)\nOUTPUTDIR := output\nSOURCEDIR = bootloader\nBDKDIR := bdk\nBDKINC := -I./$(BDKDIR)\nVPATH = $(dir ./$(SOURCEDIR)/) $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/))\nVPATH += $(dir $(wildcard ./$(BDKDIR)/)) $(dir $(wildcard ./$(BDKDIR)/*/)) $(dir $(wildcard ./$(BDKDIR)/*/*/))\n\n# Track compiler flags\nTRACK_CFLAGS = $(BUILDTDIR)/.cflags\nTRACK_LDFLAGS = $(BUILDTDIR)/.ldflags\n\n# Main and graphics.\nOBJS =  start exception_handlers main heap gfx logos tui fe_info fe_tools\n\n# Hardware.\nOBJS += bpmp ccplex clock di i2c irq timer \\\n\t\tmc sdram minerva smmu \\\n\t\tgpio pinmux pmc se tsec uart \\\n\t\tfuse kfuse \\\n\t\tsdmmc sdmmc_driver emmc sd emummc \\\n\t\tbq24193 max17050 max7762x max77620-rtc \\\n\t\thw_init\n\n# Utilities.\nOBJS += btn dirlist ianos ini util config\n\n# OS loaders.\nOBJS += l4t hos hos_config pkg1 pkg2 pkg3 pkg2_ini_kippatch secmon_exo\n\n# Libraries.\nOBJS += lz lz4 blz diskio ff ffunicode ffsystem elfload elfreloc_arm\n\nOBJS := $(addsuffix .o, $(OBJS))\nOBJS := $(addprefix $(BUILDTDIR)/, $(OBJS))\n\nGFX_INC   := '\"../$(SOURCEDIR)/gfx/gfx.h\"'\nFFCFG_INC := '\"../$(SOURCEDIR)/libs/fatfs/ffconf.h\"'\n\n################################################################################\n\nCUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) -DBL_MAGIC=$(IPL_MAGIC)\nCUSTOMDEFINES += -DBL_VER_MJ=$(BLVERSION_MAJOR) -DBL_VER_MN=$(BLVERSION_MINOR) -DBL_VER_HF=$(BLVERSION_HOTFX) -DBL_VER_RL=$(BLVERSION_REL)\nCUSTOMDEFINES += -DNYX_VER_MJ=$(NYXVERSION_MAJOR) -DNYX_VER_MN=$(NYXVERSION_MINOR) -DNYX_VER_HF=$(NYXVERSION_HOTFX) -DNYX_VER_RL=$(NYXVERSION_REL)\n\n# BDK defines.\nCUSTOMDEFINES += -DBDK_MALLOC_NO_DEFRAG -DBDK_EMUMMC_ENABLE\nCUSTOMDEFINES += -DBDK_WATCHDOG_FIQ_ENABLE -DBDK_RESTART_BL_ON_WDT\nCUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC)\n\n#CUSTOMDEFINES += -DDEBUG\n\n# UART Logging: Max baudrate 12.5M.\n# DEBUG_UART_PORT - 0: UART_A, 1: UART_B, 2: UART_C.\n#CUSTOMDEFINES += -DDEBUG_UART_BAUDRATE=115200 -DDEBUG_UART_INVERT=0 -DDEBUG_UART_PORT=1\n\n#TODO: Considering reinstating some of these when pointer warnings have been fixed.\nWARNINGS := -Wall -Wsign-compare -Wtype-limits -Wno-array-bounds -Wno-stringop-overread -Wno-stringop-overflow\n#-fno-delete-null-pointer-checks\n#-Wstack-usage=byte-size -fstack-usage\n\nARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork $(WARNINGS)\nCFLAGS = $(ARCH) -O2 -g -gdwarf-4 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 $(CUSTOMDEFINES)\nLDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR)\n\nMODULEDIRS := $(wildcard modules/*)\nNYXDIR := $(wildcard nyx)\nLDRDIR := $(wildcard loader)\nTOOLSLZ := $(wildcard tools/lz)\nTOOLSB2C := $(wildcard tools/bin2c)\nTOOLS := $(TOOLSLZ) $(TOOLSB2C)\n\nifndef IPLECHO\nT := $(shell $(MAKE) $(BUILDTDIR)/$(TARGET).elf --no-print-directory -nrRf $(firstword $(MAKEFILE_LIST)) IPLECHO=\"IPLOBJ\" | grep -c \"IPLOBJ\")\n\nN := x\nC = $(words $N)$(eval N := x $N)\nIPLECHO = echo -ne \"\\r`expr \"  [\\`expr $C '*' 100 / $T\\`\" : '.*\\(....\\)$$'`%]\\033[K\"\nendif\n\n################################################################################\n\n.PHONY: all clean $(LDRDIR) $(TOOLS) $(NYXDIR) $(MODULEDIRS)\n\nall: $(TARGET).bin $(LDRDIR)\n\t@printf ICTC49 >> $(OUTPUTDIR)/$(TARGET).bin\n\t@echo \"--------------------------------------\"\n\t@echo \"$(TARGET) size:\"\n\t@echo -n \"Uncompr:  \"\n\t$(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(TARGET)_unc.bin))\n\t@echo $(BIN_SIZE)\" Bytes\"\n\t@if [ ${BIN_SIZE} -gt 140288 ]; then echo \"\\e[1;33mUncompr size exceeds limit!\\e[0m\"; fi\n\t@echo -n \"Payload:  \"\n\t$(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(TARGET).bin))\n\t@echo $(BIN_SIZE)\" Bytes\"\n\t@if [ ${BIN_SIZE} -gt 126296 ]; then echo \"\\e[1;33mPayload size exceeds limit!\\e[0m\"; fi\n\t@echo \"--------------------------------------\"\n\nclean: $(TOOLS)\n\t@rm -rf $(BUILDDIR)\n\t@rm -rf $(OUTPUTDIR)\n\t@$(MAKE) --no-print-directory -C $(LDRDIR) $(MAKECMDGOALS) -$(MAKEFLAGS)\n\n$(MODULEDIRS): $(BUILDTDIR)/$(TARGET).elf\n\t@$(MAKE) --no-print-directory -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS)\n\n$(NYXDIR): $(BUILDTDIR)/$(TARGET).elf $(MODULEDIRS)\n\t@echo --------------------------------------\n\t@$(MAKE) --no-print-directory -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS)\n\n$(LDRDIR): $(TARGET).bin $(TOOLS) $(NYXDIR) $(MODULEDIRS)\n\t@$(TOOLSLZ)/lz77 $(OUTPUTDIR)/$(TARGET).bin\n\t@mv $(OUTPUTDIR)/$(TARGET).bin $(OUTPUTDIR)/$(TARGET)_unc.bin\n\t@mv $(OUTPUTDIR)/$(TARGET).bin.00.lz payload_00\n\t@mv $(OUTPUTDIR)/$(TARGET).bin.01.lz payload_01\n\t@$(TOOLSB2C)/bin2c payload_00 > $(LDRDIR)/payload_00.h\n\t@$(TOOLSB2C)/bin2c payload_01 > $(LDRDIR)/payload_01.h\n\t@rm payload_00\n\t@rm payload_01\n\t@$(MAKE) --no-print-directory -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS) PAYLOAD_NAME=$(TARGET)\n\n$(TOOLS):\n\t@$(MAKE) --no-print-directory -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS)\n\n$(TARGET).bin: $(BUILDTDIR)/$(TARGET).elf\n\t@$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@\n\t@echo --------------------------------------\n\n$(BUILDTDIR)/$(TARGET).elf: $(OBJS) $(TRACK_LDFLAGS)\n\t@echo -ne \"\\r[100%] Linking $(TARGET).elf\\033[K\"\n\t@$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $(OBJS) -o $@\n\t@printf \"\\n$(TARGET) was built with the following flags:\\nCFLAGS:  $(CFLAGS)\\nLDFLAGS: $(LDFLAGS)\\n\"\n\n$(BUILDTDIR)/%.o: %.c $(TRACK_CFLAGS) | $(BUILDTDIR)\n\t@$(IPLECHO) Building $@\n\t@$(CC) $(CFLAGS) $(BDKINC) -MMD -MP -c $< -o $@\n\n$(BUILDTDIR)/%.o: %.S $(TRACK_CFLAGS) | $(BUILDTDIR)\n\t@$(IPLECHO) Building $@\n\t@$(CC) $(CFLAGS) -MMD -MP -c $< -o $@\n\n$(BUILDTDIR):\n\t@mkdir -p \"$(BUILDDIR)\"\n\t@mkdir -p \"$(BUILDTDIR)\"\n\t@mkdir -p \"$(OUTPUTDIR)\"\n\n# Non objects change detectors.\n$(TRACK_CFLAGS): $(BUILDTDIR)\n\t@echo '$(CFLAGS)' | cmp -s - $@ || echo '$(CFLAGS)' > $@\n$(TRACK_LDFLAGS): $(BUILDTDIR)\n\t@echo '$(LDFLAGS)' | cmp -s - $@ || echo '$(LDFLAGS)' > $@\n-include $(OBJS:.o=.d)\n"
  },
  {
    "path": "README.md",
    "content": "# hekate - Nyx\n\n![Image of Hekate](https://user-images.githubusercontent.com/3665130/60391760-bc1e8c00-9afe-11e9-8b7a-b065873081b2.png)\n\n\nCustom Graphical Nintendo Switch bootloader, firmware patcher, tools, and many more.\n\n\n\n- [Features](#features)\n- [Bootloader folders and files](#bootloader-folders-and-files)\n- [Bootloader configuration](#bootloader-configuration)\n  * [hekate global Configuration keys/values](#hekate-global-configuration-keysvalues-when-entry-is-config)\n  * [Boot entry key/value combinations](#boot-entry-keyvalue-combinations)\n  * [Boot entry key/value combinations for Exosphère](#boot-entry-keyvalue-combinations-for-exosphère)\n  * [Payload storage](#payload-storage)\n  * [Nyx Configuration keys/values](#nyx-configuration-keysvalues-nyxini)\n\n\n\n## Features\n\n- **Fully Configurable and Graphical** with Touchscreen and Joycon input support\n- **Launcher Style, Background and Color Themes**\n- **HOS (Switch OS) Bootloader** -- For CFW Sys/Emu, OFW Sys and Stock Sys\n- **Android & Linux Bootloader**\n- **Payload Launcher**\n- **eMMC/emuMMC Backup/Restore Tools**\n- **SD Card Partition Manager** -- Prepares and formats SD Card for any combo of HOS (Sys/emuMMC), Android and Linux\n- **emuMMC Creation & Manager** -- Can also migrate and fix existing emuMMC\n- **Switch Android & Linux flasher**\n- **USB Mass Storage (UMS) for SD/eMMC/emuMMC** -- Converts Switch into a SD Card Reader\n- **USB Gamepad** -- Converts Switch with Joycon into a USB HID Gamepad\n- **Hardware and Peripherals info** (SoC, Fuses, RAM, Display, Touch, eMMC, SD, Battery, PSU, Charger)\n- **Many other tools** like Archive Bit Fixer, Touch Calibration, SD/eMMC Benchmark, AutoRCM enabler and more\n\n\n## Bootloader folders and files\n\n| Folder/File              | Description                                                           |\n| ------------------------ | --------------------------------------------------------------------- |\n| bootloader               | Main folder.                                                          |\n|  \\|__ bootlogo.bmp       | It is used if no `logopath` key is found. User provided. Can be skipped. |\n|  \\|__ hekate_ipl.ini     | Main bootloader configuration and boot entries in `Launch` menu.      |\n|  \\|__ nyx.ini            | Nyx GUI configuration                                                 |\n|  \\|__ patches.ini        | Add external patches. Can be skipped. A template can be found [here](./res/patches_template.ini) |\n|  \\|__ update.bin         | If newer, it is loaded at boot. Normally for modchips. Auto updated and created at first boot. |\n| bootloader/ini/          | For individual inis. `More configs` menu. Autoboot is supported.   |\n| bootloader/res/          | Nyx user resources. Icons and more.                                   |\n|  \\|__ background.bmp     | Nyx - Custom background. User provided.                               |\n|  \\|__ icon_switch.bmp    | Nyx - Default icon for CFWs.                                          |\n|  \\|__ icon_payload.bmp   | Nyx - Default icon for Payloads.                                      |\n| bootloader/sys/          | hekate and Nyx system modules folder. !Important!                     |\n|  \\|__ emummc.kipm        | emuMMC KIP1 module.                                                   |\n|  \\|__ libsys_lp0.bso     | LP0 (sleep mode) module.                                              |\n|  \\|__ libsys_minerva.bso | Minerva Training Cell. Used for DRAM Frequency training.              |\n|  \\|__ nyx.bin            | Nyx - hekate's GUI.                                                   |\n|  \\|__ res.pak            | Nyx resources package.                                                |\n|  \\|__ thk.bin            | Atmosphère Tsec Hovi Keygen.                                          |\n|  \\|__ /l4t/              | Folder with firmware relevant to L4T (Linux/Android).                 |\n| bootloader/screenshots/  | Folder where Nyx screenshots are saved                                |\n| bootloader/payloads/     | For the `Payloads` menu. All CFW bootloaders, tools, Linux payloads are supported. Autoboot only supported by including them into an ini. |\n| bootloader/libtools/     | Reserved                                                              |\n\n\n\n## Bootloader configuration\n\nThe bootloader can be configured via `Nyx` -> `Options` or 'bootloader/hekate_ipl.ini'. The special section 'config' controls the actual global configuration. Any other ini section represents a boot entry and can only be edited manually via the ini.\n\n\nThere are four possible type of entries. \"**[ ]**\": Boot entry, \"**{ }**\": Caption, \"**#**\": Comment, \"*newline*\": .ini cosmetic newline.\n\n\n**You can find a template [Here](./res/hekate_ipl_template.ini)**\n\n\n### hekate Configuration keys/values (section *[config]*)\n\nUse `Options` in Nyx to edit the following configuration:\n\n| Config option      | Description                                                    |\n| ------------------ | -------------------------------------------------------------- |\n| autoboot=0         | 0: Disable, #: Boot entry number to auto boot.                 |\n| autoboot_list=0    | 0: Read `autoboot` boot entry from hekate_ipl.ini, 1: Read from ini folder (ini files are ASCII ordered). |\n| bootwait=3         | 0: Disable (It also disables bootlogo. Having **VOL-** pressed since injection goes to menu.), #: Time to wait for **VOL-** to enter menu. Max: 20s. |\n| autohosoff=1       | 0: Disable, 1: If woke up from HOS via an RTC alarm, shows logo, then powers off completely, 2: No logo, immediately powers off.|\n| autonogc=1         | 0: Disable, 1: Automatically applies nogc patch if unburnt fuses found and a >= 4.0.0 HOS is booted. |\n| updater2p=0        | 0: Disable, 1: Force updates (if needed) the reboot2payload binary to be hekate. |\n| backlight=100      | Screen backlight level. 0-255.                                 |\n| ------------------ | --------- *The following can be edited via ini only* --------- |\n| noticker=0         | 0: Animated line is drawn during custom bootlogo, signifying time left to skip to menu. 1: Disable. |\n| bootprotect=0      | 0: Disable, 1: Protect bootloader folder from being corrupted by disallowing reading or editing in HOS. |\n\n\n### Boot entry key/value combinations\n\nA boot entry needs to be manually added/edited with the user's chosen key/value combos.\n\n| Config option          | Description                                                |\n| ---------------------- | ---------------------------------------------------------- |\n| warmboot={FILE path}   | Replaces the warmboot binary                               |\n| secmon={FILE path}     | Replaces the security monitor binary                       |\n| kernel={FILE path}     | Replaces the kernel binary                                 |\n| kip1={FILE path}       | Replaces/Adds kernel initial process. Multiple can be set. |\n| kip1={FOLDER path}/*   | Loads every .kip/.kip1 inside a folder. Compatible with single kip1 keys. |\n| pkg3={FILE path}       | Takes an Atmosphere `package3` binary and `extracts` all needed parts from it. kips, exosphere, warmboot and mesophere. |\n| fss0={FILE path}       | Same as above. !Deprecated! |\n| pkg3ex=1               | Enables loading of experimental content from a PKG3/FSS0 storage |\n| pkg3kip1skip={KIP name} | Skips loading a kip from `pkg3`/`fss0`. Allows multiple and `,` as separator. The name must exactly match the name in `PKG3`. |\n| exofatal={FILE path}   | Replaces the exosphere fatal binary for Mariko             |\n| ---------------------- | ---------------------------------------------------------- |\n| kip1patch=patchname    | Enables a kip1 patch. Allows multiple and `,` as separator. If actual patch is not found, a warning will show up. |\n| emupath={FOLDER path}  | Forces emuMMC to use the selected one. (=emuMMC/RAW1, =emuMMC/SD00, etc). emuMMC must be created by hekate because it uses the raw_based/file_based files. |\n| emummcforce=1          | Forces the use of emuMMC. If emummc.ini is disabled or not found, then it causes an error. |\n| emummc_force_disable=1 | Disables emuMMC, if it's enabled.                           |\n| stock=1                | OFW via hekate bootloader. Disables unneeded kernel patching and CFW kips when running stock. `If emuMMC is enabled, emummc_force_disable=1` is required. emuMMC is not supported on stock. If additional KIPs are needed other than OFW's, you can define them with `kip1` key. No kip should be used that relies on Atmosphère patching, because it will hang. If `NOGC` is needed, use `kip1patch=nogc`. |\n| fullsvcperm=1          | Disables SVC verification (full services permission). Doesn't work with Mesosphere as kernel. |\n| debugmode=1            | Enables Debug mode. Obsolete when used with exosphere as secmon. |\n| kernelprocid=1         | Enables stock kernel process id send/recv patching. Not needed when `pkg3`/`fss0` is used. |\n| ---------------------- | ---------------------------------------------------------- |\n| payload={FILE path}    | Payload launching. Tools, Android/Linux, CFW bootloaders, etc. Any key above when used with that, doesn't get into account. |\n| ---------------------- | ---------------------------------------------------------- |\n| l4t=1                  | L4T Linux/Android native launching.                        |\n| boot_prefixes={FOLDER path} | L4T bootstack directory.                              |\n| ram_oc=0               | L4T RAM Overclocking. Check README_CONFIG.txt for more info. |\n| ram_oc_vdd2=1100       | L4T RAM VDD2 Voltage. Set VDD2 (T210B01) or VDD2/VDDQ (T210) voltage. 1050-1175. |\n| ram_oc_vddq=600        | L4T RAM VDDQ Voltage. Set VDDQ (T210B01). 550-650.         |\n| uart_port=0            | Enables logging on serial port for L4T uboot/kernel.       |\n| sld_type=0x31444C53    | Controls the type of seamless display support. 0x0: Disable, 0x31444C53: L4T seamless display. |\n| Additional keys        | Each distro supports more keys. Check README_CONFIG.txt  for more info. |\n| ---------------------- | ---------------------------------------------------------- |\n| bootwait=3             | Overrides global bootwait from `[config]`.                 |\n| id=IDNAME              | Identifies boot entry for forced boot via id. Max 7 chars. |\n| logopath={FILE path}   | If it exists, it will load the specified bitmap. Otherwise `bootloader/bootlogo.bmp` will be used if exists |\n| icon={FILE path}       | Force Nyx to use the icon defined here. If this is not found, it will check for a bmp named as the boot entry ([Test 2] -> `bootloader/res/Test 2.bmp`). Otherwise defaults will be used. |\n\n\n**Note1**: When using the wildcard (`/*`) with `kip1` you can still use the normal `kip1` after that to load extra single kips.\n\n**Note2**: When using PKG3/FSS0 it parses exosphere, warmboot and all core kips. You can override the first 2 by using `secmon`/`warmboot` after defining `pkg3`/`fss0`.\nYou can define `kip1` to load an extra kip or many via the wildcard (`/*`) usage.\n\n**Warning**: Careful when you override *pkg3/fss core* kips with `kip1`.\nThat's in case the kips are incompatible between them. If compatible, you can override `pkg3`/`fss0` kips with no issues (useful for testing with intermediate kip changes). In such cases, the `kip1` line must be **after** `pkg3`/`fss0` line.\n\n\n### Boot entry key/value combinations for Exosphère\n\nThe following can be paired together with a HOS boot entry:\n\n| Config option          | Description                                                |\n| ---------------------- | ---------------------------------------------------------- |\n| nouserexceptions=1     | Disables usermode exception handlers when paired with Exosphère. |\n| userpmu=1              | Enables user access to PMU when paired with Exosphère.     |\n| cal0blank=1            | Overrides Exosphère config `blank_prodinfo_{sys/emu}mmc`. If that key doesn't exist, `exosphere.ini` will be used. |\n| cal0writesys=1         | Overrides Exosphère config `allow_writing_to_cal_sysmmc`. If that key doesn't exist, `exosphere.ini` will be used. |\n| usb3force=1            | Overrides system settings mitm config `usb30_force_enabled`. If that key doesn't exist, `system_settings.ini` will be used. |\n| memmode=1              | Enables boot config memory mode for retail units. By default, max ram is limited to 4GB. Enabling this will automatically choose size. |\n\n\n**Note**: `cal0blank`, `cal0writesys`, `usb3force`, as stated override the `exosphere.ini` or `system_settings.ini`. 0: Disable, 1: Enable, Key Missing: Use original value.\n\n\n**Note2**: `blank_prodinfo_{sys/emu}mmc`, `allow_writing_to_cal_sysmmc` and `usb30_force_enabled` in `exosphere.ini` and `system_settings.ini` respectively, are the only atmosphere config keys that can affect hekate booting configuration externally, **if** the equivalent keys in hekate config are missing.\n\n\n## Payload storage\n\nhekate has a boot storage in the binary that helps it configure it outside of BPMP environment:\n\n| Offset / Name           | Description                                                       |\n| ----------------------- | ----------------------------------------------------------------- |\n| '0x94' boot_cfg         | bit0: `Force AutoBoot`, bit1: `Show launch log`, bit2: `Boot from ID`, bit3: `Boot to emuMMC`. |\n| '0x95' autoboot         | If `Force AutoBoot`, 0: Force go to menu, else boot that entry.   |\n| '0x96' autoboot_list    | If `Force AutoBoot` and `autoboot` then it boots from ini folder. |\n| '0x97' extra_cfg        | When menu is forced: bit5: `Run UMS`.                             |\n| '0x98' xt_str[128]      | Depends on the set cfg bits.                                      |\n| '0x98' ums[1]           | When `Run UMS` is set, it will launch the selected UMS. 0: SD, 1/2/3: eMMC BOOT0/BOOT1/GPP, 4/5/6: emuMMC BOOT0/BOOT1/GPP,  |\n| '0x98' id[8]            | When `Boot from ID` is set, it will search all inis automatically and find the boot entry with that id and boot it. Must be NULL terminated. |\n| '0xA0' emummc_path[120] | When `Boot to emuMMC` is set, it will override the current emuMMC (boot entry or emummc.ini). Must be NULL terminated. |\n\n\n## Nyx Configuration keys/values (nyx.ini)\n\nUse `Nyx Settings` in Nyx to edit the following configuration:\n\n| Config option      | Description                                                |\n| ------------------ | ---------------------------------------------------------- |\n| themebg=2d2d2d     | Sets Nyx background color in HEX. 0x0B0B0B to 0xC7C7C7.    |\n| themecolor=167     | Sets Nyx color of text highlights.                         |\n| entries5col=0      | 1: Sets Launch entry columns from 4 to 5 per line. For a total of 10 entries. |\n| timeoffset=0       | Sets time offset in HEX. Must be in epoch format           |\n| timedst=1          | Enables automatic daylight saving hour adjustment          |\n| homescreen=0       | Sets home screen. 0: Home menu, 1: All configs (merges Launch and More configs), 2: Launch, 3: More Configs. |\n| verification=1     | 0: Disable Backup/Restore verification, 1: Sparse (block based, fast and mostly reliable), 2: Full (sha256 based, slow and 100% reliable). |\n| ------------------ | ----- *The following can be edited via nyx.ini only* ----- |\n| umsemmcrw=0        | 1: eMMC/emuMMC UMS will be mounted as writable by default. |\n| jcdisable=0        | 1: Disables Joycon driver completely.                      |\n| jcforceright=0     | 1: Forces right joycon to be used as main mouse control.   |\n| bpmpclock=1        | 0: Auto, 1: 589 MHz, 2: 576 MHz, 3: 563 MHz, 4: 544 MHz, 5: 408 MHz. Use 2 to 5 if Nyx hangs or some functions like UMS/Backup Verification fail. |\n\n\n```\nhekate  (c) 2018,      naehrwert, st4rk.\n        (c) 2018-2026, CTCaer.\n\nNyx GUI (c) 2019-2026, CTCaer.\n\nThanks to: derrek, nedwill, plutoo, shuffle2, smea, thexyz, yellows8.\nGreetings to: fincs, hexkyz, SciresM, Shiny Quagsire, WinterMute.\n\nOpen source and free packages used:\n - Littlev Graphics Library,\n   Copyright (c) 2016-2018 Gabor Kiss-Vamosi\n - FatFs R0.13c,\n   Copyright (c) 2006-2018, ChaN\n   Copyright (c) 2018-2022, CTCaer\n - bcl-1.2.0,\n   Copyright (c) 2003-2006, Marcus Geelnard\n - blz,\n   Copyright (c) 2018, SciresM\n - elfload,\n   Copyright (c) 2014 Owen Shepherd,\n   Copyright (c) 2018 M4xw\n\n                         ___\n                      .-'   `'.\n                     /         \\\n                     |         ;\n                     |         |           ___.--,\n            _.._     |0) = (0) |    _.---'`__.-( (_.\n     __.--'`_.. '.__.\\    '--. \\_.-' ,.--'`     `\"\"`\n    ( ,.--'`   ',__ /./;   ;, '.__.'`    __\n    _`) )  .---.__.' / |   |\\   \\__..--\"\"  \"\"\"--.,_\n   `---' .'.''-._.-'`_./  /\\ '.  \\ _.--''````'''--._`-.__.'\n         | |  .' _.-' |  |  \\  \\  '.               `----`\n          \\ \\/ .'     \\  \\   '. '-._)\n           \\/ /        \\  \\    `=.__`'-.\n           / /\\         `) )    / / `\"\".`\\\n     , _.-'.'\\ \\        / /    ( (     / /\n      `--'`   ) )    .-'.'      '.'.  | (\n             (/`    ( (`          ) )  '-;   [switchbrew]\n```\n"
  },
  {
    "path": "README_BOOTLOGO.md",
    "content": "# hekate - Bootlogo\n\nThe bootlogo can be any size with a maximum of 720 x 1280.\n\nWhen it's smaller than 720 x 1280, it is automatically centered and the background takes the color of the first pixel.\n\nThe process is to create a landscape bootlogo and then rotate it 90 degrees counterclockwise.\n\nLastly, the supported format is 32-bit (ARGB) BMP. Classic 24-bit (RGB) BMPs are not supported for performance reasons.\n\n\n## How to configure\n\nIf a boot entry specifies a custom logo path (`logopath=`), this one will be loaded.\n\nIf the above is not found or the format is not correct, it will try to load `bootloader/bootlogo.bmp`.\nIf this is not found, the default hekate logo will be used.\n\n(`bootloader/bootlogo.bmp` is basically like a global bootlogo.)\n"
  },
  {
    "path": "Versions.inc",
    "content": "# IPL Version.\nBLVERSION_MAJOR := 6\nBLVERSION_MINOR := 5\nBLVERSION_HOTFX := 2\nBLVERSION_REL   := 0\n\n# Nyx Version.\nNYXVERSION_MAJOR := 1\nNYXVERSION_MINOR := 9\nNYXVERSION_HOTFX := 2\nNYXVERSION_REL   := 0\n"
  },
  {
    "path": "bdk/bdk.h",
    "content": "/*\n * Copyright (c) 2022 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef BDK_H\n#define BDK_H\n\n#include <memory_map.h>\n\n#include <display/di.h>\n#include <display/vic.h>\n#include <input/als.h>\n#include <input/joycon.h>\n#include <input/touch.h>\n#include <mem/emc_t210.h>\n#include <mem/heap.h>\n#include <mem/mc.h>\n#include <mem/minerva.h>\n#include <mem/sdram.h>\n#include <mem/smmu.h>\n#include <module.h>\n#include <power/bm92t36.h>\n#include <power/bq24193.h>\n#include <power/max17050.h>\n#include <power/max77620.h>\n#include <power/max7762x.h>\n#include <power/max77812.h>\n#include <power/regulator_5v.h>\n#include <rtc/max77620-rtc.h>\n#include <sec/se.h>\n#include <sec/tsec.h>\n#include <soc/actmon.h>\n#include <soc/bpmp.h>\n#include <soc/ccplex.h>\n#include <soc/clock.h>\n#include <soc/fuse.h>\n#include <soc/gpio.h>\n#include <soc/hw_init.h>\n#include <soc/i2c.h>\n#include <soc/irq.h>\n#include <soc/kfuse.h>\n#include <soc/pinmux.h>\n#include <soc/pmc.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n#include <soc/uart.h>\n#include <storage/emmc.h>\n#include <storage/mbr_gpt.h>\n#include <storage/mmc_def.h>\n#include <storage/nx_emmc_bis.h>\n#include <storage/ramdisk.h>\n#include <storage/sd.h>\n#include <storage/sdmmc.h>\n#include <thermal/fan.h>\n#include <thermal/tmp451.h>\n#include <usb/usbd.h>\n#include <utils/aarch64_util.h>\n#include <utils/btn.h>\n#include <utils/dirlist.h>\n#include <utils/ini.h>\n#include <utils/list.h>\n#include <utils/sprintf.h>\n#include <utils/tegra_bct.h>\n#include <utils/tegra_bit.h>\n#include <utils/types.h>\n#include <utils/util.h>\n\n#include <gfx_utils.h>\n\n#endif\n"
  },
  {
    "path": "bdk/display/di.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include \"di.h\"\n#include <power/max77620.h>\n#include <power/max7762x.h>\n#include <soc/clock.h>\n#include <soc/fuse.h>\n#include <soc/gpio.h>\n#include <soc/hw_init.h>\n#include <soc/pinmux.h>\n#include <soc/pmc.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n#include <utils/util.h>\n\n#include \"di.inl\"\n\nstatic bool _nx_aula      = false;\nstatic u32  _panel_id     = 0;\nstatic u32  _panel_id_raw = 0;\n\nstatic void _display_panel_and_hw_end(bool no_panel_deinit);\n\nvoid display_enable_interrupt(u32 intr)\n{\n\tDISPLAY_A(DC_CMD_INT_ENABLE) |= intr;\n}\n\nvoid display_disable_interrupt(u32 intr)\n{\n\tDISPLAY_A(DC_CMD_INT_ENABLE) &= ~intr;\n\tDISPLAY_A(DC_CMD_INT_STATUS)  =  intr;\n}\n\nvoid display_wait_interrupt(u32 intr)\n{\n\tDISPLAY_A(DC_CMD_INT_STATUS) = intr;\n\n\t// Interrupts are masked. Poll status register for checking if fired.\n\twhile (!(DISPLAY_A(DC_CMD_INT_STATUS) & intr))\n\t\t;\n}\n\nstatic void _display_dsi_wait(u32 timeout, u32 off, u32 mask)\n{\n\tu32 end = get_tmr_us() + timeout * 1000;\n\twhile (get_tmr_us() < end && DSI(off) & mask)\n\t\t;\n\tusleep(5);\n}\n\nstatic void _display_dsi_soft_reset()\n{\n\t// Disable DSI interface.\n\tDSI(DSI_POWER_CONTROL) = 0;\n\n\t// Settle time.\n\tusleep(10);\n}\n\nstatic void _display_dsi_send_cmd(u8 cmd, u32 param, u32 wait)\n{\n\tDSI(DSI_WR_DATA) = (param << 8) | cmd;\n\tDSI(DSI_TRIGGER) = DSI_TRIGGER_HOST;\n\n\tif (wait)\n\t\tusleep(wait);\n}\n\nstatic void _display_dsi_wait_vblank(bool enable)\n{\n\tif (enable)\n\t{\n\t\t// Enable vblank interrupt.\n\t\tdisplay_enable_interrupt(DC_CMD_INT_FRAME_END_INT);\n\n\t\t// Use the 4th line to transmit the host cmd packet.\n\t\tDSI(DSI_VIDEO_MODE_CONTROL) = DSI_CMD_PKT_VID_ENABLE | DSI_DSI_LINE_TYPE(4);\n\n\t\t// Wait for vblank before starting the transfer.\n\t\tdisplay_wait_interrupt(DC_CMD_INT_FRAME_END_INT);\n\t}\n\telse\n\t{\n\t\t// Wait for vblank before resetting sync points.\n\t\tdisplay_wait_interrupt(DC_CMD_INT_FRAME_END_INT);\n\t\tusleep(14);\n\n\t\t// Reset all states of syncpt block.\n\t\tDSI(DSI_INCR_SYNCPT_CNTRL) = DSI_INCR_SYNCPT_SOFT_RESET;\n\t\tusleep(300); // Stabilization delay.\n\n\t\t// Clear syncpt block reset.\n\t\tDSI(DSI_INCR_SYNCPT_CNTRL) = 0;\n\t\tusleep(300); // Stabilization delay.\n\n\t\t// Restore video mode and host control.\n\t\tDSI(DSI_VIDEO_MODE_CONTROL) = 0;\n\n\t\t// Disable and clear vblank interrupt.\n\t\tdisplay_disable_interrupt(DC_CMD_INT_FRAME_END_INT);\n\t}\n}\n\nstatic void _display_dsi_read_rx_fifo(u32 *data)\n{\n\tu32 fifo_count = DSI(DSI_STATUS) & DSI_STATUS_RX_FIFO_SIZE;\n\tif (fifo_count)\n\t\tDSI(DSI_TRIGGER) = 0;\n\n\tfor (u32 i = 0; i < fifo_count; i++)\n\t{\n\t\t// Read or Drain RX FIFO.\n\t\tif (data)\n\t\t\tdata[i] = DSI(DSI_RD_DATA);\n\t\telse\n\t\t\t(void)DSI(DSI_RD_DATA);\n\t}\n}\n\nint display_dsi_read(u8 cmd, u32 len, void *data)\n{\n\tu32 fifo[DSI_STATUS_RX_FIFO_SIZE] = {0};\n\n\t// Drain RX FIFO.\n\t_display_dsi_read_rx_fifo(NULL);\n\n\t// Set reply size.\n\t_display_dsi_send_cmd(MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, len, 0);\n\t_display_dsi_wait(250, DSI_TRIGGER, DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO);\n\n\t// Request register read.\n\t_display_dsi_send_cmd(MIPI_DSI_DCS_READ, cmd, 0);\n\t_display_dsi_wait(250, DSI_TRIGGER, DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO);\n\n\t// Transfer bus control to device for transmitting the reply.\n\tDSI(DSI_HOST_CONTROL) |= DSI_HOST_CONTROL_IMM_BTA;\n\n\t// Wait for reply to complete. DSI_HOST_CONTROL_IMM_BTA bit acts as a DSI host read busy.\n\t_display_dsi_wait(150, DSI_HOST_CONTROL, DSI_HOST_CONTROL_IMM_BTA);\n\n\t// Wait a bit for the reply.\n\tusleep(5000);\n\n\t// Read RX FIFO.\n\t_display_dsi_read_rx_fifo(fifo);\n\n\t// Parse packet and copy over the data.\n\tif ((fifo[0] & 0xFF) == DSI_ESCAPE_CMD)\n\t{\n\t\t// Act based on reply type.\n\t\tswitch (fifo[1] & 0xFF)\n\t\t{\n\t\tcase GEN_LONG_RD_RES:\n\t\tcase DCS_LONG_RD_RES:\n\t\t\tmemcpy(data, &fifo[2], MIN((fifo[1] >> 8) & 0xFFFF, len));\n\t\t\tbreak;\n\n\t\tcase GEN_1_BYTE_SHORT_RD_RES:\n\t\tcase DCS_1_BYTE_SHORT_RD_RES:\n\t\t\tmemcpy(data, &fifo[2], 1);\n\t\t\tbreak;\n\n\t\tcase GEN_2_BYTE_SHORT_RD_RES:\n\t\tcase DCS_2_BYTE_SHORT_RD_RES:\n\t\t\tmemcpy(data, &fifo[2], 2);\n\t\t\tbreak;\n\n\t\tcase ACK_ERROR_RES:\n\t\tdefault:\n\t\t\treturn 1;\n\t\t}\n\t}\n\telse\n\t\treturn 1;\n\n\treturn 0;\n}\n\nint display_dsi_vblank_read(u8 cmd, u32 len, void *data)\n{\n\tint res = 0;\n\tu32 host_control = 0;\n\tu32 fifo[DSI_STATUS_RX_FIFO_SIZE] = {0};\n\n\t// Drain RX FIFO.\n\t_display_dsi_read_rx_fifo(NULL);\n\n\t// Save host control and enable host cmd packets during video.\n\thost_control = DSI(DSI_HOST_CONTROL);\n\n\t_display_dsi_wait_vblank(true);\n\n\t// Set reply size.\n\t_display_dsi_send_cmd(MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, len, 0);\n\t_display_dsi_wait(0, DSI_TRIGGER, DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO);\n\n\t// Request register read.\n\t_display_dsi_send_cmd(MIPI_DSI_DCS_READ, cmd, 0);\n\t_display_dsi_wait(0, DSI_TRIGGER, DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO);\n\n\t_display_dsi_wait_vblank(false);\n\n\t// Transfer bus control to device for transmitting the reply.\n\tDSI(DSI_HOST_CONTROL) |= DSI_HOST_CONTROL_IMM_BTA;\n\n\t// Wait for reply to complete. DSI_HOST_CONTROL_IMM_BTA bit acts as a DSI host read busy.\n\t_display_dsi_wait(150, DSI_HOST_CONTROL, DSI_HOST_CONTROL_IMM_BTA);\n\n\t// Wait a bit for the reply.\n\tusleep(5000);\n\n\t// Read RX FIFO.\n\t_display_dsi_read_rx_fifo(fifo);\n\n\t// Parse packet and copy over the data.\n\tif ((fifo[0] & 0xFF) == DSI_ESCAPE_CMD)\n\t{\n\t\t// Act based on reply type.\n\t\tswitch (fifo[1] & 0xFF)\n\t\t{\n\t\tcase GEN_LONG_RD_RES:\n\t\tcase DCS_LONG_RD_RES:\n\t\t\tmemcpy(data, &fifo[2], MIN((fifo[1] >> 8) & 0xFFFF, len));\n\t\t\tbreak;\n\n\t\tcase GEN_1_BYTE_SHORT_RD_RES:\n\t\tcase DCS_1_BYTE_SHORT_RD_RES:\n\t\t\tmemcpy(data, &fifo[2], 1);\n\t\t\tbreak;\n\n\t\tcase GEN_2_BYTE_SHORT_RD_RES:\n\t\tcase DCS_2_BYTE_SHORT_RD_RES:\n\t\t\tmemcpy(data, &fifo[2], 2);\n\t\t\tbreak;\n\n\t\tcase ACK_ERROR_RES:\n\t\tdefault:\n\t\t\tres = 1;\n\t\t\tbreak;\n\t\t}\n\t}\n\telse\n\t\tres = 1;\n\n\t// Restore host control.\n\tDSI(DSI_HOST_CONTROL) = host_control;\n\n\treturn res;\n}\n\nvoid display_dsi_write(u8 cmd, u32 len, void *data)\n{\n\tu32 host_control;\n\tu32 fifo32[DSI_STATUS_TX_FIFO_SIZE] = {0};\n\tu8 *fifo8 = (u8 *)fifo32;\n\n\t// Prepare data for long write.\n\tif (len >= 2)\n\t{\n\t\tmemcpy(&fifo8[5], data, len);\n\t\tmemset(&fifo8[5] + len, 0, len % sizeof(u32));\n\t\tlen++; // Increase length by CMD.\n\t}\n\n\t// Save host control.\n\thost_control = DSI(DSI_HOST_CONTROL);\n\n\t// Enable host transfer trigger.\n\tDSI(DSI_HOST_CONTROL) = (host_control & ~(DSI_HOST_CONTROL_TX_TRIG_MASK)) | DSI_HOST_CONTROL_TX_TRIG_HOST;\n\n\tswitch (len)\n\t{\n\tcase 0:\n\t\t_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, cmd, 0);\n\t\tbreak;\n\n\tcase 1:\n\t\t_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE_PARAM, cmd | (*(u8 *)data << 8), 0);\n\t\tbreak;\n\n\tdefault:\n\t\tfifo32[0] = (len << 8) | MIPI_DSI_DCS_LONG_WRITE;\n\t\tfifo8[4] = cmd;\n\t\tlen += sizeof(u32); // Increase length by length word and DCS CMD.\n\t\tfor (u32 i = 0; i < (ALIGN(len, sizeof(u32)) / sizeof(u32)); i++)\n\t\t\tDSI(DSI_WR_DATA) = fifo32[i];\n\t\tDSI(DSI_TRIGGER) = DSI_TRIGGER_HOST;\n\t\tbreak;\n\t}\n\n\t// Wait for the write to happen.\n\t_display_dsi_wait(250, DSI_TRIGGER, DSI_TRIGGER_HOST);\n\n\t// Restore host control.\n\tDSI(DSI_HOST_CONTROL) = host_control;\n}\n\nvoid display_dsi_vblank_write(u8 cmd, u32 len, void *data)\n{\n\tu32 fifo32[DSI_STATUS_TX_FIFO_SIZE] = {0};\n\tu8 *fifo8 = (u8 *)fifo32;\n\n\t// Prepare data for long write.\n\tif (len >= 2)\n\t{\n\t\tmemcpy(&fifo8[5], data, len);\n\t\tmemset(&fifo8[5] + len, 0, len % sizeof(u32));\n\t\tlen++; // Increase length by CMD.\n\t}\n\n\t_display_dsi_wait_vblank(true);\n\n\tswitch (len)\n\t{\n\tcase 0:\n\t\tDSI(DSI_WR_DATA) = (cmd << 8) | MIPI_DSI_DCS_SHORT_WRITE;\n\t\tbreak;\n\n\tcase 1:\n\t\tDSI(DSI_WR_DATA) = ((cmd | (*(u8 *)data << 8)) << 8) | MIPI_DSI_DCS_SHORT_WRITE_PARAM;\n\t\tbreak;\n\n\tdefault:\n\t\tfifo32[0] = (len << 8) | MIPI_DSI_DCS_LONG_WRITE;\n\t\tfifo8[4] = cmd;\n\t\tlen += sizeof(u32); // Increase length by length word and DCS CMD.\n\t\tfor (u32 i = 0; i < (ALIGN(len, sizeof(u32)) / sizeof(u32)); i++)\n\t\t\tDSI(DSI_WR_DATA) = fifo32[i];\n\t\tbreak;\n\t}\n\n\t_display_dsi_wait_vblank(false);\n}\n\nvoid display_init()\n{\n\t// Get Hardware type, as it's used in various DI functions.\n\t_nx_aula = fuse_read_hw_type() == FUSE_NX_HW_TYPE_AULA;\n\n\t// Check if display is already initialized.\n\tif (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & BIT(CLK_L_DISP1))\n\t\t_display_panel_and_hw_end(true);\n\n\t// Get Chip ID.\n\tbool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210;\n\n\t// Enable DSI AVDD.\n\tmax7762x_regulator_set_voltage(REGULATOR_LDO0, 1200000);\n\tmax7762x_regulator_enable(REGULATOR_LDO0, true);\n\n\t// Enable Display Interface specific clocks.\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = BIT(CLK_H_MIPI_CAL) | BIT(CLK_H_DSI);\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = BIT(CLK_H_MIPI_CAL) | BIT(CLK_H_DSI);\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_DISP1);\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = BIT(CLK_L_DISP1);\n\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = BIT(CLK_X_UART_FST_MIPI_CAL);\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL) = CLK_SRC_DIV(6); // Set PLLP_OUT3 and div 6 (17MHz).\n\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = BIT(CLK_W_DSIA_LP);\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = CLK_SRC_DIV(6);           // Set PLLP_OUT  and div 6 (68MHz).\n\n\t// Bring every IO rail out of deep power down. (Though no rail bit is set.)\n\tPMC(APBDEV_PMC_IO_DPD_REQ)  = PMC_IO_DPD_REQ_DPD_OFF;\n\tPMC(APBDEV_PMC_IO_DPD2_REQ) = PMC_IO_DPD_REQ_DPD_OFF;\n\n\t// Configure LCD/WLED driver pins.\n\tif (!_nx_aula)\n\t{\n\t\t// Configure LCD driver pins.\n\t\tPINMUX_AUX(PINMUX_AUX_NFC_EN)     = PINMUX_PULL_DOWN;\n\t\tPINMUX_AUX(PINMUX_AUX_NFC_INT)    = PINMUX_PULL_DOWN;\n\n\t\t// Configure WLED driver pins.\n\t\tPINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = PINMUX_PULL_DOWN;\n\t\tPINMUX_AUX(PINMUX_AUX_LCD_BL_EN)  = PINMUX_PULL_DOWN;\n\n\t\t// Enable LCD driver AVDD channels (+5.4V CH2 EN, -5.4V CH1 EN).\n\t\tgpio_direction_output(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_HIGH);\n\t\tusleep(10000); // Wait minimum 4.2ms to stabilize.\n\n\t\t// Configure WLED driver PWM/EN pins.\n\t\tgpio_direction_output(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1, GPIO_LOW);\n\n\t\t// Enable WLED driver.\n\t\tgpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH);\n\t}\n\t// else\n\t// {\n\t// \t// Configure OLED status pin.\n\t// \tPINMUX_AUX(PINMUX_AUX_WIFI_EN) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;\n\t// \tgpio_direction_input(GPIO_PORT_H, GPIO_PIN_0);\n\t// }\n\n\t// Configure Panel Reset pin.\n\tPINMUX_AUX(PINMUX_AUX_LCD_RST) = PINMUX_PULL_DOWN;\n\tgpio_direction_output(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW);\n\n\t// Power up supply regulator for display interface.\n\tMIPI_CAL(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0;\n\tMIPI_CAL(MIPI_CAL_MIPI_BIAS_PAD_CFG0) = 0;\n\n\tif (!tegra_t210)\n\t\tAPB_MISC(APB_MISC_GP_DSI_PAD_CONTROL) = 0;\n\n\t// Set DISP1 clock source, parent clock and DSI/PCLK to command mode.\n\t// T210:    DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 100.0 MHz, PLLD_OUT0 (DSI-BCLK): 50.0 MHz. (PCLK: 16.66 MHz)\n\t// T210B01: DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT:  97.8 MHz, PLLD_OUT0 (DSI-BCLK): 48.9 MHz. (PCLK: 16.30 MHz)\n\tclock_enable_plld(3, 20, true, tegra_t210);\n\n\t// Setup Display Interface initial configuration.\n\treg_write_array((vu32 *)DISPLAY_A_BASE, _di_dc_init_config, ARRAY_SIZE(_di_dc_init_config));\n\n\t// Setup DSI init sequence packets.\n\treg_write_array((vu32 *)DSI_BASE, _di_dsi_seq_pkt_reset_config0,  ARRAY_SIZE(_di_dsi_seq_pkt_reset_config0));\n\tDSI(tegra_t210 ? DSI_INIT_SEQ_DATA_15 : DSI_INIT_SEQ_DATA_15_B01) = 0;\n\treg_write_array((vu32 *)DSI_BASE, _di_dsi_seq_pkt_reset_config1,  ARRAY_SIZE(_di_dsi_seq_pkt_reset_config1));\n\n\t// Reset pad trimmers for T210B01.\n\tif (!tegra_t210)\n\t\treg_write_array((vu32 *)DSI_BASE, _di_dsi_init_pads_t210b01, ARRAY_SIZE(_di_dsi_init_pads_t210b01));\n\n\t// Setup init seq packet lengths, timings and power on DSI.\n\treg_write_array((vu32 *)DSI_BASE, _di_dsi_init_config, ARRAY_SIZE(_di_dsi_init_config));\n\tusleep(10);\n\n\t// DSI soft reset.\n\t_display_dsi_soft_reset();\n\n\t// Set DSI LP timings.\n\treg_write_array((vu32 *)DSI_BASE, _di_dsi_timing_lp_config, ARRAY_SIZE(_di_dsi_timing_lp_config));\n\tusleep(10000);\n\n\t// Enable Panel Reset.\n\tgpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH);\n\tusleep(60000);\n\n\t// Setup DSI device takeover timeout.\n\tDSI(DSI_BTA_TIMING) = _nx_aula ? 0x40103 : 0x50204;\n\n\t// Get Display ID.\n\t_panel_id_raw = 0xCCCCCC;\n\tfor (u32 i = 0; i < 3; i++)\n\t{\n\t\tif (!display_dsi_read(MIPI_DCS_GET_DISPLAY_ID, 3, &_panel_id_raw))\n\t\t\tbreak;\n\n\t\tusleep(5000);\n\t}\n\n\t// Decode Display ID.\n\t_panel_id = ((_panel_id_raw >> 8) & 0xFF00) | (_panel_id_raw & 0xFF);\n\n\tif ((_panel_id & 0xFF) == PANEL_JDI_XXX062M)\n\t\t_panel_id = PANEL_JDI_XXX062M;\n\n\t// For Aula ensure that we have a compatible panel id.\n\tif (_nx_aula)\n\t\t_panel_id = PANEL_SAM_AMS699VC01;\n\n\t// Initialize display panel.\n\tswitch (_panel_id)\n\t{\n\tcase PANEL_SAM_AMS699VC01:\n\t\t_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000);\n\t\t// Set color mode to basic (natural). Stock is Saturated (0x00). (POR/Exit value is 0x20/0x00).\n\t\t_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE_PARAM,\n\t\t\t\t\t\t\t  MIPI_DCS_PRIV_SM_SET_COLOR_MODE | (DCS_SM_COLOR_MODE_BASIC << 8), 0);\n\t\t// Enable backlight and smooth PWM.\n\t\t_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE_PARAM,\n\t\t\t\t\t\t\t  MIPI_DCS_SET_CONTROL_DISPLAY | ((DCS_CONTROL_DISPLAY_BRIGHTNESS_CTRL | DCS_CONTROL_DISPLAY_DIMMING_CTRL) << 8), 0);\n\n\t\t// Unlock Level 2 registers.\n\t\tDSI(DSI_WR_DATA) = 0x539;      // MIPI_DSI_DCS_LONG_WRITE: 5 bytes.\n\t\tDSI(DSI_WR_DATA) = 0x5A5A5AE2; // MIPI_DCS_PRIV_SM_SET_REGS_LOCK: Unlock Level 2 registers.\n\t\tDSI(DSI_WR_DATA) = 0x5A;\n\t\tDSI(DSI_TRIGGER) = DSI_TRIGGER_HOST;\n\n\t\t// Set registers offset and set PWM transition to 6 frames (100ms).\n\t\t_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE_PARAM, MIPI_DCS_PRIV_SM_SET_REG_OFFSET | (7 << 8), 0);\n\t\t_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE_PARAM, MIPI_DCS_PRIV_SM_SET_ELVSS      | (6 << 8), 0);\n\n\t\t// Relock Level 2 registers.\n\t\tDSI(DSI_WR_DATA) = 0x539;      // MIPI_DSI_DCS_LONG_WRITE: 5 bytes.\n\t\tDSI(DSI_WR_DATA) = 0xA55A5AE2; // MIPI_DCS_PRIV_SM_SET_REGS_LOCK: Lock Level 2 registers.\n\t\tDSI(DSI_WR_DATA) = 0xA5;\n\t\tDSI(DSI_TRIGGER) = DSI_TRIGGER_HOST;\n\n\t\t// Set backlight to 0%.\n\t\tDSI(DSI_WR_DATA) = 0x339;    // MIPI_DSI_DCS_LONG_WRITE: 3 bytes.\n\t\tDSI(DSI_WR_DATA) = 0x000051; // MIPI_DCS_SET_BRIGHTNESS 0000: 0%. FF07: 100%.\n\t\tDSI(DSI_TRIGGER) = DSI_TRIGGER_HOST;\n\t\tusleep(5000);\n\t\tbreak;\n\n\tcase PANEL_JDI_XXX062M:\n\t\treg_write_array((vu32 *)DSI_BASE, _di_dsi_panel_init_config_jdi, ARRAY_SIZE(_di_dsi_panel_init_config_jdi));\n\t\t_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000);\n\t\tbreak;\n\n\tcase PANEL_INL_P062CCA_AZ1:\n\tcase PANEL_AUO_A062TAN01:\n\t\t_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 180000);\n\n\t\t// Unlock extension cmds.\n\t\tDSI(DSI_WR_DATA) = 0x439;          // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.\n\t\tDSI(DSI_WR_DATA) = 0x9483FFB9;     // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94).\n\t\tDSI(DSI_TRIGGER) = DSI_TRIGGER_HOST;\n\t\tusleep(5000);\n\n\t\t// Set Power control.\n\t\tDSI(DSI_WR_DATA) = 0x739;          // MIPI_DSI_DCS_LONG_WRITE: 7 bytes.\n\t\tif (_panel_id == PANEL_INL_P062CCA_AZ1)\n\t\t\tDSI(DSI_WR_DATA) = 0x751548B1; // MIPI_DCS_PRIV_SET_POWER_CONTROL. (Not deep standby, BT5 / XDK, VRH gamma volt adj 53 / x40).\n\t\telse // PANEL_AUO_A062TAN01.\n\t\t\tDSI(DSI_WR_DATA) = 0x711148B1; // MIPI_DCS_PRIV_SET_POWER_CONTROL. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40).\n\t\tDSI(DSI_WR_DATA) = 0x143209;       // (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/32).\n\t\tDSI(DSI_TRIGGER) = DSI_TRIGGER_HOST;\n\t\tusleep(5000);\n\t\tbreak;\n\n\tcase PANEL_INL_2J055IA_27A:\n\tcase PANEL_AUO_A055TAN01:\n\tcase PANEL_SHP_LQ055T1SW10:\n\tdefault: // Allow spare part displays to work.\n\t\t_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_EXIT_SLEEP_MODE, 120000);\n\t\tbreak;\n\t}\n\n\t// Unblank display.\n\t_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_SET_DISPLAY_ON, 20000);\n\n\t// Switch to DSI HS mode.\n\t// DIVM: 1, DIVN: 24, DIVP: 1. PLLD_OUT: 468.0 MHz, PLLD_OUT0 (DSI-BCLK): 234.0 MHz. (PCLK: 78 MHz)\n\tclock_enable_plld(1, 24, false, tegra_t210);\n\n\t// Set HS PHY timing and finalize DSI packet sequence configuration.\n\treg_write_array((vu32 *)DSI_BASE, _di_dsi_seq_pkt_video_non_burst_no_eot_config, ARRAY_SIZE(_di_dsi_seq_pkt_video_non_burst_no_eot_config));\n\n\t// Set 1-by-1 pixel/clock and pixel clock to 234 / 3 = 78 MHz. For 60 Hz refresh rate.\n\tDISPLAY_A(DC_DISP_DISP_CLOCK_CONTROL) = PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(4); // div3. Default: div4.\n\n\t// Set DSI mode to HOST.\n\treg_write_array((vu32 *)DSI_BASE, _di_dsi_host_mode_config, ARRAY_SIZE(_di_dsi_host_mode_config));\n\tusleep(10000);\n\n\t/*\n\t * Calibrate display communication pads.\n\t * When switching to the 16ff pad brick, the clock lane termination control\n\t * is separated from data lane termination. This change of the mipi cal\n\t * brings in a bug that the DSI pad clock termination code can't be loaded\n\t * in one time calibration on T210B01. Trigger calibration twice.\n\t */\n\treg_write_array((vu32 *)MIPI_CAL_BASE, _di_mipi_pad_cal_config, ARRAY_SIZE(_di_mipi_pad_cal_config));\n\tfor (u32 i = 0; i < 2; i++)\n\t{\n\t\t// Set MIPI bias pad config.\n\t\tMIPI_CAL(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0x10010;\n\t\tMIPI_CAL(MIPI_CAL_MIPI_BIAS_PAD_CFG1) = tegra_t210 ? 0x300 : 0;\n\n\t\t// Set pad trimmers and set MIPI DSI cal offsets.\n\t\tif (tegra_t210)\n\t\t{\n\t\t\treg_write_array((vu32 *)DSI_BASE,      _di_dsi_pad_cal_config_t210,          ARRAY_SIZE(_di_dsi_pad_cal_config_t210));\n\t\t\treg_write_array((vu32 *)MIPI_CAL_BASE, _di_mipi_dsi_cal_prod_config_t210,    ARRAY_SIZE(_di_mipi_dsi_cal_prod_config_t210));\n\t\t}\n\t\telse\n\t\t{\n\t\t\treg_write_array((vu32 *)DSI_BASE,      _di_dsi_pad_cal_config_t210b01,       ARRAY_SIZE(_di_dsi_pad_cal_config_t210b01));\n\t\t\treg_write_array((vu32 *)MIPI_CAL_BASE, _di_mipi_dsi_cal_prod_config_t210b01, ARRAY_SIZE(_di_mipi_dsi_cal_prod_config_t210b01));\n\t\t}\n\n\t\t// Reset all unused MIPI cal offsets.\n\t\treg_write_array((vu32 *)MIPI_CAL_BASE, _di_mipi_dsi_cal_unused_config, ARRAY_SIZE(_di_mipi_dsi_cal_unused_config));\n\n\t\t// Set Prescale/filter and start calibration.\n\t\tMIPI_CAL(MIPI_CAL_MIPI_CAL_CTRL) = 0x2A000001;\n\t}\n\tusleep(10000);\n\n\t// Setup video mode.\n\treg_write_array((vu32 *)DISPLAY_A_BASE, _di_dc_video_mode_config, ARRAY_SIZE(_di_dc_video_mode_config));\n}\n\nvoid display_backlight_pwm_init()\n{\n\tif (_panel_id == PANEL_SAM_AMS699VC01)\n\t\treturn;\n\n\t// Enable PWM clock.\n\tclock_enable_pwm();\n\n\t// Enable PWM and set it to 25KHz PFM. 29.5KHz is stock.\n\tPWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN;\n\n\tPINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_FUNC_MASK) | 1; // Set PWM0 mode.\n\tusleep(2);\n\n\tgpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode.\n}\n\nvoid display_backlight(bool enable)\n{\n\tif (_panel_id == PANEL_SAM_AMS699VC01)\n\t\treturn;\n\n\t// Backlight PWM GPIO.\n\tgpio_write(GPIO_PORT_V, GPIO_PIN_0, enable ? GPIO_HIGH : GPIO_LOW);\n}\n\nstatic void _display_dsi_backlight_brightness(u32 duty)\n{\n\tif (DISPLAY_A(DC_DCS_BACKLIGHT_LEVEL) == duty)\n\t\treturn;\n\n\t// Convert duty to candela.\n\tu32 candela = duty * PANEL_SM_BL_CANDELA_MAX / 255;\n\n\tu16 bl_ctrl = byte_swap_16((u16)candela);\n\tdisplay_dsi_vblank_write(MIPI_DCS_SET_BRIGHTNESS, 2, &bl_ctrl);\n\n\t// Wait for backlight to completely turn off. 6 frames.\n\tif (!duty)\n\t\tusleep(100000);\n\n\tDISPLAY_A(DC_DCS_BACKLIGHT_LEVEL) = duty;\n}\n\nstatic void _display_pwm_backlight_brightness(u32 duty, u32 step_delay)\n{\n\tu32 old_value = (PWM(PWM_CONTROLLER_PWM_CSR_0) >> 16) & 0xFF;\n\tif (duty == old_value)\n\t\treturn;\n\n\tif (old_value < duty)\n\t{\n\t\tfor (u32 i = old_value; i <= duty; i++)\n\t\t{\n\t\t\tPWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16);\n\t\t\tusleep(step_delay);\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (int i = old_value; i >= (int)duty; i--)\n\t\t{\n\t\t\tPWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16);\n\t\t\tusleep(step_delay);\n\t\t}\n\t}\n}\n\nvoid display_backlight_brightness(u32 brightness, u32 step_delay)\n{\n\tif (brightness > 255)\n\t\tbrightness = 255;\n\n\tif (_panel_id != PANEL_SAM_AMS699VC01)\n\t\t_display_pwm_backlight_brightness(brightness, step_delay);\n\telse\n\t\t_display_dsi_backlight_brightness(brightness);\n}\n\nstatic void _display_panel_and_hw_end(bool no_panel_deinit)\n{\n\tif (no_panel_deinit)\n\t\tgoto skip_panel_deinit;\n\n\tdisplay_backlight_brightness(0, 1000);\n\n\t// Enable host cmd packets during video.\n\tDSI(DSI_VIDEO_MODE_CONTROL) = DSI_CMD_PKT_VID_ENABLE;\n\n\t// Blank display.\n\tDSI(DSI_WR_DATA) = (MIPI_DCS_SET_DISPLAY_OFF << 8) | MIPI_DSI_DCS_SHORT_WRITE;\n\n\t// Wait for 5 frames (HOST1X_CH0_SYNC_SYNCPT_9).\n\t// Not here. Wait for 1 frame + transmission manually.\n\tusleep((_panel_id == PANEL_SAM_AMS699VC01) ? (15933 + 195) : (16666 + 230));\n\n\t// Propagate changes to all register buffers and disable host cmd packets during video.\n\tDISPLAY_A(DC_CMD_STATE_ACCESS) = READ_MUX_ACTIVE | WRITE_MUX_ACTIVE;\n\tDSI(DSI_VIDEO_MODE_CONTROL) = 0;\n\n\t// De-initialize video controller.\n\treg_write_array((vu32 *)DISPLAY_A_BASE, _di_dc_video_disable_config, ARRAY_SIZE(_di_dc_video_disable_config));\n\n\t// Set DISP1 clock source, parent clock and DSI/PCLK to command mode.\n\t// T210:    DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT: 100.0 MHz, PLLD_OUT0 (DSI-BCLK): 50.0 MHz. (PCLK: 16.66 MHz)\n\t// T210B01: DIVM: 1, DIVN: 20, DIVP: 3. PLLD_OUT:  97.8 MHz, PLLD_OUT0 (DSI-BCLK): 48.9 MHz. (PCLK: 16.30 MHz)\n\tclock_enable_plld(3, 20, true, hw_get_chip_id() == GP_HIDREV_MAJOR_T210);\n\n\t// DSI soft reset.\n\t_display_dsi_soft_reset();\n\n\t// Set DSI LP timings.\n\treg_write_array((vu32 *)DSI_BASE, _di_dsi_timing_lp_config, ARRAY_SIZE(_di_dsi_timing_lp_config));\n\n\tif (_panel_id != PANEL_SAM_AMS699VC01)\n\t\tusleep(10000);\n\n\t// De-initialize display panel.\n\tswitch (_panel_id)\n\t{\n\tcase PANEL_JDI_XXX062M:\n\t\treg_write_array((vu32 *)DSI_BASE, _di_dsi_panel_deinit_config_jdi, ARRAY_SIZE(_di_dsi_panel_deinit_config_jdi));\n\t\tbreak;\n\n\tcase PANEL_AUO_A062TAN01:\n\t\treg_write_array((vu32 *)DSI_BASE, _di_dsi_panel_deinit_config_auo, ARRAY_SIZE(_di_dsi_panel_deinit_config_auo));\n\t\tusleep(5000);\n\t\tbreak;\n\n\tcase PANEL_INL_2J055IA_27A:\n\tcase PANEL_AUO_A055TAN01:\n\tcase PANEL_SHP_LQ055T1SW10:\n\t\t// Unlock extension cmds.\n\t\tDSI(DSI_WR_DATA) = 0x439;          // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.\n\t\tDSI(DSI_WR_DATA) = 0x9483FFB9;     // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94).\n\t\tDSI(DSI_TRIGGER) = DSI_TRIGGER_HOST;\n\t\tusleep(5000);\n\n\t\t// Set Power control.\n\t\tDSI(DSI_WR_DATA) = 0xB39;          // MIPI_DSI_DCS_LONG_WRITE: 11 bytes.\n\t\tif (_panel_id == PANEL_INL_2J055IA_27A)\n\t\t\tDSI(DSI_WR_DATA) = 0x751548B1; // MIPI_DCS_PRIV_SET_POWER_CONTROL. (Not deep standby, BT5 / XDK, VRH gamma volt adj 53 / x40).\n\t\telse if (_panel_id == PANEL_AUO_A055TAN01)\n\t\t\tDSI(DSI_WR_DATA) = 0x711148B1; // MIPI_DCS_PRIV_SET_POWER_CONTROL. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40).\n\t\telse // PANEL_SHP_LQ055T1SW10.\n\t\t\tDSI(DSI_WR_DATA) = 0x731348B1; // MIPI_DCS_PRIV_SET_POWER_CONTROL. (Not deep standby, BT3 / XDK, VRH gamma volt adj 51 / x40).\n\t\tif (_panel_id == PANEL_INL_2J055IA_27A || _panel_id == PANEL_AUO_A055TAN01)\n\t\t{\n\t\t\t// (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/32, Enter standby / PON / VCOMG).\n\t\t\tDSI(DSI_WR_DATA) = 0x71143209;\n\t\t\tDSI(DSI_WR_DATA) = 0x114D31;   // (Unknown).\n\t\t}\n\t\telse // PANEL_SHP_LQ055T1SW10.\n\t\t{\n\t\t\t// (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/48, Enter standby / PON / VCOMG).\n\t\t\tDSI(DSI_WR_DATA) = 0x71243209;\n\t\t\tDSI(DSI_WR_DATA) = 0x004C31;   // (Unknown).\n\t\t}\n\t\tDSI(DSI_TRIGGER) = DSI_TRIGGER_HOST;\n\t\tusleep(5000);\n\t\tbreak;\n\n\tcase PANEL_INL_P062CCA_AZ1:\n\tcase PANEL_SAM_AMS699VC01:\n\tdefault:\n\t\tbreak;\n\t}\n\n\t// Blank - powerdown.\n\t_display_dsi_send_cmd(MIPI_DSI_DCS_SHORT_WRITE, MIPI_DCS_ENTER_SLEEP_MODE,\n\t\t(_panel_id == PANEL_SAM_AMS699VC01) ? 120000 : 50000);\n\nskip_panel_deinit:\n\t// Disable Panel Reset.\n\tgpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW);\n\tusleep(10000);\n\n\tif (!_nx_aula) // HOS uses panel id.\n\t{\n\t\t// Disable LCD driver AVDD channels.\n\t\tgpio_write(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_LOW);\n\n\t\t// Make sure LCD driver PWM pin is in PWM0 mode.\n\t\tgpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM.\n\t\tPINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = PINMUX_TRISTATE | PINMUX_PULL_DOWN | 1; // Set PWM0 mode.\n\t}\n\tusleep(10000);\n\n\t// Disable Display Interface specific clocks.\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = BIT(CLK_H_MIPI_CAL) | BIT(CLK_H_DSI);\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = BIT(CLK_H_MIPI_CAL) | BIT(CLK_H_DSI);\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_DISP1);\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = BIT(CLK_L_DISP1);\n\n\t// Power down.\n\tDSI(DSI_PAD_CONTROL_0) = DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) |\n\t\t\t\t\t\t\t DSI_PAD_CONTROL_VS1_PDIO_CLK   | DSI_PAD_CONTROL_VS1_PDIO(0xF);\n\t_display_dsi_soft_reset();\n\n\t// Disable DSI AVDD.\n\tmax7762x_regulator_enable(REGULATOR_LDO0, false);\n}\n\nvoid display_end() { _display_panel_and_hw_end(false); };\n\nu32 display_get_verbose_panel_id()\n{\n\treturn _panel_id_raw;\n}\n\nu16 display_get_decoded_panel_id()\n{\n\treturn _panel_id;\n}\n\nvoid display_set_decoded_panel_id(u32 id)\n{\n\t// Get Hardware type, as it's used in various DI functions.\n\t_nx_aula = fuse_read_hw_type() == FUSE_NX_HW_TYPE_AULA;\n\n\t// Decode Display ID.\n\t_panel_id = ((id >> 8) & 0xFF00) | (id & 0xFF);\n\n\tif ((_panel_id & 0xFF) == PANEL_JDI_XXX062M)\n\t\t_panel_id = PANEL_JDI_XXX062M;\n\n\t// For Aula ensure that we have a compatible panel id.\n\tif (_nx_aula && _panel_id == 0xCCCC)\n\t\t_panel_id = PANEL_SAM_AMS699VC01;\n}\n\nvoid display_color_screen(u32 color)\n{\n\t// Disable all windows.\n\treg_write_array((vu32 *)DISPLAY_A_BASE, _di_win_one_color, ARRAY_SIZE(_di_win_one_color));\n\n\t// Configure display to show single color.\n\tDISPLAY_A(DC_DISP_BLEND_BACKGROUND_COLOR) = color;\n\n\t// Arm and activate changes.\n\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_UPDATE  | WIN_A_UPDATE |  WIN_B_UPDATE  | WIN_C_UPDATE  | WIN_D_UPDATE;\n\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ | WIN_D_ACT_REQ;\n\tusleep(35000); // Wait 2 frames. No need on Aula.\n\n\tif (_panel_id != PANEL_SAM_AMS699VC01)\n\t\tdisplay_backlight(true);\n\telse\n\t\tdisplay_backlight_brightness(150, 0);\n}\n\nu32 *display_init_window_a_pitch()\n{\n\t// Sanitize framebuffer area.\n\tmemset((u32 *)IPL_FB_ADDRESS, 0, IPL_FB_SZ);\n\n\t// This configures the framebuffer @ IPL_FB_ADDRESS with a resolution of 720x1280 (line stride 720).\n\treg_write_array((vu32 *)DISPLAY_A_BASE, _di_winA_pitch, ARRAY_SIZE(_di_winA_pitch));\n\t//usleep(35000); // Wait 2 frames. No need on Aula.\n\n\treturn (u32 *)DISPLAY_A(DC_WINBUF_START_ADDR);\n}\n\nu32 *display_init_window_a_pitch_vic()\n{\n\t// This configures the framebuffer @ NYX_FB_ADDRESS with a resolution of 720x1280 (line stride 720).\n\tif (_panel_id != PANEL_SAM_AMS699VC01)\n\t\tusleep(8000); // Wait half frame for PWM to apply.\n\treg_write_array((vu32 *)DISPLAY_A_BASE, _di_winA_pitch_vic, ARRAY_SIZE(_di_winA_pitch_vic));\n\tif (_panel_id != PANEL_SAM_AMS699VC01)\n\t\tusleep(35000); // Wait 2 frames.\n\n\treturn (u32 *)DISPLAY_A(DC_WINBUF_START_ADDR);\n}\n\nu32 *display_init_window_a_pitch_inv()\n{\n\t// This configures the framebuffer @ NYX_FB_ADDRESS with a resolution of 720x1280 (line stride 720).\n\treg_write_array((vu32 *)DISPLAY_A_BASE, _di_winA_pitch_inv, ARRAY_SIZE(_di_winA_pitch_inv));\n\tusleep(35000); // Wait 2 frames. No need on Aula.\n\n\treturn (u32 *)DISPLAY_A(DC_WINBUF_START_ADDR);\n}\n\nu32 *display_init_window_a_block()\n{\n\t// This configures the framebuffer @ NYX_FB_ADDRESS with a resolution of 720x1280.\n\treg_write_array((vu32 *)DISPLAY_A_BASE, _di_winA_block, ARRAY_SIZE(_di_winA_block));\n\tusleep(35000); // Wait 2 frames. No need on Aula.\n\n\treturn (u32 *)DISPLAY_A(DC_WINBUF_START_ADDR);\n}\n\nu32 *display_init_window_d_console()\n{\n\t// This configures the framebuffer @ LOG_FB_ADDRESS with a resolution of 1280x720 (line stride 720).\n\treg_write_array((vu32 *)DISPLAY_A_BASE, _di_winD_log, ARRAY_SIZE(_di_winD_log));\n\n\treturn (u32 *)DISPLAY_A(DC_WINBUF_START_ADDR);\n}\n\nvoid display_window_disable(u32 window)\n{\n\t// Select window C.\n\tDISPLAY_A(DC_CMD_DISPLAY_WINDOW_HEADER) = BIT(WINDOW_SELECT + window);\n\n\t// Disable window C.\n\tDISPLAY_A(DC_WIN_WIN_OPTIONS) = 0;\n\n\t// Arm and activate changes.\n\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_UPDATE  | BIT(WIN_UPDATE  + window);\n\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_ACT_REQ | BIT(WIN_ACT_REQ + window);\n}\n\nvoid display_set_framebuffer(u32 window, void *fb)\n{\n\t// Select window.\n\tDISPLAY_A(DC_CMD_DISPLAY_WINDOW_HEADER) = BIT(WINDOW_SELECT + window);\n\n\t// Set new fb address.\n\tDISPLAY_A(DC_WINBUF_START_ADDR) = (u32)fb;\n\n\t// Arm and activate changes.\n\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_UPDATE  | BIT(WIN_UPDATE  + window);\n\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_ACT_REQ | BIT(WIN_ACT_REQ + window);\n}\n\nvoid display_move_framebuffer(u32 window, void *fb)\n{\n\t// Select window.\n\tDISPLAY_A(DC_CMD_DISPLAY_WINDOW_HEADER) = BIT(WINDOW_SELECT + window);\n\n\t// Get current framebuffer address.\n\tconst void *fb_curr = (void *)DISPLAY_A(DC_WINBUF_START_ADDR);\n\tu32 win_size = DISPLAY_A(DC_WIN_PRESCALED_SIZE);\n\twin_size = (win_size & 0x7FFF) * ((win_size >> 16) & 0x1FFF);\n\n\t// Copy fb over.\n\tmemcpy(fb, fb_curr, win_size);\n\n\t// Set new fb address.\n\tDISPLAY_A(DC_WINBUF_START_ADDR) = (u32)fb;\n\n\t// Arm and activate changes.\n\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_UPDATE  | BIT(WIN_UPDATE  + window);\n\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_ACT_REQ | BIT(WIN_ACT_REQ + window);\n}\n\nvoid display_window_d_console_enable()\n{\n\t// Only update active registers on vsync.\n\tDISPLAY_A(DC_CMD_REG_ACT_CONTROL) = DISPLAY_A(DC_CMD_REG_ACT_CONTROL) & ~WIN_D_ACT_HCNTR_SEL;\n\n\t// Select window D.\n\tDISPLAY_A(DC_CMD_DISPLAY_WINDOW_HEADER) = WINDOW_D_SELECT;\n\n\t// Enable and setup window D.\n\tDISPLAY_A(DC_WIN_WIN_OPTIONS) = WIN_ENABLE;\n\tDISPLAY_A(DC_WIN_POSITION)    = 0xFF80; // X: -128.\n\n\t// Arm and activate changes.\n\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_UPDATE  | WIN_D_UPDATE;\n\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_ACT_REQ | WIN_D_ACT_REQ;\n\n\t// Pull-down effect.\n\tfor (u32 i = 0xFF80; i < 0x10000; i++)\n\t{\n\t\t// Set window position.\n\t\tDISPLAY_A(DC_WIN_POSITION) = i & 0xFFFF;\n\n\t\t// Arm and activate changes.\n\t\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_UPDATE  | WIN_D_UPDATE;\n\t\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_ACT_REQ | WIN_D_ACT_REQ;\n\t\tusleep(1000);\n\t}\n\n\tDISPLAY_A(DC_WIN_POSITION) = 0;\n\n\t// Arm and activate changes.\n\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_UPDATE  | WIN_D_UPDATE;\n\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_ACT_REQ | WIN_D_ACT_REQ;\n}\n\nvoid display_window_d_console_disable()\n{\n\t// Select window D.\n\tDISPLAY_A(DC_CMD_DISPLAY_WINDOW_HEADER) = WINDOW_D_SELECT;\n\n\t// Pull-up effect.\n\tfor (u32 i = 0xFFFF; i > 0xFF7F; i--)\n\t{\n\t\t// Set window position.\n\t\tDISPLAY_A(DC_WIN_POSITION) = i & 0xFFFF;\n\n\t\t// Arm and activate changes.\n\t\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_UPDATE  | WIN_D_UPDATE;\n\t\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_ACT_REQ | WIN_D_ACT_REQ;\n\t\tusleep(500);\n\t}\n\n\t// Disable window D.\n\tDISPLAY_A(DC_WIN_POSITION)    = 0;\n\tDISPLAY_A(DC_WIN_WIN_OPTIONS) = 0;\n\n\t// Arm and activate changes.\n\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_UPDATE  | WIN_D_UPDATE;\n\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_ACT_REQ | WIN_D_ACT_REQ;\n}\n\nvoid display_cursor_init(void *crs_fb, u32 size)\n{\n\t// Setup cursor.\n\tDISPLAY_A(DC_DISP_CURSOR_START_ADDR)    = CURSOR_CLIPPING(CURSOR_CLIP_WIN_A) | size | ((u32)crs_fb >> 10);\n\tDISPLAY_A(DC_DISP_BLEND_CURSOR_CONTROL) = CURSOR_BLEND_R8G8B8A8                    |\n\t\t\t\t\t\t\t\t\t\t\t  CURSOR_BLEND_DST_FACTOR(CURSOR_BLEND_K1) |\n\t\t\t\t\t\t\t\t\t\t\t  CURSOR_BLEND_SRC_FACTOR(CURSOR_BLEND_K1) | 0xFF;\n\n\t// Enable cursor window.\n\tDISPLAY_A(DC_DISP_DISP_WIN_OPTIONS) |= CURSOR_ENABLE;\n\n\t// Arm and activate changes.\n\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_UPDATE  | CURSOR_UPDATE;\n\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_ACT_REQ | CURSOR_ACT_REQ;\n}\n\nvoid display_cursor_set_pos(u32 x, u32 y)\n{\n\t// Set cursor position.\n\tDISPLAY_A(DC_DISP_CURSOR_POSITION) = x | (y << 16);\n\n\t// Arm and activate changes.\n\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_UPDATE  | CURSOR_UPDATE;\n\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_ACT_REQ | CURSOR_ACT_REQ;\n}\n\nvoid display_cursor_deinit()\n{\n\tDISPLAY_A(DC_DISP_BLEND_CURSOR_CONTROL) = 0;\n\tDISPLAY_A(DC_DISP_DISP_WIN_OPTIONS) &= ~CURSOR_ENABLE;\n\n\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_UPDATE  | CURSOR_UPDATE;\n\tDISPLAY_A(DC_CMD_STATE_CONTROL) = GENERAL_ACT_REQ | CURSOR_ACT_REQ;\n}\n"
  },
  {
    "path": "bdk/display/di.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _DI_H_\n#define _DI_H_\n\n#include <memory_map.h>\n#include <utils/types.h>\n\n#define DSI_VIDEO_DISABLED 0\n#define DSI_VIDEO_ENABLED  1\n\n#define WINDOW_A 0\n#define WINDOW_B 1\n#define WINDOW_C 2\n#define WINDOW_D 3\n\n/*! Display registers. */\n// All Display/DSI/MIPI register defines and macros are index based (not offset).\n// DC_CMD/DC_COM/WINC Non-shadowed. DC_DISP/DC_WIN/DC_WINBUF Shadowed.\n\n// Display controller scratch registers.\n#define DC_D_WINBUF_DD_SCRATCH_REGISTER_0 0xED\n#define DC_D_WINBUF_DD_SCRATCH_REGISTER_1 0xEE\n#define DC_T_WINBUF_TD_SCRATCH_REGISTER_0 0x16D\n#define DC_T_WINBUF_TD_SCRATCH_REGISTER_1 0x16E\n#define DC_COM_SCRATCH_REGISTER_A         0x325\n#define DC_COM_SCRATCH_REGISTER_B         0x326\n#define DC_A_WINBUF_AD_SCRATCH_REGISTER_0 0xBED\n#define DC_A_WINBUF_AD_SCRATCH_REGISTER_1 0xBEE\n#define DC_B_WINBUF_BD_SCRATCH_REGISTER_0 0xDED\n#define DC_B_WINBUF_BD_SCRATCH_REGISTER_1 0xDEE\n#define DC_C_WINBUF_CD_SCRATCH_REGISTER_0 0xFED\n#define DC_C_WINBUF_CD_SCRATCH_REGISTER_1 0xFEE\n\n// DC_CMD non-shadowed command/sync registers.\n#define DC_CMD_GENERAL_INCR_SYNCPT 0x00\n#define  SYNCPT_GENERAL_INDX(x) (((x) & 0xFF) << 0)\n#define  SYNCPT_GENERAL_COND(x) (((x) & 0xFF) << 8)\n#define  COND_REG_WR_SAFE 3\n\n#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x01\n#define  SYNCPT_CNTRL_SOFT_RESET BIT(0)\n#define  SYNCPT_CNTRL_NO_STALL   BIT(8)\n\n#define DC_CMD_CONT_SYNCPT_VSYNC 0x28\n#define  SYNCPT_VSYNC_INDX(x) (((x) & 0xFF) << 0)\n#define  SYNCPT_VSYNC_ENABLE  BIT(8)\n\n#define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031\n\n#define DC_CMD_DISPLAY_COMMAND 0x32\n#define  DISP_CTRL_MODE_STOP       (0 << 5)\n#define  DISP_CTRL_MODE_C_DISPLAY  (1 << 5)\n#define  DISP_CTRL_MODE_NC_DISPLAY (2 << 5)\n#define  DISP_CTRL_MODE_MASK       (3 << 5)\n\n#define DC_CMD_DISPLAY_POWER_CONTROL 0x36\n#define  PW0_ENABLE BIT(0)\n#define  PW1_ENABLE BIT(2)\n#define  PW2_ENABLE BIT(4)\n#define  PW3_ENABLE BIT(6)\n#define  PW4_ENABLE BIT(8)\n#define  PM0_ENABLE BIT(16)\n#define  PM1_ENABLE BIT(18)\n\n#define DC_CMD_INT_STATUS 0x37\n#define DC_CMD_INT_MASK 0x38\n#define DC_CMD_INT_ENABLE 0x39\n#define  DC_CMD_INT_FRAME_END_INT BIT(1)\n#define  DC_CMD_INT_V_BLANK_INT   BIT(2)\n#define DC_CMD_INT_POLARITY 0x3B\n\n#define DC_CMD_STATE_ACCESS 0x40\n#define  READ_MUX_ASSEMBLY  0x0\n#define  WRITE_MUX_ASSEMBLY 0x0\n#define  READ_MUX_ACTIVE    BIT(0)\n#define  WRITE_MUX_ACTIVE   BIT(2)\n\n#define DC_CMD_STATE_CONTROL 0x41\n#define  GENERAL_ACT_REQ BIT(0)\n#define  WIN_ACT_REQ     1\n#define  WIN_A_ACT_REQ   BIT(1)\n#define  WIN_B_ACT_REQ   BIT(2)\n#define  WIN_C_ACT_REQ   BIT(3)\n#define  WIN_D_ACT_REQ   BIT(4)\n#define  CURSOR_ACT_REQ  BIT(7)\n#define  GENERAL_UPDATE  BIT(8)\n#define  WIN_UPDATE      9\n#define  WIN_A_UPDATE    BIT(9)\n#define  WIN_B_UPDATE    BIT(10)\n#define  WIN_C_UPDATE    BIT(11)\n#define  WIN_D_UPDATE    BIT(12)\n#define  CURSOR_UPDATE   BIT(15)\n#define  NC_HOST_TRIG    BIT(24)\n\n#define DC_CMD_DISPLAY_WINDOW_HEADER 0x42\n#define  WINDOW_SELECT   4\n#define  WINDOW_A_SELECT BIT(4)\n#define  WINDOW_B_SELECT BIT(5)\n#define  WINDOW_C_SELECT BIT(6)\n#define  WINDOW_D_SELECT BIT(7)\n\n#define DC_CMD_REG_ACT_CONTROL 0x43\n#define  GENERAL_ACT_HCNTR_SEL BIT(0)\n#define  WIN_A_ACT_HCNTR_SEL   BIT(2)\n#define  WIN_B_ACT_HCNTR_SEL   BIT(4)\n#define  WIN_C_ACT_HCNTR_SEL   BIT(6)\n#define  CURSOR_ACT_HCNTR_SEL  BIT(7)\n#define  WIN_D_ACT_HCNTR_SEL   BIT(10)\n\n// DC_D_WIN_DD window D instance of DC_WIN\n#define DC_D_WIN_DD_WIN_OPTIONS 0x80\n#define DC_D_WIN_DD_COLOR_DEPTH 0x83\n#define DC_D_WIN_DD_POSITION    0x84\n#define DC_D_WIN_DD_SIZE        0x85\n#define DC_D_WIN_DD_LINE_STRIDE 0x8A\n#define DC_D_WIN_DD_BLEND_LAYER_CONTROL 0x96\n#define DC_D_WIN_DD_BLEND_MATCH_SELECT  0x97\n#define DC_D_WIN_DD_BLEND_ALPHA_1BIT    0x99\n\n// DC_D_WINBUF_DD window D instance of DC_WINBUF\n#define DC_D_WINBUF_DD_START_ADDR    0xC0\n#define DC_D_WINBUF_DD_ADDR_H_OFFSET 0xC6\n#define DC_D_WINBUF_DD_ADDR_V_OFFSET 0xC8\n#define DC_D_WINBUF_DD_START_ADDR_HI 0xCD\n#define DC_D_WINBUF_DD_MEMFETCH_CONTROL 0xEB\n\n// DC_T_WIN_TD macro for using DD defines.\n#define _DC_T(reg) ((reg) + 0x80)\n\n// DC_COM non-shadowed registers.\n#define DC_COM_CRC_CONTROL 0x300\n#define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x))\n#define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x))\n#define  LSC0_OUTPUT_POLARITY_LOW BIT(24)\n\n// CMU registers.\n#define DC_COM_CMU_CSC_KRR    0x32A\n#define DC_COM_CMU_CSC_KGR    0x32B\n#define DC_COM_CMU_CSC_KBR    0x32C\n#define DC_COM_CMU_CSC_KRG    0x32D\n#define DC_COM_CMU_CSC_KGG    0x32E\n#define DC_COM_CMU_CSC_KBG    0x32F\n#define DC_COM_CMU_CSC_KRB    0x330\n#define DC_COM_CMU_CSC_KGB    0x331\n#define DC_COM_CMU_CSC_KBB    0x332\n#define DC_COM_CMU_LUT1       0x336\n#define  LUT1_ADDR(x)      ((x) & 0xFF)\n#define  LUT1_DATA(x)      (((x) & 0xFFF) << 16)\n#define  LUT1_READ_DATA(x) (((x) >> 16) & 0xFFF)\n#define DC_COM_CMU_LUT2       0x337\n#define  LUT2_ADDR(x)      ((x) & 0x3FF)\n#define  LUT2_DATA(x)      (((x) & 0xFF) << 16)\n#define  LUT2_READ_DATA(x) (((x) >> 16) & 0xFF)\n#define DC_COM_CMU_LUT1_READ  0x338\n#define  LUT1_READ_ADDR(x) (((x) & 0xFF) << 8)\n#define  LUT1_READ_EN      BIT(0)\n#define DC_COM_CMU_LUT2_READ  0x339\n#define  LUT2_READ_ADDR(x) (((x) & 0x3FF) << 8)\n#define  LUT2_READ_EN      BIT(0)\n\n#define DC_COM_DSC_TOP_CTL 0x33E\n\n// DC_DISP shadowed registers.\n#define DC_DISP_DISP_WIN_OPTIONS 0x402\n#define  CURSOR_ENABLE   BIT(16)\n#define  SOR_ENABLE      BIT(25)\n#define  SOR1_ENABLE     BIT(26)\n#define  SOR1_TIMING_CYA BIT(27)\n#define  DSI_ENABLE      BIT(29)\n#define  HDMI_ENABLE     BIT(30)\n\n\n#define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403\n#define DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER 0x404\n\n#define DC_DISP_DISP_TIMING_OPTIONS 0x405\n#define  VSYNC_H_POSITION(x) (((x) & 0x1FFF) << 0)\n\n#define DC_DISP_REF_TO_SYNC 0x406\n#define  H_REF_TO_SYNC(x) (((x) & 0x1FFF) <<  0) // Min 0 pixel clock.\n#define  V_REF_TO_SYNC(x) (((x) & 0x1FFF) << 16) // Min 1 line  clock.\n\n#define DC_DISP_SYNC_WIDTH 0x407\n#define  H_SYNC_WIDTH(x) (((x) & 0x1FFF) <<  0) // Min 1 pixel clock.\n#define  V_SYNC_WIDTH(x) (((x) & 0x1FFF) << 16) // Min 1 line  clock.\n\n#define DC_DISP_BACK_PORCH 0x408\n#define  H_BACK_PORCH(x) (((x) & 0x1FFF) <<  0)\n#define  V_BACK_PORCH(x) (((x) & 0x1FFF) << 16)\n\n#define DC_DISP_ACTIVE 0x409\n#define  H_DISP_ACTIVE(x) (((x) & 0x1FFF) <<  0) // Min 16 pixel clock.\n#define  V_DISP_ACTIVE(x) (((x) & 0x1FFF) << 16) // Min 16 line  clock.\n\n#define DC_DISP_FRONT_PORCH 0x40A\n#define  H_FRONT_PORCH(x) (((x) & 0x1FFF) <<  0) // Min -=PS_=-H_REF_TO_SYNC + 1\n#define  V_FRONT_PORCH(x) (((x) & 0x1FFF) << 16) // Min -=PS_=-V_REF_TO_SYNC + 1\n\n#define DC_DISP_DISP_CLOCK_CONTROL 0x42E\n#define  SHIFT_CLK_DIVIDER(x)    ((x) & 0xFF)\n#define  PIXEL_CLK_DIVIDER_PCD1  (0 << 8)\n#define  PIXEL_CLK_DIVIDER_PCD1H (1 << 8)\n#define  PIXEL_CLK_DIVIDER_PCD2  (2 << 8)\n#define  PIXEL_CLK_DIVIDER_PCD3  (3 << 8)\n#define  PIXEL_CLK_DIVIDER_PCD4  (4 << 8)\n#define  PIXEL_CLK_DIVIDER_PCD6  (5 << 8)\n#define  PIXEL_CLK_DIVIDER_PCD8  (6 << 8)\n#define  PIXEL_CLK_DIVIDER_PCD9  (7 << 8)\n#define  PIXEL_CLK_DIVIDER_PCD12 (8 << 8)\n#define  PIXEL_CLK_DIVIDER_PCD16 (9 << 8)\n#define  PIXEL_CLK_DIVIDER_PCD18 (10 << 8)\n#define  PIXEL_CLK_DIVIDER_PCD24 (11 << 8)\n#define  PIXEL_CLK_DIVIDER_PCD13 (12 << 8)\n\n#define DC_DISP_DISP_INTERFACE_CONTROL 0x42F\n#define  DISP_DATA_FORMAT_DF1P1C    (0 << 0)\n#define  DISP_DATA_FORMAT_DF1P2C24B (1 << 0)\n#define  DISP_DATA_FORMAT_DF1P2C18B (2 << 0)\n#define  DISP_DATA_FORMAT_DF1P2C16B (3 << 0)\n#define  DISP_DATA_FORMAT_DF2S      (4 << 0)\n#define  DISP_DATA_FORMAT_DF3S      (5 << 0)\n#define  DISP_DATA_FORMAT_DFSPI     (6 << 0)\n#define  DISP_DATA_FORMAT_DF1P3C24B (7 << 0)\n#define  DISP_DATA_FORMAT_DF1P3C18B (8 << 0)\n#define  DISP_ALIGNMENT_MSB         (0 << 8)\n#define  DISP_ALIGNMENT_LSB         (1 << 8)\n#define  DISP_ORDER_RED_BLUE        (0 << 9)\n#define  DISP_ORDER_BLUE_RED        (1 << 9)\n\n#define DC_DISP_DISP_COLOR_CONTROL 0x430\n#define  BASE_COLOR_SIZE_MASK   (0xF << 0)\n#define  BASE_COLOR_SIZE_666    (0 << 0)\n#define  BASE_COLOR_SIZE_111    (1 << 0)\n#define  BASE_COLOR_SIZE_222    (2 << 0)\n#define  BASE_COLOR_SIZE_333    (3 << 0)\n#define  BASE_COLOR_SIZE_444    (4 << 0)\n#define  BASE_COLOR_SIZE_555    (5 << 0)\n#define  BASE_COLOR_SIZE_565    (6 << 0)\n#define  BASE_COLOR_SIZE_332    (7 << 0)\n#define  BASE_COLOR_SIZE_888    (8 << 0)\n#define  DITHER_CONTROL_MASK    (3 << 8)\n#define  DITHER_CONTROL_DISABLE (0 << 8)\n#define  DITHER_CONTROL_ORDERED (2 << 8)\n#define  DITHER_CONTROL_ERRDIFF (3 << 8)\n#define  DISP_COLOR_SWAP        BIT(16)\n#define  BLANK_COLOR_WHITE      BIT(17)\n#define  CMU_ENABLE             BIT(20)\n\n#define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431\n#define  SC0_H_QUALIFIER_NONE\tBIT(0)\n#define  SC1_H_QUALIFIER_NONE\tBIT(16)\n\n#define DC_DISP_DATA_ENABLE_OPTIONS 0x432\n#define  DE_SELECT_ACTIVE_BLANK  (0 << 0)\n#define  DE_SELECT_ACTIVE        (1 << 0)\n#define  DE_SELECT_ACTIVE_IS     (2 << 0)\n#define  DE_CONTROL_ONECLK       (0 << 2)\n#define  DE_CONTROL_NORMAL       (1 << 2)\n#define  DE_CONTROL_EARLY_EXT    (2 << 2)\n#define  DE_CONTROL_EARLY        (3 << 2)\n#define  DE_CONTROL_ACTIVE_BLANK (4 << 2)\n\n// Cursor configuration registers.\n#define DC_DISP_CURSOR_FOREGROUND    0x43C\n#define DC_DISP_CURSOR_BACKGROUND    0x43D\n#define  CURSOR_COLOR(r,g,b) (((r) & 0xFF) | (((g) & 0xFF) << 8) | (((b) & 0xFF) << 16))\n\n#define DC_DISP_CURSOR_START_ADDR       0x43E\n#define DC_DISP_CURSOR_START_ADDR_NS    0x43F\n#define  CURSOR_CLIPPING(w) ((w) << 28)\n#define   CURSOR_CLIP_WIN_A 1\n#define   CURSOR_CLIP_WIN_B 2\n#define   CURSOR_CLIP_WIN_C 3\n#define  CURSOR_SIZE_32  (0 << 24)\n#define  CURSOR_SIZE_64  (1 << 24)\n#define  CURSOR_SIZE_128 (2 << 24)\n#define  CURSOR_SIZE_256 (3 << 24)\n#define DC_DISP_CURSOR_POSITION         0x440\n#define DC_DISP_CURSOR_START_ADDR_HI    0x4EC\n#define DC_DISP_CURSOR_START_ADDR_HI_NS 0x4ED\n#define DC_DISP_BLEND_CURSOR_CONTROL    0x4F1\n#define  CURSOR_BLEND_2BIT     (0 << 24)\n#define  CURSOR_BLEND_R8G8B8A8 (1 << 24)\n#define  CURSOR_BLEND_SRC_FACTOR(n) ((n) << 8)\n#define  CURSOR_BLEND_DST_FACTOR(n) ((n) << 16)\n#define   CURSOR_BLEND_ZRO 0\n#define   CURSOR_BLEND_K1  1\n#define   CURSOR_BLEND_NK1 2\n// End of cursor cfg regs.\n\n#define DC_DISP_DC_MCCIF_FIFOCTRL      0x480\n#define DC_DISP_SD_BL_PARAMETERS       0x4D7\n#define DC_DISP_SD_BL_CONTROL          0x4DC\n#define DC_DISP_BLEND_BACKGROUND_COLOR 0x4E4\n\n#define DC_DISP_DISPLAY_SPARE0         0x4F7 // Used by SW/HW.\n#define DC_DISP_DISPLAY_SPARE1         0x4F8\n\n#define DC_WINC_COLOR_PALETTE 0x500\n#define  COLOR_PALETTE_IDX(off) (DC_WINC_COLOR_PALETTE + (off))\n#define  COLOR_PALETTE_RGB(rgb) (byte_swap_32(rgb) >> 8)\n#define DC_WINC_PALETTE_COLOR_EXT 0x600\n\n#define DC_WINC_H_FILTER_P(p) (0x601 + (p))\n#define DC_WINC_V_FILTER_P(p) (0x619 + (p))\n#define DC_WINC_H_FILTER_HI_P(p) (0x629 + (p))\n\n#define DC_WINC_CSC_YOF 0x611\n#define DC_WINC_CSC_KYRGB 0x612\n#define DC_WINC_CSC_KUR 0x613\n#define DC_WINC_CSC_KVR 0x614\n#define DC_WINC_CSC_KUG 0x615\n#define DC_WINC_CSC_KVG 0x616\n#define DC_WINC_CSC_KUB 0x617\n#define DC_WINC_CSC_KVB 0x618\n#define DC_WIN_AD_WIN_OPTIONS 0xB80\n#define DC_WIN_BD_WIN_OPTIONS 0xD80\n#define DC_WIN_CD_WIN_OPTIONS 0xF80\n\n// The following registers are A/B/C shadows of the 0xB80/0xD80/0xF80 registers (see DISPLAY_WINDOW_HEADER).\n#define DC_WIN_WIN_OPTIONS 0x700\n#define  H_DIRECTION          BIT(0)\n#define  V_DIRECTION          BIT(2)\n#define  SCAN_COLUMN          BIT(4)\n#define  COLOR_EXPAND         BIT(6)\n#define  H_FILTER_ENABLE      BIT(8)\n#define  V_FILTER_ENABLE      BIT(10)\n#define  COLOR_PALETTE_ENABLE BIT(16)\n#define  CSC_ENABLE           BIT(18)\n#define  DV_ENABLE            BIT(20)\n#define  WIN_ENABLE           BIT(30)\n#define  H_FILTER_EXPAND      BIT(31)\n\n#define DC_WIN_BUFFER_CONTROL 0x702\n#define  BUFFER_CONTROL_HOST  0\n#define  BUFFER_CONTROL_VI    1\n#define  BUFFER_CONTROL_SB2D  4\n\n#define DC_WIN_COLOR_DEPTH 0x703\n#define  WIN_COLOR_DEPTH_P1             0x0\n#define  WIN_COLOR_DEPTH_P2             0x1\n#define  WIN_COLOR_DEPTH_P4             0x2\n#define  WIN_COLOR_DEPTH_P8             0x3\n#define  WIN_COLOR_DEPTH_B4G4R4A4       0x4\n#define  WIN_COLOR_DEPTH_B5G5R5A        0x5\n#define  WIN_COLOR_DEPTH_B5G6R5         0x6\n#define  WIN_COLOR_DEPTH_AB5G5R5        0x7\n#define  WIN_COLOR_DEPTH_B8G8R8A8       0xC\n#define  WIN_COLOR_DEPTH_R8G8B8A8       0xD\n#define  WIN_COLOR_DEPTH_B6x2G6x2R6x2A8 0xE\n#define  WIN_COLOR_DEPTH_R6x2G6x2B6x2A8 0xF\n#define  WIN_COLOR_DEPTH_YCbCr422       0x10\n#define  WIN_COLOR_DEPTH_YUV422         0x11\n#define  WIN_COLOR_DEPTH_YCbCr420P      0x12\n#define  WIN_COLOR_DEPTH_YUV420P        0x13\n#define  WIN_COLOR_DEPTH_YCbCr422P      0x14\n#define  WIN_COLOR_DEPTH_YUV422P        0x15\n#define  WIN_COLOR_DEPTH_YCbCr422R      0x16\n#define  WIN_COLOR_DEPTH_YUV422R        0x17\n#define  WIN_COLOR_DEPTH_YCbCr422RA     0x18\n#define  WIN_COLOR_DEPTH_YUV422RA       0x19\n#define  WIN_COLOR_DEPTH_X1R5G5B5       0x1E\n#define  WIN_COLOR_DEPTH_R5G5B5X1       0x1F\n#define  WIN_COLOR_DEPTH_X1B5G5R5       0x20\n#define  WIN_COLOR_DEPTH_B5G5R5X1       0x21\n#define  WIN_COLOR_DEPTH_YCbCr444P      0x29\n#define  WIN_COLOR_DEPTH_YCrCb420SP     0x2A\n#define  WIN_COLOR_DEPTH_YCbCr420SP     0x2B\n#define  WIN_COLOR_DEPTH_YCrCb422SP     0x2C\n#define  WIN_COLOR_DEPTH_YCbCr422SP     0x2D\n#define  WIN_COLOR_DEPTH_YUV444P        0x34\n#define  WIN_COLOR_DEPTH_YVU420SP       0x35\n#define  WIN_COLOR_DEPTH_YUV420SP       0x36\n#define  WIN_COLOR_DEPTH_YVU422SP       0x37\n#define  WIN_COLOR_DEPTH_YUV422SP       0x38\n#define  WIN_COLOR_DEPTH_YVU444SP       0x3B\n#define  WIN_COLOR_DEPTH_YUV444SP       0x3C\n\n#define DC_WIN_POSITION 0x704\n#define  H_POSITION(x) (((x) & 0xFFFF) <<  0) // Support negative.\n#define  V_POSITION(x) (((x) & 0xFFFF) << 16) // Support negative.\n\n#define DC_WIN_SIZE 0x705\n#define  H_SIZE(x) (((x) & 0x1FFF) <<  0)\n#define  V_SIZE(x) (((x) & 0x1FFF) << 16)\n\n#define DC_WIN_PRESCALED_SIZE 0x706\n#define  H_PRESCALED_SIZE(x) (((x) & 0x7FFF) <<  0)\n#define  V_PRESCALED_SIZE(x) (((x) & 0x1FFF) << 16)\n\n#define DC_WIN_H_INITIAL_DDA 0x707\n#define DC_WIN_V_INITIAL_DDA 0x708\n\n#define DC_WIN_DDA_INC 0x709\n#define  H_DDA_INC(x) (((x) & 0xFFFF) <<  0)\n#define  V_DDA_INC(x) (((x) & 0xFFFF) << 16)\n\n#define DC_WIN_LINE_STRIDE 0x70A\n#define  LINE_STRIDE(x)\t   (x)\n#define  UV_LINE_STRIDE(x) (((x) & 0xFFFF) << 16)\n\n#define DC_WIN_DV_CONTROL 0x70E\n#define DV_CTRL_R(r) (((r) & 7) << 16)\n#define DV_CTRL_G(g) (((g) & 7) << 8)\n#define DV_CTRL_B(b) (((b) & 7) << 0)\n\n#define DC_WINBUF_BLEND_LAYER_CONTROL 0x716\n#define  WIN_BLEND_DEPTH(x) (((x) & 0xFF) << 0)\n#define  WIN_K1(x) (((x) & 0xFF) << 8)\n#define  WIN_K2(x) (((x) & 0xFF) << 16)\n#define  WIN_BLEND_ENABLE (0 << 24)\n#define  WIN_BLEND_BYPASS (1 << 24)\n\n#define DC_WINBUF_BLEND_MATCH_SELECT 0x717\n#define  WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_ZERO             (0 << 0)\n#define  WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_ONE              (1 << 0)\n#define  WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1               (2 << 0)\n#define  WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1_TIMES_DST     (3 << 0)\n#define  WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_NEG_K1_TIMES_DST (4 << 0)\n#define  WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1_TIMES_SRC     (5 << 0)\n\n#define  WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_ZERO             (0 << 4)\n#define  WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_ONE              (1 << 4)\n#define  WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_K1               (2 << 4)\n#define  WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_K2               (3 << 4)\n#define  WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_K1_TIMES_DST     (4 << 4)\n#define  WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1_TIMES_DST (5 << 4)\n#define  WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1_TIMES_SRC (6 << 4)\n#define  WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1           (7 << 4)\n\n#define  WIN_BLEND_FACT_SRC_ALPHA_MATCH_SEL_ZERO             (0 << 8)\n#define  WIN_BLEND_FACT_SRC_ALPHA_MATCH_SEL_K1               (1 << 8)\n#define  WIN_BLEND_FACT_SRC_ALPHA_MATCH_SEL_K2               (2 << 8)\n\n#define  WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_ZERO             (0 << 12)\n#define  WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_ONE              (1 << 12)\n#define  WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_NEG_K1_TIMES_SRC (2 << 12)\n#define  WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_K2               (3 << 12)\n\n#define DC_WINBUF_BLEND_ALPHA_1BIT 0x719\n#define  WIN_ALPHA_1BIT_WEIGHT0(x) (((x) & 0xFF) << 0)\n#define  WIN_ALPHA_1BIT_WEIGHT1(x) (((x) & 0xFF) << 8)\n\n/*! The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). */\n#define DC_WINBUF_START_ADDR 0x800\n#define DC_WINBUF_ADDR_H_OFFSET 0x806\n#define DC_WINBUF_ADDR_V_OFFSET 0x808\n#define DC_WINBUF_SURFACE_KIND 0x80B\n#define  PITCH\t(0 << 0)\n#define  TILED\t(1 << 0)\n#define  BLOCK\t(2 << 0)\n#define  BLOCK_HEIGHT(x) (((x) & 0x7) << 4)\n\n#define DC_WINBUF_MEMFETCH_CONTROL 0x82B\n\n/* Scratch register to store DCS backlight level (custom). */\n#define DC_DCS_BACKLIGHT_LEVEL DC_COM_SCRATCH_REGISTER_B\n\n/*! Display serial interface registers. */\n#define DSI_INCR_SYNCPT_CNTRL 0x1\n#define  DSI_INCR_SYNCPT_SOFT_RESET BIT(0)\n#define  DSI_INCR_SYNCPT_NO_STALL   BIT(8)\n\n#define DSI_RD_DATA 0x9\n#define DSI_WR_DATA 0xA\n\n#define DSI_POWER_CONTROL 0xB\n#define  DSI_POWER_CONTROL_ENABLE 1\n\n#define DSI_INT_ENABLE 0xC\n#define DSI_INT_STATUS 0xD\n#define DSI_INT_MASK 0xE\n\n#define DSI_HOST_CONTROL 0xF\n#define  DSI_HOST_CONTROL_ECC          BIT(0)\n#define  DSI_HOST_CONTROL_CS           BIT(1)\n#define  DSI_HOST_CONTROL_PKT_BTA      BIT(2)\n#define  DSI_HOST_CONTROL_IMM_BTA      BIT(3)\n#define  DSI_HOST_CONTROL_FIFO_SEL     BIT(4)\n#define  DSI_HOST_CONTROL_HS           BIT(5)\n#define  DSI_HOST_CONTROL_RAW          BIT(6)\n#define  DSI_HOST_CONTROL_TX_TRIG_MASK (3 << 12)\n#define  DSI_HOST_CONTROL_TX_TRIG_SOL  (0 << 12)\n#define  DSI_HOST_CONTROL_TX_TRIG_FIFO (1 << 12)\n#define  DSI_HOST_CONTROL_TX_TRIG_HOST (2 << 12)\n#define  DSI_HOST_CONTROL_CRC_RESET    BIT(20)\n#define  DSI_HOST_CONTROL_FIFO_RESET   BIT(21)\n\n#define DSI_CONTROL 0x10\n#define  DSI_CONTROL_HOST_ENABLE  BIT(0)\n#define  DSI_CONTROL_VIDEO_ENABLE BIT(1)\n#define  DSI_CONTROL_SOURCE(s)    (((s) & 0x1) <<  2)\n#define  DSI_CONTROL_DCS_ENABLE   BIT(3)\n#define  DSI_CONTROL_LANES(n)     (((n) & 0x3) <<  4)\n#define  DSI_CONTROL_TX_TRIG(x)   (((x) & 0x3) <<  8)\n#define  DSI_CONTROL_FORMAT(f)    (((f) & 0x3) << 12)\n#define  DSI_CONTROL_CHANNEL(c)   (((c) & 0x3) << 16)\n#define  DSI_CONTROL_HS_CLK_CTRL  BIT(20)\n\n#define DSI_SOL_DELAY 0x11\n#define DSI_MAX_THRESHOLD 0x12\n\n#define DSI_TRIGGER 0x13\n#define  DSI_TRIGGER_VIDEO BIT(0)\n#define  DSI_TRIGGER_HOST  BIT(1)\n\n#define DSI_TX_CRC 0x14\n\n#define DSI_STATUS 0x15\n#define  DSI_STATUS_RX_FIFO_SIZE 0x1F\n#define  DSI_STATUS_TX_FIFO_SIZE 0x20 // Actual depth is 64.\n\n#define DSI_INIT_SEQ_CONTROL 0x1A\n#define DSI_INIT_SEQ_DATA_0 0x1B\n#define DSI_INIT_SEQ_DATA_1 0x1C\n#define DSI_INIT_SEQ_DATA_2 0x1D\n#define DSI_INIT_SEQ_DATA_3 0x1E\n#define DSI_PKT_SEQ_0_LO 0x23\n#define DSI_PKT_SEQ_0_HI 0x24\n#define DSI_PKT_SEQ_1_LO 0x25\n#define DSI_PKT_SEQ_1_HI 0x26\n#define DSI_PKT_SEQ_2_LO 0x27\n#define DSI_PKT_SEQ_2_HI 0x28\n#define DSI_PKT_SEQ_3_LO 0x29\n#define DSI_PKT_SEQ_3_HI 0x2A\n#define DSI_PKT_SEQ_4_LO 0x2B\n#define DSI_PKT_SEQ_4_HI 0x2C\n#define DSI_PKT_SEQ_5_LO 0x2D\n#define DSI_PKT_SEQ_5_HI 0x2E\n#define DSI_DCS_CMDS 0x33\n\n#define DSI_PKT_LEN_0_1 0x34\n#define DSI_PKT_LEN_2_3 0x35\n#define DSI_PKT_LEN_4_5 0x36\n#define DSI_PKT_LEN_6_7 0x37\n#define  PKT0_LEN(x) (((x) & 0xFFFF) <<  0)\n#define  PKT1_LEN(x) (((x) & 0xFFFF) << 16)\n\n#define DSI_PHY_TIMING_0 0x3C\n#define DSI_PHY_TIMING_1 0x3D\n#define DSI_PHY_TIMING_2 0x3E\n#define DSI_BTA_TIMING 0x3F\n\n#define DSI_TIMEOUT_0 0x44\n#define  DSI_TIMEOUT_HTX(x) (((x) & 0xFFFF) <<  0)\n#define  DSI_TIMEOUT_LRX(x) (((x) & 0xFFFF) << 16)\n\n#define DSI_TIMEOUT_1 0x45\n#define  DSI_TIMEOUT_TA(x) (((x) & 0xFFFF) <<  0)\n#define  DSI_TIMEOUT_PR(x) (((x) & 0xFFFF) << 16)\n\n#define DSI_TO_TALLY 0x46\n\n#define DSI_PAD_CONTROL_0 0x4B\n#define  DSI_PAD_CONTROL_VS1_PDIO_CLK   BIT(8)\n#define  DSI_PAD_CONTROL_VS1_PDIO(x)    (((x) & 0xF) <<  0)\n#define  DSI_PAD_CONTROL_VS1_PULLDN_CLK BIT(24)\n#define  DSI_PAD_CONTROL_VS1_PULLDN(x)  (((x) & 0xF) << 16)\n\n#define DSI_PAD_CONTROL_CD 0x4C\n#define DSI_VIDEO_MODE_CONTROL 0x4E\n#define  DSI_CMD_PKT_VID_ENABLE 1\n#define  DSI_DSI_LINE_TYPE(x) ((x) << 1)\n\n#define DSI_PAD_CONTROL_1 0x4F\n#define DSI_PAD_CONTROL_2 0x50\n\n#define DSI_PAD_CONTROL_3 0x51\n#define  DSI_PAD_PREEMP_PU(x)     (((x) & 0x3) << 0)\n#define  DSI_PAD_PREEMP_PD(x)     (((x) & 0x3) << 4)\n#define  DSI_PAD_PREEMP_PU_CLK(x) (((x) & 0x3) << 8)\n#define  DSI_PAD_PREEMP_PD_CLK(x) (((x) & 0x3) << 12)\n\n#define DSI_PAD_CONTROL_4 0x52\n#define DSI_PAD_CONTROL_5_B01 0x53\n#define DSI_PAD_CONTROL_6_B01 0x54\n#define DSI_PAD_CONTROL_7_B01 0x55\n#define DSI_INIT_SEQ_DATA_15 0x5F\n#define DSI_INIT_SEQ_DATA_15_B01 0x62\n\n/*! DSI packet defines */\n#define DSI_ESCAPE_CMD\t0x87\n#define DSI_ACK_NO_ERR\t0x84\n\n#define ACK_ERROR_RES   0x02\n#define GEN_LONG_RD_RES 0x1A\n#define DCS_LONG_RD_RES 0x1C\n#define GEN_1_BYTE_SHORT_RD_RES 0x11\n#define DCS_1_BYTE_SHORT_RD_RES 0x21\n#define GEN_2_BYTE_SHORT_RD_RES 0x12\n#define DCS_2_BYTE_SHORT_RD_RES 0x22\n\n/*! MIPI registers. */\n#define MIPI_CAL_MIPI_CAL_CTRL          (0x00 / 0x4)\n#define MIPI_CAL_CIL_MIPI_CAL_STATUS    (0x08 / 0x4)\n#define MIPI_CAL_CILA_MIPI_CAL_CONFIG   (0x14 / 0x4)\n#define MIPI_CAL_CILB_MIPI_CAL_CONFIG   (0x18 / 0x4)\n#define MIPI_CAL_CILC_MIPI_CAL_CONFIG   (0x1C / 0x4)\n#define MIPI_CAL_CILD_MIPI_CAL_CONFIG   (0x20 / 0x4)\n#define MIPI_CAL_CILE_MIPI_CAL_CONFIG   (0x24 / 0x4)\n#define MIPI_CAL_CILF_MIPI_CAL_CONFIG   (0x28 / 0x4)\n#define MIPI_CAL_DSIA_MIPI_CAL_CONFIG   (0x38 / 0x4)\n#define MIPI_CAL_DSIB_MIPI_CAL_CONFIG   (0x3C / 0x4)\n#define MIPI_CAL_DSIC_MIPI_CAL_CONFIG   (0x40 / 0x4)\n#define MIPI_CAL_DSID_MIPI_CAL_CONFIG   (0x44 / 0x4)\n#define MIPI_CAL_MIPI_BIAS_PAD_CFG0     (0x58 / 0x4)\n#define MIPI_CAL_MIPI_BIAS_PAD_CFG1     (0x5C / 0x4)\n#define MIPI_CAL_MIPI_BIAS_PAD_CFG2     (0x60 / 0x4)\n#define MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2 (0x64 / 0x4)\n#define MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2 (0x68 / 0x4)\n#define MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2 (0x70 / 0x4)\n#define MIPI_CAL_DSID_MIPI_CAL_CONFIG_2 (0x74 / 0x4)\n\n/*! MIPI CMDs. */\n#define MIPI_DSI_V_SYNC_START        0x01\n#define MIPI_DSI_COLOR_MODE_OFF      0x02\n#define MIPI_DSI_END_OF_TRANSMISSION 0x08\n#define MIPI_DSI_NULL_PACKET         0x09\n#define MIPI_DSI_V_SYNC_END          0x11\n#define MIPI_DSI_COLOR_MODE_ON       0x12\n#define MIPI_DSI_BLANKING_PACKET     0x19\n#define MIPI_DSI_H_SYNC_START        0x21\n#define MIPI_DSI_SHUTDOWN_PERIPHERAL 0x22\n#define MIPI_DSI_H_SYNC_END          0x31\n#define MIPI_DSI_TURN_ON_PERIPHERAL  0x32\n#define MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE 0x37\n\n#define MIPI_DSI_DCS_SHORT_WRITE       0x05\n#define MIPI_DSI_DCS_READ              0x06\n#define MIPI_DSI_DCS_SHORT_WRITE_PARAM 0x15\n#define MIPI_DSI_DCS_LONG_WRITE        0x39\n\n#define MIPI_DSI_GENERIC_LONG_WRITE           0x29\n#define MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM  0x03\n#define MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM  0x13\n#define MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM  0x23\n#define MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM 0x04\n#define MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM 0x14\n#define MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM 0x24\n\n/*! MIPI DCS CMDs. */\n#define MIPI_DCS_NOP                   0x00\n#define MIPI_DCS_SOFT_RESET            0x01\n#define MIPI_DCS_GET_COMPRESSION_MODE  0x03\n#define MIPI_DCS_GET_DISPLAY_ID        0x04\n#define MIPI_DCS_GET_DISPLAY_ID1       0xDA // GET_DISPLAY_ID Byte0, Module Manufacturer ID.\n#define MIPI_DCS_GET_DISPLAY_ID2       0xDB // GET_DISPLAY_ID Byte1, Module/Driver Version ID.\n#define MIPI_DCS_GET_DISPLAY_ID3       0xDC // GET_DISPLAY_ID Byte2, Module/Driver ID.\n#define MIPI_DCS_GET_NUM_ERRORS        0x05 // 1 byte.\n#define MIPI_DCS_GET_RED_CHANNEL       0x06\n#define MIPI_DCS_GET_GREEN_CHANNEL     0x07\n#define MIPI_DCS_GET_BLUE_CHANNEL      0x08\n#define MIPI_DCS_GET_DISPLAY_STATUS    0x09 // 4 bytes.\n#define MIPI_DCS_GET_POWER_MODE\t       0x0A // 1 byte. 2: DISON, 3: NORON, 4: SLPOUT, 7: BSTON.\n#define MIPI_DCS_GET_ADDRESS_MODE      0x0B // Display Access Control. 1 byte. 0: GS, 1: SS, 3: BGR.\n#define MIPI_DCS_GET_PIXEL_FORMAT      0x0C // 1 byte. 4-6: DPI.\n#define MIPI_DCS_GET_DISPLAY_MODE      0x0D // 1 byte. 0-2: GCS, 3: ALLPOFF, 4: ALLPON, 5: INVON.\n#define MIPI_DCS_GET_SIGNAL_MODE       0x0E // 1 byte. 0: EODSI, 2: DEON, 3: PCLKON, 4: VSON, 5: HSON, 7: TEON.\n#define MIPI_DCS_GET_DIAGNOSTIC_RESULT 0x0F // 1 byte. 6: FUNDT, 7: REGLD.\n#define MIPI_DCS_ENTER_SLEEP_MODE      0x10\n#define MIPI_DCS_EXIT_SLEEP_MODE       0x11\n#define MIPI_DCS_ENTER_PARTIAL_MODE    0x12\n#define MIPI_DCS_ENTER_NORMAL_MODE     0x13\n#define MIPI_DCS_EXIT_INVERT_MODE      0x20\n#define MIPI_DCS_ENTER_INVERT_MODE     0x21\n#define MIPI_DCS_ALL_PIXELS_OFF        0x22\n#define MIPI_DCS_ALL_PIXELS_ON         0x23\n#define MIPI_DCS_SET_CONTRAST          0x25 // VCON in 40mV steps. 7-bit integer.\n#define MIPI_DCS_SET_GAMMA_CURVE       0x26 // 1 byte. 0-7: GC.\n#define MIPI_DCS_SET_DISPLAY_OFF       0x28\n#define MIPI_DCS_SET_DISPLAY_ON        0x29\n#define MIPI_DCS_SET_COLUMN_ADDRESS    0x2A\n#define MIPI_DCS_SET_PAGE_ADDRESS      0x2B\n#define MIPI_DCS_WRITE_MEMORY_START    0x2C\n#define MIPI_DCS_WRITE_LUT             0x2D // 24-bit: 192 bytes.\n#define MIPI_DCS_READ_MEMORY_START     0x2E\n#define MIPI_DCS_SET_PARTIAL_ROWS      0x30\n#define MIPI_DCS_SET_PARTIAL_COLUMNS   0x31\n#define MIPI_DCS_SET_SCROLL_AREA       0x33\n#define MIPI_DCS_SET_TEAR_OFF          0x34\n#define MIPI_DCS_SET_TEAR_ON           0x35\n#define MIPI_DCS_SET_ADDRESS_MODE      0x36 // Display Access Control. 1 byte. 0: GS, 1: SS, 3: BGR.\n#define MIPI_DCS_SET_SCROLL_START      0x37\n#define MIPI_DCS_EXIT_IDLE_MODE        0x38\n#define MIPI_DCS_ENTER_IDLE_MODE       0x39\n#define MIPI_DCS_SET_PIXEL_FORMAT      0x3A // 1 byte. 4-6: DPI.\n#define MIPI_DCS_WRITE_MEMORY_CONTINUE 0x3C\n#define MIPI_DCS_READ_MEMORY_CONTINUE  0x3E\n#define MIPI_DCS_GET_3D_CONTROL        0x3F\n#define MIPI_DCS_SET_VSYNC_TIMING      0x40\n#define MIPI_DCS_SET_TEAR_SCANLINE     0x44\n#define MIPI_DCS_GET_SCANLINE          0x45\n#define MIPI_DCS_SET_TEAR_SCANLINE_WIDTH 0x46\n#define MIPI_DCS_GET_SCANLINE_WIDTH    0x47\n#define MIPI_DSI_AREA_COLOR_MODE       0x4C\n#define MIPI_DCS_SET_BRIGHTNESS        0x51 // DCS_CONTROL_DISPLAY_BRIGHTNESS_CTRL. 1 byte. 0-7: DBV.\n#define MIPI_DCS_GET_BRIGHTNESS        0x52 // 1 byte. 0-7: DBV.\n#define MIPI_DCS_SET_CONTROL_DISPLAY   0x53 // 1 byte. 2: BL, 3: DD, 5: BCTRL.\n#define MIPI_DCS_GET_CONTROL_DISPLAY   0x54 // 1 byte. 2: BL, 3: DD, 5: BCTRL.\n#define MIPI_DCS_SET_CABC_VALUE        0x55 // 1 byte. 0-32: C, 4-7: C.\n#define MIPI_DCS_GET_CABC_VALUE        0x56 // 1 byte. 0-32: C, 4-7: C.\n#define MIPI_DCS_SET_CABC_MIN_BRI      0x5E // 1 byte. 0-7: CMB.\n#define MIPI_DCS_GET_CABC_MIN_BRI      0x5F // 1 byte. 0-7: CMB.\n#define MIPI_DCS_GET_AUTO_BRI_DIAG_RES 0x68 // 1 byte. 6-7: D.\n#define MIPI_DCS_READ_DDB_START        0xA1\n#define MIPI_DCS_READ_DDB_CONTINUE     0xA8 // 0x100 size.\n\n/*! MIPI DCS Panel Private CMDs. */\n#define MIPI_DCS_PRIV_SM_SET_COLOR_MODE 0xA0 // 43 bytes.\n#define MIPI_DCS_PRIV_SM_SET_REG_OFFSET 0xB0\n#define MIPI_DCS_PRIV_SM_SET_ELVSS      0xB1 // OLED backlight tuning. Byte7: PWM transition time in frames.\n#define MIPI_DCS_PRIV_SET_POWER_CONTROL 0xB1\n#define MIPI_DCS_PRIV_SET_EXTC          0xB9 // Enable extended commands.\n#define MIPI_DCS_PRIV_UNK_BD            0xBD\n#define MIPI_DCS_PRIV_UNK_D5            0xD5\n#define MIPI_DCS_PRIV_UNK_D6            0xD6\n#define MIPI_DCS_PRIV_UNK_D8            0xD8\n#define MIPI_DCS_PRIV_UNK_D9            0xD9\n#define MIPI_DCS_PRIV_SM_DISPLAY_ID     0xDD\n\t\t\t\t\t\t\t\t\t\t\t //                          LVL1 LVL2 LVL3 UNK0 UNK1\n#define MIPI_DCS_PRIV_SM_SET_REGS_LOCK  0xE2 // Samsung: Lock (default): 5A5A A5A5 A5A5 A500 A500. Lock/Unlock: A5/5A. LVL1 group is normal registers.\n#define MIPI_DCS_PRIV_READ_EXTC_CMD_SPI 0xFE // Read EXTC Command In SPI. 1 byte. 0-6: EXT_SPI_CNT, 7:EXT_SP.\n#define MIPI_DCS_PRIV_SET_EXTC_CMD_REG  0xFF // EXTC Command Set enable register. 5 bytes. Pass: FF 98 06 04, PAGE.\n\n/*! MIPI DCS Panel Private CMDs PAGE 1. */\n#define MIPI_DCS_PRIV_GET_DISPLAY_ID4   0x00\n#define MIPI_DCS_PRIV_GET_DISPLAY_ID5   0x01\n#define MIPI_DCS_PRIV_GET_DISPLAY_ID6   0x02\n\n/*! MIPI DCS CMD Defines. */\n#define DCS_POWER_MODE_DISPLAY_ON           BIT(2)\n#define DCS_POWER_MODE_NORMAL_MODE          BIT(3)\n#define DCS_POWER_MODE_SLEEP_MODE           BIT(4)\n#define DCS_POWER_MODE_PARTIAL_MODE         BIT(5)\n#define DCS_POWER_MODE_IDLE_MODE            BIT(6)\n\n#define DCS_ADDRESS_MODE_V_FLIP             BIT(0)\n#define DCS_ADDRESS_MODE_H_FLIP             BIT(1)\n#define DCS_ADDRESS_MODE_LATCH_RL           BIT(2) // Latch Data Order.\n#define DCS_ADDRESS_MODE_BGR_COLOR          BIT(3)\n#define DCS_ADDRESS_MODE_LINE_ORDER         BIT(4) // Line Refresh Order.\n#define DCS_ADDRESS_MODE_SWAP_XY            BIT(5) // Page/Column Addressing Reverse Order.\n#define DCS_ADDRESS_MODE_MIRROR_X           BIT(6) // Column Address Order.\n#define DCS_ADDRESS_MODE_MIRROR_Y           BIT(7) // Page Address Order.\n#define DCS_ADDRESS_MODE_ROTATION_MASK      (0xF << 4)\n#define DCS_ADDRESS_MODE_ROTATION_90        (DCS_ADDRESS_MODE_SWAP_XY | DCS_ADDRESS_MODE_LINE_ORDER)\n#define DCS_ADDRESS_MODE_ROTATION_180       (DCS_ADDRESS_MODE_MIRROR_X | DCS_ADDRESS_MODE_LINE_ORDER)\n#define DCS_ADDRESS_MODE_ROTATION_270       (DCS_ADDRESS_MODE_SWAP_XY)\n\n#define DCS_GAMMA_CURVE_NONE                0\n#define DCS_GAMMA_CURVE_GC0_1_8             BIT(0)\n#define DCS_GAMMA_CURVE_GC1_2_5             BIT(1)\n#define DCS_GAMMA_CURVE_GC2_1_0             BIT(2)\n#define DCS_GAMMA_CURVE_GC3_1_0             BIT(3) // Are there more?\n\n#define DCS_CONTROL_DISPLAY_SM_FLASHLIGHT   BIT(2)\n#define DCS_CONTROL_DISPLAY_BACKLIGHT_CTRL  BIT(2)\n#define DCS_CONTROL_DISPLAY_DIMMING_CTRL    BIT(3) // Transition fading.\n#define DCS_CONTROL_DISPLAY_BRIGHTNESS_CTRL BIT(5)\n#define DCS_CONTROL_DISPLAY_HBM_CTRL0       BIT(6)\n#define DCS_CONTROL_DISPLAY_HBM_CTRL1       BIT(7)\n\n#define DCS_SM_COLOR_MODE_SATURATED 0x00 // Disabled. Based on Vivid but over-saturated.\n#define DCS_SM_COLOR_MODE_WASHED    0x45\n#define DCS_SM_COLOR_MODE_BASIC     0x03 // Real natural profile.\n#define DCS_SM_COLOR_MODE_POR_RESET 0x20 // Reset value on power on.\n#define DCS_SM_COLOR_MODE_NATURAL   0x23 // Not actually natural.. Extra saturation.\n#define DCS_SM_COLOR_MODE_VIVID     0x65 // Saturated.\n#define DCS_SM_COLOR_MODE_NIGHT0    0x43 // Based on Washed Out.\n#define DCS_SM_COLOR_MODE_NIGHT1    0x15 // Based on Basic.\n#define DCS_SM_COLOR_MODE_NIGHT2    0x35 // Based on Natural.\n#define DCS_SM_COLOR_MODE_NIGHT3    0x75 // Based on Vivid.\n\n#define DCS_SM_COLOR_MODE_ENABLE    BIT(0)\n\n#define PANEL_SM_BL_CANDELA_MAX 2047\n\n/* Switch Panels:\n *\n * 6.2\" panels for Icosa and Iowa SKUs:\n * [10] 81 [26]: JDI LPM062M326A\n * [10] 96 [09]: JDI LAM062M109A\n * [20] 93 [0F]: InnoLux P062CCA-AZ1 (Rev A1)\n * [20] 95 [0F]: InnoLux P062CCA-AZ2 (Rev B1)\n * [20] 96 [0F]: InnoLux P062CCA-??? (Rev XX) [UNCONFIRMED MODEL+REV]\n * [20] 97 [0F]: InnoLux P062CCA-??? (Rev XX) [UNCONFIRMED MODEL+REV]\n * [20] 98 [0F]: InnoLux P062CCA-??? (Rev XX) [UNCONFIRMED MODEL+REV]\n * [20] 99 [0F]: InnoLux P062CCA-??? (Rev XX) [UNCONFIRMED MODEL+REV]\n * [30] 93 [0F]: AUO A062TAN00 (59.06A33.000)\n * [30] 94 [0F]: AUO A062TAN01 (59.06A33.001)\n * [30] 95 [0F]: AUO A062TAN02 (59.06A33.002)\n * [30] 97 [0F]: AUO A062TAN02 (59.06A33.002) [From photo of assumed same panel]\n * [30] 98 [0F]: AUO A062TAN0? [UNCONFIRMED MODEL]\n * [30] XX [0F]: AUO A062TAN03 (59.06A33.003) [UNCONFIRMED ID]\n *\n *\n * 5.5\" panels for Hoag SKU:\n * [20] 94 [10]: InnoLux 2J055IA-27A (Rev B1) (6203B001P4000)\n * [20] 95 [10]: InnoLux 2J055IA-27A (Rev XX) [UNCONFIRMED MODEL+REV]\n * [20] 96 [10]: InnoLux 2J055IA-27A (Rev XX) [UNCONFIRMED MODEL+REV]\n * [30] 93 [10]: AUO A055TAN01 (59.05A30.001)\n * [30] 94 [10]: AUO A055TAN02 (59.05A30.002)\n * [30] 95 [10]: AUO A055TAN03 (59.05A30.003)\n * [40] 94 [10]: Sharp LQ055T1SW10 (Rev P)\n *\n *\n * 7.0\" OLED panels for Aula SKU:\n * [50] 9B [20]: Samsung AMS699VC01-0 (Rev 2.5)\n */\n\n/* Display ID Decoding:\n *\n * byte0: Vendor\n * byte1: Model\n * byte2: Board\n *\n * Vendors:\n * 10h: Japan Display Inc.\n * 20h: InnoLux Corporation\n * 30h: AU Optronics\n * 40h: Sharp\n * 50h: Samsung\n *\n * Boards, Panel Size:\n * 0Fh: Icosa/Iowa, 6.2\"\n * 10h: Hoag,       5.5\"\n * 20h: Aula,       7.0\"\n */\n\nenum\n{\n\tPANEL_JDI_XXX062M     = 0x10,\n\tPANEL_JDI_LAM062M109A = 0x0910, // SI.\n\tPANEL_JDI_LPM062M326A = 0x2610, // LTPS.\n\tPANEL_INL_P062CCA_AZ1 = 0x0F20,\n\tPANEL_AUO_A062TAN01   = 0x0F30,\n\tPANEL_INL_2J055IA_27A = 0x1020,\n\tPANEL_AUO_A055TAN01   = 0x1030,\n\tPANEL_SHP_LQ055T1SW10 = 0x1040,\n\tPANEL_SAM_AMS699VC01  = 0x2050,\n\n\t// Found on 6/2\" clones. Unknown markings. Clone of AUO A062TAN01.\n\t// Quality seems JDI like. Has bad low backlight scaling. ID: [83] 94 [0F]. Sometimes reports [30] 94 [0F]. Both IDs have correct CRC16.\n\tPANEL_OEM_CLONE_6_2   = 0x0F83,\n\t// Found on 5.5\" clones with AUO A055TAN02 (59.05A30.001) fake markings.\n\tPANEL_OEM_CLONE_5_5   = 0x00B3,\n\t// Found on 5.5\" clones with AUO A055TAN02 (59.05A30.001) fake markings.\n\tPANEL_OEM_CLONE       = 0x0000\n\t//0x0F40 [40] 94 [0F], 5.5\" clone\n};\n\nvoid display_init();\nvoid display_backlight_pwm_init();\nvoid display_end();\n\n/*! Interrupt management. */\nvoid display_enable_interrupt(u32 intr);\nvoid display_disable_interrupt(u32 intr);\nvoid display_wait_interrupt(u32 intr);\n\n/*! Get/Set Display panel ID. */\nu32  display_get_verbose_panel_id();\nu16  display_get_decoded_panel_id();\nvoid display_set_decoded_panel_id(u32 id);\n\n/*! MIPI DCS register management */\nint  display_dsi_read(u8 cmd, u32 len, void *data);\nint  display_dsi_vblank_read(u8 cmd, u32 len, void *data);\nvoid display_dsi_write(u8 cmd, u32 len, void *data);\nvoid display_dsi_vblank_write(u8 cmd, u32 len, void *data);\n\n/*! Show one single color on the display. */\nvoid display_color_screen(u32 color);\n\n/*! Screen backlight ON/OFF or set via duty and fading. */\nvoid display_backlight(bool enable);\nvoid display_backlight_brightness(u32 brightness, u32 step_delay);\n\nu32 *display_init_window_a_pitch();\nu32 *display_init_window_a_pitch_vic();\nu32 *display_init_window_a_pitch_inv();\nu32 *display_init_window_a_block();\nu32 *display_init_window_d_console();\n\nvoid display_window_disable(u32 window);\n\nvoid display_set_framebuffer(u32 window,  void *fb);\nvoid display_move_framebuffer(u32 window, void *fb);\n\nvoid display_window_d_console_enable();\nvoid display_window_d_console_disable();\n\nvoid display_cursor_init(void *crs_fb, u32 size);\nvoid display_cursor_set_pos(u32 x, u32 y);\nvoid display_cursor_deinit();\n\n#endif\n"
  },
  {
    "path": "bdk/display/di.inl",
    "content": "/*\n* Copyright (c) 2018 naehrwert\n* Copyright (c) 2018-2025 CTCaer\n*\n* This program is free software; you can redistribute it and/or modify it\n* under the terms and conditions of the GNU General Public License,\n* version 2, as published by the Free Software Foundation.\n*\n* This program is distributed in the hope it will be useful, but WITHOUT\n* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n* more details.\n*\n* You should have received a copy of the GNU General Public License\n* along with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n// Display A config.\nstatic const reg_cfg_t _di_dc_init_config[] = {\n\t/* Display init */\n\t{DC_CMD_STATE_ACCESS, READ_MUX_ASSEMBLY | WRITE_MUX_ASSEMBLY},\n\t{DC_CMD_REG_ACT_CONTROL, WIN_A_ACT_HCNTR_SEL | WIN_B_ACT_HCNTR_SEL | WIN_C_ACT_HCNTR_SEL | WIN_D_ACT_HCNTR_SEL},\n\t{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},\n\t{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},\n\t{DC_DISP_DC_MCCIF_FIFOCTRL, 0},\n\t{DC_DISP_DISP_MEM_HIGH_PRIORITY, 0},\n\t{DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER, 0},\n\t{DC_CMD_DISPLAY_POWER_CONTROL, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE},\n\t{DC_CMD_GENERAL_INCR_SYNCPT_CNTRL, SYNCPT_CNTRL_NO_STALL},\n\t{DC_CMD_CONT_SYNCPT_VSYNC, SYNCPT_VSYNC_ENABLE | SYNCPT_VSYNC_INDX(9)},\n\t{DC_CMD_STATE_CONTROL, GENERAL_UPDATE  | WIN_A_UPDATE  | WIN_B_UPDATE  | WIN_C_UPDATE  | WIN_D_UPDATE},\n\t{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ | WIN_D_ACT_REQ},\n\n\t/* Disable A/B/C/D Windows */\n\t{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT | WINDOW_B_SELECT | WINDOW_C_SELECT | WINDOW_D_SELECT},\n\t{DC_WIN_WIN_OPTIONS, 0},\n\t{DC_WIN_DV_CONTROL,  0},\n\n\t/* Setup default YUV colorspace conversion coefficients */\n\t{DC_WINC_CSC_YOF,   0xF0},\n\t{DC_WINC_CSC_KYRGB, 0x12A},\n\t{DC_WINC_CSC_KUR,   0},\n\t{DC_WINC_CSC_KVR,   0x198},\n\t{DC_WINC_CSC_KUG,   0x39B},\n\t{DC_WINC_CSC_KVG,   0x32F},\n\t{DC_WINC_CSC_KUB,   0x204},\n\t{DC_WINC_CSC_KVB,   0},\n\n\t/* Init color, format and background */\n\t{DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888},\n\t{DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C},\n\t{DC_COM_PIN_OUTPUT_POLARITY(1), LSC0_OUTPUT_POLARITY_LOW},\n\t{DC_COM_PIN_OUTPUT_POLARITY(3), 0},\n\t{DC_DISP_BLEND_BACKGROUND_COLOR, 0},\n\t{DC_COM_CRC_CONTROL, 0},\n\t{DC_CMD_STATE_CONTROL, GENERAL_UPDATE  | WIN_A_UPDATE  | WIN_B_UPDATE  | WIN_C_UPDATE  | WIN_D_UPDATE},\n\t{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ | WIN_D_ACT_REQ},\n\n\t/* Stop display */\n\t{DC_WINBUF_BLEND_LAYER_CONTROL, WIN_BLEND_BYPASS | WIN_BLEND_DEPTH(255)},\n\t{DC_CMD_DISPLAY_COMMAND_OPTION0, 0},\n\t{DC_DISP_DISP_WIN_OPTIONS, 0},\n\t{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},\n\t{DC_CMD_STATE_CONTROL, GENERAL_UPDATE  | WIN_A_UPDATE  | WIN_B_UPDATE  | WIN_C_UPDATE  | WIN_D_UPDATE},\n\t{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ | WIN_D_ACT_REQ}\n};\n\n// DSI Init config.\nstatic const reg_cfg_t _di_dsi_seq_pkt_reset_config0[] = {\n\t{DSI_WR_DATA, 0},\n\t{DSI_INT_ENABLE, 0},\n\t{DSI_INT_STATUS, 0},\n\t{DSI_INT_MASK,   0},\n\t{DSI_INIT_SEQ_DATA_0, 0},\n\t{DSI_INIT_SEQ_DATA_1, 0},\n\t{DSI_INIT_SEQ_DATA_2, 0},\n\t{DSI_INIT_SEQ_DATA_3, 0}\n};\nstatic const reg_cfg_t _di_dsi_seq_pkt_reset_config1[] = {\n\t{DSI_DCS_CMDS, 0},\n\t{DSI_PKT_SEQ_0_LO, 0},\n\t{DSI_PKT_SEQ_1_LO, 0},\n\t{DSI_PKT_SEQ_2_LO, 0},\n\t{DSI_PKT_SEQ_3_LO, 0},\n\t{DSI_PKT_SEQ_4_LO, 0},\n\t{DSI_PKT_SEQ_5_LO, 0},\n\t{DSI_PKT_SEQ_0_HI, 0},\n\t{DSI_PKT_SEQ_1_HI, 0},\n\t{DSI_PKT_SEQ_2_HI, 0},\n\t{DSI_PKT_SEQ_3_HI, 0},\n\t{DSI_PKT_SEQ_4_HI, 0},\n\t{DSI_PKT_SEQ_5_HI, 0},\n\t{DSI_CONTROL, 0}\n};\nstatic const reg_cfg_t _di_dsi_init_pads_t210b01[] = {\n\t{DSI_PAD_CONTROL_1, 0},\n\t{DSI_PAD_CONTROL_2, 0},\n\t{DSI_PAD_CONTROL_3, 0},\n\t{DSI_PAD_CONTROL_4, 0},\n\t{DSI_PAD_CONTROL_5_B01, 0},\n\t{DSI_PAD_CONTROL_6_B01, 0},\n\t{DSI_PAD_CONTROL_7_B01, 0}\n};\nstatic const reg_cfg_t _di_dsi_init_config[] = {\n\t{DSI_PAD_CONTROL_CD, 0},\n\t{DSI_SOL_DELAY,     24},\n\t{DSI_MAX_THRESHOLD, 480},\n\t{DSI_TRIGGER, 0},\n\t{DSI_INIT_SEQ_CONTROL, 0},\n\n\t{DSI_PKT_LEN_0_1, 0},\n\t{DSI_PKT_LEN_2_3, 0},\n\t{DSI_PKT_LEN_4_5, 0},\n\t{DSI_PKT_LEN_6_7, 0},\n\n\t{DSI_PAD_CONTROL_1, 0},\n\n\t/* DSI PHY timings Init - 19.2 MHz */\n\t{DSI_PHY_TIMING_0, 0x6070603},\n\t{DSI_PHY_TIMING_1, 0x40A0E05},\n\t{DSI_PHY_TIMING_2, 0x30109},\n\t{DSI_BTA_TIMING,   0x190A14},\n\t/* DSI timeout */\n\t{DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)},\n\t{DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x765)   | DSI_TIMEOUT_TA(0x2000)},\n\t{DSI_TO_TALLY, 0},\n\n\t{DSI_PAD_CONTROL_0, DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0)}, // Power up.\n\t{DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},\n};\n\n// DSI LP config.\nstatic const reg_cfg_t _di_dsi_timing_lp_config[] = {\n\t{DSI_PAD_CONTROL_1, 0},\n\n\t/* DSI PHY timings LP - 50 MHz */\n\t{DSI_PHY_TIMING_0, 0x6070603},\n\t{DSI_PHY_TIMING_1, 0x40A0E05},\n\t{DSI_PHY_TIMING_2, 0x30118},\n\t{DSI_BTA_TIMING,   0x190A14},\n\t/* DSI timeout */\n\t{DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)},\n\t{DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343)  | DSI_TIMEOUT_TA(0x2000)},\n\t{DSI_TO_TALLY, 0},\n\n\t{DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},\n\t{DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE},\n\t{DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},\n\t{DSI_MAX_THRESHOLD, 64},\n\t{DSI_TRIGGER, 0},\n\t{DSI_TX_CRC, 0},\n\t{DSI_INIT_SEQ_CONTROL, 0}\n};\n\n// DSI panel JDI config.\nstatic const reg_cfg_t _di_dsi_panel_init_config_jdi[] = {\n\t{DSI_WR_DATA, 0x0439},     // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.\n\t{DSI_WR_DATA, 0x9483FFB9}, // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94).\n\t{DSI_TRIGGER, DSI_TRIGGER_HOST},\n\t{DSI_WR_DATA, 0xBD15},     // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0 to 0xBD.\n\t{DSI_TRIGGER, DSI_TRIGGER_HOST},\n\t{DSI_WR_DATA, 0x1939},     // MIPI_DSI_DCS_LONG_WRITE: 25 bytes.\n\t{DSI_WR_DATA, 0xAAAAAAD8}, // Register: 0xD8.\n\t{DSI_WR_DATA, 0xAAAAAAEB},\n\t{DSI_WR_DATA, 0xAAEBAAAA},\n\t{DSI_WR_DATA, 0xAAAAAAAA},\n\t{DSI_WR_DATA, 0xAAAAAAEB},\n\t{DSI_WR_DATA, 0xAAEBAAAA},\n\t{DSI_WR_DATA, 0xAA},\n\t{DSI_TRIGGER, DSI_TRIGGER_HOST},\n\t{DSI_WR_DATA, 0x01BD15},   // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 1 to 0xBD.\n\t{DSI_TRIGGER, DSI_TRIGGER_HOST},\n\t{DSI_WR_DATA, 0x2739},     // MIPI_DSI_DCS_LONG_WRITE: 39 bytes.\n\t{DSI_WR_DATA, 0xFFFFFFD8}, // Register: 0xD8.\n\t{DSI_WR_DATA, 0xFFFFFFFF},\n\t{DSI_WR_DATA, 0xFFFFFFFF},\n\t{DSI_WR_DATA, 0xFFFFFFFF},\n\t{DSI_WR_DATA, 0xFFFFFFFF},\n\t{DSI_WR_DATA, 0xFFFFFFFF},\n\t{DSI_WR_DATA, 0xFFFFFFFF},\n\t{DSI_WR_DATA, 0xFFFFFFFF},\n\t{DSI_WR_DATA, 0xFFFFFFFF},\n\t{DSI_WR_DATA, 0xFFFFFF},\n\t{DSI_TRIGGER, DSI_TRIGGER_HOST},\n\t{DSI_WR_DATA, 0x02BD15},   // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 2 to 0xBD.\n\t{DSI_TRIGGER, DSI_TRIGGER_HOST},\n\t{DSI_WR_DATA, 0xF39},      // MIPI_DSI_DCS_LONG_WRITE: 15 bytes.\n\t{DSI_WR_DATA, 0xFFFFFFD8}, // Register: 0xD8.\n\t{DSI_WR_DATA, 0xFFFFFFFF},\n\t{DSI_WR_DATA, 0xFFFFFFFF},\n\t{DSI_WR_DATA, 0xFFFFFF},\n\t{DSI_TRIGGER, DSI_TRIGGER_HOST},\n\t{DSI_WR_DATA, 0x00BD15},   // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 0 to 0xBD.\n\t{DSI_TRIGGER, DSI_TRIGGER_HOST},\n\t{DSI_WR_DATA, 0x06D915},   // MIPI_DSI_DCS_SHORT_WRITE_PARAM: 6 to 0xD9.\n\t{DSI_TRIGGER, DSI_TRIGGER_HOST},\n\t{DSI_WR_DATA, 0x439},      // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.\n\t{DSI_WR_DATA, 0x000000B9}, // MIPI_DCS_PRIV_SET_EXTC. Disable.\n\t{DSI_TRIGGER, DSI_TRIGGER_HOST}\n};\n\n// DSI HS packet config.\nstatic const reg_cfg_t _di_dsi_seq_pkt_video_non_burst_no_eot_config[] = {\n\t{DSI_PAD_CONTROL_1, 0},\n\n\t/* DSI PHY timings HP - 234 MHz */\n\t{DSI_PHY_TIMING_0, 0x6070603},\n\t{DSI_PHY_TIMING_1, 0x40A0E05},\n\t{DSI_PHY_TIMING_2, 0x30172},\n\t{DSI_BTA_TIMING,   0x190A14},\n\t/* DSI timeout */\n\t{DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xA40)},\n\t{DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x5A2F)  | DSI_TIMEOUT_TA(0x2000)},\n\t{DSI_TO_TALLY, 0},\n\n\t/* DSI packet sequence */\n\t{DSI_PKT_SEQ_0_LO, 0x40000208},\n\t{DSI_PKT_SEQ_2_LO, 0x40000308},\n\t{DSI_PKT_SEQ_4_LO, 0x40000308},\n\t{DSI_PKT_SEQ_1_LO, 0x40000308},\n\t{DSI_PKT_SEQ_3_LO, 0x3F3B2B08},\n\t{DSI_PKT_SEQ_3_HI, 0x2CC},\n\t{DSI_PKT_SEQ_5_LO, 0x3F3B2B08},\n\t{DSI_PKT_SEQ_5_HI, 0x2CC},\n\t{DSI_PKT_LEN_0_1, PKT1_LEN(206)  | PKT0_LEN(0)},\n\t{DSI_PKT_LEN_2_3, PKT1_LEN(2160) | PKT0_LEN(418)},\n\t{DSI_PKT_LEN_4_5, PKT1_LEN(0)    | PKT0_LEN(400)},\n\t{DSI_PKT_LEN_6_7, PKT1_LEN(0)    | PKT0_LEN(400)},\n\t{DSI_HOST_CONTROL, 0}\n};\n\n// DSI mode config.\nstatic const reg_cfg_t _di_dsi_host_mode_config[] = {\n\t{DSI_TRIGGER, 0},\n\t{DSI_CONTROL, 0},\n\t{DSI_SOL_DELAY, 6},\n\t{DSI_MAX_THRESHOLD, 480},\n\t{DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE},\n\t{DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE},\n\t{DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_FIFO_SEL | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},\n\t{DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE},\n\t{DSI_HOST_CONTROL, DSI_HOST_CONTROL_TX_TRIG_SOL | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC},\n\t{DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_TX_TRIG_SOL | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}\n};\n\n// MIPI CAL config.\nstatic const reg_cfg_t _di_mipi_pad_cal_config[] = {\n\t{MIPI_CAL_MIPI_BIAS_PAD_CFG2,  0},\n\t{MIPI_CAL_CIL_MIPI_CAL_STATUS, 0xF3F10000},\n\t{MIPI_CAL_MIPI_BIAS_PAD_CFG0,  0},\n\t{MIPI_CAL_MIPI_BIAS_PAD_CFG2,  0}\n};\n\n// DSI pad config.\nstatic const reg_cfg_t _di_dsi_pad_cal_config_t210[] = {\n\t{DSI_PAD_CONTROL_1, 0},\n\t{DSI_PAD_CONTROL_2, 0},\n\t{DSI_PAD_CONTROL_3, DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) | DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3)},\n\t{DSI_PAD_CONTROL_4, 0}\n};\nstatic const reg_cfg_t _di_dsi_pad_cal_config_t210b01[] = {\n\t{DSI_PAD_CONTROL_1,     0},\n\t{DSI_PAD_CONTROL_2,     0},\n\t{DSI_PAD_CONTROL_3,     0},\n\t{DSI_PAD_CONTROL_4,     0x77777},\n\t{DSI_PAD_CONTROL_5_B01, 0x77777},\n\t{DSI_PAD_CONTROL_6_B01, DSI_PAD_PREEMP_PD_CLK(0x1) | DSI_PAD_PREEMP_PU_CLK(0x1) | DSI_PAD_PREEMP_PD(0x01) | DSI_PAD_PREEMP_PU(0x1)},\n\t{DSI_PAD_CONTROL_7_B01, 0}\n};\n\n// MIPI CAL config.\nstatic const reg_cfg_t _di_mipi_dsi_cal_prod_config_t210[] = {\n\t{MIPI_CAL_DSIA_MIPI_CAL_CONFIG,   0x200200},\n\t{MIPI_CAL_DSIB_MIPI_CAL_CONFIG,   0x200200},\n\t{MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x200002},\n\t{MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0x200002}\n};\nstatic const reg_cfg_t _di_mipi_dsi_cal_prod_config_t210b01[] = {\n\t{MIPI_CAL_DSIA_MIPI_CAL_CONFIG,   0x200006},\n\t{MIPI_CAL_DSIB_MIPI_CAL_CONFIG,   0x200006},\n\t{MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x260000},\n\t{MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0x260000}\n};\nstatic const reg_cfg_t _di_mipi_dsi_cal_unused_config[] = {\n\t{MIPI_CAL_CILA_MIPI_CAL_CONFIG,   0},\n\t{MIPI_CAL_CILB_MIPI_CAL_CONFIG,   0},\n\t{MIPI_CAL_CILC_MIPI_CAL_CONFIG,   0},\n\t{MIPI_CAL_CILD_MIPI_CAL_CONFIG,   0},\n\t{MIPI_CAL_CILE_MIPI_CAL_CONFIG,   0},\n\t{MIPI_CAL_CILF_MIPI_CAL_CONFIG,   0},\n\t{MIPI_CAL_DSIC_MIPI_CAL_CONFIG,   0},\n\t{MIPI_CAL_DSID_MIPI_CAL_CONFIG,   0},\n\t{MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0},\n\t{MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2, 0},\n\t{MIPI_CAL_DSID_MIPI_CAL_CONFIG_2, 0}\n};\n\n// Display A enable config.\nstatic const reg_cfg_t _di_dc_video_mode_config[] = {\n\t/* Set panel timings */\n\t{DC_DISP_DISP_TIMING_OPTIONS, VSYNC_H_POSITION(0)},\n\t{DC_DISP_REF_TO_SYNC, V_REF_TO_SYNC(1)    | H_REF_TO_SYNC(0)},\n\t{DC_DISP_SYNC_WIDTH,  V_SYNC_WIDTH(1)     | H_SYNC_WIDTH(72)},\n\t{DC_DISP_BACK_PORCH,  V_BACK_PORCH(9)     | H_BACK_PORCH(72)},\n\t{DC_DISP_FRONT_PORCH, V_FRONT_PORCH(10)   | H_FRONT_PORCH(136)},\n\t{DC_DISP_ACTIVE,      V_DISP_ACTIVE(1280) | H_DISP_ACTIVE(720)},\n\t/* End of Display timings */\n\n\t{DC_DISP_SHIFT_CLOCK_OPTIONS, SC1_H_QUALIFIER_NONE | SC0_H_QUALIFIER_NONE},\n\t{DC_COM_PIN_OUTPUT_ENABLE(1), 0},\n\t{DC_DISP_DATA_ENABLE_OPTIONS, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL},\n\n\t/* Start continuous display. */\n\t{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY},\n\t{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},\n\t{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},\n\t{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},\n\t{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},\n\t{DC_CMD_GENERAL_INCR_SYNCPT, SYNCPT_GENERAL_COND(COND_REG_WR_SAFE) | SYNCPT_GENERAL_INDX(1)},\n\t{DC_CMD_GENERAL_INCR_SYNCPT, SYNCPT_GENERAL_COND(COND_REG_WR_SAFE) | SYNCPT_GENERAL_INDX(1)},\n\t{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},\n\t{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},\n};\n\n// Display A disable config.\nstatic const reg_cfg_t _di_dc_video_disable_config[] = {\n\t{DC_CMD_INT_MASK, 0},\n\t{DC_CMD_STATE_ACCESS, READ_MUX_ASSEMBLY | WRITE_MUX_ASSEMBLY},\n\t{DC_CMD_INT_ENABLE, 0},\n\t{DC_CMD_CONT_SYNCPT_VSYNC, 0},\n\n\t/* Stop display. */\n\t{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},\n\t{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},\n\t{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},\n\t{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},\n\t{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},\n\t{DC_CMD_GENERAL_INCR_SYNCPT, SYNCPT_GENERAL_COND(COND_REG_WR_SAFE) | SYNCPT_GENERAL_INDX(1)},\n\t{DC_CMD_GENERAL_INCR_SYNCPT, SYNCPT_GENERAL_COND(COND_REG_WR_SAFE) | SYNCPT_GENERAL_INDX(1)},\n\t{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},\n\t{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},\n\t// TODO: LCD panels should sleep for 40ms here.\n\t{DC_CMD_DISPLAY_POWER_CONTROL, 0},\n\t{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},\n\t{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},\n};\n\n// DSI panel JDI deinit config.\nstatic const reg_cfg_t _di_dsi_panel_deinit_config_jdi[] = {\n\t{DSI_WR_DATA, 0x439},      // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.\n\t{DSI_WR_DATA, 0x9483FFB9}, // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94).\n\t{DSI_TRIGGER, DSI_TRIGGER_HOST},\n\t{DSI_WR_DATA, 0x2139},     // MIPI_DSI_DCS_LONG_WRITE: 33 bytes.\n\t{DSI_WR_DATA, 0x191919D5}, // Register: 0xD5.\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19},\n\t{DSI_TRIGGER, DSI_TRIGGER_HOST},\n\t{DSI_WR_DATA, 0xB39},      // MIPI_DSI_DCS_LONG_WRITE: 11 bytes.\n\t{DSI_WR_DATA, 0x4F0F41B1}, // MIPI_DCS_PRIV_SET_POWER_CONTROL.\n\t{DSI_WR_DATA, 0xF179A433},\n\t{DSI_WR_DATA, 0x002D81},\n\t{DSI_TRIGGER, DSI_TRIGGER_HOST},\n\t{DSI_WR_DATA, 0x439},      // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.\n\t{DSI_WR_DATA, 0x000000B9}, // MIPI_DCS_PRIV_SET_EXTC. Disable.\n\t{DSI_TRIGGER, DSI_TRIGGER_HOST}\n};\n\n// DSI panel AUO deinit config.\nstatic const reg_cfg_t _di_dsi_panel_deinit_config_auo[] = {\n\t{DSI_WR_DATA, 0x439},      // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.\n\t{DSI_WR_DATA, 0x9483FFB9}, // MIPI_DCS_PRIV_SET_EXTC. (Pass: FF 83 94).\n\t{DSI_TRIGGER, DSI_TRIGGER_HOST},\n\t{DSI_WR_DATA, 0x2C39},     // MIPI_DSI_DCS_LONG_WRITE: 44 bytes.\n\t{DSI_WR_DATA, 0x191919D5}, // Register: 0xD5.\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_TRIGGER, DSI_TRIGGER_HOST},\n\t{DSI_WR_DATA, 0x2C39},     // MIPI_DSI_DCS_LONG_WRITE: 44 bytes.\n\t{DSI_WR_DATA, 0x191919D6}, // Register: 0xD6.\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_WR_DATA, 0x19191919},\n\t{DSI_TRIGGER, DSI_TRIGGER_HOST},\n\t{DSI_WR_DATA, 0xB39},      // MIPI_DSI_DCS_LONG_WRITE: 11 bytes.\n\t{DSI_WR_DATA, 0x711148B1}, // MIPI_DCS_PRIV_SET_POWER_CONTROL. (Not deep standby, BT1 / XDK, VRH gamma volt adj 49 / x40).\n\t// (NVRH gamma volt adj 9, Amplifier current small / x30, FS0 freq Fosc/80 / FS1 freq Fosc/32, Enter standby / PON / VCOMG).\n\t{DSI_WR_DATA, 0x71143209},\n\t{DSI_WR_DATA, 0x114D31},   // (Unknown).\n\t{DSI_TRIGGER, DSI_TRIGGER_HOST},\n\t{DSI_WR_DATA, 0x439},      // MIPI_DSI_DCS_LONG_WRITE: 4 bytes.\n\t{DSI_WR_DATA, 0x000000B9}, // MIPI_DCS_PRIV_SET_EXTC. Disable.\n\t{DSI_TRIGGER, DSI_TRIGGER_HOST}\n};\n\n/*\nstatic const reg_cfg_t _di_init_config_invert[] = {\n\t{DSI_WR_DATA, 0x239},\n\t{DSI_WR_DATA, 0x02C1}, // INV_EN.\n\t{DSI_TRIGGER, DSI_TRIGGER_HOST},\n};\n*/\n\n// Display A Window A one color config.\nstatic const reg_cfg_t _di_win_one_color[] = {\n\t{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT | WINDOW_B_SELECT | WINDOW_C_SELECT | WINDOW_D_SELECT},\n\t{DC_WIN_WIN_OPTIONS, 0},\n\t{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE},\n\t{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY} // Continuous display.\n};\n\n// Display A Window A linear pitch config.\nstatic const reg_cfg_t _di_winA_pitch[] = {\n\t{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},\n\t{DC_WIN_WIN_OPTIONS, 0},\n\t{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE},\n\t{DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, // NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8.\n\t{DC_WIN_POSITION, 0}, //(0,0)\n\t{DC_WIN_H_INITIAL_DDA, 0},\n\t{DC_WIN_V_INITIAL_DDA, 0},\n\t{DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280)  | H_PRESCALED_SIZE(720 * 4)},\n\t{DC_WIN_DDA_INC,        V_DDA_INC(0x1000)       | H_DDA_INC(0x1000)}, // 1.0x.\n\t{DC_WIN_SIZE,           V_SIZE(1280)            | H_SIZE(720)},\n\t{DC_WIN_LINE_STRIDE,    UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, // 720*2x720*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.\n\t{DC_WIN_BUFFER_CONTROL, BUFFER_CONTROL_HOST},\n\t{DC_WINBUF_SURFACE_KIND, PITCH},\n\t{DC_WINBUF_START_ADDR, IPL_FB_ADDRESS}, // Framebuffer address.\n\t{DC_WINBUF_ADDR_H_OFFSET, 0},\n\t{DC_WINBUF_ADDR_V_OFFSET, 0},\n\t{DC_WIN_WIN_OPTIONS, WIN_ENABLE}, // Enable window AD.\n\t{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display.\n\t{DC_CMD_STATE_CONTROL, GENERAL_UPDATE  | WIN_A_UPDATE},\n\t{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ}\n};\n\n// Display A Window A linear pitch + Win D support config.\nstatic const reg_cfg_t _di_winA_pitch_vic[] = {\n\t{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},\n\t{DC_WIN_WIN_OPTIONS, 0},\n\t{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE},\n\t{DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, // NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8.\n\t{DC_WIN_POSITION, 0}, //(0,0)\n\t{DC_WIN_H_INITIAL_DDA, 0},\n\t{DC_WIN_V_INITIAL_DDA, 0},\n\t{DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280)  | H_PRESCALED_SIZE(720 * 4)},\n\t{DC_WIN_DDA_INC,        V_DDA_INC(0x1000)       | H_DDA_INC(0x1000)}, // 1.0x.\n\t{DC_WIN_SIZE,           V_SIZE(1280)            | H_SIZE(720)},\n\t{DC_WIN_LINE_STRIDE,    UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, // 720*2x720*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.\n\t{DC_WIN_BUFFER_CONTROL, BUFFER_CONTROL_HOST},\n\t{DC_WINBUF_SURFACE_KIND, PITCH},\n\t{DC_WINBUF_START_ADDR, NYX_FB_ADDRESS}, // Framebuffer address.\n\t{DC_WINBUF_ADDR_H_OFFSET, 0},\n\t{DC_WINBUF_ADDR_V_OFFSET, 0},\n\t{DC_WIN_WIN_OPTIONS, WIN_ENABLE}, // Enable window AD.\n\t{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display.\n\t{DC_CMD_STATE_CONTROL, GENERAL_UPDATE  | WIN_A_UPDATE},\n\t{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ}\n};\n\n// Display A Window A linear pitch inverse + Win D support config.\nstatic const reg_cfg_t _di_winA_pitch_inv[] = {\n\t{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},\n\t{DC_WIN_WIN_OPTIONS, 0},\n\t{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE},\n\t{DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, // NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8.\n\t{DC_WIN_POSITION, 0}, //(0,0)\n\t{DC_WIN_H_INITIAL_DDA, 0},\n\t{DC_WIN_V_INITIAL_DDA, 0},\n\t{DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280)  | H_PRESCALED_SIZE(720 * 4)},\n\t{DC_WIN_DDA_INC,        V_DDA_INC(0x1000)       | H_DDA_INC(0x1000)}, // 1.0x.\n\t{DC_WIN_SIZE,           V_SIZE(1280)            | H_SIZE(720)},\n\t{DC_WIN_LINE_STRIDE,    UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, // 720*2x720*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.\n\t{DC_WIN_BUFFER_CONTROL, BUFFER_CONTROL_HOST},\n\t{DC_WINBUF_SURFACE_KIND, PITCH},\n\t{DC_WINBUF_START_ADDR, NYX_FB_ADDRESS}, // Framebuffer address.\n\t{DC_WINBUF_ADDR_H_OFFSET, 0}, // Linear: 0x383FFC, Block: 0x3813FC.\n\t{DC_WINBUF_ADDR_V_OFFSET, 1279}, // Linear: 1279, Block: 0.\n\t{DC_WIN_WIN_OPTIONS, WIN_ENABLE | V_DIRECTION}, // Enable window AD.\n\t{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display.\n\t{DC_CMD_STATE_CONTROL, GENERAL_UPDATE  | WIN_A_UPDATE},\n\t{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ}\n};\n\n// Display A Window A block linear config.\nstatic const reg_cfg_t _di_winA_block[] = {\n\t{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},\n\t{DC_WIN_WIN_OPTIONS, 0},\n\t{DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE},\n\t{DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, // NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8.\n\t{DC_WIN_POSITION, 0}, //(0,0)\n\t{DC_WIN_H_INITIAL_DDA, 0},\n\t{DC_WIN_V_INITIAL_DDA, 0},\n\t{DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280)   | H_PRESCALED_SIZE(720 * 4)},\n\t{DC_WIN_DDA_INC,        V_DDA_INC(0x1000)        | H_DDA_INC(0x1000)}, // 1.0x.\n\t{DC_WIN_SIZE,           V_SIZE(1280)             | H_SIZE(720)},\n\t{DC_WIN_LINE_STRIDE,    UV_LINE_STRIDE(1280 * 2) | LINE_STRIDE(1280 * 4)}, //720*2x720*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.\n\t{DC_WIN_BUFFER_CONTROL, BUFFER_CONTROL_HOST},\n\t{DC_WINBUF_SURFACE_KIND, BLOCK_HEIGHT(4) | BLOCK},\n\t{DC_WINBUF_START_ADDR, NYX_FB_ADDRESS}, // Framebuffer address.\n\t{DC_WINBUF_ADDR_H_OFFSET, 0x3813FC}, // Linear: 0x383FFC, Block: 0x3813FC. Block in HOS: 0x13FF.\n\t{DC_WINBUF_ADDR_V_OFFSET, 0}, // Linear: 1279, Block: 0.\n\t{DC_WIN_WIN_OPTIONS, WIN_ENABLE | SCAN_COLUMN | H_DIRECTION}, // Enable window AD. | SCAN_COLUMN | H_DIRECTION.\n\t{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, // Continuous display.\n\t{DC_CMD_STATE_CONTROL, GENERAL_UPDATE  | WIN_A_UPDATE},\n\t{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ}\n};\n\n// Display A Window D config.\nstatic const reg_cfg_t _di_winD_log[] = {\n\t{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_D_SELECT},\n\t{DC_WIN_WIN_OPTIONS, 0},\n\t{DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8},\n\t{DC_WIN_POSITION, 0}, //(0,0)\n\t{DC_WIN_H_INITIAL_DDA, 0},\n\t{DC_WIN_V_INITIAL_DDA, 0},\n\t{DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280)  | H_PRESCALED_SIZE(656 * 4)},\n\t{DC_WIN_DDA_INC,        V_DDA_INC(0x1000)       | H_DDA_INC(0x1000)}, // 1.0x.\n\t{DC_WIN_SIZE,           V_SIZE(1280)            | H_SIZE(656)},\n\t{DC_WIN_LINE_STRIDE,    UV_LINE_STRIDE(656 * 2) | LINE_STRIDE(656 * 4)}, //656*2x656*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.\n\t{DC_WIN_BUFFER_CONTROL, BUFFER_CONTROL_HOST},\n\t{DC_WINBUF_SURFACE_KIND, PITCH},\n\t{DC_WINBUF_START_ADDR, LOG_FB_ADDRESS}, // Framebuffer address.\n\t{DC_WINBUF_ADDR_H_OFFSET, 0},\n\t{DC_WINBUF_ADDR_V_OFFSET, 0},\n\t{DC_WINBUF_BLEND_LAYER_CONTROL, WIN_BLEND_ENABLE | WIN_K1(200) | WIN_BLEND_DEPTH(0)},\n\t{DC_WINBUF_BLEND_MATCH_SELECT, WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1 | WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1},\n\t{DC_CMD_STATE_CONTROL, GENERAL_UPDATE  | WIN_D_UPDATE},\n\t{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_D_ACT_REQ},\n};\n"
  },
  {
    "path": "bdk/display/vic.c",
    "content": "/*\n * VIC (4.0) driver for Tegra X1\n *\n * Copyright (c) 2018-2024 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include \"vic.h\"\n#include <mem/heap.h>\n#include <soc/bpmp.h>\n#include <soc/clock.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n#include <utils/types.h>\n\n/* VIC Private registers */\n#define PVIC_FALCON_PA_OFFSET 0x1000\n#define PVIC_FALCON_ADDR      0x10AC\n#define PVIC_FALCON_IDLESTATE 0x104C\n\n/* VIC Control and Status registers. */\n/* Fetch Control registers. */\n#define VIC_FC_COMPOSE                         0x10000\n#define  COMPOSE_START                          BIT(0)\n\n#define VIC_FC_CFG_STRUCT_SLOT_INDEX           0x10B00\n\n#define VIC_FC_CFG_STRUCT_SLOT_CFG0            0x10B04\n#define  SLOT_ENABLE                            BIT(0)\n#define  FIELD_CURRENT_ENABLE                   BIT(8)\n\n#define VIC_FC_CFG_STRUCT_SLOT_CFG2            0x10B0C\n#define  CACHE_WIDTH(n) ((n) << 16)\n#define  CACHE_WIDTH_16BX16                     0 // Block Linear.\n#define  CACHE_WIDTH_32BX8                      1 // Block Linear.\n#define  CACHE_WIDTH_64BX4                      2 // Block Linear, Pitch. Recommended.\n#define  CACHE_WIDTH_128BX2                     3 // Block Linear, Pitch.\n#define  CACHE_WIDTH_256BX1                     4 // Pitch.\n#define  OUTPUT_FLIP_X                          BIT(20)\n#define  OUTPUT_FLIP_Y                          BIT(21)\n#define  OUTPUT_TRANSPOSE                       BIT(22)\n\n#define VIC_FC_CFG_STRUCT_SLOT_SFC_SIZE        0x10B10\n#define VIC_FC_CFG_STRUCT_SLOT_LUMA_SIZE       0x10B14\n#define VIC_FC_CFG_STRUCT_SLOT_CHROMA_SIZE     0x10B18\n#define VIC_FC_CFG_STRUCT_SLOT_SRC_RECT_LR     0x10B1C\n#define VIC_FC_CFG_STRUCT_SLOT_SRC_RECT_TB     0x10B20\n#define VIC_FC_CFG_STRUCT_SLOT_DST_RECT_LR     0x10B30\n#define VIC_FC_CFG_STRUCT_SLOT_DST_RECT_TB     0x10B34\n#define VIC_FC_CFG_STRUCT_TGT_RECT_LR          0x10B38\n#define VIC_FC_CFG_STRUCT_TGT_RECT_TB          0x10B3C\n#define VIC_FC_SLOT_MAP                        0x10C00\n\n#define VIC_FC_FCE_CTRL                        0x11000\n#define  START_TRIGGER                          BIT(0)\n#define  HALT_TRIGGER                           BIT(1)\n#define  CLEAR_ERROR                            BIT(8)\n\n#define VIC_FC_FCE_UCODE_ADDR                  0x11200\n#define VIC_FC_FCE_UCODE_INST                  0x11300\n\n/* Surface List registers. */\n#define VIC_SL_CFG_STRUCT_SLOT_INDEX           0x12100\n#define VIC_SL_CFG_STRUCT_SLOT_DST_RECT_LR     0x12200\n#define VIC_SL_CFG_STRUCT_SLOT_DST_RECT_TB     0x12300\n#define VIC_SL_CFG_STRUCT_TGT_RECT_LR          0x12400\n#define VIC_SL_CFG_STRUCT_TGT_RECT_TB          0x12500\n#define VIC_SL_CFG_STRUCT_SLOT_CFG0            0x12600\n\n/* Surface Cache registers. */\n#define VIC_SC_PRAMBASE                        0x14000\n#define VIC_SC_PRAMSIZE                        0x14100\n#define VIC_SC_SFC0_BASE_LUMA(n)               (0x14300 + (n) * 0x100)\n\n/* Blending Output registers. */\n#define VIC_BL_TARGET_BASADR                   0x22000\n#define VIC_BL_CONFIG                          0x22800\n#define  SUBPARTITION_MODE                      BIT(0)\n#define  PROCESS_CFG_STRUCT_TRIGGER             BIT(2)\n#define  SLOTMASK(n) ((n) << 8)\n\n#define VIC_BL_CFG_STRUCT_CFG0                 0x22C00\n#define VIC_BL_CFG_STRUCT_SFC_SIZE             0x22C04\n#define VIC_BL_CFG_STRUCT_LUMA_SIZE            0x22C08\n#define VIC_BL_CFG_STRUCT_CHROMA_SIZE          0x22C0C\n#define VIC_BL_CFG_STRUCT_TGT_RECT_LR          0x22C10\n#define VIC_BL_CFG_STRUCT_TGT_RECT_TB          0x22C14\n\n// VIC_FC_CFG_STRUCT_SLOT_CFG2 & VIC_BL_CFG_STRUCT_CFG0.\n#define BLK_KIND(n)    ((n) << 8)\n#define  BLK_KIND_PITCH          0\n#define  BLK_KIND_GENERIC_16BX2  1\n#define BLK_HEIGHT(n)  ((n) << 12)\n#define  BLK_HEIGHT_ONE_GOB      0\n#define  BLK_HEIGHT_SIXTEEN_GOBS 4\n\n// Generic size macros.\n#define SIZE_WIDTH(n)  (((n) - 1) << 0)\n#define SIZE_HEIGHT(n) (((n) - 1) << 16)\n#define RECT_LEFT(n)   ((n) << 0)\n#define RECT_RIGHT(n)  (((n) - 1) << 16)\n#define RECT_TOP(n)    ((n) << 0)\n#define RECT_BOTTOM(n) (((n) - 1) << 16)\n\n#define FORMAT_PROGRESSIVE 0\n#define SOFT_CLAMP_MIN     0\n#define SOFT_CLAMP_MAX     0x3FFu\n#define ALPHA_1_0          0x3FFu\n\ntypedef struct _OutputConfig {\n\tu64 AlphaFillMode:3;\n\tu64 AlphaFillSlot:3;\n\tu64 BackgroundAlpha:10;\n\tu64 BackgroundR:10;\n\tu64 BackgroundG:10;\n\tu64 BackgroundB:10;\n\tu64 RegammaMode:2;\n\tu64 OutputFlipX:1;\n\tu64 OutputFlipY:1;\n\tu64 OutputTranspose:1;\n\tu64 rsvd1:1;\n\tu64 rsvd2:12;\n\tu64 TargetRectLeft:14;\n\tu64 rsvd3:2;\n\tu64 TargetRectRight:14;\n\tu64 rsvd4:2;\n\tu64 TargetRectTop:14;\n\tu64 rsvd5:2;\n\tu64 TargetRectBottom:14;\n\tu64 rsvd6:2;\n} OutputConfig;\n\ntypedef struct _OutputSurfaceConfig {\n\tu64 OutPixelFormat:7;\n\tu64 OutChromaLocHoriz:2;\n\tu64 OutChromaLocVert:2;\n\tu64 OutBlkKind:4;\n\tu64 OutBlkHeight:4;\n\tu64 rsvd0:3;\n\tu64 rsvd1:10;\n\tu64 OutSurfaceWidth:14;\n\tu64 OutSurfaceHeight:14;\n\tu64 rsvd2:4;\n\tu64 OutLumaWidth:14;\n\tu64 OutLumaHeight:14;\n\tu64 rsvd3:4;\n\tu64 OutChromaWidth:14;\n\tu64 OutChromaHeight:14;\n\tu64 rsvd4:4;\n} OutputSurfaceConfig;\n\ntypedef struct _SlotConfig {\n\tu64 SlotEnable:1;\n\tu64 DeNoise:1;\n\tu64 AdvancedDenoise:1;\n\tu64 CadenceDetect:1;\n\tu64 MotionMap:1;\n\tu64 MMapCombine:1;\n\tu64 IsEven:1;\n\tu64 ChromaEven:1;\n\tu64 CurrentFieldEnable:1;\n\tu64 PrevFieldEnable:1;\n\tu64 NextFieldEnable:1;\n\tu64 NextNrFieldEnable:1;\n\tu64 CurMotionFieldEnable:1;\n\tu64 PrevMotionFieldEnable:1;\n\tu64 PpMotionFieldEnable:1;\n\tu64 CombMotionFieldEnable:1;\n\tu64 FrameFormat:4;\n\tu64 FilterLengthY:2;\n\tu64 FilterLengthX:2;\n\tu64 Panoramic:12;\n\tu64 rsvd1:22;\n\tu64 DetailFltClamp:6;\n\tu64 FilterNoise:10;\n\tu64 FilterDetail:10;\n\tu64 ChromaNoise:10;\n\tu64 ChromaDetail:10;\n\tu64 DeinterlaceMode:4;\n\tu64 MotionAccumWeight:3;\n\tu64 NoiseIir:11;\n\tu64 LightLevel:4;\n\tu64 rsvd4:2;\n\tu64 SoftClampLow:10;\n\tu64 SoftClampHigh:10;\n\tu64 rsvd5:3;\n\tu64 rsvd6:9;\n\tu64 PlanarAlpha:10;\n\tu64 ConstantAlpha:1;\n\tu64 StereoInterleave:3;\n\tu64 ClipEnabled:1;\n\tu64 ClearRectMask:8;\n\tu64 DegammaMode:2;\n\tu64 rsvd7:1;\n\tu64 DecompressEnable:1;\n\tu64 rsvd9:5;\n\tu64 DecompressCtbCount:8;\n\tu64 DecompressZbcColor:32;\n\tu64 rsvd12:24;\n\tu64 SourceRectLeft:30;\n\tu64 rsvd14:2;\n\tu64 SourceRectRight:30;\n\tu64 rsvd15:2;\n\tu64 SourceRectTop:30;\n\tu64 rsvd16:2;\n\tu64 SourceRectBottom:30;\n\tu64 rsvd17:2;\n\tu64 DestRectLeft:14;\n\tu64 rsvd18:2;\n\tu64 DestRectRight:14;\n\tu64 rsvd19:2;\n\tu64 DestRectTop:14;\n\tu64 rsvd20:2;\n\tu64 DestRectBottom:14;\n\tu64 rsvd21:2;\n\tu64 rsvd22:32;\n\tu64 rsvd23:32;\n} SlotConfig;\n\ntypedef struct _SlotSurfaceConfig {\n\tu64 SlotPixelFormat:7;\n\tu64 SlotChromaLocHoriz:2;\n\tu64 SlotChromaLocVert:2;\n\tu64 SlotBlkKind:4;\n\tu64 SlotBlkHeight:4;\n\tu64 SlotCacheWidth:3;\n\tu64 rsvd0:10;\n\tu64 SlotSurfaceWidth:14;\n\tu64 SlotSurfaceHeight:14;\n\tu64 rsvd1:4;\n\tu64 SlotLumaWidth:14;\n\tu64 SlotLumaHeight:14;\n\tu64 rsvd2:4;\n\tu64 SlotChromaWidth:14;\n\tu64 SlotChromaHeight:14;\n\tu64 rsvd3:4;\n} SlotSurfaceConfig;\n\ntypedef struct _SlotStruct {\n\tSlotConfig slot_cfg;\n\tSlotSurfaceConfig slot_sfc_cfg;\n\n\t// No need to configure. Reset to zeros.\n\tu8 lumaKeyStruct[0x10];\n\tu8 colorMatrixStruct[0x20];\n\tu8 gamutMatrixStruct[0x20];\n\tu8 blendingSlotStruct[0x10];\n} SlotStruct;\n\ntypedef struct _vic_config_t {\n\t// No need to configure. Reset to zeros.\n\tu8 pipeConfig[0x10];\n\n\tOutputConfig out_cfg;\n\tOutputSurfaceConfig out_sfc_cfg;\n\n\t// No need to configure. Reset to zeros.\n\tu8 out_color_matrix[0x20];\n\tu8 clear_rect[0x10 * 4];\n\n\tSlotStruct slots[8];\n} vic_config_t;\n\n// VIC Fetch Control Engine microcode. Dumped from L4T r33.\nu8 vic_fce_ucode[] = {\n\t0x66, 0x00, 0x00, 0x00, 0x60, 0x07, 0x00, 0x00, 0x42, 0x40, 0x10, 0x00, 0x4E, 0x01, 0x40, 0x00,\n\t0x6A, 0x07, 0x00, 0x00, 0x6E, 0x23, 0x04, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x4E, 0x01, 0x04, 0x00,\n\t0x6A, 0x0B, 0x00, 0x00, 0x6E, 0x1F, 0x04, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x4E, 0x01, 0x10, 0x00,\n\t0x6A, 0x0F, 0x00, 0x00, 0x6E, 0x1F, 0x04, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x48, 0x80, 0x02, 0x00,\n\t0x0E, 0x11, 0x00, 0x00, 0x6A, 0x14, 0x00, 0x00, 0x6E, 0x08, 0x06, 0x00, 0x6C, 0x00, 0x00, 0x00,\n\t0x4E, 0x01, 0x08, 0x00, 0x6A, 0x18, 0x00, 0x00, 0x6E, 0x26, 0x04, 0x00, 0x6C, 0x00, 0x00, 0x00,\n\t0x4E, 0x01, 0x20, 0x00, 0x6A, 0x1C, 0x00, 0x00, 0x6E, 0x26, 0x04, 0x00, 0x6C, 0x00, 0x00, 0x00,\n\t0x4E, 0x01, 0x02, 0x00, 0x6A, 0x20, 0x00, 0x00, 0x6E, 0x24, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00,\n\t0x56, 0x00, 0x10, 0x00, 0x56, 0x40, 0x10, 0x00, 0x22, 0x41, 0x01, 0x00, 0x6C, 0x00, 0x00, 0x00,\n\t0x62, 0x80, 0x01, 0x00, 0x60, 0x47, 0x00, 0x00, 0x60, 0x87, 0x00, 0x00, 0x01, 0x4A, 0x00, 0x00,\n\t0x55, 0xC0, 0x20, 0x00, 0x00, 0x59, 0x00, 0x00, 0x60, 0x87, 0x00, 0x00, 0x60, 0xC7, 0x00, 0x00,\n\t0x01, 0x93, 0x00, 0x00, 0x40, 0x82, 0x02, 0x00, 0x4E, 0x02, 0x00, 0x00, 0x6B, 0x34, 0x00, 0x00,\n\t0x43, 0xC1, 0x10, 0x00, 0x42, 0x02, 0x03, 0x00, 0x00, 0x23, 0x01, 0x00, 0x24, 0xD4, 0x00, 0x00,\n\t0x56, 0x40, 0x3D, 0x00, 0x04, 0xEB, 0x00, 0x00, 0x60, 0x07, 0x01, 0x00, 0x60, 0x47, 0x00, 0x00,\n\t0x6A, 0x3E, 0x00, 0x00, 0x55, 0xC0, 0x30, 0x00, 0x48, 0x00, 0x01, 0x00, 0x48, 0x40, 0x01, 0x00,\n\t0x48, 0x80, 0x01, 0x00, 0x6B, 0x28, 0x02, 0x00, 0x56, 0x40, 0x09, 0x00, 0x04, 0x4D, 0x01, 0x00,\n\t0x06, 0x4D, 0x00, 0x00, 0x42, 0xC0, 0x03, 0x00, 0x56, 0x80, 0x09, 0x00, 0x04, 0xFE, 0x01, 0x00,\n\t0x00, 0xF9, 0x01, 0x00, 0x4E, 0x02, 0x00, 0x00, 0x6B, 0x32, 0x02, 0x00, 0x55, 0x40, 0x2F, 0x00,\n\t0x56, 0x80, 0x0D, 0x00, 0x4F, 0x00, 0x00, 0x00, 0x6A, 0x0D, 0x02, 0x00, 0x55, 0x40, 0x31, 0x00,\n\t0x56, 0x80, 0x0B, 0x00, 0x0C, 0x2B, 0x00, 0x00, 0x6A, 0x13, 0x02, 0x00, 0x43, 0x45, 0x03, 0x00,\n\t0x42, 0x86, 0x03, 0x00, 0x4D, 0x06, 0x02, 0x00, 0x6A, 0x0D, 0x02, 0x00, 0x42, 0x86, 0x03, 0x00,\n\t0x22, 0x7E, 0x01, 0x00, 0x4E, 0x04, 0x00, 0x00, 0x6B, 0x32, 0x02, 0x00, 0x55, 0x40, 0x17, 0x00,\n\t0x0D, 0x2C, 0x00, 0x00, 0x56, 0xC0, 0x09, 0x00, 0x6A, 0x1E, 0x02, 0x00, 0x48, 0xC0, 0x01, 0x00,\n\t0x43, 0x04, 0x03, 0x00, 0x6C, 0x20, 0x02, 0x00, 0x55, 0x40, 0x19, 0x00, 0x01, 0x2C, 0x01, 0x00,\n\t0x65, 0x23, 0x01, 0x00, 0x42, 0x42, 0x03, 0x00, 0x00, 0x2C, 0x01, 0x00, 0x24, 0x14, 0x01, 0x00,\n\t0x00, 0x2C, 0x01, 0x00, 0x24, 0x14, 0x01, 0x00, 0x00, 0x3C, 0x01, 0x00, 0x42, 0x04, 0x09, 0x00,\n\t0x42, 0xC3, 0x02, 0x00, 0x65, 0x54, 0x01, 0x00, 0x65, 0x55, 0x01, 0x00, 0x42, 0x45, 0x0D, 0x00,\n\t0x62, 0x03, 0x00, 0x00, 0x62, 0x44, 0x00, 0x00, 0x62, 0x85, 0x00, 0x00, 0x62, 0xC2, 0x00, 0x00,\n\t0x22, 0x48, 0x1F, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x48, 0x00, 0x01, 0x00, 0x6C, 0x28, 0x02, 0x00,\n\t0x62, 0x80, 0x01, 0x00, 0x60, 0x07, 0x00, 0x00, 0x60, 0x47, 0x00, 0x00, 0x60, 0x87, 0x00, 0x00,\n\t0x01, 0x01, 0x00, 0x00, 0x43, 0x00, 0x02, 0x00, 0x40, 0x00, 0x02, 0x00, 0x01, 0xCA, 0x01, 0x00,\n\t0x60, 0x03, 0x01, 0x00, 0x01, 0xA0, 0x01, 0x00, 0x60, 0x40, 0x00, 0x00, 0x65, 0x01, 0x00, 0x00,\n\t0x55, 0xC0, 0x2E, 0x00, 0x01, 0x18, 0x00, 0x00, 0x43, 0x00, 0x04, 0x00, 0x43, 0x41, 0x06, 0x00,\n\t0x6F, 0x00, 0x00, 0x00, 0x61, 0xC1, 0x00, 0x00, 0x61, 0x42, 0x01, 0x00, 0x65, 0xB5, 0x00, 0x00,\n\t0x65, 0x73, 0x01, 0x00, 0x65, 0x35, 0x01, 0x00, 0x65, 0x34, 0x01, 0x00, 0x42, 0x04, 0x0D, 0x00,\n\t0x01, 0x14, 0x01, 0x00, 0x42, 0x04, 0x03, 0x00, 0x00, 0x20, 0x00, 0x00, 0x43, 0x03, 0x05, 0x00,\n\t0x43, 0x85, 0x02, 0x00, 0x00, 0xAA, 0x00, 0x00, 0x48, 0x46, 0x01, 0x00, 0x65, 0xEB, 0x00, 0x00,\n\t0x00, 0x9A, 0x00, 0x00, 0x65, 0xB2, 0x01, 0x00, 0x00, 0xA6, 0x01, 0x00, 0x42, 0x86, 0x0D, 0x00,\n\t0x61, 0x42, 0x01, 0x00, 0x01, 0xAE, 0x01, 0x00, 0x00, 0x71, 0x00, 0x00, 0x42, 0x82, 0x08, 0x00,\n\t0x42, 0xC3, 0x08, 0x00, 0x48, 0x40, 0x01, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6E, 0x34, 0x02, 0x00,\n\t0x65, 0x79, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x6C, 0x36, 0x04, 0x00, 0x6E, 0x34, 0x02, 0x00,\n\t0x48, 0x7F, 0x01, 0x00, 0x6C, 0x0A, 0x06, 0x00, 0x6E, 0x34, 0x02, 0x00, 0x6E, 0x05, 0x04, 0x00,\n\t0x65, 0x79, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x41, 0x87, 0x03, 0x00, 0x65, 0xBA, 0x00, 0x00,\n\t0x65, 0xB2, 0x00, 0x00, 0x42, 0x82, 0x02, 0x00, 0x00, 0x51, 0x00, 0x00, 0x61, 0xC1, 0x00, 0x00,\n\t0x65, 0xFB, 0x00, 0x00, 0x65, 0xF3, 0x00, 0x00, 0x41, 0x87, 0x05, 0x00, 0x65, 0xF3, 0x00, 0x00,\n\t0x42, 0xC3, 0x08, 0x00, 0x00, 0x59, 0x00, 0x00, 0x60, 0xC7, 0x00, 0x00, 0x60, 0xC7, 0x00, 0x00,\n\t0x56, 0xC0, 0x21, 0x00, 0x04, 0xDF, 0x01, 0x00, 0x43, 0xC7, 0x15, 0x00, 0x00, 0x38, 0x00, 0x00,\n\t0x00, 0x79, 0x00, 0x00, 0x42, 0xC3, 0x20, 0x00, 0x43, 0xC3, 0x04, 0x00, 0x42, 0x00, 0x30, 0x00,\n\t0x42, 0x41, 0x30, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x60, 0xC7, 0x01, 0x00,\n\t0x22, 0x78, 0x01, 0x00, 0x22, 0x79, 0x03, 0x00, 0x22, 0x7F, 0x1F, 0x00, 0x6F, 0x00, 0x00, 0x00,\n\t0x6E, 0x34, 0x02, 0x00, 0x6E, 0x05, 0x04, 0x00, 0x4B, 0x41, 0x00, 0x00, 0x60, 0xC7, 0x01, 0x00,\n\t0x60, 0x87, 0x01, 0x00, 0x43, 0x86, 0x15, 0x00, 0x00, 0x30, 0x00, 0x00, 0x65, 0x39, 0x01, 0x00,\n\t0x42, 0x04, 0x05, 0x00, 0x4E, 0x05, 0x7E, 0x00, 0x6A, 0x1B, 0x06, 0x00, 0x55, 0xC0, 0x3D, 0x00,\n\t0x0A, 0x3C, 0x01, 0x00, 0x60, 0xC7, 0x01, 0x00, 0x22, 0x78, 0x01, 0x00, 0x22, 0x79, 0x03, 0x00,\n\t0x22, 0x7C, 0x09, 0x00, 0x22, 0x7F, 0x1F, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x65, 0x7A, 0x01, 0x00,\n\t0x42, 0x45, 0x05, 0x00, 0x65, 0xBB, 0x01, 0x00, 0x42, 0x86, 0x05, 0x00, 0x55, 0xC0, 0x3D, 0x00,\n\t0x0A, 0x7D, 0x01, 0x00, 0x0A, 0xBE, 0x01, 0x00, 0x07, 0xC7, 0x01, 0x00, 0x0B, 0x7D, 0x01, 0x00,\n\t0x0B, 0xBE, 0x01, 0x00, 0x55, 0xC0, 0x3D, 0x00, 0x0A, 0x3C, 0x01, 0x00, 0x60, 0xC7, 0x01, 0x00,\n\t0x22, 0x78, 0x01, 0x00, 0x22, 0x79, 0x03, 0x00, 0x22, 0x7A, 0x05, 0x00, 0x22, 0x7B, 0x07, 0x00,\n\t0x22, 0x7C, 0x09, 0x00, 0x22, 0x7D, 0x0B, 0x00, 0x22, 0x7E, 0x0D, 0x00, 0x22, 0x7F, 0x1F, 0x00,\n\t0x6F, 0x00, 0x00, 0x00\n};\n\nvic_config_t __attribute__((aligned (0x100))) vic_cfg = {0};\n\nu32 _vic_read_priv(u32 addr)\n{\n\tu32 addr_lsb = addr & 0xFF;\n\n\t// Set address LSB.\n\tif (addr_lsb)\n\t\tVIC(PVIC_FALCON_ADDR) = addr_lsb >> 2;\n\n\t// Set address.\n\tu32 val = VIC(PVIC_FALCON_PA_OFFSET + (addr >> 6));\n\n\t// Unset address LSB.\n\tif (addr_lsb)\n\t\tVIC(PVIC_FALCON_ADDR) = 0;\n\n\treturn val;\n}\n\nstatic void _vic_write_priv(u32 addr, u32 data)\n{\n\tu32 addr_lsb = addr & 0xFF;\n\n\t// Set address LSB.\n\tif (addr_lsb)\n\t\tVIC(PVIC_FALCON_ADDR) = addr_lsb >> 2;\n\n\t// Set address.\n\tVIC(PVIC_FALCON_PA_OFFSET + (addr >> 6)) = data;\n\n\t// Unset address LSB.\n\tif (addr_lsb)\n\t\tVIC(PVIC_FALCON_ADDR) = 0;\n}\n\nint vic_wait_idle()\n{\n\tu32 timeout_count = 15000; // 150ms.\n\n\twhile (VIC(PVIC_FALCON_IDLESTATE))\n\t{\n\t\tusleep(10);\n\n\t\ttimeout_count--;\n\t\tif (!timeout_count)\n\t\t\treturn 1;\n\t};\n\n\treturn 0;\n}\n\nvoid vic_set_surface(const vic_surface_t *sfc)\n{\n\tu32 flip_x  = 0;\n\tu32 flip_y  = 0;\n\tu32 swap_xy = 0;\n\tu32 const_alpha = 0;\n\n\tu32 width   = sfc->width;\n\tu32 height  = sfc->height;\n\tu32 pix_fmt = sfc->pix_fmt;\n\tu32 src_buf = sfc->src_buf;\n\tu32 dst_buf = sfc->dst_buf;\n\n\t// Get format alpha type.\n\tswitch (sfc->pix_fmt)\n\t{\n\tcase VIC_PIX_FORMAT_L8:\n\tcase VIC_PIX_FORMAT_X1B5G5R5:\n\tcase VIC_PIX_FORMAT_B5G5R5X1:\n\tcase VIC_PIX_FORMAT_X8B8G8R8:\n\tcase VIC_PIX_FORMAT_X8R8G8B8:\n\tcase VIC_PIX_FORMAT_B8G8R8X8:\n\tcase VIC_PIX_FORMAT_R8G8B8X8:\n\t\tconst_alpha = 1;\n\t\tbreak;\n\n\tcase VIC_PIX_FORMAT_A8B8G8R8:\n\tcase VIC_PIX_FORMAT_A8R8G8B8:\n\tcase VIC_PIX_FORMAT_B8G8R8A8:\n\tcase VIC_PIX_FORMAT_R8G8B8A8:\n\tdefault:\n\t\tbreak;\n\t}\n\n\t// Get rotation parameters.\n\tswitch (sfc->rotation)\n\t{\n\tcase VIC_ROTATION_90:\n\t\tswap_xy = 1;\n\t\tbreak;\n\n\tcase VIC_ROTATION_180:\n\t\tflip_x  = 1;\n\t\tflip_y  = 1;\n\t\tbreak;\n\n\tcase VIC_ROTATION_270:\n\t\tflip_x  = 1;\n\t\tswap_xy = 1;\n\t\tbreak;\n\n\tcase VIC_ROTATION_0:\n\tdefault:\n\t\tbreak;\n\t}\n\n\t// Set output surface format.\n\tvic_cfg.out_sfc_cfg.OutPixelFormat = pix_fmt;\n\tvic_cfg.out_sfc_cfg.OutBlkKind     = BLK_KIND_PITCH;\n\tvic_cfg.out_sfc_cfg.OutBlkHeight   = 0;\n\n\t// Set output rotation/flip.\n\tvic_cfg.out_cfg.OutputFlipX     = flip_x;\n\tvic_cfg.out_cfg.OutputFlipY     = flip_y;\n\tvic_cfg.out_cfg.OutputTranspose = swap_xy;\n\n\t// Set output surface resolution.\n\tvic_cfg.out_sfc_cfg.OutSurfaceWidth  = width  - 1;\n\tvic_cfg.out_sfc_cfg.OutSurfaceHeight = height - 1;\n\tvic_cfg.out_sfc_cfg.OutLumaWidth     = width  - 1;\n\tvic_cfg.out_sfc_cfg.OutLumaHeight    = height - 1;\n\n\t// Set output destination rectangle. Anything outside will not be touched at output buffer.\n\tvic_cfg.out_cfg.TargetRectLeft   = 0;\n\tvic_cfg.out_cfg.TargetRectRight  = width - 1;\n\tvic_cfg.out_cfg.TargetRectTop    = 0;\n\tvic_cfg.out_cfg.TargetRectBottom = height - 1;\n\n\t// Initialize slot parameters.\n\tvic_cfg.slots[0].slot_cfg.SlotEnable    = 1;\n\tvic_cfg.slots[0].slot_cfg.SoftClampLow  = SOFT_CLAMP_MIN;\n\tvic_cfg.slots[0].slot_cfg.SoftClampHigh = SOFT_CLAMP_MAX;\n\tvic_cfg.slots[0].slot_cfg.PlanarAlpha   = ALPHA_1_0;\n\tvic_cfg.slots[0].slot_cfg.ConstantAlpha = const_alpha;\n\tvic_cfg.slots[0].slot_cfg.FrameFormat   = FORMAT_PROGRESSIVE;\n\n\t// Set input source rectangle.\n\tvic_cfg.slots[0].slot_cfg.SourceRectLeft   = 0;\n\tvic_cfg.slots[0].slot_cfg.SourceRectRight  = (width  - 1) << 16;\n\tvic_cfg.slots[0].slot_cfg.SourceRectTop    = 0;\n\tvic_cfg.slots[0].slot_cfg.SourceRectBottom = (height - 1) << 16;\n\n\t// Set input destination rectangle.\n\tvic_cfg.slots[0].slot_cfg.DestRectLeft   = 0;\n\tvic_cfg.slots[0].slot_cfg.DestRectRight  = (width  - 1);\n\tvic_cfg.slots[0].slot_cfg.DestRectTop    = 0;\n\tvic_cfg.slots[0].slot_cfg.DestRectBottom = (height - 1);\n\n\t// Set input surface format.\n\tvic_cfg.slots[0].slot_sfc_cfg.SlotPixelFormat = pix_fmt;\n\tvic_cfg.slots[0].slot_sfc_cfg.SlotBlkKind     = BLK_KIND_PITCH;\n\tvic_cfg.slots[0].slot_sfc_cfg.SlotBlkHeight   = 0;\n\tvic_cfg.slots[0].slot_sfc_cfg.SlotCacheWidth  = CACHE_WIDTH_64BX4;\n\n\t// Set input surface resolution.\n\tvic_cfg.slots[0].slot_sfc_cfg.SlotSurfaceWidth  = width  - 1;\n\tvic_cfg.slots[0].slot_sfc_cfg.SlotSurfaceHeight = height - 1;\n\tvic_cfg.slots[0].slot_sfc_cfg.SlotLumaWidth     = width  - 1;\n\tvic_cfg.slots[0].slot_sfc_cfg.SlotLumaHeight    = height - 1;\n\n\t// Flush data.\n\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_CLEAN_WAY, false);\n\n\t// Set parameters base and size. Causes a parse by surface cache.\n\t_vic_write_priv(VIC_SC_PRAMBASE, (u32)&vic_cfg >> 8);\n\t_vic_write_priv(VIC_SC_PRAMSIZE, sizeof(vic_config_t) >> 6);\n\n\t// Wait for surface cache to get ready.\n\tvic_wait_idle();\n\n\t// Set slot mapping.\n\t_vic_write_priv(VIC_FC_SLOT_MAP, 0xFFFFFFF0);\n\n\t// Set input surface buffer.\n\t_vic_write_priv(VIC_SC_SFC0_BASE_LUMA(0), src_buf >> 8);\n\n\t// Set output surface buffer.\n\t_vic_write_priv(VIC_BL_TARGET_BASADR, dst_buf >> 8);\n\n\t// Set blending config and push changes to surface cache.\n\t_vic_write_priv(VIC_BL_CONFIG, SLOTMASK(0x1F) | PROCESS_CFG_STRUCT_TRIGGER | SUBPARTITION_MODE);\n\n\t// Wait for surface cache to get ready.\n\tvic_wait_idle();\n}\n\nint vic_compose()\n{\n\t// Wait for surface cache to get ready. Otherwise VIC will hang.\n\tint res = vic_wait_idle();\n\n\t// Start composition of a single frame.\n\t_vic_write_priv(VIC_FC_COMPOSE, COMPOSE_START);\n\n\treturn res;\n}\n\nint vic_init()\n{\n\tclock_enable_vic();\n\n\t// Load Fetch Control Engine microcode.\n\tfor (u32 i = 0; i < sizeof(vic_fce_ucode) / sizeof(u32); i++)\n\t{\n\t\t_vic_write_priv(VIC_FC_FCE_UCODE_ADDR, (i * sizeof(u32)));\n\t\t_vic_write_priv(VIC_FC_FCE_UCODE_INST, *(u32 *)&vic_fce_ucode[i * sizeof(u32)]);\n\t}\n\n\t// Start Fetch Control Engine.\n\t_vic_write_priv(VIC_FC_FCE_CTRL, START_TRIGGER);\n\n\treturn vic_wait_idle();\n}\n\nvoid vic_end()\n{\n\tclock_disable_vic();\n}\n"
  },
  {
    "path": "bdk/display/vic.h",
    "content": "/*\n * VIC driver for Tegra X1\n *\n * Copyright (c) 2018-2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _VIC_H_\n#define _VIC_H_\n\n#include <utils/types.h>\n\n#define VIC_THI_SLCG_OVERRIDE_LOW_A 0x8C\n\ntypedef enum _vic_rotation_t\n{\n\tVIC_ROTATION_0   = 0,\n\tVIC_ROTATION_90  = 1,\n\tVIC_ROTATION_180 = 2,\n\tVIC_ROTATION_270 = 3,\n} vic_rotation_t;\n\ntypedef enum _vic_pix_format_t\n{\n\tVIC_PIX_FORMAT_L8       =  1, //  8-bit LUT.\n\tVIC_PIX_FORMAT_X1B5G5R5 = 21, // 16-bit XBGR.\n\tVIC_PIX_FORMAT_B5G5R5X1 = 23, // 16-bit BGRX.\n\n\tVIC_PIX_FORMAT_A8B8G8R8 = 31, // 32-bit ABGR.\n\tVIC_PIX_FORMAT_A8R8G8B8 = 32, // 32-bit ARGB.\n\tVIC_PIX_FORMAT_B8G8R8A8 = 33, // 32-bit BGRA.\n\tVIC_PIX_FORMAT_R8G8B8A8 = 34, // 32-bit RGBA.\n\n\tVIC_PIX_FORMAT_X8B8G8R8 = 35, // 32-bit XBGR.\n\tVIC_PIX_FORMAT_X8R8G8B8 = 36, // 32-bit XRGB.\n\tVIC_PIX_FORMAT_B8G8R8X8 = 37, // 32-bit BGRX.\n\tVIC_PIX_FORMAT_R8G8B8X8 = 38, // 32-bit RGBX.\n} vic_pix_format_t;\n\ntypedef struct _vic_surface_t\n{\n\tu32 src_buf;\n\tu32 dst_buf;\n\tu32 width;\n\tu32 height;\n\tu32 pix_fmt;\n\tu32 rotation;\n} vic_surface_t;\n\nvoid vic_set_surface(const vic_surface_t *sfc);\nint  vic_wait_idle();\nint  vic_compose();\nint  vic_init();\nvoid vic_end();\n\n#endif\n"
  },
  {
    "path": "bdk/exception_handlers.S",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/*\n * Armv7tdmi Status register.\n *\n * bit0: Mode 0.\n * bit1: Mode 1.\n * bit2: Mode 2.\n * bit3: Mode 3.\n * bit4: Mode 4.\n * bit5: Thumb state.\n * bit6: FIQ disable.\n * bit7: IRQ disable.\n * bit8-27: Reserved.\n * bit28: Overflow condition.\n * bit29: Carry/Borrow/Extend condition.\n * bit30: Zero condition.\n * bit31: Negative/Less than condition.\n *\n * M[4:0] | Mode | Visible Thumb-state registers             | Visible ARM-state registers\n * 10000  | USER | r0–r7, SP,     LR,     PC, CPSR           | r0–r14,                   PC, CPSR\n * 10001  | FIQ  | r0–r7, SP_fiq, LR_fiq, PC, CPSR, SPSR_fiq | r0–r7,  r8_fiq–r14_fiq,   PC, CPSR, SPSR_fiq\n * 10010  | IRQ  | r0–r7, SP_irq, LR_irq, PC, CPSR, SPSR_irq | r0–r12, r13_irq, r14_irq, PC, CPSR, SPSR_irq\n * 10011  | SVC  | r0–r7, SP_svc, LR_svc, PC, CPSR, SPSR_svc | r0–r12, r13_svc, r14_svc, PC, CPSR, SPSR_svc\n * 10111  | ABRT | r0–r7, SP_abt, LR_abt, PC, CPSR, SPSR_abt | r0–r12, r13_abt, r14_abt, PC, CPSR, SPSR_abt\n * 11011  | UNDF | r0–r7, SP_und, LR_und, PC, CPSR, SPSR_und | r0–r12, r13_und, r14_und, PC, CPSR, SPSR_und\n * 11111  | SYS  | r0–r7, SP,     LR,     PC, CPSR           | r0–r14,                   PC, CPSR\n */\n\n#define EXCP_EN_ADDR   0x4003FF1C\n#define EXCP_TYPE_ADDR 0x4003FF18\n#define EXCP_LR_ADDR   0x4003FF14\n\n#define EXCP_VEC_BASE  0x6000F000\n#define EVP_COP_RESET_VECTOR          0x200\n#define EVP_COP_UNDEF_VECTOR          0x204\n#define EVP_COP_SWI_VECTOR            0x208\n#define EVP_COP_PREFETCH_ABORT_VECTOR 0x20C\n#define EVP_COP_DATA_ABORT_VECTOR     0x210\n#define EVP_COP_RSVD_VECTOR           0x214\n#define EVP_COP_IRQ_VECTOR            0x218\n#define EVP_COP_FIQ_VECTOR            0x21C\n\n#define MODE_USR  0x10\n#define MODE_FIQ  0x11\n#define MODE_IRQ  0x12\n#define MODE_SVC  0x13\n#define MODE_ABT  0x17\n#define MODE_UDF  0x1B\n#define MODE_SYS  0x1F\n#define MODE_MASK 0x1F\n\n#define FIQ 0x40\n#define IRQ 0x80\n\n.section .text._irq_setup\n.arm\n\n.extern ipl_main\n.type ipl_main, %function\n\n.extern svc_handler\n.type svc_handler, %function\n\n.extern irq_handler\n.type irq_handler, %function\n\n.extern fiq_setup\n.type fiq_setup, %function\n\n.extern fiq_handler\n.type fiq_handler, %function\n\n.globl _irq_setup\n.type _irq_setup, %function\n_irq_setup:\n\tMRS R0, CPSR\n\tBIC R0, R0, #MODE_MASK              /* Clear mode bits */\n\tORR R0, R0, #(MODE_SVC | IRQ | FIQ) /* SUPERVISOR mode, IRQ/FIQ disabled */\n\tMSR CPSR, R0\n\n\t/* Setup IRQ stack pointer */\n\tMSR CPSR, #(MODE_IRQ | IRQ | FIQ) /* IRQ mode, IRQ/FIQ disabled */\n\tLDR SP, =0x40040000\n\n\t/* Setup FIQ stack pointer */\n\tMSR CPSR, #(MODE_FIQ | IRQ | FIQ) /* FIQ mode, IRQ/FIQ disabled */\n\tLDR SP, =0x40040000\n\n\t/* Setup SYS stack pointer */\n\tMSR CPSR, #(MODE_SYS | IRQ | FIQ) /* SYSTEM mode, IRQ/FIQ disabled */\n\tLDR SP, =0x4003FF00               /* Will be changed later to DRAM */\n\n\tMOV LR, PC\n\tBL setup_vectors\n\t/*BL fiq_setup*/\n\n\t/* Enable interrupts */\n\tBL irq_enable_cpu_irq_exceptions\n\n\tB ipl_main\n\tB .\n\n.globl excp_reset\n.type excp_reset, %function\nexcp_reset:\n\tLDR R0, =EXCP_EN_ADDR\n\tLDR R1, =0x30505645 /* EVP0 */\n\tSTR R1, [R0]        /* EVP0 in EXCP_EN_ADDR */\n\tLDR R0, =EXCP_LR_ADDR\n\tMOV R1, LR\n\tSTR R1, [R0]        /* Save LR in EXCP_LR_ADDR */\n\tLDR R0, =__bss_start\n\tEOR R1, R1, R1\n\tLDR R2, =__bss_end\n\tSUB R2, R2, R0\n\tBL memset\n\tB _irq_setup\n\n_reset_handler:\n\tLDR R0, =EXCP_TYPE_ADDR\n\tLDR R1, =0x545352   /* RST */\n\tSTR R1, [R0]        /* RST in EXCP_TYPE_ADDR */\n\tB excp_reset\n\n_undefined_handler:\n\tLDR R0, =EXCP_TYPE_ADDR\n\tLDR R1, =0x464455   /* UDF */\n\tSTR R1, [R0]        /* UDF in EXCP_TYPE_ADDR */\n\tB excp_reset\n\n_prefetch_abort_handler:\n\tLDR R0, =EXCP_TYPE_ADDR\n\tLDR R1, =0x54424150 /* PABT */\n\tSTR R1, [R0]        /* PABT in EXCP_TYPE_ADDR */\n\tB excp_reset\n\n_data_abort_handler:\n\tLDR R0, =EXCP_TYPE_ADDR\n\tLDR R1, =0x54424144 /* DABT */\n\tSTR R1, [R0]        /* DABT in EXCP_TYPE_ADDR */\n\tB excp_reset\n\n.globl irq_enable_cpu_irq_exceptions\n.type irq_enable_cpu_irq_exceptions, %function\nirq_enable_cpu_irq_exceptions:\n\tMRS R12, CPSR\n\tBIC R12, R12, #(IRQ | FIQ) /* IRQ/FIQ enabled */\n\tMSR CPSR, R12\n\tBX LR\n\n.globl irq_disable_cpu_irq_exceptions\n.type irq_disable_cpu_irq_exceptions, %function\nirq_disable_cpu_irq_exceptions:\n\tMRS R12, CPSR\n\tORR R12, R12, #(IRQ | FIQ) /* IRQ/FIQ disabled */\n\tMSR CPSR, R12\n\tBX LR\n\n_irq_handler:\n\tMOV R13, R0    /* Save R0 in R13_IRQ */\n\tSUB R0, LR, #4 /* Put return address in R0_SYS */\n\tMOV LR, R1     /* Save R1 in R14_IRQ (LR) */\n\tMRS R1, SPSR   /* Put the SPSR in R1_SYS */\n\n\tMSR CPSR_c, #(MODE_SYS | IRQ)  /* SYSTEM mode, IRQ disabled */\n\tSTMFD SP!, {R0, R1}            /* SPSR and PC */\n\tSTMFD SP!, {R2-R3, R12, LR}    /* AAPCS-clobbered registers */\n\tMOV R0, SP                     /* Make SP_SYS visible to IRQ mode */\n\tSUB SP, SP, #8                 /* Make room for stacking R0 and R1 */\n\n\tMSR CPSR_c, #(MODE_IRQ | IRQ) /* IRQ mode, IRQ disabled */\n\tSTMFD R0!, {R13, R14}         /* Finish saving the context (R0, R1) */\n\n\tMSR CPSR_c, #(MODE_SYS | IRQ) /* SYSTEM mode, IRQ disabled */\n\tLDR R12, =irq_handler\n\tMOV LR, PC                    /* Copy the return address to link register */\n\tBX R12                        /* Call the C IRQ handler (ARM/THUMB) */\n\n\tMSR CPSR_c, #(MODE_SYS | IRQ | FIQ) /* SYSTEM mode, IRQ/FIQ disabled */\n\tMOV R0, SP                          /* Make SP_SYS visible to IRQ mode */\n\tADD SP, SP, #32                     /* Fake unstacking 8 registers from SP_SYS */\n\n\tMSR CPSR_c, #(MODE_IRQ | IRQ | FIQ) /* IRQ mode, IRQ/FIQ disabled */\n\tMOV SP, R0                          /* Copy SP_SYS to SP_IRQ */\n\tLDR R0, [SP, #28]                   /* Load the saved SPSR from the stack */\n\tMSR SPSR_cxsf, R0                   /* Copy it into SPSR_IRQ */\n\n\tLDMFD SP, {R0-R3, R12, LR}^ /* Unstack all saved USER/SYSTEM registers */\n\tNOP                         /* Cant access barked registers immediately */\n\tLDR LR, [SP, #24]           /* Load return address from the SYS stack */\n\tMOVS PC, LR                 /* Return restoring CPSR from SPSR */\n\n_fiq_handler:\n\tBL fiq_handler\n\nsetup_vectors:\n\t/* Setup vectors */\n\tLDR R0, =EXCP_VEC_BASE\n\n\tLDR R1, =_reset_handler\n\tSTR R1, [R0, #EVP_COP_RESET_VECTOR]\n\n\tLDR R1, =_undefined_handler\n\tSTR R1, [R0, #EVP_COP_UNDEF_VECTOR]\n\n\tLDR R1, =_reset_handler\n\tSTR R1, [R0, #EVP_COP_SWI_VECTOR]\n\n\tLDR R1, =_prefetch_abort_handler\n\tSTR R1, [R0, #EVP_COP_PREFETCH_ABORT_VECTOR]\n\n\tLDR R1, =_data_abort_handler\n\tSTR R1, [R0, #EVP_COP_DATA_ABORT_VECTOR]\n\n\tLDR R1, =_reset_handler\n\tSTR R1, [R0, #EVP_COP_RSVD_VECTOR]\n\n\tLDR R1, =_irq_handler\n\tSTR R1, [R0, #EVP_COP_IRQ_VECTOR]\n\n\tLDR R1, =_fiq_handler\n\tSTR R1, [R0, #EVP_COP_FIQ_VECTOR]\n\n\tBX LR\n"
  },
  {
    "path": "bdk/fatfs_cfg.h",
    "content": "/*\n * Copyright (c) 2020 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _FATFS_CFG_H_\n#define _FATFS_CFG_H_\n\n// define FFCFG_INC in a project to use a specific FatFS configuration.\n// Example: FFCFG_INC := '\"../$(PROJECT_DIR)/libs/fatfs/ffconf.h\"'\n#ifdef FFCFG_INC\n#include FFCFG_INC\n#else\n#include \"fatfs_conf.h\"\n#endif\n\n#endif\n"
  },
  {
    "path": "bdk/fatfs_conf.h",
    "content": "/*---------------------------------------------------------------------------/\n/  FatFs Functional Configurations\n/---------------------------------------------------------------------------*/\n\n#define FFCONF_DEF\t86604\t/* Revision ID */\n\n/*---------------------------------------------------------------------------/\n/ Function Configurations\n/---------------------------------------------------------------------------*/\n\n#define FF_FS_READONLY\t0\n/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)\n/  Read-only configuration removes writing API functions, f_write(), f_sync(),\n/  f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()\n/  and optional writing functions as well. */\n\n\n#define FF_FS_MINIMIZE\t0\n/* This option defines minimization level to remove some basic API functions.\n/\n/   0: Basic functions are fully enabled.\n/   1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()\n/      are removed.\n/   2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.\n/   3: f_lseek() function is removed in addition to 2. */\n\n\n#define FF_USE_STRFUNC\t2\n/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().\n/\n/  0: Disable string functions.\n/  1: Enable without LF-CRLF conversion.\n/  2: Enable with LF-CRLF conversion. */\n\n\n#define FF_USE_FIND\t\t1\n/* This option switches filtered directory read functions, f_findfirst() and\n/  f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */\n\n\n#define FF_USE_MKFS\t\t0\n/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */\n\n#if FF_USE_MKFS\n#define FF_MKFS_LABEL \"SWITCH SD  \"\n#endif\n/* This sets FAT/FAT32 label. Exactly 11 characters, all caps. */\n\n\n#define FF_USE_FASTSEEK\t0\n/* This option switches fast seek function. (0:Disable or 1:Enable) */\n\n#define FF_FASTFS 0\n#if FF_FASTFS\n#undef FF_USE_FASTSEEK\n#define FF_USE_FASTSEEK\t1\n#endif\n/* This option switches fast access to chained clusters. (0:Disable or 1:Enable) */\n\n\n#define FF_SIMPLE_GPT 1\n/* This option switches support for the first GPT partition. (0:Disable or 1:Enable) */\n\n\n#define FF_USE_EXPAND\t0\n/* This option switches f_expand function. (0:Disable or 1:Enable) */\n\n\n#define FF_USE_CHMOD\t1\n/* This option switches attribute manipulation functions, f_chmod() and f_utime().\n/  (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */\n\n\n#define FF_USE_LABEL\t0\n/* This option switches volume label functions, f_getlabel() and f_setlabel().\n/  (0:Disable or 1:Enable) */\n\n\n#define FF_USE_FORWARD\t0\n/* This option switches f_forward() function. (0:Disable or 1:Enable) */\n\n\n/*---------------------------------------------------------------------------/\n/ Locale and Namespace Configurations\n/---------------------------------------------------------------------------*/\n\n#define FF_CODE_PAGE\t850\n/* This option specifies the OEM code page to be used on the target system.\n/  Incorrect code page setting can cause a file open failure.\n/\n/   437 - U.S.\n/   720 - Arabic\n/   737 - Greek\n/   771 - KBL\n/   775 - Baltic\n/   850 - Latin 1\n/   852 - Latin 2\n/   855 - Cyrillic\n/   857 - Turkish\n/   860 - Portuguese\n/   861 - Icelandic\n/   862 - Hebrew\n/   863 - Canadian French\n/   864 - Arabic\n/   865 - Nordic\n/   866 - Russian\n/   869 - Greek 2\n/   932 - Japanese (DBCS)\n/   936 - Simplified Chinese (DBCS)\n/   949 - Korean (DBCS)\n/   950 - Traditional Chinese (DBCS)\n/     0 - Include all code pages above and configured by f_setcp()\n*/\n\n\n#define FF_USE_LFN\t\t3\n#define FF_MAX_LFN\t\t255\n/* The FF_USE_LFN switches the support for LFN (long file name).\n/\n/   0: Disable LFN. FF_MAX_LFN has no effect.\n/   1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.\n/   2: Enable LFN with dynamic working buffer on the STACK.\n/   3: Enable LFN with dynamic working buffer on the HEAP.\n/\n/  To enable the LFN, ffunicode.c needs to be added to the project. The LFN function\n/  requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and\n/  additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.\n/  The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can\n/  be in range of 12 to 255. It is recommended to be set 255 to fully support LFN\n/  specification.\n/  When use stack for the working buffer, take care on stack overflow. When use heap\n/  memory for the working buffer, memory management functions, ff_memalloc() and\n/  ff_memfree() in ffsystem.c, need to be added to the project. */\n\n\n#define FF_LFN_UNICODE\t0\n/* This option switches the character encoding on the API when LFN is enabled.\n/\n/   0: ANSI/OEM in current CP (TCHAR = char)\n/   1: Unicode in UTF-16 (TCHAR = WCHAR)\n/   2: Unicode in UTF-8 (TCHAR = char)\n/   3: Unicode in UTF-32 (TCHAR = DWORD)\n/\n/  Also behavior of string I/O functions will be affected by this option.\n/  When LFN is not enabled, this option has no effect. */\n\n\n#define FF_LFN_BUF\t\t255\n#define FF_SFN_BUF\t\t12\n/* This set of options defines size of file name members in the FILINFO structure\n/  which is used to read out directory items. These values should be suffcient for\n/  the file names to read. The maximum possible length of the read file name depends\n/  on character encoding. When LFN is not enabled, these options have no effect. */\n\n\n#define FF_STRF_ENCODE\t0\n/* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(),\n/  f_putc(), f_puts and f_printf() convert the character encoding in it.\n/  This option selects assumption of character encoding ON THE FILE to be\n/  read/written via those functions.\n/\n/   0: ANSI/OEM in current CP\n/   1: Unicode in UTF-16LE\n/   2: Unicode in UTF-16BE\n/   3: Unicode in UTF-8\n*/\n\n\n#define FF_FS_RPATH\t\t0\n/* This option configures support for relative path.\n/\n/   0: Disable relative path and remove related functions.\n/   1: Enable relative path. f_chdir() and f_chdrive() are available.\n/   2: f_getcwd() function is available in addition to 1.\n*/\n\n\n/*---------------------------------------------------------------------------/\n/ Drive/Volume Configurations\n/---------------------------------------------------------------------------*/\n\n#define FF_VOLUMES\t\t1\n/* Number of volumes (logical drives) to be used. (1-10) */\n\n\n#define FF_STR_VOLUME_ID\t0\n#define FF_VOLUME_STRS\t\t\"sd\"\n/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings.\n/  When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive\n/  number in the path name. FF_VOLUME_STRS defines the volume ID strings for each\n/  logical drives. Number of items must not be less than FF_VOLUMES. Valid\n/  characters for the volume ID strings are A-Z, a-z and 0-9, however, they are\n/  compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is\n/  not defined, a user defined volume string table needs to be defined as:\n/\n/  const char* VolumeStr[FF_VOLUMES] = {\"ram\",\"flash\",\"sd\",\"usb\",...\n/  Order is important. Any change to order, must also be reflected to diskio drive enum.\n*/\n\n\n#define FF_MULTI_PARTITION\t0\n/* This option switches support for multiple volumes on the physical drive.\n/  By default (0), each logical drive number is bound to the same physical drive\n/  number and only an FAT volume found on the physical drive will be mounted.\n/  When this function is enabled (1), each logical drive number can be bound to\n/  arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()\n/  funciton will be available. */\n\n\n#define FF_MIN_SS\t\t512\n#define FF_MAX_SS\t\t512\n/* This set of options configures the range of sector size to be supported. (512,\n/  1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and\n/  harddisk. But a larger value may be required for on-board flash memory and some\n/  type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured\n/  for variable sector size mode and disk_ioctl() function needs to implement\n/  GET_SECTOR_SIZE command. */\n\n\n#define FF_USE_TRIM\t\t0\n/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable)\n/  To enable Trim function, also CTRL_TRIM command should be implemented to the\n/  disk_ioctl() function. */\n\n\n#define FF_FS_NOFSINFO\t1\n/* If you need to know correct free space on the FAT32 volume, set bit 0 of this\n/  option, and f_getfree() function at first time after volume mount will force\n/  a full FAT scan. Bit 1 controls the use of last allocated cluster number.\n/\n/  bit0=0: Use free cluster count in the FSINFO if available.\n/  bit0=1: Do not trust free cluster count in the FSINFO.\n/  bit1=0: Use last allocated cluster number in the FSINFO if available.\n/  bit1=1: Do not trust last allocated cluster number in the FSINFO.\n*/\n\n\n\n/*---------------------------------------------------------------------------/\n/ System Configurations\n/---------------------------------------------------------------------------*/\n\n#define FF_FS_TINY\t\t0\n/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)\n/  At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes.\n/  Instead of private sector buffer eliminated from the file object, common sector\n/  buffer in the filesystem object (FATFS) is used for the file data transfer. */\n\n\n#define FF_FS_EXFAT\t\t1\n/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)\n/  To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)\n/  Note that enabling exFAT discards ANSI C (C89) compatibility. */\n\n\n#define FF_FS_NORTC\t\t1\n#define FF_NORTC_MON\t1\n#define FF_NORTC_MDAY\t1\n#define FF_NORTC_YEAR\t2022\n/* The option FF_FS_NORTC switches timestamp function. If the system does not have\n/  any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable\n/  the timestamp function. Every object modified by FatFs will have a fixed timestamp\n/  defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.\n/  To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be\n/  added to the project to read current time form real-time clock. FF_NORTC_MON,\n/  FF_NORTC_MDAY and FF_NORTC_YEAR have no effect.\n/  These options have no effect at read-only configuration (FF_FS_READONLY = 1). */\n\n\n#define FF_FS_LOCK\t\t0\n/* The option FF_FS_LOCK switches file lock function to control duplicated file open\n/  and illegal operation to open objects. This option must be 0 when FF_FS_READONLY\n/  is 1.\n/\n/  0:  Disable file lock function. To avoid volume corruption, application program\n/      should avoid illegal open, remove and rename to the open objects.\n/  >0: Enable file lock function. The value defines how many files/sub-directories\n/      can be opened simultaneously under file lock control. Note that the file\n/      lock control is independent of re-entrancy. */\n\n\n/* #include <somertos.h>\t// O/S definitions */\n#define FF_FS_REENTRANT\t0\n#define FF_FS_TIMEOUT\t1000\n#define FF_SYNC_t\t\tHANDLE\n/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs\n/  module itself. Note that regardless of this option, file access to different\n/  volume is always re-entrant and volume control functions, f_mount(), f_mkfs()\n/  and f_fdisk() function, are always not re-entrant. Only file/directory access\n/  to the same volume is under control of this function.\n/\n/   0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect.\n/   1: Enable re-entrancy. Also user provided synchronization handlers,\n/      ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()\n/      function, must be added to the project. Samples are available in\n/      option/syscall.c.\n/\n/  The FF_FS_TIMEOUT defines timeout period in unit of time tick.\n/  The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,\n/  SemaphoreHandle_t and etc. A header file for O/S definitions needs to be\n/  included somewhere in the scope of ff.h. */\n\n\n\n/*--- End of configuration options ---*/\n"
  },
  {
    "path": "bdk/gfx_utils.h",
    "content": "/*\n * Copyright (c) 2020 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _GFX_UTILS_H_\n#define _GFX_UTILS_H_\n\n#ifdef GFX_INC\n#include GFX_INC\n#endif\n\n#endif\n"
  },
  {
    "path": "bdk/ianos/elfload/elf.h",
    "content": "/*    $OpenBSD: exec_elf.h,v 1.53 2014/01/03 03:00:39 guenther Exp $    */\n/*\n * Copyright (c) 1995, 1996 Erik Theisen.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/* imported sys/exec_elf.h from OpenBSD */\n\n#ifndef ELF_H\n#define ELF_H\n\n#include <utils/types.h>\n\ntypedef u8 Elf_Byte;\n\ntypedef u32 Elf32_Addr; /* Unsigned program address */\ntypedef u32 Elf32_Off;  /* Unsigned file offset */\ntypedef s32 Elf32_Sword; /* Signed large integer */\ntypedef u32 Elf32_Word; /* Unsigned large integer */\ntypedef u16 Elf32_Half; /* Unsigned medium integer */\n\ntypedef u64 Elf64_Addr;\ntypedef u64 Elf64_Off;\ntypedef s32 Elf64_Shalf;\n\n#ifdef __alpha__\ntypedef s64 Elf64_Sword;\ntypedef u64 Elf64_Word;\n#else\ntypedef s32 Elf64_Sword;\ntypedef u32 Elf64_Word;\n#endif\n\ntypedef s64 Elf64_Sxword;\ntypedef u64 Elf64_Xword;\n\ntypedef u32 Elf64_Half;\ntypedef u16 Elf64_Quarter;\n\n/*\n * e_ident[] identification indexes\n * See http://www.sco.com/developers/gabi/latest/ch4.eheader.html\n */\n#define EI_MAG0 0       /* file ID */\n#define EI_MAG1 1       /* file ID */\n#define EI_MAG2 2       /* file ID */\n#define EI_MAG3 3       /* file ID */\n#define EI_CLASS 4      /* file class */\n#define EI_DATA 5       /* data encoding */\n#define EI_VERSION 6    /* ELF header version */\n#define EI_OSABI 7      /* OS/ABI ID */\n#define EI_ABIVERSION 8 /* ABI version */\n#define EI_PAD 9        /* start of pad bytes */\n#define EI_NIDENT 16    /* Size of e_ident[] */\n\n/* e_ident[] magic number */\n#define ELFMAG0 0x7f     /* e_ident[EI_MAG0] */\n#define ELFMAG1 'E'      /* e_ident[EI_MAG1] */\n#define ELFMAG2 'L'      /* e_ident[EI_MAG2] */\n#define ELFMAG3 'F'      /* e_ident[EI_MAG3] */\n#define ELFMAG \"\\177ELF\" /* magic */\n#define SELFMAG 4        /* size of magic */\n\n/* e_ident[] file class */\n#define ELFCLASSNONE 0 /* invalid */\n#define ELFCLASS32 1   /* 32-bit objs */\n#define ELFCLASS64 2   /* 64-bit objs */\n#define ELFCLASSNUM 3  /* number of classes */\n\n/* e_ident[] data encoding */\n#define ELFDATANONE 0 /* invalid */\n#define ELFDATA2LSB 1 /* Little-Endian */\n#define ELFDATA2MSB 2 /* Big-Endian */\n#define ELFDATANUM 3  /* number of data encode defines */\n\n/* e_ident[] Operating System/ABI */\n#define ELFOSABI_SYSV 0         /* UNIX System V ABI */\n#define ELFOSABI_HPUX 1         /* HP-UX operating system */\n#define ELFOSABI_NETBSD 2       /* NetBSD */\n#define ELFOSABI_LINUX 3        /* GNU/Linux */\n#define ELFOSABI_HURD 4         /* GNU/Hurd */\n#define ELFOSABI_86OPEN 5       /* 86Open common IA32 ABI */\n#define ELFOSABI_SOLARIS 6      /* Solaris */\n#define ELFOSABI_MONTEREY 7     /* Monterey */\n#define ELFOSABI_IRIX 8         /* IRIX */\n#define ELFOSABI_FREEBSD 9      /* FreeBSD */\n#define ELFOSABI_TRU64 10       /* TRU64 UNIX */\n#define ELFOSABI_MODESTO 11     /* Novell Modesto */\n#define ELFOSABI_OPENBSD 12     /* OpenBSD */\n#define ELFOSABI_ARM 97         /* ARM */\n#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */\n\n/* e_ident */\n#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \\\n                      (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \\\n                      (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \\\n                      (ehdr).e_ident[EI_MAG3] == ELFMAG3)\n\n/* ELF Header */\ntypedef struct\n{\n    unsigned char e_ident[EI_NIDENT]; /* ELF Identification */\n    Elf32_Half e_type;                /* object file type */\n    Elf32_Half e_machine;             /* machine */\n    Elf32_Word e_version;             /* object file version */\n    Elf32_Addr e_entry;               /* virtual entry point */\n    Elf32_Off e_phoff;                /* program header table offset */\n    Elf32_Off e_shoff;                /* section header table offset */\n    Elf32_Word e_flags;               /* processor-specific flags */\n    Elf32_Half e_ehsize;              /* ELF header size */\n    Elf32_Half e_phentsize;           /* program header entry size */\n    Elf32_Half e_phnum;               /* number of program header entries */\n    Elf32_Half e_shentsize;           /* section header entry size */\n    Elf32_Half e_shnum;               /* number of section header entries */\n    Elf32_Half e_shstrndx;            /* section header table's \"section\n                                                header string table\" entry offset */\n} Elf32_Ehdr;\n\ntypedef struct\n{\n    unsigned char e_ident[EI_NIDENT]; /* Id bytes */\n    Elf64_Quarter e_type;             /* file type */\n    Elf64_Quarter e_machine;          /* machine type */\n    Elf64_Half e_version;             /* version number */\n    Elf64_Addr e_entry;               /* entry point */\n    Elf64_Off e_phoff;                /* Program hdr offset */\n    Elf64_Off e_shoff;                /* Section hdr offset */\n    Elf64_Half e_flags;               /* Processor flags */\n    Elf64_Quarter e_ehsize;           /* sizeof ehdr */\n    Elf64_Quarter e_phentsize;        /* Program header entry size */\n    Elf64_Quarter e_phnum;            /* Number of program headers */\n    Elf64_Quarter e_shentsize;        /* Section header entry size */\n    Elf64_Quarter e_shnum;            /* Number of section headers */\n    Elf64_Quarter e_shstrndx;         /* String table index */\n} Elf64_Ehdr;\n\n/* e_type */\n#define ET_NONE 0        /* No file type */\n#define ET_REL 1         /* relocatable file */\n#define ET_EXEC 2        /* executable file */\n#define ET_DYN 3         /* shared object file */\n#define ET_CORE 4        /* core file */\n#define ET_NUM 5         /* number of types */\n#define ET_LOPROC 0xff00 /* reserved range for processor */\n#define ET_HIPROC 0xffff /*  specific e_type */\n\n/* e_machine */\n#define EM_NONE 0  /* No Machine */\n#define EM_M32 1   /* AT&T WE 32100 */\n#define EM_SPARC 2 /* SPARC */\n#define EM_386 3   /* Intel 80386 */\n#define EM_68K 4   /* Motorola 68000 */\n#define EM_88K 5   /* Motorola 88000 */\n#define EM_486 6   /* Intel 80486 - unused? */\n#define EM_860 7   /* Intel 80860 */\n#define EM_MIPS 8  /* MIPS R3000 Big-Endian only */\n/*\n * Don't know if EM_MIPS_RS4_BE,\n * EM_SPARC64, EM_PARISC,\n * or EM_PPC are ABI compliant\n */\n#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */\n#define EM_SPARC64 11     /* SPARC v9 64-bit unofficial */\n#define EM_PARISC 15      /* HPPA */\n#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */\n#define EM_PPC 20         /* PowerPC */\n#define EM_ARM 40         /* ARM AArch32 */\n#define EM_ALPHA 41       /* DEC ALPHA */\n#define EM_SH 42          /* Hitachi/Renesas Super-H */\n#define EM_SPARCV9 43     /* SPARC version 9 */\n#define EM_IA_64 50       /* Intel IA-64 Processor */\n#define EM_AMD64 62       /* AMD64 architecture */\n#define EM_VAX 75         /* DEC VAX */\n#define EM_AARCH64 183    /* ARM AArch64 */\n\n/* Non-standard */\n#define EM_ALPHA_EXP 0x9026 /* DEC ALPHA */\n\n/* Version */\n#define EV_NONE 0    /* Invalid */\n#define EV_CURRENT 1 /* Current */\n#define EV_NUM 2     /* number of versions */\n\n/* Section Header */\ntypedef struct\n{\n    Elf32_Word sh_name;      /* name - index into section header\n                                 * string table section */\n    Elf32_Word sh_type;      /* type */\n    Elf32_Word sh_flags;     /* flags */\n    Elf32_Addr sh_addr;      /* address */\n    Elf32_Off sh_offset;     /* file offset */\n    Elf32_Word sh_size;      /* section size */\n    Elf32_Word sh_link;      /* section header table index link */\n    Elf32_Word sh_info;      /* extra information */\n    Elf32_Word sh_addralign; /* address alignment */\n    Elf32_Word sh_entsize;   /* section entry size */\n} Elf32_Shdr;\n\ntypedef struct\n{\n    Elf64_Half sh_name;       /* section name */\n    Elf64_Half sh_type;       /* section type */\n    Elf64_Xword sh_flags;     /* section flags */\n    Elf64_Addr sh_addr;       /* virtual address */\n    Elf64_Off sh_offset;      /* file offset */\n    Elf64_Xword sh_size;      /* section size */\n    Elf64_Half sh_link;       /* link to another */\n    Elf64_Half sh_info;       /* misc info */\n    Elf64_Xword sh_addralign; /* memory alignment */\n    Elf64_Xword sh_entsize;   /* table entry size */\n} Elf64_Shdr;\n\n/* Special Section Indexes */\n#define SHN_UNDEF 0          /* undefined */\n#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */\n#define SHN_LOPROC 0xff00    /* reserved range for processor */\n#define SHN_HIPROC 0xff1f    /*   specific section indexes */\n#define SHN_ABS 0xfff1       /* absolute value */\n#define SHN_COMMON 0xfff2    /* common symbol */\n#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */\n\n/* sh_type */\n#define SHT_NULL 0            /* inactive */\n#define SHT_PROGBITS 1        /* program defined information */\n#define SHT_SYMTAB 2          /* symbol table section */\n#define SHT_STRTAB 3          /* string table section */\n#define SHT_RELA 4            /* relocation section with addends*/\n#define SHT_HASH 5            /* symbol hash table section */\n#define SHT_DYNAMIC 6         /* dynamic section */\n#define SHT_NOTE 7            /* note section */\n#define SHT_NOBITS 8          /* no space section */\n#define SHT_REL 9             /* relation section without addends */\n#define SHT_SHLIB 10          /* reserved - purpose unknown */\n#define SHT_DYNSYM 11         /* dynamic symbol table section */\n#define SHT_NUM 12            /* number of section types */\n#define SHT_LOPROC 0x70000000 /* reserved range for processor */\n#define SHT_HIPROC 0x7fffffff /*  specific section header types */\n#define SHT_LOUSER 0x80000000 /* reserved range for application */\n#define SHT_HIUSER 0xffffffff /*  specific indexes */\n\n/* Section names */\n#define ELF_BSS \".bss\"               /* uninitialized data */\n#define ELF_DATA \".data\"             /* initialized data */\n#define ELF_DEBUG \".debug\"           /* debug */\n#define ELF_DYNAMIC \".dynamic\"       /* dynamic linking information */\n#define ELF_DYNSTR \".dynstr\"         /* dynamic string table */\n#define ELF_DYNSYM \".dynsym\"         /* dynamic symbol table */\n#define ELF_FINI \".fini\"             /* termination code */\n#define ELF_GOT \".got\"               /* global offset table */\n#define ELF_HASH \".hash\"             /* symbol hash table */\n#define ELF_INIT \".init\"             /* initialization code */\n#define ELF_REL_DATA \".rel.data\"     /* relocation data */\n#define ELF_REL_FINI \".rel.fini\"     /* relocation termination code */\n#define ELF_REL_INIT \".rel.init\"     /* relocation initialization code */\n#define ELF_REL_DYN \".rel.dyn\"       /* relocation dynamic link info */\n#define ELF_REL_RODATA \".rel.rodata\" /* relocation read-only data */\n#define ELF_REL_TEXT \".rel.text\"     /* relocation code */\n#define ELF_RODATA \".rodata\"         /* read-only data */\n#define ELF_SHSTRTAB \".shstrtab\"     /* section header string table */\n#define ELF_STRTAB \".strtab\"         /* string table */\n#define ELF_SYMTAB \".symtab\"         /* symbol table */\n#define ELF_TEXT \".text\"             /* code */\n\n/* Section Attribute Flags - sh_flags */\n#define SHF_WRITE 0x1           /* Writable */\n#define SHF_ALLOC 0x2           /* occupies memory */\n#define SHF_EXECINSTR 0x4       /* executable */\n#define SHF_TLS 0x400           /* thread local storage */\n#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor \\\n                                 *  specific section attributes */\n\n/* Symbol Table Entry */\ntypedef struct elf32_sym\n{\n    Elf32_Word st_name;     /* name - index into string table */\n    Elf32_Addr st_value;    /* symbol value */\n    Elf32_Word st_size;     /* symbol size */\n    unsigned char st_info;  /* type and binding */\n    unsigned char st_other; /* 0 - no defined meaning */\n    Elf32_Half st_shndx;    /* section header index */\n} Elf32_Sym;\n\ntypedef struct\n{\n    Elf64_Half st_name;     /* Symbol name index in str table */\n    Elf_Byte st_info;       /* type / binding attrs */\n    Elf_Byte st_other;      /* unused */\n    Elf64_Quarter st_shndx; /* section index of symbol */\n    Elf64_Xword st_value;   /* value of symbol */\n    Elf64_Xword st_size;    /* size of symbol */\n} Elf64_Sym;\n\n/* Symbol table index */\n#define STN_UNDEF 0 /* undefined */\n\n/* Extract symbol info - st_info */\n#define ELF32_ST_BIND(x) ((x) >> 4)\n#define ELF32_ST_TYPE(x) (((unsigned int)x) & 0xf)\n#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t)&0xf))\n\n#define ELF64_ST_BIND(x) ((x) >> 4)\n#define ELF64_ST_TYPE(x) (((unsigned int)x) & 0xf)\n#define ELF64_ST_INFO(b, t) (((b) << 4) + ((t)&0xf))\n\n/* Symbol Binding - ELF32_ST_BIND - st_info */\n#define STB_LOCAL 0   /* Local symbol */\n#define STB_GLOBAL 1  /* Global symbol */\n#define STB_WEAK 2    /* like global - lower precedence */\n#define STB_NUM 3     /* number of symbol bindings */\n#define STB_LOPROC 13 /* reserved range for processor */\n#define STB_HIPROC 15 /*  specific symbol bindings */\n\n/* Symbol type - ELF32_ST_TYPE - st_info */\n#define STT_NOTYPE 0  /* not specified */\n#define STT_OBJECT 1  /* data object */\n#define STT_FUNC 2    /* function */\n#define STT_SECTION 3 /* section */\n#define STT_FILE 4    /* file */\n#define STT_TLS 6     /* thread local storage */\n#define STT_LOPROC 13 /* reserved range for processor */\n#define STT_HIPROC 15 /*  specific symbol types */\n\n/* Relocation entry with implicit addend */\ntypedef struct\n{\n    Elf32_Addr r_offset; /* offset of relocation */\n    Elf32_Word r_info;   /* symbol table index and type */\n} Elf32_Rel;\n\n/* Relocation entry with explicit addend */\ntypedef struct\n{\n    Elf32_Addr r_offset; /* offset of relocation */\n    Elf32_Word r_info;   /* symbol table index and type */\n    Elf32_Sword r_addend;\n} Elf32_Rela;\n\n/* Extract relocation info - r_info */\n#define ELF32_R_SYM(i) ((i) >> 8)\n#define ELF32_R_TYPE(i) ((unsigned char)(i))\n#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t))\n\ntypedef struct\n{\n    Elf64_Xword r_offset; /* where to do it */\n    Elf64_Xword r_info;   /* index & type of relocation */\n} Elf64_Rel;\n\ntypedef struct\n{\n    Elf64_Xword r_offset;  /* where to do it */\n    Elf64_Xword r_info;    /* index & type of relocation */\n    Elf64_Sxword r_addend; /* adjustment value */\n} Elf64_Rela;\n\n#define ELF64_R_SYM(info) ((info) >> 32)\n#define ELF64_R_TYPE(info) ((info)&0xFFFFFFFF)\n#define ELF64_R_INFO(s, t) (((s) << 32) + (u32)(t))\n\n#if defined(__mips64__) && defined(__MIPSEL__)\n/*\n * The 64-bit MIPS ELF ABI uses a slightly different relocation format\n * than the regular ELF ABI: the r_info field is split into several\n * pieces (see gnu/usr.bin/binutils/include/elf/mips.h for details).\n */\n#undef ELF64_R_SYM\n#undef ELF64_R_TYPE\n#undef ELF64_R_INFO\n#define ELF64_R_TYPE(info) (swap32((info) >> 32))\n#define ELF64_R_SYM(info) ((info)&0xFFFFFFFF)\n#define ELF64_R_INFO(s, t) (((u64)swap32(t) << 32) + (u32)(s))\n#endif /* __mips64__ && __MIPSEL__ */\n\n/* Program Header */\ntypedef struct\n{\n    Elf32_Word p_type;   /* segment type */\n    Elf32_Off p_offset;  /* segment offset */\n    Elf32_Addr p_vaddr;  /* virtual address of segment */\n    Elf32_Addr p_paddr;  /* physical address - ignored? */\n    Elf32_Word p_filesz; /* number of bytes in file for seg. */\n    Elf32_Word p_memsz;  /* number of bytes in mem. for seg. */\n    Elf32_Word p_flags;  /* flags */\n    Elf32_Word p_align;  /* memory alignment */\n} Elf32_Phdr;\n\ntypedef struct\n{\n    Elf64_Half p_type;    /* entry type */\n    Elf64_Half p_flags;   /* flags */\n    Elf64_Off p_offset;   /* offset */\n    Elf64_Addr p_vaddr;   /* virtual address */\n    Elf64_Addr p_paddr;   /* physical address */\n    Elf64_Xword p_filesz; /* file size */\n    Elf64_Xword p_memsz;  /* memory size */\n    Elf64_Xword p_align;  /* memory & file alignment */\n} Elf64_Phdr;\n\n/* Segment types - p_type */\n#define PT_NULL 0            /* unused */\n#define PT_LOAD 1            /* loadable segment */\n#define PT_DYNAMIC 2         /* dynamic linking section */\n#define PT_INTERP 3          /* the RTLD */\n#define PT_NOTE 4            /* auxiliary information */\n#define PT_SHLIB 5           /* reserved - purpose undefined */\n#define PT_PHDR 6            /* program header */\n#define PT_TLS 7             /* thread local storage */\n#define PT_LOOS 0x60000000   /* reserved range for OS */\n#define PT_HIOS 0x6fffffff   /*  specific segment types */\n#define PT_LOPROC 0x70000000 /* reserved range for processor */\n#define PT_HIPROC 0x7fffffff /*  specific segment types */\n\n#define PT_OPENBSD_RANDOMIZE 0x65a3dbe6 /* fill with random data */\n#define PT_GANDR_KERNEL 0x67646b6c      /* gdkl */\n\n/* Segment flags - p_flags */\n#define PF_X 0x1               /* Executable */\n#define PF_W 0x2               /* Writable */\n#define PF_R 0x4               /* Readable */\n#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */\n                               /*  specific segment flags */\n\n/* Dynamic structure */\ntypedef struct\n{\n    Elf32_Word d_tag; /* controls meaning of d_val */\n    union {\n        Elf32_Word d_val; /* Multiple meanings - see d_tag */\n        Elf32_Addr d_ptr; /* program virtual address */\n    } d_un;\n} Elf32_Dyn;\n\ntypedef struct\n{\n    Elf64_Xword d_tag; /* controls meaning of d_val */\n    union {\n        Elf64_Addr d_ptr;\n        Elf64_Xword d_val;\n    } d_un;\n} Elf64_Dyn;\n\n/* Dynamic Array Tags - d_tag */\n#define DT_NULL 0            /* marks end of _DYNAMIC array */\n#define DT_NEEDED 1          /* string table offset of needed lib */\n#define DT_PLTRELSZ 2        /* size of relocation entries in PLT */\n#define DT_PLTGOT 3          /* address PLT/GOT */\n#define DT_HASH 4            /* address of symbol hash table */\n#define DT_STRTAB 5          /* address of string table */\n#define DT_SYMTAB 6          /* address of symbol table */\n#define DT_RELA 7            /* address of relocation table */\n#define DT_RELASZ 8          /* size of relocation table */\n#define DT_RELAENT 9         /* size of relocation entry */\n#define DT_STRSZ 10          /* size of string table */\n#define DT_SYMENT 11         /* size of symbol table entry */\n#define DT_INIT 12           /* address of initialization func. */\n#define DT_FINI 13           /* address of termination function */\n#define DT_SONAME 14         /* string table offset of shared obj */\n#define DT_RPATH 15          /* string table offset of library \\\n                              * search path */\n#define DT_SYMBOLIC 16       /* start sym search in shared obj. */\n#define DT_REL 17            /* address of rel. tbl. w addends */\n#define DT_RELSZ 18          /* size of DT_REL relocation table */\n#define DT_RELENT 19         /* size of DT_REL relocation entry */\n#define DT_PLTREL 20         /* PLT referenced relocation entry */\n#define DT_DEBUG 21          /* bugger */\n#define DT_TEXTREL 22        /* Allow rel. mod. to unwritable seg */\n#define DT_JMPREL 23         /* add. of PLT's relocation entries */\n#define DT_BIND_NOW 24       /* Bind now regardless of env setting */\n#define DT_LOOS 0x6000000d   /* reserved range for OS */\n#define DT_HIOS 0x6ffff000   /*  specific dynamic array tags */\n#define DT_LOPROC 0x70000000 /* reserved range for processor */\n#define DT_HIPROC 0x7fffffff /*  specific dynamic array tags */\n\n/* some other useful tags */\n#define DT_RELACOUNT 0x6ffffff9 /* if present, number of RELATIVE */\n#define DT_RELCOUNT 0x6ffffffa  /* relocs, which must come first */\n#define DT_FLAGS_1 0x6ffffffb\n\n/* Dynamic Flags - DT_FLAGS_1 .dynamic entry */\n#define DF_1_NOW 0x00000001\n#define DF_1_GLOBAL 0x00000002\n#define DF_1_GROUP 0x00000004\n#define DF_1_NODELETE 0x00000008\n#define DF_1_LOADFLTR 0x00000010\n#define DF_1_INITFIRST 0x00000020\n#define DF_1_NOOPEN 0x00000040\n#define DF_1_ORIGIN 0x00000080\n#define DF_1_DIRECT 0x00000100\n#define DF_1_TRANS 0x00000200\n#define DF_1_INTERPOSE 0x00000400\n#define DF_1_NODEFLIB 0x00000800\n#define DF_1_NODUMP 0x00001000\n#define DF_1_CONLFAT 0x00002000\n\n/* ld.so: number of low tags that are used saved internally (0 .. DT_NUM-1) */\n#define DT_NUM (DT_JMPREL + 1)\n\n/*\n * Note Definitions\n */\ntypedef struct\n{\n    Elf32_Word namesz;\n    Elf32_Word descsz;\n    Elf32_Word type;\n} Elf32_Note;\n\ntypedef struct\n{\n    Elf64_Half namesz;\n    Elf64_Half descsz;\n    Elf64_Half type;\n} Elf64_Note;\n\n#if defined(ELFSIZE) && (ELFSIZE == 32)\n#define Elf_Ehdr Elf32_Ehdr\n#define Elf_Phdr Elf32_Phdr\n#define Elf_Shdr Elf32_Shdr\n#define Elf_Sym Elf32_Sym\n#define Elf_Rel Elf32_Rel\n#define Elf_RelA Elf32_Rela\n#define Elf_Dyn Elf32_Dyn\n#define Elf_Half Elf32_Half\n#define Elf_Word Elf32_Word\n#define Elf_Sword Elf32_Sword\n#define Elf_Addr Elf32_Addr\n#define Elf_Off Elf32_Off\n#define Elf_Nhdr Elf32_Nhdr\n#define Elf_Note Elf32_Note\n\n#define ELF_R_SYM ELF32_R_SYM\n#define ELF_R_TYPE ELF32_R_TYPE\n#define ELF_R_INFO ELF32_R_INFO\n#define ELFCLASS ELFCLASS32\n\n#define ELF_ST_BIND ELF32_ST_BIND\n#define ELF_ST_TYPE ELF32_ST_TYPE\n#define ELF_ST_INFO ELF32_ST_INFO\n\n#elif defined(ELFSIZE) && (ELFSIZE == 64)\n\n#define Elf_Ehdr Elf64_Ehdr\n#define Elf_Phdr Elf64_Phdr\n#define Elf_Shdr Elf64_Shdr\n#define Elf_Sym Elf64_Sym\n#define Elf_Rel Elf64_Rel\n#define Elf_RelA Elf64_Rela\n#define Elf_Dyn Elf64_Dyn\n#define Elf_Half Elf64_Half\n#define Elf_Word Elf64_Word\n#define Elf_Sword Elf64_Sword\n#define Elf_Addr Elf64_Addr\n#define Elf_Off Elf64_Off\n#define Elf_Nhdr Elf64_Nhdr\n#define Elf_Note Elf64_Note\n\n#define ELF_R_SYM ELF64_R_SYM\n#define ELF_R_TYPE ELF64_R_TYPE\n#define ELF_R_INFO ELF64_R_INFO\n#define ELFCLASS ELFCLASS64\n\n#define ELF_ST_BIND ELF64_ST_BIND\n#define ELF_ST_TYPE ELF64_ST_TYPE\n#define ELF_ST_INFO ELF64_ST_INFO\n\n#endif\n\n#endif\n"
  },
  {
    "path": "bdk/ianos/elfload/elfarch.h",
    "content": "/*\n * Copyright © 2014, Owen Shepherd\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\n * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\n * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\n * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\n * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\n * PERFORMANCE OF THIS SOFTWARE.\n */\n\n#ifndef ELFARCH_H\n#define ELFARCH_H\n\n#if defined(__i386__)\n#define EM_THIS EM_386\n#define EL_ARCH_USES_REL\n#elif defined(__amd64__)\n#define EM_THIS EM_AMD64\n#define EL_ARCH_USES_RELA\n#elif defined(__arm__)\n#define EM_THIS EM_ARM\n#define EL_ARCH_USES_REL\n#elif defined(__aarch64__)\n#define EM_THIS EM_AARCH64\n#define EL_ARCH_USES_RELA\n#define EL_ARCH_USES_REL\n#else\n#error specify your ELF architecture\n#endif\n\n#if defined(__LP64__) || defined(__LLP64__)\n#define ELFSIZE 64\n#else\n#define ELFSIZE 32\n#endif\n\n#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n#define ELFDATATHIS ELFDATA2LSB\n#else\n#define ELFDATATHIS ELFDATA2MSB\n#endif\n\n#endif\n"
  },
  {
    "path": "bdk/ianos/elfload/elfload.c",
    "content": "/*\n * Copyright © 2018, M4xw\n * Copyright © 2014, Owen Shepherd\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\n * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\n * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\n * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\n * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\n * PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <string.h>\n\n#include \"elfload.h\"\n\nel_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset)\n{\n\treturn ctx->pread(ctx, def, nb, offset);\n}\n\n#define EL_PHOFF(ctx, num) (((ctx)->ehdr.e_phoff + (num) *(ctx)->ehdr.e_phentsize))\nel_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, u32 type, unsigned *i)\n{\n\tel_status rv = EL_OK;\n\tfor (; *i < ctx->ehdr.e_phnum; (*i)++)\n\t{\n\t\tif ((rv = el_pread(ctx, phdr, sizeof *phdr, EL_PHOFF(ctx, *i))))\n\t\t\treturn rv;\n\n\t\tif (phdr->p_type == type)\n\t\t{\n\t\t\treturn rv;\n\t\t}\n\t}\n\n\t*i = -1;\n\treturn rv;\n}\n\n#define EL_SHOFF(ctx, num) (((ctx)->ehdr.e_shoff + (num) *(ctx)->ehdr.e_shentsize))\nel_status el_findshdr(el_ctx *ctx, Elf_Shdr *shdr, u32 type, unsigned *i)\n{\n\tel_status rv = EL_OK;\n\n\tfor (; *i < ctx->ehdr.e_shnum; (*i)++)\n\t{\n\t\tif ((rv = el_pread(ctx, shdr, sizeof *shdr, EL_SHOFF(ctx, *i))))\n\n\t\t\treturn rv;\n\n\t\tif (shdr->sh_type == type)\n\t\t{\n\t\t\treturn rv;\n\t\t}\n\t}\n\n\t*i = -1;\n\n\treturn rv;\n}\n\nel_status el_init(el_ctx *ctx)\n{\n\tel_status rv = EL_OK;\n\tif ((rv = el_pread(ctx, &ctx->ehdr, sizeof ctx->ehdr, 0)))\n\t\treturn rv;\n\n\t/* validate header */\n\n\tif (!IS_ELF(ctx->ehdr))\n\t\treturn EL_NOTELF;\n\n\tif (ctx->ehdr.e_ident[EI_CLASS] != ELFCLASS)\n\t\treturn EL_WRONGBITS;\n\n\tif (ctx->ehdr.e_ident[EI_DATA] != ELFDATATHIS)\n\t\treturn EL_WRONGENDIAN;\n\n\tif (ctx->ehdr.e_ident[EI_VERSION] != EV_CURRENT)\n\t\treturn EL_NOTELF;\n\n\tif (ctx->ehdr.e_type != ET_EXEC && ctx->ehdr.e_type != ET_DYN)\n\t\treturn EL_NOTEXEC;\n\n\tif (ctx->ehdr.e_machine != EM_THIS)\n\t\treturn EL_WRONGARCH;\n\n\tif (ctx->ehdr.e_version != EV_CURRENT)\n\t\treturn EL_NOTELF;\n\n\t/* load phdrs */\n\tElf_Phdr ph;\n\n\t/* iterate through, calculate extents */\n\tctx->base_load_paddr = ctx->base_load_vaddr = 0;\n\tctx->align = 1;\n\tctx->memsz = 0;\n\n\tunsigned i = 0;\n\tfor (;;)\n\t{\n\t\tif ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i)))\n\t\t\treturn rv;\n\n\t\tif (i == (unsigned)-1)\n\t\t\tbreak;\n\n\t\tElf_Addr phend = ph.p_vaddr + ph.p_memsz;\n\t\tif (phend > ctx->memsz)\n\t\t\tctx->memsz = phend;\n\n\t\tif (ph.p_align > ctx->align)\n\t\t\tctx->align = ph.p_align;\n\n\t\ti++;\n\t}\n\n\t// Program Header\n\tif (ctx->ehdr.e_type == ET_DYN)\n\t{\n\t\ti = 0;\n\n\t\tif ((rv = el_findphdr(ctx, &ph, PT_DYNAMIC, &i)))\n\t\t\treturn rv;\n\n\t\tif (i == (unsigned)-1)\n\t\t\treturn EL_NODYN;\n\n\t\tctx->dynoff = ph.p_offset;\n\t\tctx->dynsize = ph.p_filesz;\n\t}\n\telse\n\t{\n\t\tctx->dynoff = 0;\n\t\tctx->dynsize = 0;\n\t}\n\n\t// Section String Table\n\tif (ctx->ehdr.e_type == ET_DYN)\n\t{\n\t\ti = ctx->ehdr.e_shstrndx - 1;\n\n\t\tif ((rv = el_findshdr(ctx, &ctx->shstr, SHT_STRTAB, &i)))\n\t\t\treturn rv;\n\n\t\t// Reset\n\t\ti = 0;\n\n\t\tif ((rv = el_findshdr(ctx, &ctx->symtab, SHT_SYMTAB, &i)))\n\t\t\treturn rv;\n\n\t\tif (i == (unsigned)-1)\n\t\t\treturn EL_NODYN;\n\t}\n\n\treturn rv;\n}\n\n/*\ntypedef void* (*el_alloc_cb)(\n\tel_ctx *ctx,\n\tElf_Addr phys,\n\tElf_Addr virt,\n\tElf_Addr size);\n*/\n\nel_status el_load(el_ctx *ctx, el_alloc_cb alloc)\n{\n\tel_status rv = EL_OK;\n\n\t/* address deltas */\n\tElf_Addr pdelta = ctx->base_load_paddr;\n\tElf_Addr vdelta = ctx->base_load_vaddr;\n\n\t/* iterate paddrs */\n\tElf_Phdr ph;\n\tunsigned i = 0;\n\tfor (;;)\n\t{\n\t\tif ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i)))\n\t\t\treturn rv;\n\n\t\tif (i == (unsigned)-1)\n\t\t\tbreak;\n\n\t\tElf_Addr pload = ph.p_paddr + pdelta;\n\t\tElf_Addr vload = ph.p_vaddr + vdelta;\n\n\t\t/* allocate mem */\n\t\tchar *dest = alloc(ctx, pload, vload, ph.p_memsz);\n\t\tif (!dest)\n\t\t\treturn EL_ENOMEM;\n\n\t\tEL_DEBUG(\"Loading seg fileoff %x, vaddr %x to %p\\n\",\n\t\t\t\tph.p_offset, ph.p_vaddr, dest);\n\n\t\t/* read loaded portion */\n\t\tif ((rv = el_pread(ctx, dest, ph.p_filesz, ph.p_offset)))\n\t\t\treturn rv;\n\n\t\t/* zero mem-only portion */\n\t\tmemset(dest + ph.p_filesz, 0, ph.p_memsz - ph.p_filesz);\n\n\t\ti++;\n\t}\n\n\treturn rv;\n}\n\nel_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, u32 tag)\n{\n\tel_status rv = EL_OK;\n\tsize_t ndyn = ctx->dynsize / sizeof(Elf_Dyn);\n\n\tfor (unsigned i = 0; i < ndyn; i++)\n\t{\n\t\tif ((rv = el_pread(ctx, dyn, sizeof *dyn, ctx->dynoff + i * sizeof *dyn)))\n\t\t\treturn rv;\n\n\t\tif (dyn->d_tag == tag)\n\t\t\treturn EL_OK;\n\t}\n\n\tdyn->d_tag = DT_NULL;\n\treturn EL_OK;\n}\n\nel_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, u32 type)\n{\n\tel_status rv = EL_OK;\n\n\tElf_Dyn rel, relsz, relent;\n\n\tif ((rv = el_finddyn(ctx, &rel, type)))\n\t\treturn rv;\n\n\tif ((rv = el_finddyn(ctx, &relsz, type + 1)))\n\t\treturn rv;\n\n\tif ((rv = el_finddyn(ctx, &relent, type + 2)))\n\t\treturn rv;\n\n\tif (rel.d_tag == DT_NULL || relsz.d_tag == DT_NULL || relent.d_tag == DT_NULL)\n\t{\n\t\tri->entrysize = 0;\n\t\tri->tablesize = 0;\n\t\tri->tableoff = 0;\n\t}\n\telse\n\t{\n\t\tri->tableoff = rel.d_un.d_ptr;\n\t\tri->tablesize = relsz.d_un.d_val;\n\t\tri->entrysize = relent.d_un.d_val;\n\t}\n\n\treturn rv;\n}\n\nextern el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel);\nextern el_status el_applyrela(el_ctx *ctx, Elf_RelA *rela);\n\nel_status el_relocate(el_ctx *ctx)\n{\n\tel_status rv = EL_OK;\n\n\t// not dynamic\n\tif (ctx->ehdr.e_type != ET_DYN)\n\t\treturn EL_OK;\n\n\tchar *base = (char *)ctx->base_load_paddr;\n\n\tel_relocinfo ri;\n#ifdef EL_ARCH_USES_REL\n\tif ((rv = el_findrelocs(ctx, &ri, DT_REL)))\n\t\treturn rv;\n\n\tif (ri.entrysize != sizeof(Elf_Rel) && ri.tablesize)\n\t{\n\t\tEL_DEBUG(\"Relocation size %u doesn't match expected %u\\n\",\n\t\t\t\tri.entrysize, sizeof(Elf_Rel));\n\t\treturn EL_BADREL;\n\t}\n\n\tsize_t relcnt = ri.tablesize / sizeof(Elf_Rel);\n\tElf_Rel *reltab = (Elf_Rel *)(base + ri.tableoff);\n\tfor (size_t i = 0; i < relcnt; i++)\n\t{\n\t\tif ((rv = el_applyrel(ctx, &reltab[i])))\n\t\t\treturn rv;\n\t}\n#endif\n\n#ifdef EL_ARCH_USES_RELA\n\tif ((rv = el_findrelocs(ctx, &ri, DT_RELA)))\n\t\treturn rv;\n\n\tif (ri.entrysize != sizeof(Elf_RelA) && ri.tablesize)\n\t{\n\t\tEL_DEBUG(\"Relocation size %u doesn't match expected %u\\n\",\n\t\t\t\tri.entrysize, sizeof(Elf_RelA));\n\t\treturn EL_BADREL;\n\t}\n\n\tsize_t relacnt = ri.tablesize / sizeof(Elf_RelA);\n\tElf_RelA *relatab = (Elf_RelA *)(base + ri.tableoff);\n\tfor (size_t i = 0; i < relacnt; i++)\n\t{\n\t\tif ((rv = el_applyrela(ctx, &relatab[i])))\n\t\t\treturn rv;\n\t}\n#endif\n\n#if !defined(EL_ARCH_USES_REL) && !defined(EL_ARCH_USES_RELA)\n#error No relocation type defined!\n#endif\n\n\treturn rv;\n}\n"
  },
  {
    "path": "bdk/ianos/elfload/elfload.h",
    "content": "/*\n * Copyright © 2018, M4xw\n * Copyright © 2014, Owen Shepherd\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\n * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\n * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\n * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\n * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\n * PERFORMANCE OF THIS SOFTWARE.\n */\n\n#ifndef ELFLOAD_H\n#define ELFLOAD_H\n#include <stddef.h>\n\n#include \"elfarch.h\"\n#include \"elf.h\"\n\n#ifdef DEBUG\n#include <gfx_utils.h>\n#define EL_DEBUG(format, ...) \\\n\tgfx_printf(format __VA_OPT__(, ) __VA_ARGS__)\n#else\n#define EL_DEBUG(...) \\\n\tdo                \\\n\t{                 \\\n\t} while (0)\n#endif\n\ntypedef enum\n{\n\tEL_OK = 0,\n\n\tEL_EIO,\n\tEL_ENOMEM,\n\n\tEL_NOTELF,\n\tEL_WRONGBITS,\n\tEL_WRONGENDIAN,\n\tEL_WRONGARCH,\n\tEL_WRONGOS,\n\tEL_NOTEXEC,\n\tEL_NODYN,\n\tEL_BADREL,\n\n} el_status;\n\ntypedef struct el_ctx\n{\n\tel_status (*pread)(struct el_ctx *ctx, void *dest, size_t nb, size_t offset);\n\n\t/* base_load_* -> address we are actually going to load at\n\t */\n\tElf_Addr\n\t\tbase_load_paddr,\n\t\tbase_load_vaddr;\n\n\t/* original memory of binary */\n\tElf_Addr eaddr;\n\n\t/* size in memory of binary */\n\tElf_Addr memsz;\n\n\t/* required alignment */\n\tElf_Addr align;\n\n\t/* ELF header */\n\tElf_Ehdr ehdr;\n\n\t// Section Header Str Table\n\tElf_Shdr shstr;\n\tElf_Shdr symtab;\n\n\t/* Offset of dynamic table (0 if not ET_DYN) */\n\tElf_Off dynoff;\n\t/* Size of dynamic table (0 if not ET_DYN) */\n\tElf_Addr dynsize;\n} el_ctx;\n\nel_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset);\n\nel_status el_init(el_ctx *ctx);\ntypedef void *(*el_alloc_cb)(\n\tel_ctx *ctx,\n\tElf_Addr phys,\n\tElf_Addr virt,\n\tElf_Addr size);\n\nel_status el_load(el_ctx *ctx, el_alloc_cb alloccb);\n\n/* find the next phdr of type \\p type, starting at \\p *i.\n * On success, returns EL_OK with *i set to the phdr number, and the phdr loaded\n * in *phdr.\n *\n * If the end of the phdrs table was reached, *i is set to -1 and the contents\n * of *phdr are undefined\n */\nel_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, u32 type, unsigned *i);\n\n/* Relocate the loaded executable */\nel_status el_relocate(el_ctx *ctx);\n\n/* find a dynamic table entry\n * returns the entry on success, dyn->d_tag = DT_NULL on failure\n */\nel_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, u32 type);\n\ntypedef struct\n{\n\tElf_Off tableoff;\n\tElf_Addr tablesize;\n\tElf_Addr entrysize;\n} el_relocinfo;\n\n/* find all information regarding relocations of a specific type.\n *\n * pass DT_REL or DT_RELA for type\n * sets ri->entrysize = 0 if not found\n */\nel_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, u32 type);\n\n#endif\n"
  },
  {
    "path": "bdk/ianos/elfload/elfreloc_aarch64.c",
    "content": "/*\n * Copyright © 2014, Owen Shepherd\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\n * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\n * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\n * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\n * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\n * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\n * PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include \"elfload.h\"\n\n#if defined(__aarch64__)\n\n#define R_AARCH64_NONE 0\n#define R_AARCH64_RELATIVE 1027\n\nel_status el_applyrela(el_ctx *ctx, Elf_RelA *rel)\n{\n\tuptr *p = (uptr *)(rel->r_offset + ctx->base_load_paddr);\n\tu32 type = ELF_R_TYPE(rel->r_info);\n\tu32 sym = ELF_R_SYM(rel->r_info);\n\n\tswitch (type)\n\t{\n\tcase R_AARCH64_NONE:\n\t\tEL_DEBUG(\"R_AARCH64_NONE\\n\");\n\t\tbreak;\n\tcase R_AARCH64_RELATIVE:\n\t\tif (sym)\n\t\t{\n\t\t\tEL_DEBUG(\"R_AARCH64_RELATIVE with symbol ref!\\n\");\n\t\t\treturn EL_BADREL;\n\t\t}\n\n\t\tEL_DEBUG(\"Applying R_AARCH64_RELATIVE reloc @%p\\n\", p);\n\t\t*p = rel->r_addend + ctx->base_load_vaddr;\n\t\tbreak;\n\n\tdefault:\n\t\tEL_DEBUG(\"Bad relocation %u\\n\", type);\n\t\treturn EL_BADREL;\n\t}\n\n\treturn EL_OK;\n}\n\nel_status el_applyrel(el_ctx *ctx, Elf_Rel *rel)\n{\n\tuptr *p = (uptr *)(rel->r_offset + ctx->base_load_paddr);\n\tu32 type = ELF_R_TYPE(rel->r_info);\n\tu32 sym = ELF_R_SYM(rel->r_info);\n\n\tswitch (type)\n\t{\n\tcase R_AARCH64_NONE:\n\t\tEL_DEBUG(\"R_AARCH64_NONE\\n\");\n\t\tbreak;\n\tcase R_AARCH64_RELATIVE:\n\t\tif (sym)\n\t\t{\n\t\t\tEL_DEBUG(\"R_AARCH64_RELATIVE with symbol ref!\\n\");\n\t\t\treturn EL_BADREL;\n\t\t}\n\n\t\tEL_DEBUG(\"Applying R_AARCH64_RELATIVE reloc @%p\\n\", p);\n\t\t*p += ctx->base_load_vaddr;\n\t\tbreak;\n\n\tdefault:\n\t\tEL_DEBUG(\"Bad relocation %u\\n\", type);\n\t\treturn EL_BADREL;\n\t}\n\n\treturn EL_OK;\n}\n\n#endif\n"
  },
  {
    "path": "bdk/ianos/elfload/elfreloc_arm.c",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * <m4x@m4xw.net> wrote this file. As long as you retain this notice you can do\n * whatever you want with this stuff. If we meet some day, and you think this\n * stuff is worth it, you can buy me a beer in return.                     M4xw\n * ----------------------------------------------------------------------------\n */\n\n#include \"elfload.h\"\n\n#if defined(__arm__)\n\n// Taken from http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044f/IHI0044F_aaelf.pdf\n#define R_ARM_NONE 0\n#define R_ARM_ABS32 2\n#define R_ARM_JUMP_SLOT 22\n#define R_ARM_GLOB_DAT 21\n#define R_ARM_RELATIVE 23\n\nel_status el_applyrel(el_ctx *ctx, Elf_Rel *rel)\n{\n\tu32 sym = ELF_R_SYM(rel->r_info);                              // Symbol offset\n\tu32 type = ELF_R_TYPE(rel->r_info);                            // Relocation Type\n\tuptr *p = (uptr *)(rel->r_offset + ctx->base_load_paddr); // Target Addr\n\n#if 0 // For later symbol usage\n\tElf32_Sym *elfSym;\n\tconst char *symbolName;\n\n\t// We resolve relocs from the originating elf-image\n\telfSym = (Elf32_Sym *)(ctx->symtab.sh_offset + (char *)buffteg) + sym;\n\tint strtab_offset = ctx->shstr.sh_offset;\n\tchar *strtab = (char *)buffteg + strtab_offset;\n\tsymbolName = strtab + elfSym->st_name;\n\t//EL_DEBUG(\"Str: %s sz: %x val: %x\\n\", symbolName, elfSym->st_size, elfSym->st_value);\n#endif\n\n\tswitch (type)\n\t{\n\tcase R_ARM_NONE:\n\t\tEL_DEBUG(\"R_ARM_NONE\\n\");\n\t\tbreak;\n\tcase R_ARM_JUMP_SLOT:\n\tcase R_ARM_ABS32:\n\tcase R_ARM_GLOB_DAT:\n\t\t// Stubbed for later purpose\n\t\t//*p += elfSym->st_value; // + vaddr from sec\n\t\t//*p |= 0; // 1 if Thumb && STT_FUNC, ignored for now\n\t\tbreak;\n\tcase R_ARM_RELATIVE: // Needed for PIE\n\t\tif (sym)\n\t\t{\n\t\t\treturn EL_BADREL;\n\t\t}\n\t\t*p += ctx->base_load_vaddr;\n\t\tbreak;\n\n\tdefault:\n\t\treturn EL_BADREL;\n\t}\n\n\treturn EL_OK;\n}\n\n#endif\n"
  },
  {
    "path": "bdk/ianos/ianos.c",
    "content": "/*\n * Copyright (c) 2018 M4xw\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include \"ianos.h\"\n#include \"elfload/elfload.h\"\n#include <module.h>\n#include <mem/heap.h>\n#include <storage/sd.h>\n#include <utils/types.h>\n\n#include <gfx_utils.h>\n\nextern heap_t _heap;\n\nstatic bdk_params_t _bdk_params = {\n\t.gfx_con = (void *)&gfx_con,\n\t.gfx_ctx = (void *)&gfx_ctxt,\n\t.heap    = &_heap,\n\t.memcpy  = (memcpy_t)&memcpy,\n\t.memset  = (memset_t)&memset,\n\n\t.extension_magic = 0\n};\n\nstatic void *_ianos_alloc_cb(el_ctx *ctx, Elf_Addr phys, Elf_Addr virt, Elf_Addr size)\n{\n\treturn (void *)virt;\n}\n\nstatic el_status _ianos_read_cb(el_ctx *ctx, void *dest, size_t nb, size_t offset)\n{\n\tmemcpy(dest, (void *)(ctx->eaddr + offset), nb);\n\n\treturn EL_OK;\n}\n\n//TODO: Support shared libraries.\nint ianos_loader(ianos_lib_t *lib, char *path)\n{\n\tel_ctx ctx;\n\tlib->buf = NULL;\n\tif (!lib->bdk)\n\t\tlib->bdk = &_bdk_params;\n\n\t// Read library.\n\tctx.eaddr = (Elf_Addr)sd_file_read(path, NULL);\n\tif (!ctx.eaddr)\n\t\tgoto error;\n\n\tctx.pread = _ianos_read_cb;\n\n\tif (el_init(&ctx))\n\t\tgoto error;\n\n\tif (lib->type & IA_SHARED_LIB)\n\t\tgoto error; // No support for shared libs now.\n\n\t// Set our relocated library's buffer.\n\tswitch (lib->type & ~IA_SHARED_LIB)\n\t{\n\tcase IA_DRAM_LIB:\n\t\tlib->buf = malloc(ctx.memsz); // Aligned to 0x10 by default.\n\t\tbreak;\n\n\tcase IA_IRAM_LIB:\n\t\tbreak;\n\n\tcase IA_AUTO_LIB: // Default to DRAM for now.\n\tdefault:\n\t\tlib->buf = malloc(ctx.memsz); // Aligned to 0x10 by default.\n\t\tbreak;\n\t}\n\n\tif (!lib->buf)\n\t\tgoto error;\n\n\t// Load and relocate library.\n\tctx.base_load_vaddr = ctx.base_load_paddr = (Elf_Addr)lib->buf;\n\tif (el_load(&ctx, _ianos_alloc_cb))\n\t\tgoto error;\n\n\tif (el_relocate(&ctx))\n\t\tgoto error;\n\n\tfree((void *)ctx.eaddr);\n\n\t// Launch.\n\tElf_Addr epaddr = ctx.ehdr.e_entry + (Elf_Addr)lib->buf;\n\tmoduleEntrypoint ep = (moduleEntrypoint)epaddr;\n\tep(lib->private, lib->bdk);\n\n\treturn 0;\n\nerror:\n\tfree((void *)ctx.eaddr);\n\tfree(lib->buf);\n\n\treturn 1;\n}\n\nuintptr_t ianos_static_module(char *path, void *private)\n{\n\tel_ctx ctx;\n\tElf_Addr buf = 0;\n\tElf_Addr epaddr = 0;\n\n\t// Read library.\n\tctx.eaddr = (Elf_Addr)sd_file_read(path, NULL);\n\tif (!ctx.eaddr)\n\t\tgoto error;\n\n\tctx.pread = _ianos_read_cb;\n\n\t// Initialize elfload context.\n\tif (el_init(&ctx))\n\t\tgoto error;\n\n\t// Set our relocated library's buffer.\n\tbuf = (Elf_Addr)malloc(ctx.memsz); // Aligned to 0x10 by default.\n\tif (!buf)\n\t\tgoto error;\n\n\t// Load and relocate library.\n\tctx.base_load_vaddr = ctx.base_load_paddr = buf;\n\tif (el_load(&ctx, _ianos_alloc_cb))\n\t\tgoto error;\n\n\tif (el_relocate(&ctx))\n\t\tgoto error;\n\n\tfree((void *)ctx.eaddr);\n\n\t// Launch.\n\tepaddr = ctx.ehdr.e_entry + buf;\n\tmoduleEntrypoint ep = (moduleEntrypoint)epaddr;\n\tep(private, &_bdk_params);\n\n\treturn (uintptr_t)epaddr;\n\nerror:\n\tfree((void *)ctx.eaddr);\n\tfree((void *)buf);\n\n\treturn 0;\n}\n"
  },
  {
    "path": "bdk/ianos/ianos.h",
    "content": "/*\n * Copyright (c) 2018 M4xw\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef IANOS_H\n#define IANOS_H\n\n#include <utils/types.h>\n#include <module.h>\n\ntypedef enum\n{\n\tIA_DRAM_LIB   = 0, // DRAM library.\n\tIA_IRAM_LIB   = 1, // IRAM library. No support for now.\n\tIA_AUTO_LIB   = 2, // AUTO library. Defaults to DRAM for now.\n\tIA_SHARED_LIB = BIT(7) // Shared library mask. No support for now.\n} ianos_type_t;\n\ntypedef struct _ianos_lib_t\n{\n\tuintptr_t epaddr;\n\tvoid *buf;\n\tvoid *private;\n\tianos_type_t type;\n\tbdk_params_t *bdk;\n} ianos_lib_t;\n\nint       ianos_loader(ianos_lib_t *lib, char *path);\nuintptr_t ianos_static_module(char *path, void *private); // Session-lived DRAM lib.\n\n#endif\n"
  },
  {
    "path": "bdk/input/als.c",
    "content": "/*\n * Ambient light sensor driver for Nintendo Switch's Rohm BH1730\n *\n * Copyright (c) 2018 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include \"als.h\"\n#include <power/max7762x.h>\n#include <soc/clock.h>\n#include <soc/i2c.h>\n#include <soc/pinmux.h>\n#include <utils/util.h>\n\n#define BH1730_DEFAULT_GAIN        BH1730_GAIN_64X\n#define BH1730_DEFAULT_ICYCLE       38\n\n#define BH1730_INTERNAL_CLOCK_NS   2800\n#define BH1730_ADC_CALC_DELAY_US   2000 /* BH1730_INTERNAL_CLOCK_MS * 714 */\n#define BH1730_ITIME_CYCLE_TO_US   2700 /* BH1730_INTERNAL_CLOCK_MS * 964 */\n\n#define BH1730_DEFAULT_ITIME_MS\t   100\n\n#define BH1730_LUX_MULTIPLIER      3600\n#define BH1730_LUX_MULTIPLIER_AULA 1410\n\n#define BH1730_LUX_MAX            100000\n\ntypedef struct _opt_win_cal_t\n{\n\tu32 rc;\n\tu32 cv;\n\tu32 ci;\n} opt_win_cal_t;\n\n// Nintendo Switch Icosa/Iowa Optical Window calibration.\nstatic const opt_win_cal_t opt_win_cal_default[] = {\n\t{  500, 5002, 7502 },\n\t{  754, 2250, 2000 },\n\t{ 1029, 1999, 1667 },\n\t{ 1373,  884,  583 },\n\t{ 1879,  309,  165 }\n};\n\n// Nintendo Switch Aula Optical Window calibration.\nstatic const opt_win_cal_t opt_win_cal_aula[] = {\n\t{  231, 9697, 30300 },\n\t{  993, 3333,  2778 },\n\t{ 1478, 1621,  1053 },\n\t{ 7500,   81,    10 }\n};\n\nstatic const u32 als_gain_idx_tbl[4] = { 1, 2, 64, 128 };\n\nvoid set_als_cfg(als_ctxt_t *als_ctxt, u8 gain, u8 cycle)\n{\n\tif (gain > BH1730_GAIN_128X)\n\t\tgain = BH1730_GAIN_128X;\n\n\tif (!cycle)\n\t\tcycle = 1;\n\n\ti2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG),   gain);\n\ti2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - cycle));\n\n\tals_ctxt->gain = gain;\n\tals_ctxt->cycle = cycle;\n}\n\nvoid get_als_lux(als_ctxt_t *als_ctxt)\n{\n\tu32 data[2];\n\tu32 vi_light;\n\tu32 ir_light;\n\tu64 lux = 0;\n\tu32 itime_us = BH1730_ITIME_CYCLE_TO_US * als_ctxt->cycle;\n\n\t// Get visible and ir light raw data. Mode is continuous so waiting for new values doesn't matter.\n\tdata[0] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0LOW_REG)) +\n\t\t     (i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0HIGH_REG)) << 8);\n\tdata[1] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1LOW_REG)) +\n\t\t     (i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1HIGH_REG)) << 8);\n\n\tvi_light = data[0];\n\tir_light = data[1];\n\n\tals_ctxt->vi_light = vi_light;\n\tals_ctxt->ir_light = ir_light;\n\tals_ctxt->over_limit = vi_light > 65534 || ir_light > 65534;\n\n\tif (!vi_light)\n\t{\n\t\tals_ctxt->lux = 0;\n\n\t\treturn;\n\t}\n\n\t// Set calibration parameters.\n\tu32 lux_multiplier = BH1730_LUX_MULTIPLIER;\n\tu32 opt_win_cal_count = ARRAY_SIZE(opt_win_cal_default);\n\tconst opt_win_cal_t *opt_win_cal = opt_win_cal_default;\n\n\t// Apply optical window calibration coefficients.\n\tfor (u32 i = 0; i < opt_win_cal_count; i++)\n\t{\n\t\tif (1000 * ir_light / vi_light < opt_win_cal[i].rc)\n\t\t{\n\t\t\tlux = ((u64)opt_win_cal[i].cv * data[0]) - (opt_win_cal[i].ci * data[1]);\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tlux *= BH1730_DEFAULT_ITIME_MS * lux_multiplier;\n\tlux /= als_gain_idx_tbl[als_ctxt->gain] * itime_us;\n\tlux /= 1000;\n\n\tif (lux > BH1730_LUX_MAX)\n\t\tlux = BH1730_LUX_MAX;\n\n\tals_ctxt->lux = lux;\n}\n\nu8 als_power_on(als_ctxt_t *als_ctxt)\n{\n\t// Enable power to ALS IC.\n\tmax7762x_regulator_set_voltage(REGULATOR_LDO6, 2900000);\n\tmax7762x_regulator_enable(REGULATOR_LDO6, true);\n\n\t// Init I2C2.\n\tpinmux_config_i2c(I2C_2);\n\tclock_enable_i2c(I2C_2);\n\ti2c_init(I2C_2);\n\n\t// Initialize ALS.\n\tu8 id = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(0x12));\n\ti2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_SPEC(BH1730_SPECCMD_RESET), 0);\n\n\tset_als_cfg(als_ctxt, BH1730_DEFAULT_GAIN, BH1730_DEFAULT_ICYCLE);\n\n\ti2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_CONTROL_REG), BH1730_CTL_POWER_ON | BH1730_CTL_ADC_EN);\n\n\treturn id;\n}\n"
  },
  {
    "path": "bdk/input/als.h",
    "content": "/*\n * Ambient light sensor driver for Nintendo Switch's Rohm BH1730\n *\n * Copyright (c) 2018 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef __ALS_H_\n#define __ALS_H_\n\n#include <utils/types.h>\n\n#define BH1730_I2C_ADDR 0x29\n\n#define BH1730_CMD_MAGIC   0x80\n#define BH1730_CMD_SETADDR 0x00\n#define BH1730_CMD_SPECCMD 0x60\n#define  BH1730_SPECCMD_RESET 0x4\n\n#define BH1730_CONTROL_REG   0x00\n#define  BH1730_CTL_ADC_VALID 0x10\n#define  BH1730_CTL_ONE_TIME  0x08\n#define  BH1730_CTL_DAT0_ONLY 0x04\n#define  BH1730_CTL_ADC_EN    0x02\n#define  BH1730_CTL_POWER_ON  0x01\n#define BH1730_TIMING_REG    0x01\n#define BH1730_GAIN_REG      0x07\n#define  BH1730_GAIN_1X      0x00\n#define  BH1730_GAIN_2X      0x01\n#define  BH1730_GAIN_64X     0x02\n#define  BH1730_GAIN_128X    0x03\n#define BH1730_DATA0LOW_REG  0x14\n#define BH1730_DATA0HIGH_REG 0x15\n#define BH1730_DATA1LOW_REG  0x16\n#define BH1730_DATA1HIGH_REG 0x17\n\n#define BH1730_ADDR(reg) (BH1730_CMD_MAGIC | BH1730_CMD_SETADDR | (reg))\n#define BH1730_SPEC(cmd) (BH1730_CMD_MAGIC | BH1730_CMD_SPECCMD | (cmd))\n\ntypedef struct _als_ctxt_t\n{\n\tu32  lux;\n\tbool over_limit;\n\tu32  vi_light;\n\tu32  ir_light;\n\tu8   gain;\n\tu8   cycle;\n} als_ctxt_t;\n\nvoid set_als_cfg(als_ctxt_t *als_ctxt, u8 gain, u8 cycle);\nvoid get_als_lux(als_ctxt_t *als_ctxt);\nu8   als_power_on(als_ctxt_t *als_ctxt);\n\n#endif /* __ALS_H_ */\n"
  },
  {
    "path": "bdk/input/joycon.c",
    "content": "/*\n * Joy-Con UART driver for Nintendo Switch\n *\n * Copyright (c) 2019-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include \"joycon.h\"\n#include <gfx_utils.h>\n#include <power/max17050.h>\n#include <power/regulator_5v.h>\n#include <soc/clock.h>\n#include <soc/fuse.h>\n#include <soc/gpio.h>\n#include <soc/pinmux.h>\n#include <soc/timer.h>\n#include <soc/uart.h>\n#include <soc/t210.h>\n\n// For disabling driver when logging is enabled.\n#include <libs/lv_conf.h>\n\n#define JC_WIRED_SND_MAGIC \"\\x19\\x01\\x03\"  // Type, Destination, Group.\n#define JC_WIRED_RCV_MAGIC \"\\x19\\x81\\x03\"  // Type, Destination, Group.\n\n#define JC_WIRED_RPT_OUT         0x43\n#define JC_WIRED_RPT_IN          0x53\n#define JC_WIRED_CMD             0x91\n#define JC_WIRED_HID             0x92\n#define JC_WIRED_ECHO            0x93 // CMD OUT.\n#define JC_WIRED_INIT_REPLY      0x94\n#define JC_WIRED_HANDSHAKE       0xA5 // Enable Wired CMDs (JC_WIRED_CMD).\n\n#define JC_HORI_INPUT_RPT_CMD    0x9A\n#define JC_HORI_INPUT_RPT        0x00\n\n#define JC_WIRED_CMD_GET_INFO    0x01\n#define JC_WIRED_CMD_SET_CHARGER 0x02\n#define JC_WIRED_CMD_GET_CHARGER 0x03\n#define JC_WIRED_CMD_SET_ATTACH  0x04\n#define JC_WIRED_CMD_GET_ATTACH  0x05\n#define JC_WIRED_CMD_BATT_VOLT   0x06\n#define JC_WIRED_CMD_WAKE_REASON 0x07\n#define JC_WIRED_CMD_HID_CONN    0x10 // Enable HID CMDs (JC_WIRED_HID).\n#define JC_WIRED_CMD_HID_DISC    0x11\n#define JC_WIRED_CMD_SET_HIDRATE 0x12 // Output report rate.\n#define JC_WIRED_CMD_GET_HIDRATE 0x13\n#define JC_WIRED_CMD_SET_PAIRING 0x18 // Manual pairing.\n#define JC_WIRED_CMD_SET_BRATE   0x20\n#define JC_WIRED_CMD_ECHO_TEST   0x40\n\n#define JC_HID_OUTPUT_RPT        0x01\n#define JC_HID_RUMBLE_RPT        0x10\n\n#define JC_HID_INPUT_RPT         0x30\n#define JC_HID_SUBMCD_RPT        0x21\n\n#define JC_HID_SUBCMD_HCI_STATE  0x06\n#define  HCI_STATE_SLEEP         0x00\n#define  HCI_STATE_RECONNECT     0x01\n#define  HCI_STATE_PAIR          0x02\n#define  HCI_STATE_HOME          0x04\n#define JC_HID_SUBCMD_SPI_READ   0x10\n#define  SPI_READ_OFFSET         0x20\n#define JC_HID_SUBCMD_RUMBLE_CTL 0x48\n#define JC_HID_SUBCMD_CHARGE_SET 0x51\n#define JC_HID_SUBCMD_SND_RUMBLE 0xFF // Custom.\n\n#define JC_SIO_OUTPUT_RPT        0x91\n#define JC_SIO_INPUT_RPT         0x92\n#define  JC_SIO_CMD_ACK          0x80\n\n#define JC_SIO_CMD_INIT          0x01\n#define JC_SIO_CMD_UNK02         0x02\n#define JC_SIO_CMD_VER_RPT       0x03\n#define JC_SIO_CMD_UNK20         0x20 // JC_WIRED_CMD_SET_BRATE\n#define JC_SIO_CMD_UNK21         0x21\n#define JC_SIO_CMD_UNK22         0x22\n#define JC_SIO_CMD_UNK40         0x40\n#define JC_SIO_CMD_STATUS        0x41\n#define JC_SIO_CMD_IAP_VER       0x42\n\n\n#define JC_BTN_MASK_L 0xFF2900 // 0xFFE900: with charge status.\n#define JC_BTN_MASK_R 0x0056FF\n\n#define JC_ID_L     0x01 // Joycon (L). Mask for Hori (L).\n#define JC_ID_R     0x02 // Joycon (R). Mask for Hori (R).\n#define JC_ID_HORI  0x20 // Mask for Hori. Actual ids: 0x21, 0x22.\n\n#define JC_CRC8_POLY 0x8D\n\nenum\n{\n\tJC_STATE_START         = 0,\n\tJC_STATE_HANDSHAKED    = 1,\n\tJC_STATE_INFO_PARSED   = 2,\n\tJC_STATE_BRATE_CHANGED = 3,\n\tJC_STATE_HID_NO_CONN   = 4,\n\tJC_STATE_HID_CONN      = 5,\n\tJC_STATE_INIT_DONE     = 6\n};\n\nenum\n{\n\tJC_BATT_EMPTY = 0,\n\tJC_BATT_CRIT  = 1, // 3300 - 3599 mV.\n\tJC_BATT_LOW   = 2, // 3600 - 3759 mV.\n\tJC_BATT_MID   = 3, // 3760 - 3899 mV.\n\tJC_BATT_FULL  = 4  // 3900 - 4200 mV.\n};\n\n#define JC_CHRG_CFG_SUPL0 0x00 // 100 OFF.\n#define JC_CHRG_CFG_SUPL1 0x10 // EN2 OFF.\n#define JC_CHRG_CFG_100MA 0x04 // 100 ON.\n#define JC_CHRG_CFG_200MA 0x14 // EN2 ON.\n\nenum\n{\n\tJC_CHRG_STATE_INIT = 0,\n\tJC_CHRG_STATE_OFF  = 1, // Regulator OFF.\n\tJC_CHRG_STATE_SUPL = 2, // JC_CHRG_CFG_SUPL0.\n\tJC_CHRG_STATE_SLOW = 3, // JC_CHRG_CFG_100MA.\n\tJC_CHRG_STATE_FAST = 4, // JC_CHRG_CFG_200MA.\n};\n\nstatic const u8 _sio_init[] = {\n\tJC_SIO_OUTPUT_RPT, JC_SIO_CMD_INIT,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x95\n};\n\nstatic const u8 _sio_set_rpt_version[] = {\n\tJC_SIO_OUTPUT_RPT, JC_SIO_CMD_VER_RPT,\n\t// old fw:   0x00, 0x0D (0.13). New 3.4.\n\t// force_update_en:      0x01\n\t0x00, 0x00, 0x03, 0x04, 0x00, 0xDA\n};\n\n// Every 8ms.\nstatic const u8 _sio_pad_status[] = {\n\tJC_SIO_OUTPUT_RPT, JC_SIO_CMD_STATUS,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0xB0\n};\n\nstatic const u8 _jc_init_wake[] = {\n\t0xA1, 0xA2, 0xA3, 0xA4\n};\n\nstatic const u8 _jc_init_handshake[] = {\n\t0x19, 0x01, 0x03, 0x07, 0x00,           // Uart header.\n\tJC_WIRED_HANDSHAKE, 0x02,               // Cmd and Replay echo.\n\t0x01, 0x7E, 0x00, 0x00, 0x00            // Handshake magic.\n};\n\nstatic const u8 _jc_init_get_info[]  = {\n\t0x19, 0x01, 0x03, 0x07, 0x00,           // Uart header.\n\tJC_WIRED_CMD, JC_WIRED_CMD_GET_INFO,    // Cmd and subcmd.\n\t0x00, 0x00, 0x00, 0x00,  0x24           // Hdr crc.\n};\n\nstatic const u8 _jc_init_switch_brate[]  = {\n\t0x19, 0x01, 0x03, 0x0F, 0x00,           // Uart header.\n\tJC_WIRED_CMD, JC_WIRED_CMD_SET_BRATE,   // Cmd and subcmd.\n\t0x08, 0x00, 0x00, 0xBD,  0xB1,          // Subcmd data size, data crc and hdr crc.\n\t// Baudrate 3 megabaud.\n\t0xC0, 0xC6, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00\n};\n\nstatic const u8 _jc_init_hid_disconnect[]  = {\n\t0x19, 0x01, 0x03, 0x07, 0x00,           // Uart header.\n\tJC_WIRED_CMD, JC_WIRED_CMD_HID_DISC,    // Cmd and subcmd.\n\t0x00, 0x00, 0x00, 0x00,  0x0E           // Hdr crc.\n};\n\nstatic const u8 _jc_init_set_hid_rate[]  = {\n\t0x19, 0x01, 0x03, 0x0B, 0x00,           // Uart header.\n\tJC_WIRED_CMD, JC_WIRED_CMD_SET_HIDRATE, // Cmd and subcmd.\n\t0x04, 0x00, 0x00, 0x12,  0xA6,          // Subcmd data size, data crc and hdr crc.\n\t// Output report rate 15 ms. (5/10/15 supported).\n\t0x0F, 0x00, 0x00, 0x00\n\n\t// 5 ms.\n\t// 0x04, 0x00, 0x00, 0x0E, 0xD5,\n\t// 0x05, 0x00, 0x00, 0x00\n};\n\nstatic const u8 _jc_init_hid_connect[]  = {\n\t0x19, 0x01, 0x03, 0x07, 0x00,           // Uart header.\n\tJC_WIRED_CMD, JC_WIRED_CMD_HID_CONN,    // Cmd and subcmd.\n\t0x00, 0x00, 0x00, 0x00, 0x3D            // Hdr crc.\n};\n\nstatic const u8 _jc_nx_pad_status[]  = {\n\t0x19, 0x01, 0x03, 0x08, 0x00,           // Uart header.\n\tJC_WIRED_HID, 0x00,                     // Cmd.\n\t0x01, 0x00, 0x00, 0x69,  0x2D,          // Subcmd data size, data crc and hdr crc.\n\t// Contents do not matter.\n\t0x1F\n};\n\nstatic const u8 _jc_hori_pad_status[] = {\n\t0x19, 0x01, 0x03, 0x07, 0x00,           // Uart header.\n\tJC_HORI_INPUT_RPT_CMD, 0x01,            // Hori cmd and hori subcmd.\n\t0x00, 0x00, 0x00, 0x00, 0x48            // Hdr crc.\n};\n\n// code: Channel code. vibc: Vibration code.\ntypedef struct\n{\n\tu32 rsvd   :20;\n\tu32 code_hi:5;\n\tu32 code_lo:5;\n\tu32 fmt    :2; // Must be 1.\n} jc_rumble_fmt1_t;\n\ntypedef struct\n{\n\tu32 rsvd   :2;\n\tu32 freq_hi:7;\n\tu32 amp_hi :7;\n\tu32 freq_lo:7;\n\tu32 amp_lo :7;\n\tu32 fmt    :2; // Must be 1.\n} jc_rumble_fmt1_28bit_t;\n\ntypedef struct\n{\n\tu32 rdvd   :10;\n\tu32 vibc_hi:5;\n\tu32 vibc_lo:5;\n\tu32 code_hi:5;\n\tu32 code_lo:5;\n\tu32 fmt    :2; // Must be 2.\n} jc_rumble_fmt2_t;\n\ntypedef struct\n{\n\tu32 is_high :1;\n\tu32 freq    :7;\n\tu32 vibc_hi1:5;\n\tu32 vibc_lo1:5;\n\tu32 vibc_hi0:5; // vibc_lo0 if is_high.\n\tu32 amp     :7;\n\tu32 fmt     :2; // Must be 2.\n} jc_rumble_fmt2_14bit_t;\n\ntypedef struct\n{\n\tu32 vibc_hi1:5;\n\tu32 vibc_lo1:5;\n\tu32 vibc_hi0:5;\n\tu32 vibc_lo0:5;\n\tu32 code_hi :5;\n\tu32 code_lo :5;\n\tu32 fmt     :2; // Must be 3.\n} jc_rumble_fmt3_t;\n\ntypedef struct\n{\n\tu32 is_high:1;\n\tu32 is_7bit:1;\n\tu32 is_fm  :1;\n\tu32 vibc_hi1:5;\n\tu32 vibc_lo1:5;\n\tu32 vibc_hi0:5;\n\tu32 vibc_lo0:5;\n\tu32 amfm    :7;\n\tu32 fmt     :2; // Must be 1 (not 3).\n} jc_rumble_fmt3_7bit_t;\n\ntypedef struct _jc_rumble_t\n{\n\tunion {\n\t\tjc_rumble_fmt1_t       fmt1;\n\t\tjc_rumble_fmt1_28bit_t fmt1_28b;\n\t\tjc_rumble_fmt3_7bit_t  fmt3_7b;\n\t\tjc_rumble_fmt2_t       fmt2;\n\t\tjc_rumble_fmt2_14bit_t fmt2_14b;\n\t\tjc_rumble_fmt3_t       fmt3;\n\t\tu32 r32;\n\t\tu8  r8[4];\n\t};\n} __attribute__((packed)) jc_rumble_t;\n\ntypedef struct _jc_uart_hdr_t\n{\n\tu8  magic[3]; // Type, Destination, Group.\n\tu16 total_size;\n} __attribute__((packed)) jc_uart_hdr_t;\n\ntypedef struct _jc_wired_hdr_t\n{\n\tjc_uart_hdr_t uart_hdr;\n\tu8  cmd;\n\tu8  subcmd;\n\tu16 payload_size;\n\t// As out, cmd exists query. For JC_WIRED_CMD_SET_PAIRING: 1-4 pairing step.\n\t// As in, 0xF: exists. For JC_WIRED_CMD_SET_HIDRATE: 1 wrong rate.\n\tu8  status;\n\tu8  crc_payload;\n\tu8  crc_hdr;\n\tu8  payload[];\n} __attribute__((packed)) jc_wired_hdr_t;\n\ntypedef struct _jc_hid_out_rpt_t\n{\n\tu8 cmd;\n\tu8 pkt_id;\n\tjc_rumble_t rumble[2];\n\tu8 subcmd;\n\tu8 subcmd_data[];\n} __attribute__((packed)) jc_hid_out_rpt_t;\n\ntypedef struct _jc_hid_in_rpt_t\n{\n\tu8  cmd;\n\tu8  pkt_id;      // Latency timer. 5 ms lsb (every 4 x 1.25 ms).\n\tu8  conn_info:4; // Connection detect.\n\tu8  batt_info:4; // Power info.\n\tu16 btn_right:12;\n\tu16 btn_left:12;\n\tu16 stick_left_x:12;\n\tu16 stick_left_y:12;\n\tu16 stick_right_x:12;\n\tu16 stick_right_y:12;\n\tu8  vib_decider; // right:4, left:4 (bit3 en, bit2-0 buffer avail).\n\tu8  submcd_ack;\n\tu8  subcmd;\n\tu8  subcmd_data[];\n} __attribute__((packed)) jc_hid_in_rpt_t;\n\ntypedef struct _jc_hid_out_spi_read_t\n{\n\tu32 addr;\n\tu8  size;\n} __attribute__((packed)) jc_hid_out_spi_read_t;\n\ntypedef struct _jc_hid_in_spi_read_t\n{\n\tu32 addr;\n\tu8  size;\n\tu8  data[];\n} __attribute__((packed)) jc_hid_in_spi_read_t;\n\ntypedef struct _jc_hid_in_pair_data_t\n{\n\tu8  magic;\n\tu8  size;\n\tu16 checksum;\n\tu8  mac[6];\n\tu8  ltk[16];\n\tu8  pad0[10];\n\tu8  bt_caps; // bit3: Secure conn supported host, bit5: Paired to TBFC supported host, bit6: iTBFC page supported\n\tu8  pad1;\n} __attribute__((packed)) jc_hid_in_pair_data_t;\n\ntypedef struct _jc_sio_out_rpt_t\n{\n\tu8  cmd;\n\tu8  subcmd;\n\tu16 payload_size;\n\tu8  data[2];\n\tu8  crc_payload;\n\tu8  crc_hdr;\n\tu8  payload[];\n} __attribute__((packed)) jc_sio_out_rpt_t;\n\ntypedef struct _jc_sio_in_rpt_t\n{\n\tu8  cmd;\n\tu8  subcmd;\n\tu16 payload_size;\n\tu8  status;\n\tu8  unk;\n\tu8  crc_payload;\n\tu8  crc_hdr;\n\tu8  payload[];\n} __attribute__((packed)) jc_sio_in_rpt_t;\n\ntypedef struct _jc_hid_in_sixaxis_rpt_t\n{\n\ts16 acc_x;\n\ts16 acc_y;\n\ts16 acc_z;\n\ts16 gyr_x;\n\ts16 gyr_y;\n\ts16 gyr_z;\n} __attribute__((packed)) jc_hid_in_sixaxis_rpt_t;\n\ntypedef struct _jc_sio_hid_in_rpt_t\n{\n\tu8  type;\n\tu8  pkt_id; // Latency timer.\n\tu8  unk;\n\tu16 btn_right:12;\n\tu16 btn_left:12;\n\tu16 stick_left_x:12;\n\tu16 stick_left_y:12;\n\tu16 stick_right_x:12;\n\tu16 stick_right_y:12;\n\tu8  sixaxis_rpt; // bit0-3: report num. bit4-7: imu type.\n\t// Each report is 800 us?\n\tjc_hid_in_sixaxis_rpt_t sixaxis[15];\n} __attribute__((packed)) jc_sio_hid_in_rpt_t;\n\ntypedef struct _jc_dev_t\n{\n\tu8   buf[0x100];\n\tu8   uart;\n\tu8   type;\n\tu8   state;\n\tu8   pkt_id;\n\tbool detected;\n\tbool connected;\n\tbool sio_mode;\n\tbool rumble_sent;\n\tbool charger_req;\n\tu32  last_received_time; // Reset with JC_WIRED_CMD_HID_CONN/JC_WIRED_HID. If exceeded HID mode disconnects.\n\tu32  last_status_req_time;\n\tu32  last_chrger_chk_time;\n\tu8   mac[6];\n} jc_dev_t;\n\nstatic jc_dev_t jc_l = {0};\nstatic jc_dev_t jc_r = {0};\n\nstatic bool jc_init_done = false;\n\nstatic jc_gamepad_rpt_t jc_gamepad;\n\nstatic void _jc_rcv_pkt(jc_dev_t *jc);\n\nstatic u8 _jc_crc(const u8 *data, u16 len)\n{\n\tu8 crc = 0;\n\tfor (u16 i = 0; i < len; i++)\n\t{\n\t\tcrc ^= data[i];\n\t\tfor (u16 j = 0; j < 8; j++)\n\t\t{\n\t\t\tif ((crc & 0x80) != 0)\n\t\t\t\tcrc = (u8)((crc << 1) ^ JC_CRC8_POLY);\n\t\t\telse\n\t\t\t\tcrc <<= 1;\n\t\t}\n\t}\n\treturn crc;\n}\n\nstatic void _jc_power_supply(u8 uart, bool enable)\n{\n\tif (enable)\n\t{\n\t\tif (regulator_5v_get_dev_enabled(1 << uart))\n\t\t\treturn;\n\n\t\tregulator_5v_enable(1 << uart);\n\n\t\tif (jc_gamepad.sio_mode)\n\t\t\treturn;\n\n\t\tif (jc_init_done)\n\t\t{\n\t\t\tif (uart == UART_C)\n\t\t\t\tgpio_write(GPIO_PORT_CC, GPIO_PIN_3, GPIO_HIGH);\n\t\t\telse\n\t\t\t\tgpio_write(GPIO_PORT_K, GPIO_PIN_3, GPIO_HIGH);\n\t\t\treturn;\n\t\t}\n\n\t\tif (uart == UART_C)\n\t\t{\n\t\t\t// Joy-Con(L) Charge Enable.\n\t\t\tPINMUX_AUX(PINMUX_AUX_SPDIF_IN) = PINMUX_PULL_DOWN | 1;\n\t\t\tgpio_direction_output(GPIO_PORT_CC, GPIO_PIN_3, GPIO_HIGH);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Joy-Con(R) Charge Enable.\n\t\t\tPINMUX_AUX(PINMUX_AUX_GPIO_PK3) = PINMUX_DRIVE_4X | PINMUX_PULL_DOWN | 2;\n\t\t\tgpio_direction_output(GPIO_PORT_K, GPIO_PIN_3, GPIO_HIGH);\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (!regulator_5v_get_dev_enabled(1 << uart))\n\t\t\treturn;\n\n\t\tregulator_5v_disable(1 << uart);\n\n\t\tif (jc_gamepad.sio_mode)\n\t\t\treturn;\n\n\t\tif (uart == UART_C)\n\t\t\tgpio_write(GPIO_PORT_CC, GPIO_PIN_3, GPIO_LOW);\n\t\telse\n\t\t\tgpio_write(GPIO_PORT_K, GPIO_PIN_3, GPIO_LOW);\n\t}\n}\n\nstatic void _jc_rail_detect()\n{\n\t// Turn on Joy-Con detect. (UARTB/C TX). UART CTS also if HW flow control and irq is enabled.\n\tPINMUX_AUX(PINMUX_AUX_UART2_TX) = PINMUX_INPUT_ENABLE;\n\tPINMUX_AUX(PINMUX_AUX_UART3_TX) = PINMUX_INPUT_ENABLE;\n\tgpio_direction_input(GPIO_PORT_G, GPIO_PIN_0);\n\tgpio_direction_input(GPIO_PORT_D, GPIO_PIN_1);\n\tusleep(20);\n\n\t//! HW BUG: Unlatch gpio buffer.\n\t(void)gpio_read(GPIO_PORT_H, GPIO_PIN_6);\n\t(void)gpio_read(GPIO_PORT_E, GPIO_PIN_6);\n\n\t// Read H6/E6 which are shared with UART TX pins.\n\tjc_r.detected = !gpio_read(GPIO_PORT_H, GPIO_PIN_6);\n\tjc_l.detected = !gpio_read(GPIO_PORT_E, GPIO_PIN_6);\n\n\t// Turn off Joy-Con detect. (UARTB/C TX).\n\tPINMUX_AUX(PINMUX_AUX_UART2_TX) = 0;\n\tPINMUX_AUX(PINMUX_AUX_UART3_TX) = 0;\n\tgpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);\n\tgpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);\n\tusleep(20);\n}\n\nstatic void _jc_conn_check()\n{\n\tif (jc_gamepad.sio_mode)\n\t{\n\t\t//! TODO: Is there a way to detect a broken Sio?\n\t\tjc_l.detected = true;\n\n\t\treturn;\n\t}\n\n\t_jc_rail_detect();\n\n\t// Check if a Joy-Con was disconnected.\n\tif (!jc_l.detected)\n\t{\n\t\tjc_l.pkt_id = 0;\n\n\t\tjc_l.connected   = false;\n\t\tjc_l.rumble_sent = false;\n\t\tjc_l.charger_req = false;\n\t\tjc_l.last_received_time = 0;\n\n\t\tjc_gamepad.conn_l = false;\n\n\t\tjc_gamepad.batt_info_l    = 0;\n\t\tjc_gamepad.batt_chrg_l    = 0;\n\t\tjc_gamepad.bt_conn_l.type = 0;\n\t\tjc_gamepad.buttons &= ~JC_BTN_MASK_L;\n\t}\n\n\tif (!jc_r.detected)\n\t{\n\t\tjc_r.pkt_id = 0;\n\n\t\tjc_r.connected   = false;\n\t\tjc_r.rumble_sent = false;\n\t\tjc_r.charger_req = false;\n\t\tjc_r.last_received_time = 0;\n\n\t\tjc_gamepad.conn_r = false;\n\n\t\tjc_gamepad.batt_info_r    = 0;\n\t\tjc_gamepad.batt_chrg_r    = 0;\n\t\tjc_gamepad.bt_conn_r.type = 0;\n\t\tjc_gamepad.buttons &= ~JC_BTN_MASK_R;\n\t}\n}\n\nstatic void _joycon_send_raw(u8 uart_port, const u8 *buf, u16 size)\n{\n\tuart_send(uart_port, buf, size);\n\tuart_wait_xfer(uart_port, UART_TX_IDLE);\n}\n\nstatic u16 _jc_packet_add_uart_hdr(jc_wired_hdr_t *rpt, u8 cmd, u8 subcmd, u16 payload_size, bool crc)\n{\n\tmemcpy(rpt->uart_hdr.magic, JC_WIRED_SND_MAGIC, sizeof(rpt->uart_hdr.magic));\n\n\trpt->uart_hdr.total_size = sizeof(jc_wired_hdr_t) - sizeof(jc_uart_hdr_t) + payload_size;\n\trpt->cmd = cmd;\n\trpt->subcmd = subcmd;\n\trpt->payload_size = payload_size; // Only used if JC_WIRED_CMD.\n\n\t// Only calculated if JC_WIRED_CMD/JC_WIRED_HID and result never checked?\n\t// if (payload_size)\n\t// \trpt->crc_payload = crc ? _jc_crc(rpt->payload, payload_size) : 0;\n\n\t// Only calculated if JC_WIRED_CMD/JC_WIRED_HID/JC_WIRED_HANDSHAKE and result only checked on HORI.\n\trpt->crc_hdr = crc ? _jc_crc(&rpt->cmd, sizeof(jc_wired_hdr_t) - sizeof(jc_uart_hdr_t) - 1) : 0;\n\n\treturn (rpt->uart_hdr.total_size + sizeof(jc_uart_hdr_t));\n}\n\nstatic u16 _jc_hid_output_rpt_craft(jc_wired_hdr_t *rpt, const u8 *payload, u16 payload_size, bool crc)\n{\n\tif (payload)\n\t\tmemcpy(rpt->payload, payload, payload_size);\n\n\treturn _jc_packet_add_uart_hdr(rpt, JC_WIRED_HID, 0, payload_size, crc);\n}\n\nstatic void _jc_send_hid_output_rpt(jc_dev_t *jc, jc_hid_out_rpt_t *hid_pkt, u16 size, bool crc)\n{\n\tu8 rpt[0x50];\n\tmemset(rpt, 0, sizeof(rpt));\n\n\thid_pkt->pkt_id = (jc->pkt_id++ & 0xF);\n\tu32 rpt_size = _jc_hid_output_rpt_craft((jc_wired_hdr_t *)rpt, (u8 *)hid_pkt, size, crc);\n\n\t_joycon_send_raw(jc->uart, rpt, rpt_size);\n}\n\nstatic void _jc_send_hid_cmd(jc_dev_t *jc, u8 subcmd, const u8 *data, u16 size)\n{\n\tstatic const u8 rumble_mute[8] = { 0x00, 0x01, 0x40, 0x40, 0x00, 0x01, 0x40, 0x40 };\n\tstatic const u8 rumble_init[8] = { 0xc2, 0xc8, 0x03, 0x72, 0xc2, 0xc8, 0x03, 0x72 };\n\n\tu8 temp[0x30] = {0};\n\n\tjc_hid_out_rpt_t *hid_pkt = (jc_hid_out_rpt_t *)temp;\n\tmemcpy(hid_pkt->rumble, rumble_mute, sizeof(rumble_mute));\n\n\tif (subcmd == JC_HID_SUBCMD_SND_RUMBLE)\n\t{\n\t\tbool send_r_rumble = jc_r.connected && !jc_r.rumble_sent;\n\t\tbool send_l_rumble = jc_l.connected && !jc_l.rumble_sent;\n\n\t\t// Enable rumble.\n\t\thid_pkt->cmd    = JC_HID_OUTPUT_RPT;\n\t\thid_pkt->subcmd = JC_HID_SUBCMD_RUMBLE_CTL;\n\t\thid_pkt->subcmd_data[0] = 1;\n\t\tif (send_r_rumble)\n\t\t\t_jc_send_hid_output_rpt(&jc_r, hid_pkt, 0x10, false);\n\t\tif (send_l_rumble)\n\t\t\t_jc_send_hid_output_rpt(&jc_l, hid_pkt, 0x10, false);\n\n\t\tmsleep(15);\n\n\t\tif (send_r_rumble)\n\t\t\t_jc_rcv_pkt(&jc_r);\n\t\tif (send_l_rumble)\n\t\t\t_jc_rcv_pkt(&jc_l);\n\n\t\t// Send rumble.\n\t\thid_pkt->cmd = JC_HID_RUMBLE_RPT;\n\t\tmemcpy(hid_pkt->rumble, rumble_init, sizeof(rumble_init));\n\t\tif (send_r_rumble)\n\t\t\t_jc_send_hid_output_rpt(&jc_r, hid_pkt, 10, false);\n\t\tif (send_l_rumble)\n\t\t\t_jc_send_hid_output_rpt(&jc_l, hid_pkt, 10, false);\n\n\t\tmsleep(15);\n\n\t\t// Mute rumble.\n\t\thid_pkt->cmd = JC_HID_RUMBLE_RPT;\n\t\tmemcpy(hid_pkt->rumble, rumble_mute, sizeof(rumble_mute));\n\t\tif (send_r_rumble)\n\t\t\t_jc_send_hid_output_rpt(&jc_r, hid_pkt, 10, false);\n\t\tif (send_l_rumble)\n\t\t\t_jc_send_hid_output_rpt(&jc_l, hid_pkt, 10, false);\n\t}\n\telse\n\t{\n\t\tbool crc_needed = jc->type & JC_ID_HORI;\n\n\t\thid_pkt->cmd    = JC_HID_OUTPUT_RPT;\n\t\thid_pkt->subcmd = subcmd;\n\t\tif (data)\n\t\t\tmemcpy(hid_pkt->subcmd_data, data, size);\n\n\t\t_jc_send_hid_output_rpt(jc, hid_pkt, sizeof(jc_hid_out_rpt_t) + size, crc_needed);\n\t}\n}\n\nstatic void _jc_parse_input(jc_dev_t *jc, const jc_hid_in_rpt_t *hid_pkt)\n{\n\tu32 btn_tmp;\n\tbtn_tmp = hid_pkt->btn_right | hid_pkt->btn_left << 12;\n\n\tif (jc->type & JC_ID_L)\n\t{\n\t\tjc_gamepad.buttons &= ~JC_BTN_MASK_L;\n\t\tjc_gamepad.buttons |= (btn_tmp & JC_BTN_MASK_L);\n\n\t\tjc_gamepad.lstick_x = hid_pkt->stick_left_x;\n\t\tjc_gamepad.lstick_y = hid_pkt->stick_left_y;\n\n\t\tjc_gamepad.batt_info_l = hid_pkt->batt_info;\n\t}\n\telse if (jc->type & JC_ID_R)\n\t{\n\t\tjc_gamepad.buttons &= ~JC_BTN_MASK_R;\n\t\tjc_gamepad.buttons |= (btn_tmp & JC_BTN_MASK_R);\n\n\t\tjc_gamepad.rstick_x = hid_pkt->stick_right_x;\n\t\tjc_gamepad.rstick_y = hid_pkt->stick_right_y;\n\n\t\tjc_gamepad.batt_info_r = hid_pkt->batt_info;\n\t}\n}\n\nstatic void _jc_parse_wired_hid(jc_dev_t *jc, const u8 *packet, int size)\n{\n\tconst jc_hid_in_rpt_t *hid_pkt = (jc_hid_in_rpt_t *)packet;\n\n\tswitch (hid_pkt->cmd)\n\t{\n\tcase JC_HORI_INPUT_RPT:\n\t\tif (!(jc->type & JC_ID_HORI))\n\t\t\treturn;\n\n\tcase JC_HID_INPUT_RPT:\n\t\t// Discard incomplete hid packets.\n\t\tif (size < 12)\n\t\t\tbreak;\n\n\t\t_jc_parse_input(jc, hid_pkt);\n\n\t\tjc_gamepad.conn_l = jc_l.connected;\n\t\tjc_gamepad.conn_r = jc_r.connected;\n\t\tbreak;\n\n\tcase JC_HID_SUBMCD_RPT:\n\t\tif (hid_pkt->subcmd == JC_HID_SUBCMD_SPI_READ)\n\t\t{\n\t\t\tjc_bt_conn_t *bt_conn;\n\n\t\t\tif (jc->type & JC_ID_L)\n\t\t\t\tbt_conn = &jc_gamepad.bt_conn_l;\n\t\t\telse\n\t\t\t\tbt_conn = &jc_gamepad.bt_conn_r;\n\n\t\t\tjc_hid_in_spi_read_t  *spi_info  = (jc_hid_in_spi_read_t *)hid_pkt->subcmd_data;\n\t\t\tjc_hid_in_pair_data_t *pair_data = (jc_hid_in_pair_data_t *)spi_info->data;\n\n\t\t\t// Check if the reply is pairing info.\n\t\t\tif (spi_info->size == 0x1A && pair_data->magic == 0x95 && pair_data->size == 0x22)\n\t\t\t{\n\t\t\t\tbt_conn->type = jc->type;\n\n\t\t\t\tmemcpy(bt_conn->mac, jc->mac, 6);\n\t\t\t\tmemcpy(bt_conn->host_mac, pair_data->mac, 6);\n\t\t\t\tfor (u32 i = 16; i > 0; i--)\n\t\t\t\t\tbt_conn->ltk[16 - i] = pair_data->ltk[i - 1];\n\t\t\t}\n\t\t}\n\t\telse if (hid_pkt->subcmd == JC_HID_SUBCMD_CHARGE_SET)\n\t\t\tjc->charger_req = false;\n\n\t\t_jc_parse_input(jc, hid_pkt);\n\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n}\n\nstatic void _jc_parse_wired_init(jc_dev_t *jc, const jc_wired_hdr_t *pkt, int size)\n{\n\t// Discard empty packets.\n\tif (size <= 0)\n\t\treturn;\n\n\tconst u8 *payload = pkt->payload;\n\n\tswitch (pkt->subcmd)\n\t{\n\tcase JC_WIRED_CMD_GET_INFO:\n\t\tif (!pkt->status)\n\t\t{\n\t\t\tfor (int i = 6; i > 0; i--)\n\t\t\tjc->mac[6 - i] = payload[i];\n\t\t\tjc->type = payload[0];\n\t\t\tjc->state = JC_STATE_INFO_PARSED;\n\t\t}\n\t\tbreak;\n\n\tcase JC_WIRED_CMD_SET_BRATE:\n\t\tif (!pkt->status)\n\t\t\tjc->state = JC_STATE_BRATE_CHANGED;\n\t\tbreak;\n\n\tcase JC_WIRED_CMD_HID_DISC:\n\t\tif (pkt->status == 0xF)\n\t\t\tjc->state = JC_STATE_HID_NO_CONN;\n\t\tbreak;\n\n\tcase JC_WIRED_CMD_HID_CONN:\n\t\tif (!pkt->status)\n\t\t\tjc->state = JC_STATE_HID_CONN;\n\t\tbreak;\n\n\tcase JC_WIRED_CMD_SET_HIDRATE:\n\t\tjc->state = JC_STATE_INIT_DONE;\n\t\tjc->connected = true;\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n}\n\nstatic void _jc_uart_pkt_parse(jc_dev_t *jc, const jc_wired_hdr_t *pkt, int size)\n{\n\tswitch (pkt->cmd)\n\t{\n\tcase JC_HORI_INPUT_RPT_CMD:\n\tcase JC_WIRED_HID:\n\t\t_jc_parse_wired_hid(jc, pkt->payload, size - sizeof(jc_wired_hdr_t));\n\t\tbreak;\n\n\tcase JC_WIRED_INIT_REPLY:\n\t\t_jc_parse_wired_init(jc, pkt, size);\n\t\tbreak;\n\n\tcase JC_WIRED_HANDSHAKE:\n\t\tjc->state = JC_STATE_HANDSHAKED;\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\tjc->last_received_time = get_tmr_ms();\n}\n\nstatic void _jc_sio_parse_payload(jc_dev_t *jc, u8 cmd, const u8 *payload, int size)\n{\n\tswitch (cmd)\n\t{\n\tcase JC_SIO_CMD_STATUS:\n\t\t// Discard incomplete packets.\n\t\tif (size < 12)\n\t\t\tbreak;\n\n\t\tjc_sio_hid_in_rpt_t *hid_pkt = (jc_sio_hid_in_rpt_t *)payload;\n\t\tjc_gamepad.buttons = hid_pkt->btn_right | hid_pkt->btn_left << 12;\n\t\tjc_gamepad.home    = !gpio_read(GPIO_PORT_V, GPIO_PIN_3);\n\n\t\tjc_gamepad.lstick_x = hid_pkt->stick_left_x;\n\t\tjc_gamepad.lstick_y = hid_pkt->stick_left_y;\n\t\tjc_gamepad.rstick_x = hid_pkt->stick_right_x;\n\t\tjc_gamepad.rstick_y = hid_pkt->stick_right_y;\n\n\t\tjc_gamepad.batt_info_l = jc_l.connected;\n\t\tjc_gamepad.batt_info_r = gpio_read(GPIO_PORT_E, GPIO_PIN_7); // Set IRQ status.\n\n\t\tjc_gamepad.conn_l = jc_l.connected;\n\t\tjc_gamepad.conn_r = jc_l.connected;\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n}\n\nstatic void _jc_sio_uart_pkt_parse(jc_dev_t *jc, const jc_sio_in_rpt_t *pkt, int size)\n{\n\tif (pkt->crc_hdr != _jc_crc((u8 *)pkt, sizeof(jc_sio_in_rpt_t) - 1))\n\t\treturn;\n\n\tu8 cmd = pkt->subcmd & (~JC_SIO_CMD_ACK);\n\tswitch (cmd)\n\t{\n\tcase JC_SIO_CMD_INIT:\n\t\tif (!pkt->status)\n\t\t\tjc->state = JC_STATE_HANDSHAKED;\n\t\tbreak;\n\n\tcase JC_SIO_CMD_VER_RPT:\n\t\tif (!pkt->status)\n\t\t\tjc->state = JC_STATE_HID_CONN;\n\t\tbreak;\n\n\tcase JC_SIO_CMD_IAP_VER:\n\tcase JC_SIO_CMD_STATUS:\n\t\t_jc_sio_parse_payload(jc, cmd, pkt->payload, size - sizeof(jc_sio_in_rpt_t));\n\t\tbreak;\n\n\tcase JC_SIO_CMD_UNK02:\n\tcase JC_SIO_CMD_UNK20:\n\tcase JC_SIO_CMD_UNK21:\n\tcase JC_SIO_CMD_UNK22:\n\tcase JC_SIO_CMD_UNK40:\n\tdefault:\n\t\tbreak;\n\t}\n\n\tjc->last_received_time = get_tmr_ms();\n}\n\nstatic void _jc_rcv_pkt(jc_dev_t *jc)\n{\n\tif (!jc->detected)\n\t\treturn;\n\n\tu32 len = uart_recv(jc->uart, (u8 *)jc->buf, sizeof(jc->buf));\n\tif (len < 8)\n\t\treturn;\n\n\t// For Joycon, check uart reply magic.\n\tjc_wired_hdr_t *jc_pkt = (jc_wired_hdr_t *)jc->buf;\n\tif (!jc->sio_mode && !memcmp(jc_pkt->uart_hdr.magic, JC_WIRED_RCV_MAGIC, sizeof(jc_pkt->uart_hdr.magic)))\n\t{\n\t\t_jc_uart_pkt_parse(jc, jc_pkt, len);\n\n\t\treturn;\n\t}\n\n\t// For Sio, check uart output report and command ack.\n\tjc_sio_in_rpt_t *sio_pkt = (jc_sio_in_rpt_t *)(jc->buf);\n\tif (jc->sio_mode && sio_pkt->cmd == JC_SIO_INPUT_RPT && (sio_pkt->subcmd & JC_SIO_CMD_ACK) == JC_SIO_CMD_ACK)\n\t{\n\t\t_jc_sio_uart_pkt_parse(jc, sio_pkt, len);\n\n\t\treturn;\n\t}\n}\n\nstatic bool _jc_handle_charging(jc_dev_t *jc)\n{\n\tif (jc->last_chrger_chk_time > get_tmr_ms())\n\t\treturn false;\n\n\tjc->last_chrger_chk_time = get_tmr_ms() + 5000;\n\n\tu8 old_mode, batt_now;\n\tif (jc->uart == UART_B)\n\t{\n\t\tbatt_now = jc_gamepad.batt_info_r;\n\t\told_mode = jc_gamepad.batt_chrg_r;\n\t}\n\telse\n\t{\n\t\tbatt_now = jc_gamepad.batt_info_l;\n\t\told_mode = jc_gamepad.batt_chrg_l;\n\t}\n\n\t// Let battery level settle if init.\n\tu8 new_mode = old_mode;\n\tif (!old_mode)\n\t{\n\t\tnew_mode = JC_CHRG_STATE_SUPL;\n\t\tif ((batt_now >> 1) <= JC_BATT_LOW)\n\t\t\tnew_mode = JC_CHRG_STATE_SLOW;\n\n\t\tgoto set_mode;\n\t}\n\n\t// Resend if no reply.\n\tif (jc->charger_req)\n\t\tgoto set_mode;\n\n\t// Power supply control based on battery levels and charging.\n\tswitch (batt_now >> 1)\n\t{\n\tcase JC_BATT_EMPTY:\n\tcase JC_BATT_CRIT:\n\tcase JC_BATT_LOW:\n\t\tnew_mode = JC_CHRG_STATE_SLOW;\n\t\tbreak;\n\n\tcase JC_BATT_MID:\n\t\tif (!(batt_now & 1))\n\t\t\tnew_mode = JC_CHRG_STATE_SUPL;\n\t\tbreak;\n\n\tcase JC_BATT_FULL:\n\t\tnew_mode = JC_CHRG_STATE_OFF;\n\t\tbreak;\n\t}\n\n\t// Check if already configured.\n\tif (new_mode == old_mode)\n\t\treturn false;\n\nset_mode:\n\tif (jc->uart == UART_B)\n\t\tjc_gamepad.batt_chrg_r = new_mode;\n\telse\n\t\tjc_gamepad.batt_chrg_l = new_mode;\n\n\tswitch (new_mode)\n\t{\n\tcase JC_CHRG_STATE_OFF:\n\t\t_jc_power_supply(jc->uart, false);\n\t\tnew_mode = JC_CHRG_CFG_SUPL0;\n\t\tbreak;\n\tcase JC_CHRG_STATE_SUPL:\n\t\t_jc_power_supply(jc->uart, true);\n\t\tnew_mode = JC_CHRG_CFG_SUPL0;\n\t\tbreak;\n\tcase JC_CHRG_STATE_SLOW:\n\t\t_jc_power_supply(jc->uart, true);\n\t\tnew_mode = JC_CHRG_CFG_100MA;\n\t\tbreak;\n\t}\n\n\t_jc_send_hid_cmd(jc, JC_HID_SUBCMD_CHARGE_SET, (u8 *)&new_mode, sizeof(new_mode));\n\tjc->charger_req = true;\n\n\tjc->last_status_req_time = get_tmr_ms() + 15;\n\n\treturn true;\n}\n\nstatic bool _jc_send_enable_rumble(jc_dev_t *jc)\n{\n\tbool send_r_rumble = jc_r.connected && !jc_r.rumble_sent;\n\tbool send_l_rumble = jc_l.connected && !jc_l.rumble_sent;\n\n\t// Do not sent report yet if second Joy-Con is expected to be initialized.\n\tif ((send_r_rumble && !jc_l.rumble_sent && jc_l.state == JC_STATE_HID_CONN) ||\n\t\t(send_l_rumble && !jc_r.rumble_sent && jc_r.state == JC_STATE_HID_CONN))\n\t\treturn 1;\n\n\t// Send init rumble or request nx pad status report.\n\tif (send_r_rumble || send_l_rumble)\n\t{\n\t\t_jc_send_hid_cmd(jc, JC_HID_SUBCMD_SND_RUMBLE, NULL, 0);\n\n\t\tif (jc_l.connected)\n\t\t\tjc_l.rumble_sent = true;\n\t\tif (jc_r.connected)\n\t\t\tjc_r.rumble_sent = true;\n\n\t\tjc->last_chrger_chk_time = get_tmr_ms() + 5000;\n\n\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n\nstatic void _jc_req_status(jc_dev_t *jc)\n{\n\tif (!jc->connected)\n\t\treturn;\n\n\tif (jc->last_status_req_time > get_tmr_ms())\n\t\treturn;\n\n\tbool is_nxpad = !(jc->type & JC_ID_HORI) && !jc->sio_mode;\n\n\t// Init/maintenance for Joy-Con.\n\tif (is_nxpad)\n\t{\n\t\tif (_jc_send_enable_rumble(jc))\n\t\t\treturn;\n\n\t\tif (_jc_handle_charging(jc))\n\t\t\treturn;\n\t}\n\n\tif (is_nxpad)\n\t\t_joycon_send_raw(jc->uart, _jc_nx_pad_status,   sizeof(_jc_nx_pad_status));\n\telse if (jc->sio_mode)\n\t\t_joycon_send_raw(jc->uart, _sio_pad_status,     sizeof(_sio_pad_status));\n\telse\n\t\t_joycon_send_raw(jc->uart, _jc_hori_pad_status, sizeof(_jc_hori_pad_status));\n\n\tjc->last_status_req_time = get_tmr_ms() + (!jc->sio_mode ? 15 : 7);\n}\n\nstatic bool _jc_validate_pairing_info(const u8 *buf, bool *is_hos)\n{\n\tu8 crc = 0;\n\tfor (u32 i = 0; i < 0x22; i++)\n\t\tcrc += buf[4 + i];\n\n\tcrc += 0x68; // Host is Switch.\n\n\tif ((crc ^ 0x55) == buf[2])\n\t\t*is_hos = true;\n\n\tcrc -= 0x68;\n\tcrc += 0x08; // Host is PC.\n\n\tif (*is_hos || (crc ^ 0x55) == buf[2])\n\t\treturn true;\n\n\treturn false;\n}\n\njc_gamepad_rpt_t *jc_get_bt_pairing_info(bool *is_l_hos, bool *is_r_hos)\n{\n\tu8 retries;\n\tjc_bt_conn_t *bt_conn;\n\n\tif (!jc_init_done || jc_gamepad.sio_mode)\n\t\treturn NULL;\n\n\t// Detect and init if needed.\n\tfor (u32 i = 0; i < 6; i++)\n\t{\n\t\tjoycon_poll();\n\t\tmsleep(15);\n\t}\n\n\twhile ((jc_l.last_status_req_time + 15) > get_tmr_ms())\n\t{\n\t\t_jc_rcv_pkt(&jc_r);\n\t\t_jc_rcv_pkt(&jc_l);\n\t}\n\n\tbt_conn = &jc_gamepad.bt_conn_l;\n\tmemset(bt_conn->host_mac, 0, 6);\n\tmemset(bt_conn->ltk,      0, 16);\n\n\tbt_conn = &jc_gamepad.bt_conn_r;\n\tmemset(bt_conn->host_mac, 0, 6);\n\tmemset(bt_conn->ltk,      0, 16);\n\n\t// Setup initial SPI address.\n\tjc_hid_out_spi_read_t subcmd_data_l;\n\tsubcmd_data_l.addr = 0x2000;\n\tsubcmd_data_l.size = 0x1A;\n\n\tjc_hid_out_spi_read_t subcmd_data_r;\n\tsubcmd_data_r.addr = 0x2000;\n\tsubcmd_data_r.size = 0x1A;\n\n\tbool jc_r_found = jc_r.connected ? false : true;\n\tbool jc_l_found = jc_l.connected ? false : true;\n\n\t// Set mode to HW controlled RTS.\n\tuart_set_mode(jc_l.uart, UART_AO_TX_HW_RX);\n\tuart_set_mode(jc_r.uart, UART_AO_TX_HW_RX);\n\n\tu32 total_retries = 10;\nretry:\n\tretries = 10;\n\twhile (retries)\n\t{\n\t\tu32 time_now = get_tmr_ms();\n\t\tif ((!jc_l_found && jc_l.last_status_req_time < time_now) || (!jc_r_found && jc_r.last_status_req_time < time_now))\n\t\t{\n\t\t\tif (!jc_l_found)\n\t\t\t{\n\t\t\t\t_jc_send_hid_cmd(&jc_l, JC_HID_SUBCMD_SPI_READ, (u8 *)&subcmd_data_l, sizeof(jc_hid_out_spi_read_t));\n\t\t\t\tjc_l.last_status_req_time = get_tmr_ms() + 15;\n\t\t\t}\n\n\t\t\tif (!jc_r_found)\n\t\t\t{\n\t\t\t\t_jc_send_hid_cmd(&jc_r, JC_HID_SUBCMD_SPI_READ, (u8 *)&subcmd_data_r, sizeof(jc_hid_out_spi_read_t));\n\t\t\t\tjc_r.last_status_req_time = get_tmr_ms() + 15;\n\t\t\t}\n\n\t\t\tretries--;\n\t\t}\n\n\t\t// Wait for the first 36 bytes to arrive.\n\t\tmsleep(5);\n\n\t\tif (!jc_l_found)\n\t\t{\n\t\t\tmemset(jc_l.buf, 0, 0x100);\n\t\t\t_jc_rcv_pkt(&jc_l);\n\n\t\t\tbool is_hos = false;\n\t\t\tif (_jc_validate_pairing_info(&jc_l.buf[SPI_READ_OFFSET], &is_hos))\n\t\t\t{\n\t\t\t\tbool is_active = jc_l.buf[SPI_READ_OFFSET] == 0x95;\n\n\t\t\t\tif (!is_active)\n\t\t\t\t\tsubcmd_data_l.addr += sizeof(jc_hid_in_pair_data_t); // Get next slot.\n\t\t\t\telse\n\t\t\t\t\tjc_l_found = true; // Entry is active.\n\n\t\t\t\tif (jc_l_found && is_hos)\n\t\t\t\t\t*is_l_hos = true;\n\t\t\t}\n\t\t}\n\n\t\tif (!jc_r_found)\n\t\t{\n\t\t\tmemset(jc_r.buf, 0, 0x100);\n\t\t\t_jc_rcv_pkt(&jc_r);\n\n\t\t\tbool is_hos = false;\n\t\t\tif (_jc_validate_pairing_info(&jc_r.buf[SPI_READ_OFFSET], &is_hos))\n\t\t\t{\n\t\t\t\tbool is_active = jc_r.buf[SPI_READ_OFFSET] == 0x95;\n\n\t\t\t\tif (!is_active)\n\t\t\t\t\tsubcmd_data_r.addr += sizeof(jc_hid_in_pair_data_t); // Get next slot.\n\t\t\t\telse\n\t\t\t\t\tjc_r_found = true; // Entry is active.\n\n\t\t\t\tif (jc_r_found && is_hos)\n\t\t\t\t\t*is_r_hos = true;\n\t\t\t}\n\t\t}\n\n\t\tif (jc_l_found && jc_r_found)\n\t\t\tbreak;\n\t}\n\n\tif (!jc_l_found || !jc_r_found)\n\t{\n\t\tif (total_retries)\n\t\t{\n\t\t\ttotal_retries--;\n\t\t\tgoto retry;\n\t\t}\n\n\t\tif (!jc_l_found)\n\t\t{\n\t\t\tbt_conn = &jc_gamepad.bt_conn_l;\n\t\t\tmemset(bt_conn->host_mac, 0, 6);\n\t\t\tmemset(bt_conn->ltk,      0, 16);\n\t\t}\n\n\t\tif (!jc_r_found)\n\t\t{\n\t\t\tbt_conn = &jc_gamepad.bt_conn_r;\n\t\t\tmemset(bt_conn->host_mac, 0, 6);\n\t\t\tmemset(bt_conn->ltk,      0, 16);\n\t\t}\n\t}\n\n\t// Restore mode to manual RTS.\n\tuart_set_mode(jc_l.uart, UART_AO_TX_MN_RX);\n\tuart_set_mode(jc_r.uart, UART_AO_TX_MN_RX);\n\n\treturn &jc_gamepad;\n}\n\nstatic void _jc_conn_init(jc_dev_t *jc)\n{\n\tif (!jc->detected)\n\t\treturn;\n\n\t/*\n\t * Try to reinit if no input report.\n\t * Actual connection timeout is 2000ms on official Joycon.\n\t * Based on last JC_WIRED_CMD_HID_CONN/JC_WIRED_HID sent.\n\t */\n\tif (((u32)get_tmr_ms() - jc->last_received_time) > 1800)\n\t{\n\t\tif (!jc->sio_mode)\n\t\t\t_jc_power_supply(jc->uart, true);\n\n\t\t// Mask out buttons and set connected to false.\n\t\tif (jc->uart == UART_B)\n\t\t{\n\t\t\tjc_gamepad.batt_chrg_r = 0;\n\t\t\tjc_gamepad.buttons &= ~JC_BTN_MASK_R;\n\t\t\tjc_gamepad.conn_r = false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tjc_gamepad.batt_chrg_l = 0;\n\t\t\tjc_gamepad.buttons &= ~JC_BTN_MASK_L;\n\t\t\tjc_gamepad.conn_l = false;\n\t\t}\n\n\t\t// Initialize uart to 1 megabaud and manual RTS.\n\t\tuart_init(jc->uart, 1000000, UART_AO_TX_MN_RX);\n\n\t\tjc->state = JC_STATE_START;\n\n\t\tif (!jc->sio_mode)\n\t\t{\n\t\t\tjc_gamepad.buttons = 0;\n\n\t\t\t// Set TX and RTS inversion for Joycon.\n\t\t\tuart_invert(jc->uart, true, UART_INVERT_TXD | UART_INVERT_RTS);\n\n\t\t\t// Initialize.\n\t\t\tu32 retries = 10;\n\t\t\twhile (retries && jc->state != JC_STATE_HANDSHAKED)\n\t\t\t{\n\t\t\t\t// Wake up the controller.\n\t\t\t\t_joycon_send_raw(jc->uart, _jc_init_wake, sizeof(_jc_init_wake));\n\t\t\t\t_jc_rcv_pkt(jc); // Clear RX FIFO.\n\n\t\t\t\t// Do a handshake.\n\t\t\t\t_joycon_send_raw(jc->uart, _jc_init_handshake, sizeof(_jc_init_handshake));\n\t\t\t\tmsleep(4);\n\t\t\t\t_jc_rcv_pkt(jc);\n\t\t\t\tretries--;\n\t\t\t}\n\n\t\t\tif (jc->state != JC_STATE_HANDSHAKED)\n\t\t\t\tgoto out;\n\n\t\t\t// Get info about the controller.\n\t\t\t_joycon_send_raw(jc->uart, _jc_init_get_info, sizeof(_jc_init_get_info));\n\t\t\tmsleep(2);\n\t\t\t_jc_rcv_pkt(jc);\n\n\t\t\tif (jc->state != JC_STATE_INFO_PARSED)\n\t\t\t\tgoto out;\n\n\t\t\tif (!(jc->type & JC_ID_HORI))\n\t\t\t{\n\t\t\t\t// Request 3 megabaud change.\n\t\t\t\t_joycon_send_raw(jc->uart, _jc_init_switch_brate, sizeof(_jc_init_switch_brate));\n\t\t\t\tmsleep(2);\n\t\t\t\t_jc_rcv_pkt(jc);\n\n\t\t\t\tif (jc->state == JC_STATE_BRATE_CHANGED)\n\t\t\t\t{\n\t\t\t\t\t// Reinitialize uart to 3 megabaud and manual RTS.\n\t\t\t\t\tuart_init(jc->uart, 3000000, UART_AO_TX_MN_RX);\n\t\t\t\t\tuart_invert(jc->uart, true, UART_INVERT_TXD | UART_INVERT_RTS);\n\n\t\t\t\t\t// Make sure HID is disconnected and check connection. Reply expected after 30ms.\n\t\t\t\t\tretries = 10;\n\t\t\t\t\twhile (retries && jc->state != JC_STATE_HID_NO_CONN)\n\t\t\t\t\t{\n\t\t\t\t\t\t_joycon_send_raw(jc->uart, _jc_init_hid_disconnect, sizeof(_jc_init_hid_disconnect));\n\t\t\t\t\t\tmsleep(5);\n\t\t\t\t\t\t_jc_rcv_pkt(jc);\n\t\t\t\t\t\tretries--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Was connected before or no response. Do a reinit.\n\t\t\t\t\tif (jc->state != JC_STATE_HID_NO_CONN)\n\t\t\t\t\t\tgoto out;\n\t\t\t\t}\n\n\t\t\t\t// Create HID connection with the new rate.\n\t\t\t\t_joycon_send_raw(jc->uart, _jc_init_hid_connect, sizeof(_jc_init_hid_connect));\n\t\t\t\tmsleep(2);\n\t\t\t\t_jc_rcv_pkt(jc);\n\n\t\t\t\tif (jc->state != JC_STATE_HID_CONN)\n\t\t\t\t\tgoto out;\n\n\t\t\t\t// Set hid packet rate.\n\t\t\t\t_joycon_send_raw(jc->uart, _jc_init_set_hid_rate, sizeof(_jc_init_set_hid_rate));\n\t\t\t\tmsleep(2);\n\t\t\t\t_jc_rcv_pkt(jc);\n\n\t\t\t\tgoto out; // Wait for set hid rate reply.\n\t\t\t}\n\t\t\telse // Hori. Unset RTS inversion.\n\t\t\t\tuart_invert(jc->uart, false, UART_INVERT_RTS);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Set Sio NPOR low to configure BOOT0 mode.\n\t\t\tgpio_write(GPIO_PORT_CC, GPIO_PIN_5, GPIO_LOW);\n\t\t\tusleep(300);\n\t\t\tgpio_write(GPIO_PORT_T, GPIO_PIN_0, GPIO_LOW);\n\t\t\tgpio_write(GPIO_PORT_CC, GPIO_PIN_5, GPIO_HIGH);\n\t\t\tmsleep(100);\n\n\t\t\t// Clear RX FIFO.\n\t\t\t_jc_rcv_pkt(jc);\n\n\t\t\t// Initialize the controller.\n\t\t\tu32 retries = 10;\n\t\t\twhile (retries && jc->state != JC_STATE_HANDSHAKED)\n\t\t\t{\n\t\t\t\t_joycon_send_raw(jc->uart, _sio_init, sizeof(_sio_init));\n\t\t\t\tmsleep(5);\n\t\t\t\t_jc_rcv_pkt(jc);\n\t\t\t\tretries--;\n\t\t\t}\n\n\t\t\tif (jc->state != JC_STATE_HANDSHAKED)\n\t\t\t\tgoto out;\n\n\t\t\t// Set output report version.\n\t\t\tretries = 10;\n\t\t\twhile (retries && jc->state != JC_STATE_HID_CONN)\n\t\t\t{\n\t\t\t\t_joycon_send_raw(jc->uart, _sio_set_rpt_version, sizeof(_sio_set_rpt_version));\n\t\t\t\tmsleep(5);\n\t\t\t\t_jc_rcv_pkt(jc);\n\t\t\t\tretries--;\n\t\t\t}\n\n\t\t\tif (jc->state != JC_STATE_HID_CONN)\n\t\t\t\tgoto out;\n\t\t}\n\n\t\t// Initialization done.\n\t\tjc->state = JC_STATE_INIT_DONE;\n\t\tjc->connected = true;\n\nout:\n\t\tjc->last_received_time = get_tmr_ms();\n\t}\n}\n\nvoid jc_init_hw()\n{\n\tjc_l.uart = UART_C;\n\tjc_r.uart = UART_B;\n\n\tjc_l.sio_mode = fuse_read_hw_type() == FUSE_NX_HW_TYPE_HOAG;\n\tjc_gamepad.sio_mode = jc_l.sio_mode;\n\n#if !defined(DEBUG_UART_PORT) || !(DEBUG_UART_PORT)\n\t// Sio Initialization.\n\tif (jc_gamepad.sio_mode)\n\t{\n\t\t// Enable 4 MHz clock to Sio.\n\t\tclock_enable_extperiph2();\n\t\tPINMUX_AUX(PINMUX_AUX_TOUCH_CLK) = PINMUX_PULL_DOWN;\n\n\t\t// Configure Sio HOME BUTTON.\n\t\tPINMUX_AUX(PINMUX_AUX_LCD_GPIO1) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE | PINMUX_PULL_UP | 1;\n\t\tgpio_direction_input(GPIO_PORT_V, GPIO_PIN_3);\n\n\t\t// Configure Sio IRQ\n\t\tPINMUX_AUX(PINMUX_AUX_GPIO_PE7)  = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE | PINMUX_PULL_UP;\n\t\tgpio_direction_input(GPIO_PORT_E, GPIO_PIN_7);\n\n\t\t// Configure Sio NRST and BOOT0.\n\t\tPINMUX_AUX(PINMUX_AUX_CAM1_STROBE) = PINMUX_PULL_DOWN | 1;\n\t\tPINMUX_AUX(PINMUX_AUX_CAM2_PWDN)   = PINMUX_PULL_DOWN | 1;\n\n\t\t// Set BOOT0 to flash mode. (output high is sram mode).\n\t\tgpio_direction_output(GPIO_PORT_T, GPIO_PIN_0, GPIO_LOW);\n\n\t\t// NRST to pull down.\n\t\tgpio_direction_input(GPIO_PORT_T, GPIO_PIN_1);\n\n\t\t// Configure Sio NPOR.\n\t\tPINMUX_AUX(PINMUX_AUX_USB_VBUS_EN1) = PINMUX_IO_HV | PINMUX_LPDR | 1;\n\t\tgpio_direction_output(GPIO_PORT_CC, GPIO_PIN_5, GPIO_LOW);\n\t}\n\telse\n\t{\n\t\t_jc_power_supply(UART_C, true);\n\t\t_jc_power_supply(UART_B, true);\n\t}\n\n#if 0 // Already set by hw init.\n\t// Set Joy-Con IsAttached pinmux. Shared with UARTB/UARTC TX.\n\tPINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;\n\tPINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;\n\n\t// Set Joy-Con IsAttached mode. Shared with UARTB/UARTC TX.\n\tgpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO);\n\tgpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO);\n#endif\n\n\t// Configure pinmuxing for UART B and C.\n\tif (!jc_gamepad.sio_mode)\n\t\tpinmux_config_uart(UART_B);\n\tpinmux_config_uart(UART_C);\n\n\t// Enable UART B and C clocks.\n\tif (!jc_gamepad.sio_mode)\n\t\tclock_enable_uart(UART_B);\n\tclock_enable_uart(UART_C);\n\n\tjc_init_done = true;\n#endif\n}\n\nvoid jc_deinit()\n{\n\tif (!jc_init_done)\n\t\treturn;\n\n\tjc_init_done = false;\n\n\tif (!jc_gamepad.sio_mode)\n\t{\n\t\t// Disable power.\n\t\t_jc_power_supply(UART_B, false);\n\t\t_jc_power_supply(UART_C, false);\n\n\t\t// Send sleep command.\n\t\tu8 data = HCI_STATE_SLEEP;\n\t\tif (jc_r.connected && !(jc_r.type & JC_ID_HORI))\n\t\t{\n\t\t\t_jc_send_hid_cmd(&jc_r, JC_HID_SUBCMD_HCI_STATE, &data, 1);\n\t\t\t_jc_rcv_pkt(&jc_r);\n\t\t}\n\t\tif (jc_l.connected && !(jc_l.type & JC_ID_HORI))\n\t\t{\n\t\t\t_jc_send_hid_cmd(&jc_l, JC_HID_SUBCMD_HCI_STATE, &data, 1);\n\t\t\t_jc_rcv_pkt(&jc_l);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Disable Sio NPOR.\n\t\tgpio_write(GPIO_PORT_CC, GPIO_PIN_5, GPIO_LOW);\n\n\t\t// Disable 4 MHz clock to Sio.\n\t\tclock_disable_extperiph2();\n\t}\n\n\t// Disable UART B and C clocks.\n\tif (!jc_gamepad.sio_mode)\n\t\tclock_disable_uart(UART_B);\n\tclock_disable_uart(UART_C);\n}\n\njc_gamepad_rpt_t *joycon_poll()\n{\n\tif (!jc_init_done)\n\t\treturn NULL;\n\n\t_jc_conn_check();\n\n\t_jc_conn_init(&jc_r);\n\t_jc_conn_init(&jc_l);\n\n\t_jc_req_status(&jc_r);\n\t_jc_req_status(&jc_l);\n\n\t_jc_rcv_pkt(&jc_r);\n\t_jc_rcv_pkt(&jc_l);\n\n\treturn &jc_gamepad;\n}\n"
  },
  {
    "path": "bdk/input/joycon.h",
    "content": "/*\n * Ambient light sensor driver for Nintendo Switch's Rohm BH1730\n *\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef __JOYCON_H_\n#define __JOYCON_H_\n\n#include <utils/types.h>\n\n#define JC_BTNS_DIRECTION_PAD 0xF0000\n#define JC_BTNS_PREV_NEXT     0x800080\n#define JC_BTNS_ENTER         0x400008\n#define JC_BTNS_ESC           0x4\n\n#define JC_BTNS_ALL (JC_BTNS_PREV_NEXT | JC_BTNS_ENTER | JC_BTNS_DIRECTION_PAD | JC_BTNS_ESC)\n\ntypedef struct _jc_bt_conn_t\n{\n\tu8 type;\n\tu8 mac[6];\n\tu8 host_mac[6];\n\tu8 ltk[16];\n} jc_bt_conn_t;\n\ntypedef struct _jc_gamepad_rpt_t\n{\n\tunion\n\t{\n\t\tstruct\n\t\t{\n\t\t\t// Joy-Con (R).\n/*00*/\t\tu32 y:1;\n/*01*/\t\tu32 x:1;\n/*02*/\t\tu32 b:1;\n/*03*/\t\tu32 a:1;\n/*04*/\t\tu32 sr_r:1;\n/*05*/\t\tu32 sl_r:1;\n/*06*/\t\tu32 r:1;\n/*07*/\t\tu32 zr:1;\n\n\t\t\t// Shared\n/*08*/\t\tu32 minus:1;\n/*09*/\t\tu32 plus:1;\n/*10*/\t\tu32 r3:1;\n/*11*/\t\tu32 l3:1;\n/*12*/\t\tu32 home:1;\n/*13*/\t\tu32 cap:1;\n/*14*/\t\tu32 pad:1;\n/*15*/\t\tu32 wired:1;\n\n\t\t\t// Joy-Con (L).\n/*16*/\t\tu32 down:1;\n/*17*/\t\tu32 up:1;\n/*18*/\t\tu32 right:1;\n/*19*/\t\tu32 left:1;\n/*20*/\t\tu32 sr_l:1;\n/*21*/\t\tu32 sl_l:1;\n/*22*/\t\tu32 l:1;\n/*23*/\t\tu32 zl:1;\n\t\t};\n\t\tu32 buttons;\n\t};\n\n\tu16 lstick_x;\n\tu16 lstick_y;\n\tu16 rstick_x;\n\tu16 rstick_y;\n\tbool center_stick_l;\n\tbool center_stick_r;\n\tbool conn_l;\n\tbool conn_r;\n\tbool sio_mode;\n\tu8 batt_info_l; // Also Sio Connected status.\n\tu8 batt_info_r; // Also Sio IRQ.\n\tu8 batt_chrg_l;\n\tu8 batt_chrg_r;\n\tjc_bt_conn_t bt_conn_l;\n\tjc_bt_conn_t bt_conn_r;\n} jc_gamepad_rpt_t;\n\ntypedef struct _jc_calib_t\n{\n\tu16 x_max:12;\n\tu16 y_max:12;\n\tu16 x_center:12;\n\tu16 y_center:12;\n\tu16 x_min:12;\n\tu16 y_min:12;\n} __attribute__((packed)) jc_calib_t;\n\nvoid jc_init_hw();\nvoid jc_deinit();\njc_gamepad_rpt_t *joycon_poll();\njc_gamepad_rpt_t *jc_get_bt_pairing_info(bool *is_l_hos, bool *is_r_hos);\n\n#endif\n"
  },
  {
    "path": "bdk/input/touch.c",
    "content": "/*\n * Touch driver for Nintendo Switch's STM FingerTip S (FTM4CD60DA1BE/FTM4CD50TA1BE) touch controller\n *\n * Copyright (c) 2018 langerhans\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <soc/clock.h>\n#include <soc/i2c.h>\n#include <soc/pinmux.h>\n#include <power/max7762x.h>\n#include <soc/gpio.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n#include <utils/btn.h>\n#include \"touch.h\"\n\nstatic touch_panel_info_t _panels[] =\n{\n\t{  0,  1, 1, 1,  \"NISSHA NFT-K12D\" },// 0.\n\t{  1,  0, 1, 1,  \"GiS GGM6 B2X\"    },// 1.\n\t{  2,  0, 0, 0,  \"NISSHA NBF-K9A\"  },// 3.\n\t{  3,  1, 0, 0,  \"GiS 5.5\\\"\"       },// 4.\n\t{  4,  0, 0, 1,  \"Samsung TSP\"     },// 5?\n\t{ -1,  1, 0, 1,  \"GiS VA 6.2\\\"\"    } // 2.\n};\n\nstatic touch_info_t _touch_info = { 0 };\nstatic touch_panel_info_t _touch_panel_info = { 0 };\n\nstatic int _touch_command(u8 cmd, u8 *buf, u8 size)\n{\n\treturn i2c_send_buf_small(I2C_3, FTS4_I2C_ADDR, cmd, buf, size);\n}\n\nstatic int _touch_read_reg(u8 *cmd, u32 csize, u8 *buf, u32 size)\n{\n\treturn i2c_xfer_packet(I2C_3, FTS4_I2C_ADDR, cmd, csize, buf, size);\n}\n\nint touch_get_event_count()\n{\n\tu8 cmd[3] = { FTS4_CMD_HW_REG_READ, 0, FTS4_HW_REG_EVENT_COUNT };\n\tu8 buf[2];\n\n\tif (_touch_read_reg(cmd, sizeof(cmd), buf, sizeof(buf)))\n\t\treturn 0;\n\n\treturn (buf[1] >> 1);\n}\n\nstatic int _touch_wait_event(u8 event, u8 status, u32 timeout, u8 *buf)\n{\n\tu32 timer = get_tmr_ms() + timeout;\n\twhile (true)\n\t{\n\t\tif (!touch_get_event_count())\n\t\t\tgoto retry;\n\n\t\tu8 tmp[FTS4_EVENT_SIZE];\n\t\tint res = i2c_recv_buf_big(tmp, FTS4_EVENT_SIZE, I2C_3, FTS4_I2C_ADDR, FTS4_CMD_READ_ONE_EVENT);\n\n\t\t// Check that event type and status match.\n\t\tif (!res && tmp[0] == event && tmp[1] == status)\n\t\t{\n\t\t\tif (buf)\n\t\t\t\tmemcpy(buf, &tmp[2], 6);\n\t\t\treturn 0;\n\t\t}\n\nretry:\n\t\tusleep(500);\n\n\t\tif (get_tmr_ms() > timer)\n\t\t\treturn 1;\n\t}\n}\n\n#define X_REAL_MAX 1264\n#define Y_REAL_MAX 704\n#define EDGE_OFFSET 15\n\nstatic void _touch_compensate_limits(touch_event_t *event, bool touching)\n{\n\tevent->x  = MAX(event->x, EDGE_OFFSET);\n\tevent->x  = MIN(event->x, X_REAL_MAX);\n\tevent->x -= EDGE_OFFSET;\n\tu32 x_adj = (1280 * 1000) / (X_REAL_MAX - EDGE_OFFSET);\n\tevent->x  = ((u32)event->x * x_adj) / 1000;\n\n\tif (touching)\n\t{\n\t\tevent->y  = MAX(event->y, EDGE_OFFSET);\n\t\tevent->y  = MIN(event->y, Y_REAL_MAX);\n\t\tevent->y -= EDGE_OFFSET;\n\t\tu32 y_adj = (720 * 1000) / (Y_REAL_MAX - EDGE_OFFSET);\n\t\tevent->y  = ((u32)event->y * y_adj) / 1000;\n\t}\n}\n\nstatic void _touch_process_contact_event(touch_event_t *event, bool touching)\n{\n\tevent->x = (event->raw[1] << 4) | ((event->raw[3] & FTS4_MASK_Y_LSB) >> 4);\n\n\t// Normally, GUI elements have bigger horizontal estate.\n\t// Avoid parsing y axis when finger is removed to minimize touch noise.\n\tif (touching)\n\t{\n\t\tevent->y = (event->raw[2] << 4) | (event->raw[3] & FTS4_MASK_X_MSB);\n\n\t\tevent->z = event->raw[4] | (event->raw[5] << 8);\n\t\tevent->z = event->z << 6;\n\n\t\tu16 tmp = 0x40;\n\t\tif ((event->raw[6] & 0x3F) != 1 && (event->raw[6] & 0x3F) != 0x3F)\n\t\t\ttmp = event->raw[6] & 0x3F;\n\t\tevent->z /= tmp + 0x40;\n\n\t\tevent->finger = ((event->raw[0] & FTS4_MASK_TOUCH_ID) >> 4) + 1;\n\t}\n\telse\n\t\tevent->finger = 0;\n\n\t_touch_compensate_limits(event, touching);\n}\n\nstatic int _touch_parse_input_event(touch_event_t *event)\n{\n\tswitch (event->raw[0] & FTS4_MASK_EVENT_ID)\n\t{\n\tcase FTS4_EV_MULTI_TOUCH_ENTER:\n\tcase FTS4_EV_MULTI_TOUCH_MOTION:\n\t\t_touch_process_contact_event(event, true);\n\t\tif (event->z < 500) // Reject palm rest.\n\t\t\tevent->touch = true;\n\t\telse\n\t\t\tevent->touch = false;\n\t\treturn 0;\n\n\tcase FTS4_EV_MULTI_TOUCH_LEAVE:\n\t\tevent->touch = false;\n\t\t_touch_process_contact_event(event, false);\n\t\treturn 0;\n\n\tdefault:\n\t\treturn 1; // No event.\n\t}\n}\n\nint touch_poll(touch_event_t *event)\n{\n\tu8 cmd = !_touch_info.clone ? FTS4_CMD_LATEST_EVENT : FTS4_CMD_READ_ONE_EVENT;\n\n\tint res = i2c_recv_buf_big(event->raw, FTS4_EVENT_SIZE, I2C_3, FTS4_I2C_ADDR, cmd);\n\tif (!res)\n\t\tres = _touch_parse_input_event(event);\n\n\treturn res;\n}\n\ntouch_info_t *touch_get_chip_info()\n{\n\tu8 buf[7] = { 0 };\n\n\t// Get chip info.\n\tu8 cmd[3] = { FTS4_CMD_HW_REG_READ, 0, FTS4_HW_REG_CHIP_ID_INFO };\n\tif (_touch_read_reg(cmd, sizeof(cmd), buf, sizeof(buf)))\n\t{\n\t\tmemset(&_touch_info, 0, sizeof(touch_info_t));\n\t\tgoto exit;\n\t}\n\n\t_touch_info.chip_id    = buf[1] << 8 | buf[2];\n\t_touch_info.fw_ver     = buf[3] << 8 | buf[4];\n\t_touch_info.config_id  = buf[5];\n\t_touch_info.config_ver = buf[6];\n\n\t// Validate that device is genuine or proper.\n\tcmd[2] = 2;\n\t_touch_read_reg(cmd, sizeof(cmd), buf, sizeof(buf));\n\t_touch_info.clone = _touch_info.chip_id != (buf[3] << 8 | buf[4]);\n\nexit:\n\treturn &_touch_info;\n}\n\ntouch_panel_info_t *touch_get_panel_vendor()\n{\n\t_touch_panel_info.idx = -2;\n\n\tu8 cmd = FTS4_VENDOR_GPIO_STATE;\n\tif (_touch_command(FTS4_CMD_VENDOR, &cmd, 1))\n\t\treturn NULL;\n\n\tu8 buf[6] = { 0 };\n\tif (_touch_wait_event(FTS4_EV_VENDOR, FTS4_VENDOR_GPIO_STATE, 2000, buf))\n\t\treturn NULL;\n\n\tfor (u32 i = 0; i < ARRAY_SIZE(_panels); i++)\n\t{\n\t\ttouch_panel_info_t *panel = &_panels[i];\n\t\tif (buf[0] == panel->gpio0 && buf[1] == panel->gpio1 && buf[2] == panel->gpio2)\n\t\t\treturn panel;\n\t}\n\n\t// Touch panel not found, return current gpios.\n\t_touch_panel_info.gpio0 = buf[0];\n\t_touch_panel_info.gpio1 = buf[1];\n\t_touch_panel_info.gpio2 = buf[2];\n\n\treturn &_touch_panel_info;\n}\n\nint touch_get_fw_info(touch_fw_info_t *fw)\n{\n\tu8 buf[9] = { 0 };\n\n\tmemset(fw, 0, sizeof(touch_fw_info_t));\n\n\t// Get fw address info.\n\tu8 cmd[3] = { FTS4_CMD_FB_REG_READ, 0, 0x60 };\n\tint res = _touch_read_reg(cmd, sizeof(cmd), buf, 3);\n\tif (!res)\n\t{\n\t\t// Get fw info.\n\t\tcmd[1] = buf[2]; cmd[2] = buf[1];\n\t\tres = _touch_read_reg(cmd, sizeof(cmd), buf, sizeof(buf));\n\t\tif (!res)\n\t\t{\n\t\t\tfw->fw_id   = (buf[1] << 24) | (buf[2] << 16) | (buf[3] << 8) | buf[4];\n\t\t\tfw->ftb_ver = (buf[6] <<  8) |  buf[5];\n\t\t\tfw->fw_rev  = (buf[8] <<  8) |  buf[7];\n\t\t}\n\t}\n\n\treturn res;\n}\n\nint touch_sys_reset()\n{\n\tu8 cmd[3] = { 0, FTS4_HW_REG_SYS_RESET, 0x80 }; // System reset cmd.\n\tfor (u8 retries = 0; retries < 3; retries++)\n\t{\n\t\tif (_touch_command(FTS4_CMD_HW_REG_WRITE, cmd, 3))\n\t\t{\n\t\t\tmsleep(10);\n\t\t\tcontinue;\n\t\t}\n\t\tmsleep(10);\n\n\t\tif (_touch_wait_event(FTS4_EV_CONTROLLER_READY, 0, 20, NULL))\n\t\t\tcontinue;\n\t\telse\n\t\t\treturn 0;\n\t}\n\n\treturn 1;\n}\n\nint touch_panel_ito_test(u8 *err)\n{\n\t// Check that touch IC is supported.\n\ttouch_info_t *info = touch_get_chip_info();\n\tif (info->chip_id != FTS4_I2C_CHIP_ID || info->clone)\n\t\treturn 1;\n\n\t// Reset touchscreen module.\n\tif (touch_sys_reset())\n\t\treturn 1;\n\n\t// Do ITO Production test.\n\tif (_touch_command(FTS4_CMD_ITO_CHECK, NULL, 0))\n\t\treturn 1;\n\n\tu8 buf[6] = { 0 };\n\tint res = _touch_wait_event(FTS4_EV_ERROR, FTS4_EV_ERROR_ITO_TEST, 2000, buf);\n\tif (!res && err)\n\t{\n\t\terr[0] = buf[0];\n\t\terr[1] = buf[1];\n\t}\n\n\t// Reset touchscreen module.\n\ttouch_sys_reset();\n\n\treturn res;\n}\n\nint touch_get_fb_info(u8 *buf)\n{\n\tu8 cmd[3] = { FTS4_CMD_FB_REG_READ, 0, 0 };\n\tint res = 0;\n\n\tfor (u32 i = 0; i < 0x10000; i += 4)\n\t{\n\t\tif (!res)\n\t\t{\n\t\t\tcmd[1] = (i >> 8) & 0xFF;\n\t\t\tcmd[2] = i & 0xFF;\n\n\t\t\tu8 tmp[5];\n\t\t\tmemset(tmp, 0xCC, sizeof(tmp));\n\t\t\tres = _touch_read_reg(cmd, sizeof(cmd), tmp, sizeof(tmp));\n\t\t\tmemcpy(&buf[i], tmp + 1, 4);\n\t\t}\n\t}\n\n\treturn res;\n}\n\nint touch_switch_sense_mode(u8 mode, bool gis_6_2)\n{\n\t// Set detection config.\n\tu8 cmd[3] = { 1, 0x64, 0 };\n\n\tswitch (mode)\n\t{\n\tcase FTS4_STYLUS_MODE:\n\t\tcmd[2] = !gis_6_2 ? 0xC8 : 0xAD;\n\t\tbreak;\n\tcase FTS4_FINGER_MODE:\n\t\tcmd[2] = !gis_6_2 ? 0x8C : 0x79;\n\t\tbreak;\n\t}\n\n\tif (_touch_command(FTS4_CMD_DETECTION_CONFIG, cmd, 3))\n\t\treturn 1;\n\n\t// Sense mode.\n\tcmd[0] = mode;\n\n\treturn _touch_command(FTS4_CMD_SWITCH_SENSE_MODE, cmd, 1);\n}\n\nint touch_sense_enable()\n{\n\t// Switch sense mode and enable multi-touch sensing.\n\tu8 cmd = FTS4_FINGER_MODE;\n\tif (_touch_command(FTS4_CMD_SWITCH_SENSE_MODE, &cmd, 1))\n\t\treturn 1;\n\n\tif (_touch_command(FTS4_CMD_MS_MT_SENSE_ON, NULL, 0))\n\t\treturn 1;\n\n\tif (_touch_command(FTS4_CMD_CLEAR_EVENT_STACK, NULL, 0))\n\t\treturn 1;\n\n\treturn 0;\n}\n\nint touch_execute_autotune()\n{\n\tu8 buf[6] = { 0 };\n\n\t// Reset touchscreen module.\n\tif (touch_sys_reset())\n\t\treturn 1;\n\n\t// Trim low power oscillator.\n\tif (_touch_command(FTS4_CMD_LP_TIMER_CALIB, NULL, 0))\n\t\treturn 1;\n\n\tmsleep(200);\n\n\t// Apply Mutual Sense Compensation tuning.\n\tif (_touch_command(FTS4_CMD_MS_CX_TUNING, NULL, 0))\n\t\treturn 1;\n\tif (_touch_wait_event(FTS4_EV_STATUS, FTS4_EV_STATUS_MS_CX_TUNING_DONE, 2000, buf) || buf[0] || buf[1])\n\t\treturn 1;\n\n\t// Apply Self Sense Compensation tuning.\n\tif (_touch_command(FTS4_CMD_SS_CX_TUNING, NULL, 0))\n\t\treturn 1;\n\tif (_touch_wait_event(FTS4_EV_STATUS, FTS4_EV_STATUS_SS_CX_TUNING_DONE, 2000, buf) || buf[0] || buf[1])\n\t\treturn 1;\n\n\t// Save Compensation data to EEPROM.\n\tif (_touch_command(FTS4_CMD_SAVE_CX_TUNING, NULL, 0))\n\t\treturn 1;\n\tif (_touch_wait_event(FTS4_EV_STATUS, FTS4_EV_STATUS_WRITE_CX_TUNE_DONE, 2000, buf) || buf[0] || buf[1])\n\t\treturn 1;\n\n\treturn touch_sense_enable();\n}\n\nstatic int touch_init()\n{\n\t// Check that touch IC is supported.\n\ttouch_info_t *info = touch_get_chip_info();\n\tif (info->chip_id != FTS4_I2C_CHIP_ID)\n\t\treturn 1;\n\n\t// Initialize touchscreen module.\n\tif (touch_sys_reset())\n\t\treturn 1;\n\n\treturn touch_sense_enable();\n}\n\nint touch_power_on()\n{\n\t// Configure touchscreen Touch Reset pin.\n\tPINMUX_AUX(PINMUX_AUX_DAP4_SCLK) = PINMUX_PULL_DOWN | 1;\n\tgpio_direction_output(GPIO_PORT_J, GPIO_PIN_7, GPIO_LOW);\n\tusleep(20);\n\n\t// Enable LDO6 for touchscreen AVDD and DVDD supply.\n\tmax7762x_regulator_set_voltage(REGULATOR_LDO6, 2900000);\n\tmax7762x_regulator_enable(REGULATOR_LDO6, true);\n\n\t// Initialize I2C3.\n\tpinmux_config_i2c(I2C_3);\n\tclock_enable_i2c(I2C_3);\n\ti2c_init(I2C_3);\n\tusleep(1000);\n\n\t// Set Touch Reset pin.\n\tgpio_write(GPIO_PORT_J, GPIO_PIN_7, GPIO_HIGH);\n\tusleep(10000);\n\n\t// Wait for the touchscreen module to get ready.\n\t_touch_wait_event(FTS4_EV_CONTROLLER_READY, 0, 20, NULL);\n\n\t// Check for forced boot time calibration.\n\tif (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))\n\t{\n\t\tu8 err[2];\n\t\tif (!touch_panel_ito_test(err))\n\t\t\tif (!err[0] && !err[1])\n\t\t\t\treturn touch_execute_autotune();\n\t}\n\n\t// Initialize touchscreen.\n\tu32 retries = 3;\n\twhile (retries)\n\t{\n\t\tif (!touch_init())\n\t\t\treturn 0;\n\t\tretries--;\n\t}\n\n\treturn 1;\n}\n\nvoid touch_power_off()\n{\n\t// Disable touchscreen power.\n\tgpio_write(GPIO_PORT_J, GPIO_PIN_7, GPIO_LOW);\n\n\t// Disables LDO6 for touchscreen VDD, AVDD supply\n\tmax7762x_regulator_enable(REGULATOR_LDO6, false);\n\n\tclock_disable_i2c(I2C_3);\n}\n"
  },
  {
    "path": "bdk/input/touch.h",
    "content": "/*\n * Touch driver for Nintendo Switch's STM FingerTip S (4CD60D) touch controller\n *\n * Copyright (c) 2018 langerhans\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef __TOUCH_H_\n#define __TOUCH_H_\n\n#include <utils/types.h>\n\n#define FTS4_I2C_ADDR 0x49\n\n#define FTS4_I2C_CHIP_ID 0x3670\n\n/* I2C commands. */\n#define FTS4_CMD_READ_INFO           0x80\n#define FTS4_CMD_READ_STATUS         0x84\n#define FTS4_CMD_READ_ONE_EVENT      0x85\n#define FTS4_CMD_READ_ALL_EVENT      0x86\n#define FTS4_CMD_LATEST_EVENT        0x87 // Clears event stack.\n#define FTS4_CMD_SLEEP_IN            0x90\n#define FTS4_CMD_SLEEP_OUT           0x91\n#define FTS4_CMD_MS_MT_SENSE_OFF     0x92\n#define FTS4_CMD_MS_MT_SENSE_ON      0x93\n#define FTS4_CMD_SS_HOVER_SENSE_OFF  0x94\n#define FTS4_CMD_SS_HOVER_SENSE_ON   0x95\n#define FTS4_CMD_LP_TIMER_CALIB      0x97\n#define FTS4_CMD_MS_KEY_SENSE_OFF    0x9A\n#define FTS4_CMD_MS_KEY_SENSE_ON     0x9B\n#define FTS4_CMD_SYSTEM_RESET        0xA0\n#define FTS4_CMD_CLEAR_EVENT_STACK   0xA1\n#define FTS4_CMD_FULL_FORCE_CALIB    0xA2\n#define FTS4_CMD_MS_CX_TUNING        0xA3\n#define FTS4_CMD_SS_CX_TUNING        0xA4\n#define FTS4_CMD_ITO_CHECK           0xA7\n#define FTS4_CMD_RELEASEINFO         0xAA\n#define FTS4_CMD_HW_REG_READ         0xB6                 // u16be address offset. Any size read.\n#define FTS4_CMD_HW_REG_WRITE        FTS4_CMD_HW_REG_READ // u16be address offset, bytes to write.\n#define FTS4_CMD_SWITCH_SENSE_MODE   0xC3\n#define FTS4_CMD_NOISE_WRITE         0xC7\n#define FTS4_CMD_NOISE_READ          0xC8\n#define FTS4_CMD_FB_REG_READ         0xD0\n#define FTS4_CMD_FB_REG_WRITE        FTS4_CMD_FB_REG_READ\n#define FTS4_CMD_SAVE_CX_TUNING      0xFC\n\n#define FTS4_CMD_DETECTION_CONFIG    0xB0\n#define FTS4_CMD_REQ_CX_DATA         0xB8\n#define FTS4_CMD_VENDOR              0xCF\n#define FTS4_CMD_FLASH_UNLOCK        0xF7\n#define FTS4_CMD_FLASH_WRITE_64K     0xF8\n#define FTS4_CMD_FLASH_STATUS        0xF9\n#define FTS4_CMD_FLASH_OP            0xFA\n#define FTS4_CMD_UNK_62 0x62\n\n/* Command parameters. */\n#define FTS4_VENDOR_GPIO_STATE       0x01\n#define FTS4_VENDOR_SENSE_MODE       0x02\n#define FTS4_STYLUS_MODE             0x00\n#define FTS4_FINGER_MODE             0x01\n#define FTS4_HOVER_MODE              0x02\n\n/* HW Registers */\n#define FTS4_HW_REG_CHIP_ID_INFO     0x0004\n#define FTS4_HW_REG_EVENT_COUNT      0x0023\n#define FTS4_HW_REG_SYS_RESET        0x0028\n\n/* FB Addresses */\n#define FTS4_FB_REG_FW_INFO_ADDRESS  0x0060\n\n/* Events. */\n#define FTS4_EV_NO_EVENT             0x00\n#define FTS4_EV_MULTI_TOUCH_DETECTED 0x02\n#define FTS4_EV_MULTI_TOUCH_ENTER    0x03\n#define FTS4_EV_MULTI_TOUCH_LEAVE    0x04\n#define FTS4_EV_MULTI_TOUCH_MOTION   0x05\n#define FTS4_EV_HOVER_ENTER          0x07\n#define FTS4_EV_HOVER_LEAVE          0x08\n#define FTS4_EV_HOVER_MOTION         0x09\n#define FTS4_EV_KEY_STATUS           0x0E\n#define FTS4_EV_ERROR                0x0F\n#define FTS4_EV_CONTROLLER_READY     0x10\n#define FTS4_EV_STATUS               0x16\n#define FTS4_EV_NOISE_READ           0x17\n#define FTS4_EV_NOISE_WRITE          0x18\n#define FTS4_EV_VENDOR               0x20\n#define FTS4_EV_DEBUG                0xDB\n\n/* FTS4_EV_STATUS Events. */\n#define FTS4_EV_STATUS_MS_CX_TUNING_DONE  0x01\n#define FTS4_EV_STATUS_SS_CX_TUNING_DONE  0x02\n#define FTS4_EV_STATUS_WRITE_CX_TUNE_DONE 0x04\n\n#define FTS4_EV_ERROR_ITO_TEST            0x05\n\n/* Multi touch related event masks. */\n#define FTS4_MASK_EVENT_ID   0x0F\n#define FTS4_MASK_TOUCH_ID   0xF0\n#define FTS4_MASK_X_MSB      0x0F\n#define FTS4_MASK_Y_LSB      0xF0\n\n#define FTS4_EVENT_SIZE     8\n#define FTS4_STACK_DEPTH   32 // Actual 128.\n#define FTS4_DATA_MAX_SIZE (FTS4_EVENT_SIZE * FTS4_STACK_DEPTH)\n#define FTS4_MAX_FINGERS   10\n\ntypedef enum _touch_ito_error {\n\tITO_NO_ERROR = 0,\n\tITO_FORCE_OPEN,\n\tITO_SENSE_OPEN,\n\tITO_FORCE_SHRT_GND,\n\tITO_SENSE_SHRT_GND,\n\tITO_FORCE_SHRT_VCM,\n\tITO_SENSE_SHRT_VCM,\n\tITO_FORCE_SHRT_FORCE,\n\tITO_SENSE_SHRT_SENSE,\n\tITO_F2E_SENSE,\n\tITO_FPC_FORCE_OPEN,\n\tITO_FPC_SENSE_OPEN,\n\tITO_KEY_FORCE_OPEN,\n\tITO_KEY_SENSE_OPEN,\n\tITO_RESERVED0,\n\tITO_RESERVED1,\n\tITO_RESERVED2,\n\tITO_MAX_ERR_REACHED = 0xFF\n} touch_ito_error;\n\ntypedef struct _touch_event_t {\n\tu8   raw[FTS4_EVENT_SIZE];\n\tu16  x, y; // Coordinates.\n\tu32  z;    // Orientation.\n\tbool touch;\n\tint  finger;\n} touch_event_t;\n\ntypedef struct _touch_panel_info_t\n{\n\tu8 idx;\n\tu8 gpio0;\n\tu8 gpio1;\n\tu8 gpio2;\n\tchar *vendor;\n} touch_panel_info_t;\n\ntypedef struct _touch_info_t {\n\tu16  chip_id;\n\tu16  fw_ver;\n\tu16  config_id;\n\tu16  config_ver;\n\tbool clone;\n} touch_info_t;\n\ntypedef struct _touch_fw_info_t {\n\tu32 fw_id;\n\tu16 ftb_ver;\n\tu16 fw_rev;\n} touch_fw_info_t;\n\nint touch_poll(touch_event_t *event);\ntouch_info_t *touch_get_chip_info();\ntouch_panel_info_t *touch_get_panel_vendor();\nint touch_get_fw_info(touch_fw_info_t *fw);\nint touch_get_event_count();\nint touch_panel_ito_test(u8 *err);\nint touch_execute_autotune();\nint touch_switch_sense_mode(u8 mode, bool gis_6_2);\nint touch_sense_enable();\nint touch_power_on();\nvoid touch_power_off();\n\n#endif /* __TOUCH_H_ */\n"
  },
  {
    "path": "bdk/libs/compr/blz.c",
    "content": "/*\n * Copyright (c) 2018 rajkosto\n * Copyright (c) 2018 SciresM\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"blz.h\"\n\nconst blz_footer *blz_get_footer(const u8 *comp_data, u32 comp_data_size, blz_footer *out_footer)\n{\n\tif (comp_data_size < sizeof(blz_footer))\n\t\treturn NULL;\n\n\tconst blz_footer *src_footer = (const blz_footer *)&comp_data[comp_data_size - sizeof(blz_footer)];\n\tif (out_footer)\n\t\tmemcpy(out_footer, src_footer, sizeof(blz_footer)); // Must be a memcpy because no unaligned accesses on ARMv4.\n\n\treturn src_footer;\n}\n\n// From https://github.com/SciresM/hactool/blob/master/kip.c which is exactly how kernel does it, thanks SciresM!\nint blz_uncompress_inplace(u8 *data, u32 comp_size, const blz_footer *footer)\n{\n\tu32 addl_size = footer->addl_size;\n\tu32 header_size = footer->header_size;\n\tu32 cmp_and_hdr_size = footer->cmp_and_hdr_size;\n\n\tu8 *cmp_start = &data[comp_size] - cmp_and_hdr_size;\n\tu32 cmp_ofs = cmp_and_hdr_size - header_size;\n\tu32 out_ofs = cmp_and_hdr_size + addl_size;\n\n\twhile (out_ofs)\n\t{\n\t\tu8 control = cmp_start[--cmp_ofs];\n\t\tfor (u32 i = 0; i < 8; i++)\n\t\t{\n\t\t\tif (control & 0x80)\n\t\t\t{\n\t\t\t\tif (cmp_ofs < 2)\n\t\t\t\t\treturn 0; // Out of bounds.\n\n\t\t\t\tcmp_ofs -= 2;\n\t\t\t\tu16 seg_val = ((u32)(cmp_start[cmp_ofs + 1]) << 8) | cmp_start[cmp_ofs];\n\t\t\t\tu32 seg_size = ((seg_val >> 12) & 0xF) + 3;\n\t\t\t\tu32 seg_ofs = (seg_val & 0x0FFF) + 3;\n\n\t\t\t\t// Kernel restricts segment copy to stay in bounds.\n\t\t\t\tif (out_ofs < seg_size)\n\t\t\t\t\tseg_size = out_ofs;\n\n\t\t\t\tout_ofs -= seg_size;\n\n\t\t\t\tfor (u32 j = 0; j < seg_size; j++)\n\t\t\t\t\tcmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs];\n\t\t\t}\n\t\t\telse // Copy directly.\n\t\t\t{\n\t\t\t\tif (cmp_ofs < 1)\n\t\t\t\t\treturn 0; // Out of bounds.\n\n\t\t\t\tcmp_start[--out_ofs] = cmp_start[--cmp_ofs];\n\t\t\t}\n\n\t\t\tcontrol <<= 1;\n\n\t\t\tif (!out_ofs) // Blz works backwards, so if it reaches byte 0, it's done.\n\t\t\t\treturn 1;\n\t\t}\n\t}\n\n\treturn 1;\n}\n\nint blz_uncompress_srcdest(const u8 *comp_data, u32 comp_data_size, u8 *dst_data, u32 dst_size)\n{\n\tblz_footer footer;\n\tconst blz_footer *comp_footer = blz_get_footer(comp_data, comp_data_size, &footer);\n\tif (!comp_footer)\n\t\treturn 0;\n\n\t// Decompression happens in-place, so need to copy the relevant compressed data first.\n\tu32 comp_bytes = (const u8 *)comp_footer - comp_data;\n\tmemcpy(dst_data, comp_data, comp_bytes);\n\tmemset(&dst_data[comp_bytes], 0, dst_size - comp_bytes);\n\n\treturn blz_uncompress_inplace(dst_data, comp_data_size, &footer);\n}\n"
  },
  {
    "path": "bdk/libs/compr/blz.h",
    "content": "/*\n * Copyright (c) 2018 rajkosto\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _BLZ_H_\n#define _BLZ_H_\n\n#include <utils/types.h>\n\ntypedef struct _blz_footer\n{\n\tu32 cmp_and_hdr_size;\n\tu32 header_size;\n\tu32 addl_size;\n} blz_footer;\n\n// Returns pointer to footer in comp_data if present, additionally copies it to out_footer if not NULL.\nconst blz_footer *blz_get_footer(const u8 *comp_data, u32 comp_data_size, blz_footer *out_footer);\n// Returns 0 on failure.\nint blz_uncompress_inplace(u8 *data, u32 comp_size, const blz_footer *footer);\n// Returns 0 on failure.\nint blz_uncompress_srcdest(const u8 *comp_data, u32 comp_data_size, u8 *dst_data, u32 dst_size);\n\n#endif\n"
  },
  {
    "path": "bdk/libs/compr/lz.c",
    "content": "/*************************************************************************\n* Name:        lz.c\n* Author:      Marcus Geelnard\n* Description: LZ77 coder/decoder implementation.\n* Reentrant:   Yes\n*\n* The LZ77 compression scheme is a substitutional compression scheme\n* proposed by Abraham Lempel and Jakob Ziv in 1977. It is very simple in\n* its design, and uses no fancy bit level compression.\n*\n* This is my first attempt at an implementation of a LZ77 code/decoder.\n*\n* The principle of the LZ77 compression algorithm is to store repeated\n* occurrences of strings as references to previous occurrences of the same\n* string. The point is that the reference consumes less space than the\n* string itself, provided that the string is long enough (in this\n* implementation, the string has to be at least 4 bytes long, since the\n* minimum coded reference is 3 bytes long). Also note that the term\n* \"string\" refers to any kind of byte sequence (it does not have to be\n* an ASCII string, for instance).\n*\n* The coder uses a brute force approach to finding string matches in the\n* history buffer (or \"sliding window\", if you wish), which is very, very\n* slow. I recon the complexity is somewhere between O(n^2) and O(n^3),\n* depending on the input data.\n*\n* There is also a faster implementation that uses a large working buffer\n* in which a \"jump table\" is stored, which is used to quickly find\n* possible string matches (see the source code for LZ_CompressFast() for\n* more information). The faster method is an order of magnitude faster,\n* but still quite slow compared to other compression methods.\n*\n* The upside is that decompression is very fast, and the compression ratio\n* is often very good.\n*\n* The reference to a string is coded as a (length,offset) pair, where the\n* length indicates the length of the string, and the offset gives the\n* offset from the current data position. To distinguish between string\n* references and literal strings (uncompressed bytes), a string reference\n* is preceded by a marker byte, which is chosen as the least common byte\n* symbol in the input data stream (this marker byte is stored in the\n* output stream as the first byte).\n*\n* Occurrences of the marker byte in the stream are encoded as the marker\n* byte followed by a zero byte, which means that occurrences of the marker\n* byte have to be coded with two bytes.\n*\n* The lengths and offsets are coded in a variable length fashion, allowing\n* values of any magnitude (up to 4294967295 in this implementation).\n*\n* With this compression scheme, the worst case compression result is\n* (257/256)*insize + 1.\n*\n*-------------------------------------------------------------------------\n* Copyright (c) 2003-2006 Marcus Geelnard\n*\n* This software is provided 'as-is', without any express or implied\n* warranty. In no event will the authors be held liable for any damages\n* arising from the use of this software.\n*\n* Permission is granted to anyone to use this software for any purpose,\n* including commercial applications, and to alter it and redistribute it\n* freely, subject to the following restrictions:\n*\n* 1. The origin of this software must not be misrepresented; you must not\n*    claim that you wrote the original software. If you use this software\n*    in a product, an acknowledgment in the product documentation would\n*    be appreciated but is not required.\n*\n* 2. Altered source versions must be plainly marked as such, and must not\n*    be misrepresented as being the original software.\n*\n* 3. This notice may not be removed or altered from any source\n*    distribution.\n*\n* Marcus Geelnard\n* marcus.geelnard at home.se\n*************************************************************************/\n\n\n/*************************************************************************\n*                           INTERNAL FUNCTIONS                           *\n*************************************************************************/\n\n\n/*************************************************************************\n* _LZ_ReadVarSize() - Read unsigned integer with variable number of\n* bytes depending on value.\n*************************************************************************/\n\nstatic int _LZ_ReadVarSize( unsigned int * x, const unsigned char * buf )\n{\n    unsigned int y, b, num_bytes;\n\n    /* Read complete value (stop when byte contains zero in 8:th bit) */\n    y = 0;\n    num_bytes = 0;\n    do\n    {\n        b = (unsigned int) (*buf ++);\n        y = (y << 7) | (b & 0x0000007f);\n        ++ num_bytes;\n    }\n    while( b & 0x00000080 );\n\n    /* Store value in x */\n    *x = y;\n\n    /* Return number of bytes read */\n    return num_bytes;\n}\n\n\n\n/*************************************************************************\n*                            PUBLIC FUNCTIONS                            *\n*************************************************************************/\n\n\n/*************************************************************************\n* LZ_Uncompress() - Uncompress a block of data using an LZ77 decoder.\n*  in      - Input (compressed) buffer.\n*  out     - Output (uncompressed) buffer. This buffer must be large\n*            enough to hold the uncompressed data.\n*  insize  - Number of input bytes.\n*************************************************************************/\n\nunsigned int LZ_Uncompress( const unsigned char *in, unsigned char *out,\n    unsigned int insize )\n{\n    unsigned char marker, symbol;\n    unsigned int  i, inpos, outpos, length, offset;\n\n    /* Do we have anything to uncompress? */\n    if( insize < 1 )\n    {\n        return 0;\n    }\n\n    /* Get marker symbol from input stream */\n    marker = in[ 0 ];\n    inpos = 1;\n\n    /* Main decompression loop */\n    outpos = 0;\n    do\n    {\n        symbol = in[ inpos ++ ];\n        if( symbol == marker )\n        {\n            /* We had a marker byte */\n            if( in[ inpos ] == 0 )\n            {\n                /* It was a single occurrence of the marker byte */\n                out[ outpos ++ ] = marker;\n                ++ inpos;\n            }\n            else\n            {\n                /* Extract true length and offset */\n                inpos += _LZ_ReadVarSize( &length, &in[ inpos ] );\n                inpos += _LZ_ReadVarSize( &offset, &in[ inpos ] );\n\n                /* Copy corresponding data from history window */\n                for( i = 0; i < length; ++ i )\n                {\n                    out[ outpos ] = out[ outpos - offset ];\n                    ++ outpos;\n                }\n            }\n        }\n        else\n        {\n            /* No marker, plain copy */\n            out[ outpos ++ ] = symbol;\n        }\n    }\n    while( inpos < insize );\n\n    return outpos;\n}\n"
  },
  {
    "path": "bdk/libs/compr/lz.h",
    "content": "/*************************************************************************\n* Name:        lz.h\n* Author:      Marcus Geelnard\n* Description: LZ77 coder/decoder interface.\n* Reentrant:   Yes\n*-------------------------------------------------------------------------\n* Copyright (c) 2003-2006 Marcus Geelnard\n*\n* This software is provided 'as-is', without any express or implied\n* warranty. In no event will the authors be held liable for any damages\n* arising from the use of this software.\n*\n* Permission is granted to anyone to use this software for any purpose,\n* including commercial applications, and to alter it and redistribute it\n* freely, subject to the following restrictions:\n*\n* 1. The origin of this software must not be misrepresented; you must not\n*    claim that you wrote the original software. If you use this software\n*    in a product, an acknowledgment in the product documentation would\n*    be appreciated but is not required.\n*\n* 2. Altered source versions must be plainly marked as such, and must not\n*    be misrepresented as being the original software.\n*\n* 3. This notice may not be removed or altered from any source\n*    distribution.\n*\n* Marcus Geelnard\n* marcus.geelnard at home.se\n*************************************************************************/\n\n#ifndef _lz_h_\n#define _lz_h_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n/*************************************************************************\n* Function prototypes\n*************************************************************************/\n\nunsigned int LZ_Uncompress( const unsigned char *in, unsigned char *out,\n                    unsigned int insize );\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _lz_h_ */\n"
  },
  {
    "path": "bdk/libs/compr/lz4.c",
    "content": "/*\n   LZ4 - Fast LZ compression algorithm\n   Copyright (C) 2011-2017, Yann Collet.\n\n   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions are\n   met:\n\n       * Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n       * Redistributions in binary form must reproduce the above\n   copyright notice, this list of conditions and the following disclaimer\n   in the documentation and/or other materials provided with the\n   distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n   You can contact the author at :\n    - LZ4 homepage : http://www.lz4.org\n    - LZ4 source repository : https://github.com/lz4/lz4\n*/\n\n\n/*-************************************\n*  Tuning parameters\n**************************************/\n/*\n * ACCELERATION_DEFAULT :\n * Select \"acceleration\" for LZ4_compress_fast() when parameter value <= 0\n */\n#define ACCELERATION_DEFAULT 1\n\n\n/*-************************************\n*  Dependency\n**************************************/\n#define LZ4_STATIC_LINKING_ONLY\n#include \"lz4.h\"\n/* see also \"memory routines\" below */\n\n\n/*-************************************\n*  Compiler Options\n**************************************/\n#ifndef LZ4_FORCE_INLINE\n#  ifdef _MSC_VER    /* Visual Studio */\n#    define LZ4_FORCE_INLINE static __forceinline\n#  else\n#    if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   /* C99 */\n#      ifdef __GNUC__\n#        define LZ4_FORCE_INLINE static inline __attribute__((always_inline))\n#      else\n#        define LZ4_FORCE_INLINE static inline\n#      endif\n#    else\n#      define LZ4_FORCE_INLINE static\n#    endif /* __STDC_VERSION__ */\n#  endif  /* _MSC_VER */\n#endif /* LZ4_FORCE_INLINE */\n\n/* LZ4_FORCE_O2_GCC_PPC64LE and LZ4_FORCE_O2_INLINE_GCC_PPC64LE\n * Gcc on ppc64le generates an unrolled SIMDized loop for LZ4_wildCopy,\n * together with a simple 8-byte copy loop as a fall-back path.\n * However, this optimization hurts the decompression speed by >30%,\n * because the execution does not go to the optimized loop\n * for typical compressible data, and all of the preamble checks\n * before going to the fall-back path become useless overhead.\n * This optimization happens only with the -O3 flag, and -O2 generates\n * a simple 8-byte copy loop.\n * With gcc on ppc64le, all of the LZ4_decompress_* and LZ4_wildCopy\n * functions are annotated with __attribute__((optimize(\"O2\"))),\n * and also LZ4_wildCopy is forcibly inlined, so that the O2 attribute\n * of LZ4_wildCopy does not affect the compression speed.\n */\n#if defined(__PPC64__) && defined(__LITTLE_ENDIAN__) && defined(__GNUC__)\n#  define LZ4_FORCE_O2_GCC_PPC64LE __attribute__((optimize(\"O2\")))\n#  define LZ4_FORCE_O2_INLINE_GCC_PPC64LE __attribute__((optimize(\"O2\"))) LZ4_FORCE_INLINE\n#else\n#  define LZ4_FORCE_O2_GCC_PPC64LE\n#  define LZ4_FORCE_O2_INLINE_GCC_PPC64LE static\n#endif\n\n/*-************************************\n*  Memory routines\n**************************************/\n#include <mem/heap.h>   /* malloc, calloc, free */\n#define ALLOC(s) malloc(s)\n#define ALLOC_AND_ZERO(s) zalloc(s)\n#define FREEMEM        free\n#include <string.h>   /* memset, memcpy */\n#define MEM_INIT       memset\n\n\n/*-************************************\n*  Basic Types\n**************************************/\ntypedef uint16_t U16;\ntypedef uint32_t U32;\ntypedef  int32_t S32;\ntypedef uint64_t U64;\ntypedef uintptr_t uptrval;\ntypedef size_t reg_t;   /* 32-bits in x32 mode */\n\n/*-************************************\n*  Reading and writing into memory\n**************************************/\nstatic unsigned LZ4_isLittleEndian(void)\n{\n    const union { U32 u; BYTE c[4]; } one = { 1 };   /* don't use static : performance detrimental */\n    return one.c[0];\n}\n\nstatic U16 LZ4_read16(const void* memPtr)\n{\n    U16 val; memcpy(&val, memPtr, sizeof(val)); return val;\n}\n\nstatic U32 LZ4_read32(const void* memPtr)\n{\n    U32 val; memcpy(&val, memPtr, sizeof(val)); return val;\n}\n\nstatic reg_t LZ4_read_ARCH(const void* memPtr)\n{\n    reg_t val; memcpy(&val, memPtr, sizeof(val)); return val;\n}\n\nstatic void LZ4_write16(void* memPtr, U16 value)\n{\n    memcpy(memPtr, &value, sizeof(value));\n}\n\nstatic void LZ4_write32(void* memPtr, U32 value)\n{\n    memcpy(memPtr, &value, sizeof(value));\n}\n\nstatic U16 LZ4_readLE16(const void* memPtr)\n{\n    if (LZ4_isLittleEndian()) {\n        return LZ4_read16(memPtr);\n    } else {\n        const BYTE* p = (const BYTE*)memPtr;\n        return (U16)((U16)p[0] + (p[1]<<8));\n    }\n}\n\nstatic void LZ4_writeLE16(void* memPtr, U16 value)\n{\n    if (LZ4_isLittleEndian()) {\n        LZ4_write16(memPtr, value);\n    } else {\n        BYTE* p = (BYTE*)memPtr;\n        p[0] = (BYTE) value;\n        p[1] = (BYTE)(value>>8);\n    }\n}\n\n/* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */\nLZ4_FORCE_O2_INLINE_GCC_PPC64LE\nvoid LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd)\n{\n    BYTE* d = (BYTE*)dstPtr;\n    const BYTE* s = (const BYTE*)srcPtr;\n    BYTE* const e = (BYTE*)dstEnd;\n\n    do { memcpy(d,s,8); d+=8; s+=8; } while (d<e);\n}\n\n\n/*-************************************\n*  Common Constants\n**************************************/\n#define MINMATCH 4\n\n#define WILDCOPYLENGTH 8\n#define LASTLITERALS 5\n#define MFLIMIT (WILDCOPYLENGTH+MINMATCH)\nstatic const int LZ4_minLength = (MFLIMIT+1);\n\n#define KB *(1 <<10)\n#define MB *(1 <<20)\n#define GB *(1U<<30)\n\n#define MAXD_LOG 16\n#define MAX_DISTANCE ((1 << MAXD_LOG) - 1)\n\n#define ML_BITS  4\n#define ML_MASK  ((1U<<ML_BITS)-1)\n#define RUN_BITS (8-ML_BITS)\n#define RUN_MASK ((1U<<RUN_BITS)-1)\n\n\n/*-************************************\n*  Error detection\n**************************************/\n\n#define LZ4_STATIC_ASSERT(c)   { enum { LZ4_static_assert = 1/(int)(!!(c)) }; }   /* use only *after* variable declarations */\n\n#if defined(LZ4_DEBUG) && (LZ4_DEBUG>=2)\n#  include <stdio.h>\nstatic int g_debuglog_enable = 1;\n#  define DEBUGLOG(l, ...) {                                  \\\n                if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) {  \\\n                    fprintf(stderr, __FILE__ \": \");           \\\n                    fprintf(stderr, __VA_ARGS__);             \\\n                    fprintf(stderr, \" \\n\");                   \\\n            }   }\n#else\n#  define DEBUGLOG(l, ...)      {}    /* disabled */\n#endif\n\n\n/*-************************************\n*  Common functions\n**************************************/\nstatic unsigned LZ4_NbCommonBytes (reg_t val)\n{\n    if (LZ4_isLittleEndian()) {\n        if (sizeof(val)==8) {\n            return (__builtin_ctzll((U64)val) >> 3);\n        } else /* 32 bits */ {\n            return (__builtin_ctz((U32)val) >> 3);\n        }\n    } else   /* Big Endian CPU */ {\n        if (sizeof(val)==8) {   /* 64-bits */\n            return (__builtin_clzll((U64)val) >> 3);\n        } else /* 32 bits */ {\n            return (__builtin_clz((U32)val) >> 3);\n        }\n    }\n}\n\n#define STEPSIZE sizeof(reg_t)\nLZ4_FORCE_INLINE\nunsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)\n{\n    const BYTE* const pStart = pIn;\n\n    if (likely(pIn < pInLimit-(STEPSIZE-1))) {\n        reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn);\n        if (!diff) {\n            pIn+=STEPSIZE; pMatch+=STEPSIZE;\n        } else {\n            return LZ4_NbCommonBytes(diff);\n    }   }\n\n    while (likely(pIn < pInLimit-(STEPSIZE-1))) {\n        reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn);\n        if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; continue; }\n        pIn += LZ4_NbCommonBytes(diff);\n        return (unsigned)(pIn - pStart);\n    }\n\n    if ((STEPSIZE==8) && (pIn<(pInLimit-3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { pIn+=4; pMatch+=4; }\n    if ((pIn<(pInLimit-1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { pIn+=2; pMatch+=2; }\n    if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;\n    return (unsigned)(pIn - pStart);\n}\n\n\n#ifndef LZ4_COMMONDEFS_ONLY\n/*-************************************\n*  Local Constants\n**************************************/\nstatic const int LZ4_64Klimit = ((64 KB) + (MFLIMIT-1));\nstatic const U32 LZ4_skipTrigger = 6;  /* Increase this value ==> compression run slower on incompressible data */\n\n\n/*-************************************\n*  Local Structures and types\n**************************************/\ntypedef enum { notLimited = 0, limitedOutput = 1 } limitedOutput_directive;\ntypedef enum { clearedTable = 0, byPtr, byU32, byU16 } tableType_t;\n\n/**\n * This enum distinguishes several different modes of accessing previous\n * content in the stream.\n *\n * - noDict        : There is no preceding content.\n * - withPrefix64k : Table entries up to ctx->dictSize before the current blob\n *                   blob being compressed are valid and refer to the preceding\n *                   content (of length ctx->dictSize), which is available\n *                   contiguously preceding in memory the content currently\n *                   being compressed.\n * - usingExtDict  : Like withPrefix64k, but the preceding content is somewhere\n *                   else in memory, starting at ctx->dictionary with length\n *                   ctx->dictSize.\n * - usingDictCtx  : Like usingExtDict, but everything concerning the preceding\n *                   content is in a separate context, pointed to by\n *                   ctx->dictCtx. ctx->dictionary, ctx->dictSize, and table\n *                   entries in the current context that refer to positions\n *                   preceding the beginning of the current compression are\n *                   ignored. Instead, ctx->dictCtx->dictionary and ctx->dictCtx\n *                   ->dictSize describe the location and size of the preceding\n *                   content, and matches are found by looking in the ctx\n *                   ->dictCtx->hashTable.\n */\ntypedef enum { noDict = 0, withPrefix64k, usingExtDict, usingDictCtx } dict_directive;\ntypedef enum { noDictIssue = 0, dictSmall } dictIssue_directive;\n\ntypedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive;\ntypedef enum { full = 0, partial = 1 } earlyEnd_directive;\n\n\n/*-************************************\n*  Local Utils\n**************************************/\nint LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; }\nconst char* LZ4_versionString(void) { return LZ4_VERSION_STRING; }\nint LZ4_compressBound(int isize)  { return LZ4_COMPRESSBOUND(isize); }\nint LZ4_sizeofState() { return LZ4_STREAMSIZE; }\n\n\n/*-******************************\n*  Compression functions\n********************************/\nstatic U32 LZ4_hash4(U32 sequence, tableType_t const tableType)\n{\n    if (tableType == byU16)\n        return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1)));\n    else\n        return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG));\n}\n\nstatic U32 LZ4_hash5(U64 sequence, tableType_t const tableType)\n{\n    static const U64 prime5bytes = 889523592379ULL;\n    static const U64 prime8bytes = 11400714785074694791ULL;\n    const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG;\n    if (LZ4_isLittleEndian())\n        return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog));\n    else\n        return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog));\n}\n\nLZ4_FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType)\n{\n    if ((sizeof(reg_t)==8) && (tableType != byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType);\n    return LZ4_hash4(LZ4_read32(p), tableType);\n}\n\nstatic void LZ4_putIndexOnHash(U32 idx, U32 h, void* tableBase, tableType_t const tableType)\n{\n    switch (tableType)\n    {\n    default: /* fallthrough */\n    case clearedTable: /* fallthrough */\n    case byPtr: { /* illegal! */ return; }\n    case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = idx; return; }\n    case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)idx; return; }\n    }\n}\n\nstatic void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase)\n{\n    switch (tableType)\n    {\n    case clearedTable: { /* illegal! */ return; }\n    case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; }\n    case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; }\n    case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; }\n    }\n}\n\nLZ4_FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)\n{\n    U32 const h = LZ4_hashPosition(p, tableType);\n    LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase);\n}\n\n/* LZ4_getIndexOnHash() :\n * Index of match position registered in hash table.\n * hash position must be calculated by using base+index, or dictBase+index.\n * Assumption 1 : only valid if tableType == byU32 or byU16.\n * Assumption 2 : h is presumed valid (within limits of hash table)\n */\nstatic U32 LZ4_getIndexOnHash(U32 h, const void* tableBase, tableType_t tableType)\n{\n    LZ4_STATIC_ASSERT(LZ4_MEMORY_USAGE > 2);\n    if (tableType == byU32) { const U32* const hashTable = (const U32*) tableBase; return hashTable[h]; }\n    if (tableType == byU16) { const U16* const hashTable = (const U16*) tableBase; return hashTable[h]; }\n    return 0;  /* forbidden case */\n}\n\nstatic const BYTE* LZ4_getPositionOnHash(U32 h, const void* tableBase, tableType_t tableType, const BYTE* srcBase)\n{\n    if (tableType == byPtr) { const BYTE* const* hashTable = (const BYTE* const*) tableBase; return hashTable[h]; }\n    if (tableType == byU32) { const U32* const hashTable = (const U32*) tableBase; return hashTable[h] + srcBase; }\n    { const U16* const hashTable = (const U16*) tableBase; return hashTable[h] + srcBase; }   /* default, to ensure a return */\n}\n\nLZ4_FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, const void* tableBase, tableType_t tableType, const BYTE* srcBase)\n{\n    U32 const h = LZ4_hashPosition(p, tableType);\n    return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase);\n}\n\nLZ4_FORCE_INLINE void LZ4_prepareTable(\n        LZ4_stream_t_internal* const cctx,\n        const int inputSize,\n        const tableType_t tableType) {\n    /* If the table hasn't been used, it's guaranteed to be zeroed out, and is\n     * therefore safe to use no matter what mode we're in. Otherwise, we figure\n     * out if it's safe to leave as is or whether it needs to be reset.\n     */\n    if (cctx->tableType != clearedTable) {\n        if (cctx->tableType != tableType\n          || (tableType == byU16 && cctx->currentOffset + inputSize >= 0xFFFFU)\n          || (tableType == byU32 && cctx->currentOffset > 1 GB)\n          || tableType == byPtr\n          || inputSize >= 4 KB)\n        {\n            DEBUGLOG(4, \"LZ4_prepareTable: Resetting table in %p\", cctx);\n            MEM_INIT(cctx->hashTable, 0, LZ4_HASHTABLESIZE);\n            cctx->currentOffset = 0;\n            cctx->tableType = clearedTable;\n        } else {\n            DEBUGLOG(4, \"LZ4_prepareTable: Re-use hash table (no reset)\");\n        }\n    }\n\n    /* Adding a gap, so all previous entries are > MAX_DISTANCE back, is faster\n     * than compressing without a gap. However, compressing with\n     * currentOffset == 0 is faster still, so we preserve that case.\n     */\n    if (cctx->currentOffset != 0 && tableType == byU32) {\n        DEBUGLOG(5, \"LZ4_prepareTable: adding 64KB to currentOffset\");\n        cctx->currentOffset += 64 KB;\n    }\n\n    /* Finally, clear history */\n    cctx->dictCtx = NULL;\n    cctx->dictionary = NULL;\n    cctx->dictSize = 0;\n}\n\n/** LZ4_compress_generic() :\n    inlined, to ensure branches are decided at compilation time */\nLZ4_FORCE_INLINE int LZ4_compress_generic(\n                 LZ4_stream_t_internal* const cctx,\n                 const char* const source,\n                 char* const dest,\n                 const int inputSize,\n                 const int maxOutputSize,\n                 const limitedOutput_directive outputLimited,\n                 const tableType_t tableType,\n                 const dict_directive dictDirective,\n                 const dictIssue_directive dictIssue,\n                 const U32 acceleration)\n{\n    const BYTE* ip = (const BYTE*) source;\n\n    U32 const startIndex = cctx->currentOffset;\n    const BYTE* base = (const BYTE*) source - startIndex;\n    const BYTE* lowLimit;\n\n    const LZ4_stream_t_internal* dictCtx = (const LZ4_stream_t_internal*) cctx->dictCtx;\n    const BYTE* const dictionary =\n        dictDirective == usingDictCtx ? dictCtx->dictionary : cctx->dictionary;\n    const U32 dictSize =\n        dictDirective == usingDictCtx ? dictCtx->dictSize : cctx->dictSize;\n    const U32 dictDelta = (dictDirective == usingDictCtx) ? startIndex - dictCtx->currentOffset : 0;   /* make indexes in dictCtx comparable with index in current context */\n\n    int const maybe_extMem = (dictDirective == usingExtDict) || (dictDirective == usingDictCtx);\n    U32 const prefixIdxLimit = startIndex - dictSize;   /* used when dictDirective == dictSmall */\n    const BYTE* const dictEnd = dictionary + dictSize;\n    const BYTE* anchor = (const BYTE*) source;\n    const BYTE* const iend = ip + inputSize;\n    const BYTE* const mflimitPlusOne = iend - MFLIMIT + 1;\n    const BYTE* const matchlimit = iend - LASTLITERALS;\n\n    /* the dictCtx currentOffset is indexed on the start of the dictionary,\n     * while a dictionary in the current context precedes the currentOffset */\n    const BYTE* dictBase = dictDirective == usingDictCtx ?\n        dictionary + dictSize - dictCtx->currentOffset :   /* is it possible that dictCtx->currentOffset != dictCtx->dictSize ? Yes if the dictionary context is not reset */\n        dictionary + dictSize - startIndex;\n\n    BYTE* op = (BYTE*) dest;\n    BYTE* const olimit = op + maxOutputSize;\n\n    U32 offset = 0;\n    U32 forwardH;\n\n    DEBUGLOG(5, \"LZ4_compress_generic: srcSize=%i, tableType=%u\", inputSize, tableType);\n    /* Init conditions */\n    if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0;   /* Unsupported inputSize, too large (or negative) */\n\n    lowLimit = (const BYTE*)source - (dictDirective == withPrefix64k ? dictSize : 0);\n\n    if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0;   /* Size too large (not within 64K limit) */\n\n    /* Update context state */\n    if (dictDirective == usingDictCtx) {\n        /* Subsequent linked blocks can't use the dictionary. */\n        /* Instead, they use the block we just compressed. */\n        cctx->dictCtx = NULL;\n        cctx->dictSize = (U32)inputSize;\n    } else {\n        cctx->dictSize += (U32)inputSize;\n    }\n    cctx->currentOffset += (U32)inputSize;\n    cctx->tableType = tableType;\n\n    if (inputSize<LZ4_minLength) goto _last_literals;                  /* Input too small, no compression (all literals) */\n\n    /* First Byte */\n    LZ4_putPosition(ip, cctx->hashTable, tableType, base);\n    ip++; forwardH = LZ4_hashPosition(ip, tableType);\n\n    /* Main Loop */\n    for ( ; ; ) {\n        const BYTE* match;\n        BYTE* token;\n\n        /* Find a match */\n        if (tableType == byPtr) {\n            const BYTE* forwardIp = ip;\n            unsigned step = 1;\n            unsigned searchMatchNb = acceleration << LZ4_skipTrigger;\n            do {\n                U32 const h = forwardH;\n                ip = forwardIp;\n                forwardIp += step;\n                step = (searchMatchNb++ >> LZ4_skipTrigger);\n\n                if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals;\n\n                match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base);\n                forwardH = LZ4_hashPosition(forwardIp, tableType);\n                LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base);\n\n            } while ( (match+MAX_DISTANCE < ip)\n                   || (LZ4_read32(match) != LZ4_read32(ip)) );\n\n        } else {   /* byU32, byU16 */\n\n            const BYTE* forwardIp = ip;\n            unsigned step = 1;\n            unsigned searchMatchNb = acceleration << LZ4_skipTrigger;\n            do {\n                U32 const h = forwardH;\n                U32 const current = (U32)(forwardIp - base);\n                U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType);\n                ip = forwardIp;\n                forwardIp += step;\n                step = (searchMatchNb++ >> LZ4_skipTrigger);\n\n                if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals;\n\n                if (dictDirective == usingDictCtx) {\n                    if (matchIndex < startIndex) {\n                        /* there was no match, try the dictionary */\n                        matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32);\n                        match = dictBase + matchIndex;\n                        matchIndex += dictDelta;   /* make dictCtx index comparable with current context */\n                        lowLimit = dictionary;\n                    } else {\n                        match = base + matchIndex;\n                        lowLimit = (const BYTE*)source;\n                    }\n                } else if (dictDirective==usingExtDict) {\n                    if (matchIndex < startIndex) {\n                        DEBUGLOG(7, \"extDict candidate: matchIndex=%5u  <  startIndex=%5u\", matchIndex, startIndex);\n                        match = dictBase + matchIndex;\n                        lowLimit = dictionary;\n                    } else {\n                        match = base + matchIndex;\n                        lowLimit = (const BYTE*)source;\n                    }\n                } else {   /* single continuous memory segment */\n                    match = base + matchIndex;\n                }\n                forwardH = LZ4_hashPosition(forwardIp, tableType);\n                LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType);\n\n                if ((dictIssue == dictSmall) && (matchIndex < prefixIdxLimit)) continue;     /* match outside of valid area */\n                if ((tableType != byU16) && (current - matchIndex > MAX_DISTANCE)) continue; /* too far - note: works even if matchIndex overflows */\n\n                if (LZ4_read32(match) == LZ4_read32(ip)) {\n                    if (maybe_extMem) offset = current - matchIndex;\n                    break;   /* match found */\n                }\n\n            } while(1);\n        }\n\n        /* Catch up */\n        while (((ip>anchor) & (match > lowLimit)) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; }\n\n        /* Encode Literals */\n        {   unsigned const litLength = (unsigned)(ip - anchor);\n            token = op++;\n            if ((outputLimited) &&  /* Check output buffer overflow */\n                (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)))\n                return 0;\n            if (litLength >= RUN_MASK) {\n                int len = (int)litLength-RUN_MASK;\n                *token = (RUN_MASK<<ML_BITS);\n                for(; len >= 255 ; len-=255) *op++ = 255;\n                *op++ = (BYTE)len;\n            }\n            else *token = (BYTE)(litLength<<ML_BITS);\n\n            /* Copy Literals */\n            LZ4_wildCopy(op, anchor, op+litLength);\n            op+=litLength;\n            DEBUGLOG(6, \"seq.start:%i, literals=%u, match.start:%i\", (int)(anchor-(const BYTE*)source), litLength, (int)(ip-(const BYTE*)source));\n        }\n\n_next_match:\n        /* at this stage, the following variables must be correctly set :\n         * - ip : at start of LZ operation\n         * - match : at start of previous pattern occurence; can be within current prefix, or within extDict\n         * - offset : if maybe_ext_memSegment==1 (constant)\n         * - lowLimit : must be == dictionary to mean \"match is within extDict\"; must be == source otherwise\n         * - token and *token : position to write 4-bits for match length; higher 4-bits for literal length supposed already written\n         */\n\n        /* Encode Offset */\n        if (maybe_extMem) {   /* static test */\n            LZ4_writeLE16(op, (U16)offset); op+=2;\n        } else  {\n            LZ4_writeLE16(op, (U16)(ip - match)); op+=2;\n        }\n\n        /* Encode MatchLength */\n        {   unsigned matchCode;\n\n            if ( (dictDirective==usingExtDict || dictDirective==usingDictCtx)\n              && (lowLimit==dictionary) /* match within extDict */ ) {\n                const BYTE* limit = ip + (dictEnd-match);\n                if (limit > matchlimit) limit = matchlimit;\n                matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit);\n                ip += MINMATCH + matchCode;\n                if (ip==limit) {\n                    unsigned const more = LZ4_count(limit, (const BYTE*)source, matchlimit);\n                    matchCode += more;\n                    ip += more;\n                }\n                DEBUGLOG(6, \"             with matchLength=%u starting in extDict\", matchCode+MINMATCH);\n            } else {\n                matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit);\n                ip += MINMATCH + matchCode;\n                DEBUGLOG(6, \"             with matchLength=%u\", matchCode+MINMATCH);\n            }\n\n            if ( outputLimited &&    /* Check output buffer overflow */\n                (unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) )\n                return 0;\n            if (matchCode >= ML_MASK) {\n                *token += ML_MASK;\n                matchCode -= ML_MASK;\n                LZ4_write32(op, 0xFFFFFFFF);\n                while (matchCode >= 4*255) {\n                    op+=4;\n                    LZ4_write32(op, 0xFFFFFFFF);\n                    matchCode -= 4*255;\n                }\n                op += matchCode / 255;\n                *op++ = (BYTE)(matchCode % 255);\n            } else\n                *token += (BYTE)(matchCode);\n        }\n\n        anchor = ip;\n\n        /* Test end of chunk */\n        if (ip >= mflimitPlusOne) break;\n\n        /* Fill table */\n        LZ4_putPosition(ip-2, cctx->hashTable, tableType, base);\n\n        /* Test next position */\n        if (tableType == byPtr) {\n\n            match = LZ4_getPosition(ip, cctx->hashTable, tableType, base);\n            LZ4_putPosition(ip, cctx->hashTable, tableType, base);\n            if ( (match+MAX_DISTANCE >= ip)\n              && (LZ4_read32(match) == LZ4_read32(ip)) )\n            { token=op++; *token=0; goto _next_match; }\n\n        } else {   /* byU32, byU16 */\n\n            U32 const h = LZ4_hashPosition(ip, tableType);\n            U32 const current = (U32)(ip-base);\n            U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType);\n            if (dictDirective == usingDictCtx) {\n                if (matchIndex < startIndex) {\n                    /* there was no match, try the dictionary */\n                    matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32);\n                    match = dictBase + matchIndex;\n                    lowLimit = dictionary;   /* required for match length counter */\n                    matchIndex += dictDelta;\n                } else {\n                    match = base + matchIndex;\n                    lowLimit = (const BYTE*)source;  /* required for match length counter */\n                }\n            } else if (dictDirective==usingExtDict) {\n                if (matchIndex < startIndex) {\n                    match = dictBase + matchIndex;\n                    lowLimit = dictionary;   /* required for match length counter */\n                } else {\n                    match = base + matchIndex;\n                    lowLimit = (const BYTE*)source;   /* required for match length counter */\n                }\n            } else {   /* single memory segment */\n                match = base + matchIndex;\n            }\n            LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType);\n            if ( ((dictIssue==dictSmall) ? (matchIndex >= prefixIdxLimit) : 1)\n              && ((tableType==byU16) ? 1 : (current - matchIndex <= MAX_DISTANCE))\n              && (LZ4_read32(match) == LZ4_read32(ip)) ) {\n                token=op++;\n                *token=0;\n                if (maybe_extMem) offset = current - matchIndex;\n                DEBUGLOG(6, \"seq.start:%i, literals=%u, match.start:%i\", (int)(anchor-(const BYTE*)source), 0, (int)(ip-(const BYTE*)source));\n                goto _next_match;\n            }\n        }\n\n        /* Prepare next loop */\n        forwardH = LZ4_hashPosition(++ip, tableType);\n\n    }\n\n_last_literals:\n    /* Encode Last Literals */\n    {   size_t const lastRun = (size_t)(iend - anchor);\n        if ( (outputLimited) &&  /* Check output buffer overflow */\n            ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) )\n            return 0;\n        if (lastRun >= RUN_MASK) {\n            size_t accumulator = lastRun - RUN_MASK;\n            *op++ = RUN_MASK << ML_BITS;\n            for(; accumulator >= 255 ; accumulator-=255) *op++ = 255;\n            *op++ = (BYTE) accumulator;\n        } else {\n            *op++ = (BYTE)(lastRun<<ML_BITS);\n        }\n        memcpy(op, anchor, lastRun);\n        op += lastRun;\n    }\n\n    return (int)(((char*)op) - dest);\n}\n\n\nint LZ4_compress_fast_extState(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)\n{\n    LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)state)->internal_donotuse;\n    if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;\n    LZ4_resetStream((LZ4_stream_t*)state);\n    if (maxOutputSize >= LZ4_compressBound(inputSize)) {\n        if (inputSize < LZ4_64Klimit) {\n            return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration);\n        } else {\n            const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > MAX_DISTANCE)) ? byPtr : byU32;\n            return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, tableType, noDict, noDictIssue, acceleration);\n        }\n    } else {\n        if (inputSize < LZ4_64Klimit) {;\n            return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);\n        } else {\n            const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > MAX_DISTANCE)) ? byPtr : byU32;\n            return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, noDict, noDictIssue, acceleration);\n        }\n    }\n}\n\n/**\n * LZ4_compress_fast_extState_fastReset() :\n * A variant of LZ4_compress_fast_extState().\n *\n * Using this variant avoids an expensive initialization step. It is only safe\n * to call if the state buffer is known to be correctly initialized already\n * (see comment in lz4.h on LZ4_resetStream_fast() for a definition of\n * \"correctly initialized\").\n */\nint LZ4_compress_fast_extState_fastReset(void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration)\n{\n    LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)state)->internal_donotuse;\n    if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;\n\n    if (dstCapacity >= LZ4_compressBound(srcSize)) {\n        if (srcSize < LZ4_64Klimit) {\n            const tableType_t tableType = byU16;\n            LZ4_prepareTable(ctx, srcSize, tableType);\n            if (ctx->currentOffset) {\n                return LZ4_compress_generic(ctx, src, dst, srcSize, 0, notLimited, tableType, noDict, dictSmall, acceleration);\n            } else {\n                return LZ4_compress_generic(ctx, src, dst, srcSize, 0, notLimited, tableType, noDict, noDictIssue, acceleration);\n            }\n        } else {\n            const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > MAX_DISTANCE)) ? byPtr : byU32;\n            LZ4_prepareTable(ctx, srcSize, tableType);\n            return LZ4_compress_generic(ctx, src, dst, srcSize, 0, notLimited, tableType, noDict, noDictIssue, acceleration);\n        }\n    } else {\n        if (srcSize < LZ4_64Klimit) {\n            const tableType_t tableType = byU16;\n            LZ4_prepareTable(ctx, srcSize, tableType);\n            if (ctx->currentOffset) {\n                return LZ4_compress_generic(ctx, src, dst, srcSize, dstCapacity, limitedOutput, tableType, noDict, dictSmall, acceleration);\n            } else {\n                return LZ4_compress_generic(ctx, src, dst, srcSize, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration);\n            }\n        } else {\n            const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > MAX_DISTANCE)) ? byPtr : byU32;\n            LZ4_prepareTable(ctx, srcSize, tableType);\n            return LZ4_compress_generic(ctx, src, dst, srcSize, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration);\n        }\n    }\n}\n\n\nint LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)\n{\n    int result;\n    LZ4_stream_t* ctx = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));\n    LZ4_stream_t* const ctxPtr = ctx;\n    result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration);\n\n    FREEMEM(ctx);\n\n    return result;\n}\n\n\nint LZ4_compress_default(const char* source, char* dest, int inputSize, int maxOutputSize)\n{\n    return LZ4_compress_fast(source, dest, inputSize, maxOutputSize, 1);\n}\n\n\n/* hidden debug function */\n/* strangely enough, gcc generates faster code when this function is uncommented, even if unused */\nint LZ4_compress_fast_force(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)\n{\n    int result;\n    LZ4_stream_t* ctx = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));\n    LZ4_resetStream(ctx);\n\n    if (inputSize < LZ4_64Klimit)\n        result = LZ4_compress_generic(&ctx->internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, byU16,                        noDict, noDictIssue, acceleration);\n    else\n        result = LZ4_compress_generic(&ctx->internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, sizeof(void*)==8 ? byU32 : byPtr, noDict, noDictIssue, acceleration);\n\n    FREEMEM(ctx);\n\n    return result;\n}\n\n\n/*-******************************\n*  *_destSize() variant\n********************************/\n\nstatic int LZ4_compress_destSize_generic(\n                       LZ4_stream_t_internal* const ctx,\n                 const char* const src,\n                       char* const dst,\n                       int*  const srcSizePtr,\n                 const int targetDstSize,\n                 const tableType_t tableType)\n{\n    const BYTE* ip = (const BYTE*) src;\n    const BYTE* base = (const BYTE*) src;\n    const BYTE* lowLimit = (const BYTE*) src;\n    const BYTE* anchor = ip;\n    const BYTE* const iend = ip + *srcSizePtr;\n    const BYTE* const mflimit = iend - MFLIMIT;\n    const BYTE* const matchlimit = iend - LASTLITERALS;\n\n    BYTE* op = (BYTE*) dst;\n    BYTE* const oend = op + targetDstSize;\n    BYTE* const oMaxLit = op + targetDstSize - 2 /* offset */ - 8 /* because 8+MINMATCH==MFLIMIT */ - 1 /* token */;\n    BYTE* const oMaxMatch = op + targetDstSize - (LASTLITERALS + 1 /* token */);\n    BYTE* const oMaxSeq = oMaxLit - 1 /* token */;\n\n    U32 forwardH;\n\n\n    /* Init conditions */\n    if (targetDstSize < 1) return 0;                                     /* Impossible to store anything */\n    if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0;            /* Unsupported input size, too large (or negative) */\n    if ((tableType == byU16) && (*srcSizePtr>=LZ4_64Klimit)) return 0;   /* Size too large (not within 64K limit) */\n    if (*srcSizePtr<LZ4_minLength) goto _last_literals;                  /* Input too small, no compression (all literals) */\n\n    /* First Byte */\n    *srcSizePtr = 0;\n    LZ4_putPosition(ip, ctx->hashTable, tableType, base);\n    ip++; forwardH = LZ4_hashPosition(ip, tableType);\n\n    /* Main Loop */\n    for ( ; ; ) {\n        const BYTE* match;\n        BYTE* token;\n\n        /* Find a match */\n        {   const BYTE* forwardIp = ip;\n            unsigned step = 1;\n            unsigned searchMatchNb = 1 << LZ4_skipTrigger;\n\n            do {\n                U32 h = forwardH;\n                ip = forwardIp;\n                forwardIp += step;\n                step = (searchMatchNb++ >> LZ4_skipTrigger);\n\n                if (unlikely(forwardIp > mflimit)) goto _last_literals;\n\n                match = LZ4_getPositionOnHash(h, ctx->hashTable, tableType, base);\n                forwardH = LZ4_hashPosition(forwardIp, tableType);\n                LZ4_putPositionOnHash(ip, h, ctx->hashTable, tableType, base);\n\n            } while ( ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip))\n                || (LZ4_read32(match) != LZ4_read32(ip)) );\n        }\n\n        /* Catch up */\n        while ((ip>anchor) && (match > lowLimit) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; }\n\n        /* Encode Literal length */\n        {   unsigned litLength = (unsigned)(ip - anchor);\n            token = op++;\n            if (op + ((litLength+240)/255) + litLength > oMaxLit) {\n                /* Not enough space for a last match */\n                op--;\n                goto _last_literals;\n            }\n            if (litLength>=RUN_MASK) {\n                unsigned len = litLength - RUN_MASK;\n                *token=(RUN_MASK<<ML_BITS);\n                for(; len >= 255 ; len-=255) *op++ = 255;\n                *op++ = (BYTE)len;\n            }\n            else *token = (BYTE)(litLength<<ML_BITS);\n\n            /* Copy Literals */\n            LZ4_wildCopy(op, anchor, op+litLength);\n            op += litLength;\n        }\n\n_next_match:\n        /* Encode Offset */\n        LZ4_writeLE16(op, (U16)(ip-match)); op+=2;\n\n        /* Encode MatchLength */\n        {   size_t matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit);\n\n            if (op + ((matchLength+240)/255) > oMaxMatch) {\n                /* Match description too long : reduce it */\n                matchLength = (15-1) + (oMaxMatch-op) * 255;\n            }\n            ip += MINMATCH + matchLength;\n\n            if (matchLength>=ML_MASK) {\n                *token += ML_MASK;\n                matchLength -= ML_MASK;\n                while (matchLength >= 255) { matchLength-=255; *op++ = 255; }\n                *op++ = (BYTE)matchLength;\n            }\n            else *token += (BYTE)(matchLength);\n        }\n\n        anchor = ip;\n\n        /* Test end of block */\n        if (ip > mflimit) break;\n        if (op > oMaxSeq) break;\n\n        /* Fill table */\n        LZ4_putPosition(ip-2, ctx->hashTable, tableType, base);\n\n        /* Test next position */\n        match = LZ4_getPosition(ip, ctx->hashTable, tableType, base);\n        LZ4_putPosition(ip, ctx->hashTable, tableType, base);\n        if ( (match+MAX_DISTANCE>=ip)\n            && (LZ4_read32(match)==LZ4_read32(ip)) )\n        { token=op++; *token=0; goto _next_match; }\n\n        /* Prepare next loop */\n        forwardH = LZ4_hashPosition(++ip, tableType);\n    }\n\n_last_literals:\n    /* Encode Last Literals */\n    {   size_t lastRunSize = (size_t)(iend - anchor);\n        if (op + 1 /* token */ + ((lastRunSize+240)/255) /* litLength */ + lastRunSize /* literals */ > oend) {\n            /* adapt lastRunSize to fill 'dst' */\n            lastRunSize  = (oend-op) - 1;\n            lastRunSize -= (lastRunSize+240)/255;\n        }\n        ip = anchor + lastRunSize;\n\n        if (lastRunSize >= RUN_MASK) {\n            size_t accumulator = lastRunSize - RUN_MASK;\n            *op++ = RUN_MASK << ML_BITS;\n            for(; accumulator >= 255 ; accumulator-=255) *op++ = 255;\n            *op++ = (BYTE) accumulator;\n        } else {\n            *op++ = (BYTE)(lastRunSize<<ML_BITS);\n        }\n        memcpy(op, anchor, lastRunSize);\n        op += lastRunSize;\n    }\n\n    /* End */\n    *srcSizePtr = (int) (((const char*)ip)-src);\n    return (int) (((char*)op)-dst);\n}\n\n\nstatic int LZ4_compress_destSize_extState (LZ4_stream_t* state, const char* src, char* dst, int* srcSizePtr, int targetDstSize)\n{\n    LZ4_resetStream(state);\n\n    if (targetDstSize >= LZ4_compressBound(*srcSizePtr)) {  /* compression success is guaranteed */\n        return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1);\n    } else {\n        if (*srcSizePtr < LZ4_64Klimit) {\n            return LZ4_compress_destSize_generic(&state->internal_donotuse, src, dst, srcSizePtr, targetDstSize, byU16);\n        } else {\n            tableType_t const tableType = ((sizeof(void*)==4) && ((uptrval)src > MAX_DISTANCE)) ? byPtr : byU32;\n            return LZ4_compress_destSize_generic(&state->internal_donotuse, src, dst, srcSizePtr, targetDstSize, tableType);\n    }   }\n}\n\n\nint LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize)\n{\n    LZ4_stream_t* ctxBody = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));;\n    LZ4_stream_t* ctx = ctxBody;\n\n    int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize);\n\n    FREEMEM(ctxBody);\n\n    return result;\n}\n\n\n\n/*-******************************\n*  Streaming functions\n********************************/\n\nLZ4_stream_t* LZ4_createStream(void)\n{\n    LZ4_stream_t* lz4s = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));\n    LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal));    /* A compilation error here means LZ4_STREAMSIZE is not large enough */\n    DEBUGLOG(4, \"LZ4_createStream %p\", lz4s);\n    if (lz4s == NULL) return NULL;\n    LZ4_resetStream(lz4s);\n    return lz4s;\n}\n\nvoid LZ4_resetStream (LZ4_stream_t* LZ4_stream)\n{\n    DEBUGLOG(5, \"LZ4_resetStream (ctx:%p)\", LZ4_stream);\n    MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t));\n}\n\nvoid LZ4_resetStream_fast(LZ4_stream_t* ctx) {\n    LZ4_prepareTable(&(ctx->internal_donotuse), 0, byU32);\n}\n\nint LZ4_freeStream (LZ4_stream_t* LZ4_stream)\n{\n    if (!LZ4_stream) return 0;   /* support free on NULL */\n    DEBUGLOG(5, \"LZ4_freeStream %p\", LZ4_stream);\n    FREEMEM(LZ4_stream);\n    return (0);\n}\n\n\n#define HASH_UNIT sizeof(reg_t)\nint LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize)\n{\n    LZ4_stream_t_internal* dict = &LZ4_dict->internal_donotuse;\n    const tableType_t tableType = byU32;\n    const BYTE* p = (const BYTE*)dictionary;\n    const BYTE* const dictEnd = p + dictSize;\n    const BYTE* base;\n\n    DEBUGLOG(4, \"LZ4_loadDict (%i bytes from %p into %p)\", dictSize, dictionary, LZ4_dict);\n\n    LZ4_prepareTable(dict, 0, tableType);\n\n    /* We always increment the offset by 64 KB, since, if the dict is longer,\n     * we truncate it to the last 64k, and if it's shorter, we still want to\n     * advance by a whole window length so we can provide the guarantee that\n     * there are only valid offsets in the window, which allows an optimization\n     * in LZ4_compress_fast_continue() where it uses noDictIssue even when the\n     * dictionary isn't a full 64k. */\n\n    if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB;\n    base = dictEnd - 64 KB - dict->currentOffset;\n    dict->dictionary = p;\n    dict->dictSize = (U32)(dictEnd - p);\n    dict->currentOffset += 64 KB;\n    dict->tableType = tableType;\n\n    if (dictSize < (int)HASH_UNIT) {\n        return 0;\n    }\n\n    while (p <= dictEnd-HASH_UNIT) {\n        LZ4_putPosition(p, dict->hashTable, tableType, base);\n        p+=3;\n    }\n\n    return dict->dictSize;\n}\n\nvoid LZ4_attach_dictionary(LZ4_stream_t *working_stream, const LZ4_stream_t *dictionary_stream) {\n    if (dictionary_stream != NULL) {\n        /* If the current offset is zero, we will never look in the\n         * external dictionary context, since there is no value a table\n         * entry can take that indicate a miss. In that case, we need\n         * to bump the offset to something non-zero.\n         */\n        if (working_stream->internal_donotuse.currentOffset == 0) {\n            working_stream->internal_donotuse.currentOffset = 64 KB;\n        }\n        working_stream->internal_donotuse.dictCtx = &(dictionary_stream->internal_donotuse);\n    } else {\n        working_stream->internal_donotuse.dictCtx = NULL;\n    }\n}\n\n\nstatic void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, int nextSize)\n{\n    if (LZ4_dict->currentOffset + nextSize > 0x80000000) {   /* potential ptrdiff_t overflow (32-bits mode) */\n        /* rescale hash table */\n        U32 const delta = LZ4_dict->currentOffset - 64 KB;\n        const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize;\n        int i;\n        DEBUGLOG(4, \"LZ4_renormDictT\");\n        for (i=0; i<LZ4_HASH_SIZE_U32; i++) {\n            if (LZ4_dict->hashTable[i] < delta) LZ4_dict->hashTable[i]=0;\n            else LZ4_dict->hashTable[i] -= delta;\n        }\n        LZ4_dict->currentOffset = 64 KB;\n        if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB;\n        LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize;\n    }\n}\n\n\nint LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)\n{\n    const tableType_t tableType = byU32;\n    LZ4_stream_t_internal* streamPtr = &LZ4_stream->internal_donotuse;\n    const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize;\n\n    if (streamPtr->initCheck) return 0;   /* Uninitialized structure detected */\n    LZ4_renormDictT(streamPtr, inputSize);   /* avoid index overflow */\n    if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;\n\n    /* Check overlapping input/dictionary space */\n    {   const BYTE* sourceEnd = (const BYTE*) source + inputSize;\n        if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) {\n            streamPtr->dictSize = (U32)(dictEnd - sourceEnd);\n            if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB;\n            if (streamPtr->dictSize < 4) streamPtr->dictSize = 0;\n            streamPtr->dictionary = dictEnd - streamPtr->dictSize;\n        }\n    }\n\n    /* prefix mode : source data follows dictionary */\n    if (dictEnd == (const BYTE*)source) {\n        if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset))\n            return LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, withPrefix64k, dictSmall, acceleration);\n        else\n            return LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, withPrefix64k, noDictIssue, acceleration);\n    }\n\n    /* external dictionary mode */\n    {   int result;\n        if (streamPtr->dictCtx) {\n            /* We depend here on the fact that dictCtx'es (produced by\n             * LZ4_loadDict) guarantee that their tables contain no references\n             * to offsets between dictCtx->currentOffset - 64 KB and\n             * dictCtx->currentOffset - dictCtx->dictSize. This makes it safe\n             * to use noDictIssue even when the dict isn't a full 64 KB.\n             */\n            if (inputSize > 4 KB) {\n                /* For compressing large blobs, it is faster to pay the setup\n                 * cost to copy the dictionary's tables into the active context,\n                 * so that the compression loop is only looking into one table.\n                 */\n                memcpy(streamPtr, streamPtr->dictCtx, sizeof(LZ4_stream_t));\n                result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration);\n            } else {\n                result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, usingDictCtx, noDictIssue, acceleration);\n            }\n        } else {\n            if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) {\n                result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, usingExtDict, dictSmall, acceleration);\n            } else {\n                result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration);\n            }\n        }\n        streamPtr->dictionary = (const BYTE*)source;\n        streamPtr->dictSize = (U32)inputSize;\n        return result;\n    }\n}\n\n\n/* Hidden debug function, to force-test external dictionary mode */\nint LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int srcSize)\n{\n    LZ4_stream_t_internal* streamPtr = &LZ4_dict->internal_donotuse;\n    int result;\n\n    LZ4_renormDictT(streamPtr, srcSize);\n\n    if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) {\n        result = LZ4_compress_generic(streamPtr, source, dest, srcSize, 0, notLimited, byU32, usingExtDict, dictSmall, 1);\n    } else {\n        result = LZ4_compress_generic(streamPtr, source, dest, srcSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1);\n    }\n\n    streamPtr->dictionary = (const BYTE*)source;\n    streamPtr->dictSize = (U32)srcSize;\n\n    return result;\n}\n\n\n/*! LZ4_saveDict() :\n *  If previously compressed data block is not guaranteed to remain available at its memory location,\n *  save it into a safer place (char* safeBuffer).\n *  Note : you don't need to call LZ4_loadDict() afterwards,\n *         dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue().\n *  Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error.\n */\nint LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize)\n{\n    LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse;\n    const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize;\n\n    if ((U32)dictSize > 64 KB) dictSize = 64 KB;   /* useless to define a dictionary > 64 KB */\n    if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize;\n\n    memmove(safeBuffer, previousDictEnd - dictSize, dictSize);\n\n    dict->dictionary = (const BYTE*)safeBuffer;\n    dict->dictSize = (U32)dictSize;\n\n    return dictSize;\n}\n\n\n\n/*-*****************************\n*  Decompression functions\n*******************************/\n/*! LZ4_decompress_generic() :\n *  This generic decompression function covers all use cases.\n *  It shall be instantiated several times, using different sets of directives.\n *  Note that it is important for performance that this function really get inlined,\n *  in order to remove useless branches during compilation optimization.\n */\nLZ4_FORCE_O2_GCC_PPC64LE\nLZ4_FORCE_INLINE int LZ4_decompress_generic(\n                 const char* const src,\n                 char* const dst,\n                 int srcSize,\n                 int outputSize,         /* If endOnInput==endOnInputSize, this value is `dstCapacity` */\n\n                 int endOnInput,         /* endOnOutputSize, endOnInputSize */\n                 int partialDecoding,    /* full, partial */\n                 int targetOutputSize,   /* only used if partialDecoding==partial */\n                 int dict,               /* noDict, withPrefix64k, usingExtDict */\n                 const BYTE* const lowPrefix,  /* always <= dst, == dst when no prefix */\n                 const BYTE* const dictStart,  /* only if dict==usingExtDict */\n                 const size_t dictSize         /* note : = 0 if noDict */\n                 )\n{\n    const BYTE* ip = (const BYTE*) src;\n    const BYTE* const iend = ip + srcSize;\n\n    BYTE* op = (BYTE*) dst;\n    BYTE* const oend = op + outputSize;\n    BYTE* cpy;\n    BYTE* oexit = op + targetOutputSize;\n\n    const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize;\n    const unsigned inc32table[8] = {0, 1, 2,  1,  0,  4, 4, 4};\n    const int      dec64table[8] = {0, 0, 0, -1, -4,  1, 2, 3};\n\n    const int safeDecode = (endOnInput==endOnInputSize);\n    const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB)));\n\n\n    /* Special cases */\n    if ((partialDecoding) && (oexit > oend-MFLIMIT)) oexit = oend-MFLIMIT;                      /* targetOutputSize too high => just decode everything */\n    if ((endOnInput) && (unlikely(outputSize==0))) return ((srcSize==1) && (*ip==0)) ? 0 : -1;  /* Empty output buffer */\n    if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1);\n\n    /* Main Loop : decode sequences */\n    while (1) {\n        size_t length;\n        const BYTE* match;\n        size_t offset;\n\n        unsigned const token = *ip++;\n\n        /* shortcut for common case :\n         * in most circumstances, we expect to decode small matches (<= 18 bytes) separated by few literals (<= 14 bytes).\n         * this shortcut was tested on x86 and x64, where it improves decoding speed.\n         * it has not yet been benchmarked on ARM, Power, mips, etc. */\n        if (((ip + 14 /*maxLL*/ + 2 /*offset*/ <= iend)\n          & (op + 14 /*maxLL*/ + 18 /*maxML*/ <= oend))\n          & ((token < (15<<ML_BITS)) & ((token & ML_MASK) != 15)) ) {\n            size_t const ll = token >> ML_BITS;\n            size_t const off = LZ4_readLE16(ip+ll);\n            const BYTE* const matchPtr = op + ll - off;  /* pointer underflow risk ? */\n            if ((off >= 8) /* do not deal with overlapping matches */ & (matchPtr >= lowPrefix)) {\n                size_t const ml = (token & ML_MASK) + MINMATCH;\n                memcpy(op, ip, 16); op += ll; ip += ll + 2 /*offset*/;\n                memcpy(op + 0, matchPtr + 0, 8);\n                memcpy(op + 8, matchPtr + 8, 8);\n                memcpy(op +16, matchPtr +16, 2);\n                op += ml;\n                continue;\n            }\n        }\n\n        /* decode literal length */\n        if ((length=(token>>ML_BITS)) == RUN_MASK) {\n            unsigned s;\n            do {\n                s = *ip++;\n                length += s;\n            } while ( likely(endOnInput ? ip<iend-RUN_MASK : 1) & (s==255) );\n            if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)(op))) goto _output_error;   /* overflow detection */\n            if ((safeDecode) && unlikely((uptrval)(ip)+length<(uptrval)(ip))) goto _output_error;   /* overflow detection */\n        }\n\n        /* copy literals */\n        cpy = op+length;\n        if ( ((endOnInput) && ((cpy>(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) )\n            || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) )\n        {\n            if (partialDecoding) {\n                if (cpy > oend) goto _output_error;                           /* Error : write attempt beyond end of output buffer */\n                if ((endOnInput) && (ip+length > iend)) goto _output_error;   /* Error : read attempt beyond end of input buffer */\n            } else {\n                if ((!endOnInput) && (cpy != oend)) goto _output_error;       /* Error : block decoding must stop exactly there */\n                if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error;   /* Error : input must be consumed */\n            }\n            memcpy(op, ip, length);\n            ip += length;\n            op += length;\n            break;     /* Necessarily EOF, due to parsing restrictions */\n        }\n        LZ4_wildCopy(op, ip, cpy);\n        ip += length; op = cpy;\n\n        /* get offset */\n        offset = LZ4_readLE16(ip); ip+=2;\n        match = op - offset;\n        if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) goto _output_error;   /* Error : offset outside buffers */\n        LZ4_write32(op, (U32)offset);   /* costs ~1%; silence an msan warning when offset==0 */\n\n        /* get matchlength */\n        length = token & ML_MASK;\n        if (length == ML_MASK) {\n            unsigned s;\n            do {\n                s = *ip++;\n                if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error;\n                length += s;\n            } while (s==255);\n            if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error;   /* overflow detection */\n        }\n        length += MINMATCH;\n\n        /* check external dictionary */\n        if ((dict==usingExtDict) && (match < lowPrefix)) {\n            if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error;   /* doesn't respect parsing restriction */\n\n            if (length <= (size_t)(lowPrefix-match)) {\n                /* match can be copied as a single segment from external dictionary */\n                memmove(op, dictEnd - (lowPrefix-match), length);\n                op += length;\n            } else {\n                /* match encompass external dictionary and current block */\n                size_t const copySize = (size_t)(lowPrefix-match);\n                size_t const restSize = length - copySize;\n                memcpy(op, dictEnd - copySize, copySize);\n                op += copySize;\n                if (restSize > (size_t)(op-lowPrefix)) {  /* overlap copy */\n                    BYTE* const endOfMatch = op + restSize;\n                    const BYTE* copyFrom = lowPrefix;\n                    while (op < endOfMatch) *op++ = *copyFrom++;\n                } else {\n                    memcpy(op, lowPrefix, restSize);\n                    op += restSize;\n            }   }\n            continue;\n        }\n\n        /* copy match within block */\n        cpy = op + length;\n        if (unlikely(offset<8)) {\n            op[0] = match[0];\n            op[1] = match[1];\n            op[2] = match[2];\n            op[3] = match[3];\n            match += inc32table[offset];\n            memcpy(op+4, match, 4);\n            match -= dec64table[offset];\n        } else { memcpy(op, match, 8); match+=8; }\n        op += 8;\n\n        if (unlikely(cpy>oend-12)) {\n            BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1);\n            if (cpy > oend-LASTLITERALS) goto _output_error;    /* Error : last LASTLITERALS bytes must be literals (uncompressed) */\n            if (op < oCopyLimit) {\n                LZ4_wildCopy(op, match, oCopyLimit);\n                match += oCopyLimit - op;\n                op = oCopyLimit;\n            }\n            while (op<cpy) *op++ = *match++;\n        } else {\n            memcpy(op, match, 8);\n            if (length>16) LZ4_wildCopy(op+8, match+8, cpy);\n        }\n        op = cpy;   /* correction */\n    }\n\n    /* end of decoding */\n    if (endOnInput)\n       return (int) (((char*)op)-dst);     /* Nb of output bytes decoded */\n    else\n       return (int) (((const char*)ip)-src);   /* Nb of input bytes read */\n\n    /* Overflow error detected */\n_output_error:\n    return (int) (-(((const char*)ip)-src))-1;\n}\n\n\nLZ4_FORCE_O2_GCC_PPC64LE\nint LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize)\n{\n    return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0);\n}\n\nLZ4_FORCE_O2_GCC_PPC64LE\nint LZ4_decompress_safe_partial(const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize)\n{\n    return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, partial, targetOutputSize, noDict, (BYTE*)dest, NULL, 0);\n}\n\nLZ4_FORCE_O2_GCC_PPC64LE\nint LZ4_decompress_fast(const char* source, char* dest, int originalSize)\n{\n    return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)(dest - 64 KB), NULL, 64 KB);\n}\n\n\n/*===== streaming decompression functions =====*/\n\nLZ4_streamDecode_t* LZ4_createStreamDecode(void)\n{\n    LZ4_streamDecode_t* lz4s = (LZ4_streamDecode_t*) ALLOC_AND_ZERO(sizeof(LZ4_streamDecode_t));\n    return lz4s;\n}\n\nint LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream)\n{\n    if (!LZ4_stream) return 0;   /* support free on NULL */\n    FREEMEM(LZ4_stream);\n    return 0;\n}\n\n/*!\n * LZ4_setStreamDecode() :\n * Use this function to instruct where to find the dictionary.\n * This function is not necessary if previous data is still available where it was decoded.\n * Loading a size of 0 is allowed (same effect as no dictionary).\n * Return : 1 if OK, 0 if error\n */\nint LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize)\n{\n    LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse;\n    lz4sd->prefixSize = (size_t) dictSize;\n    lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize;\n    lz4sd->externalDict = NULL;\n    lz4sd->extDictSize  = 0;\n    return 1;\n}\n\n/*\n*_continue() :\n    These decoding functions allow decompression of multiple blocks in \"streaming\" mode.\n    Previously decoded blocks must still be available at the memory position where they were decoded.\n    If it's not possible, save the relevant part of decoded data into a safe buffer,\n    and indicate where it stands using LZ4_setStreamDecode()\n*/\nLZ4_FORCE_O2_GCC_PPC64LE\nint LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize)\n{\n    LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse;\n    int result;\n\n    if (lz4sd->prefixEnd == (BYTE*)dest) {\n        result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,\n                                        endOnInputSize, full, 0,\n                                        usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);\n        if (result <= 0) return result;\n        lz4sd->prefixSize += result;\n        lz4sd->prefixEnd  += result;\n    } else {\n        lz4sd->extDictSize = lz4sd->prefixSize;\n        lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;\n        result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,\n                                        endOnInputSize, full, 0,\n                                        usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize);\n        if (result <= 0) return result;\n        lz4sd->prefixSize = result;\n        lz4sd->prefixEnd  = (BYTE*)dest + result;\n    }\n\n    return result;\n}\n\nLZ4_FORCE_O2_GCC_PPC64LE\nint LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize)\n{\n    LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse;\n    int result;\n\n    if (lz4sd->prefixEnd == (BYTE*)dest) {\n        result = LZ4_decompress_generic(source, dest, 0, originalSize,\n                                        endOnOutputSize, full, 0,\n                                        usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);\n        if (result <= 0) return result;\n        lz4sd->prefixSize += originalSize;\n        lz4sd->prefixEnd  += originalSize;\n    } else {\n        lz4sd->extDictSize = lz4sd->prefixSize;\n        lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;\n        result = LZ4_decompress_generic(source, dest, 0, originalSize,\n                                        endOnOutputSize, full, 0,\n                                        usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize);\n        if (result <= 0) return result;\n        lz4sd->prefixSize = originalSize;\n        lz4sd->prefixEnd  = (BYTE*)dest + originalSize;\n    }\n\n    return result;\n}\n\n\n/*\nAdvanced decoding functions :\n*_usingDict() :\n    These decoding functions work the same as \"_continue\" ones,\n    the dictionary must be explicitly provided within parameters\n*/\n\nLZ4_FORCE_O2_GCC_PPC64LE\nLZ4_FORCE_INLINE int LZ4_decompress_usingDict_generic(const char* source, char* dest, int compressedSize, int maxOutputSize, int safe, const char* dictStart, int dictSize)\n{\n    if (dictSize==0)\n        return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest, NULL, 0);\n    if (dictStart+dictSize == dest) {\n        if (dictSize >= (int)(64 KB - 1))\n            return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, (BYTE*)dest-64 KB, NULL, 0);\n        return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest-dictSize, NULL, 0);\n    }\n    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize);\n}\n\nLZ4_FORCE_O2_GCC_PPC64LE\nint LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)\n{\n    return LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize);\n}\n\nLZ4_FORCE_O2_GCC_PPC64LE\nint LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize)\n{\n    return LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize);\n}\n\n/* debug function */\nLZ4_FORCE_O2_GCC_PPC64LE\nint LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)\n{\n    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize);\n}\n\n\n/*=*************************************************\n*  Obsolete Functions\n***************************************************/\n/* obsolete compression functions */\nint LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize) { return LZ4_compress_default(source, dest, inputSize, maxOutputSize); }\nint LZ4_compress(const char* source, char* dest, int inputSize) { return LZ4_compress_default(source, dest, inputSize, LZ4_compressBound(inputSize)); }\nint LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1); }\nint LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1); }\nint LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, maxDstSize, 1); }\nint LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize) { return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1); }\n\n/*\nThese function names are deprecated and should no longer be used.\nThey are only provided here for compatibility with older user programs.\n- LZ4_uncompress is totally equivalent to LZ4_decompress_fast\n- LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe\n*/\nint LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); }\nint LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); }\n\n/* Obsolete Streaming functions */\n\nint LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; }\n\nint LZ4_resetStreamState(void* state, char* inputBuffer)\n{\n    (void)inputBuffer;\n    LZ4_resetStream((LZ4_stream_t*)state);\n    return 0;\n}\n\nvoid* LZ4_create (char* inputBuffer)\n{\n    (void)inputBuffer;\n    return LZ4_createStream();\n}\n\nchar* LZ4_slideInputBuffer (void* state)\n{\n    /* avoid const char * -> char * conversion warning */\n    return (char *)(uptrval)((LZ4_stream_t*)state)->internal_donotuse.dictionary;\n}\n\n/* Obsolete streaming decompression functions */\n\nint LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize)\n{\n    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB);\n}\n\nint LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize)\n{\n    return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB);\n}\n\n#endif   /* LZ4_COMMONDEFS_ONLY */\n"
  },
  {
    "path": "bdk/libs/compr/lz4.h",
    "content": "/*\n *  LZ4 - Fast LZ compression algorithm\n *  Header File\n *  Copyright (C) 2011-2017, Yann Collet.\n\n   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions are\n   met:\n\n       * Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n       * Redistributions in binary form must reproduce the above\n   copyright notice, this list of conditions and the following disclaimer\n   in the documentation and/or other materials provided with the\n   distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n   You can contact the author at :\n    - LZ4 homepage : http://www.lz4.org\n    - LZ4 source repository : https://github.com/lz4/lz4\n*/\n#if defined (__cplusplus)\nextern \"C\" {\n#endif\n\n#ifndef LZ4_H_2983827168210\n#define LZ4_H_2983827168210\n\n/* --- Dependency --- */\n#include <stddef.h>   /* size_t */\n\n\n/**\n  Introduction\n\n  LZ4 is lossless compression algorithm, providing compression speed at 400 MB/s per core,\n  scalable with multi-cores CPU. It features an extremely fast decoder, with speed in\n  multiple GB/s per core, typically reaching RAM speed limits on multi-core systems.\n\n  The LZ4 compression library provides in-memory compression and decompression functions.\n  Compression can be done in:\n    - a single step (described as Simple Functions)\n    - a single step, reusing a context (described in Advanced Functions)\n    - unbounded multiple steps (described as Streaming compression)\n\n  lz4.h provides block compression functions. It gives full buffer control to user.\n  Decompressing an lz4-compressed block also requires metadata (such as compressed size).\n  Each application is free to encode such metadata in whichever way it wants.\n\n  An additional format, called LZ4 frame specification (doc/lz4_Frame_format.md),\n  take care of encoding standard metadata alongside LZ4-compressed blocks.\n  If your application requires interoperability, it's recommended to use it.\n  A library is provided to take care of it, see lz4frame.h.\n*/\n\n/*^***************************************************************\n*  Export parameters\n*****************************************************************/\n/*\n*  LZ4_DLL_EXPORT :\n*  Enable exporting of functions when building a Windows DLL\n*  LZ4LIB_VISIBILITY :\n*  Control library symbols visibility.\n*/\n#ifndef LZ4LIB_VISIBILITY\n#  if defined(__GNUC__) && (__GNUC__ >= 4)\n#    define LZ4LIB_VISIBILITY __attribute__ ((visibility (\"default\")))\n#  else\n#    define LZ4LIB_VISIBILITY\n#  endif\n#endif\n#if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT==1)\n#  define LZ4LIB_API __declspec(dllexport) LZ4LIB_VISIBILITY\n#elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT==1)\n#  define LZ4LIB_API __declspec(dllimport) LZ4LIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/\n#else\n#  define LZ4LIB_API LZ4LIB_VISIBILITY\n#endif\n\n/*------   Version   ------*/\n#define LZ4_VERSION_MAJOR    1    /* for breaking interface changes  */\n#define LZ4_VERSION_MINOR    8    /* for new (non-breaking) interface capabilities */\n#define LZ4_VERSION_RELEASE  2    /* for tweaks, bug-fixes, or development */\n\n#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE)\n\n#define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE\n#define LZ4_QUOTE(str) #str\n#define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str)\n#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION)\n\nLZ4LIB_API int LZ4_versionNumber (void);  /**< library version number; useful to check dll version */\nLZ4LIB_API const char* LZ4_versionString (void);   /**< library version string; unseful to check dll version */\n\n\n/*-************************************\n*  Tuning parameter\n**************************************/\n/*!\n * LZ4_MEMORY_USAGE :\n * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)\n * Increasing memory usage improves compression ratio\n * Reduced memory usage may improve speed, thanks to cache effect\n * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache\n */\n#ifndef LZ4_MEMORY_USAGE\n# define LZ4_MEMORY_USAGE 14\n#endif\n\n/*-************************************\n*  Simple Functions\n**************************************/\n/*! LZ4_compress_default() :\n    Compresses 'srcSize' bytes from buffer 'src'\n    into already allocated 'dst' buffer of size 'dstCapacity'.\n    Compression is guaranteed to succeed if 'dstCapacity' >= LZ4_compressBound(srcSize).\n    It also runs faster, so it's a recommended setting.\n    If the function cannot compress 'src' into a more limited 'dst' budget,\n    compression stops *immediately*, and the function result is zero.\n    Note : as a consequence, 'dst' content is not valid.\n    Note 2 : This function is protected against buffer overflow scenarios (never writes outside 'dst' buffer, nor read outside 'source' buffer).\n        srcSize : max supported value is LZ4_MAX_INPUT_SIZE.\n        dstCapacity : size of buffer 'dst' (which must be already allocated)\n        return  : the number of bytes written into buffer 'dst' (necessarily <= dstCapacity)\n                  or 0 if compression fails */\nLZ4LIB_API int LZ4_compress_default(const char* src, char* dst, int srcSize, int dstCapacity);\n\n/*! LZ4_decompress_safe() :\n    compressedSize : is the exact complete size of the compressed block.\n    dstCapacity : is the size of destination buffer, which must be already allocated.\n    return : the number of bytes decompressed into destination buffer (necessarily <= dstCapacity)\n             If destination buffer is not large enough, decoding will stop and output an error code (negative value).\n             If the source stream is detected malformed, the function will stop decoding and return a negative result.\n             This function is protected against malicious data packets.\n*/\nLZ4LIB_API int LZ4_decompress_safe (const char* src, char* dst, int compressedSize, int dstCapacity);\n\n\n/*-************************************\n*  Advanced Functions\n**************************************/\n#define LZ4_MAX_INPUT_SIZE        0x7E000000   /* 2 113 929 216 bytes */\n#define LZ4_COMPRESSBOUND(isize)  ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16)\n\n/*!\nLZ4_compressBound() :\n    Provides the maximum size that LZ4 compression may output in a \"worst case\" scenario (input data not compressible)\n    This function is primarily useful for memory allocation purposes (destination buffer size).\n    Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example).\n    Note that LZ4_compress_default() compresses faster when dstCapacity is >= LZ4_compressBound(srcSize)\n        inputSize  : max supported value is LZ4_MAX_INPUT_SIZE\n        return : maximum output size in a \"worst case\" scenario\n              or 0, if input size is incorrect (too large or negative)\n*/\nLZ4LIB_API int LZ4_compressBound(int inputSize);\n\n/*!\nLZ4_compress_fast() :\n    Same as LZ4_compress_default(), but allows selection of \"acceleration\" factor.\n    The larger the acceleration value, the faster the algorithm, but also the lesser the compression.\n    It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed.\n    An acceleration value of \"1\" is the same as regular LZ4_compress_default()\n    Values <= 0 will be replaced by ACCELERATION_DEFAULT (currently == 1, see lz4.c).\n*/\nLZ4LIB_API int LZ4_compress_fast (const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);\n\n\n/*!\nLZ4_compress_fast_extState() :\n    Same compression function, just using an externally allocated memory space to store compression state.\n    Use LZ4_sizeofState() to know how much memory must be allocated,\n    and allocate it on 8-bytes boundaries (using malloc() typically).\n    Then, provide it as 'void* state' to compression function.\n*/\nLZ4LIB_API int LZ4_sizeofState(void);\nLZ4LIB_API int LZ4_compress_fast_extState (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);\n\n\n/*!\nLZ4_compress_destSize() :\n    Reverse the logic : compresses as much data as possible from 'src' buffer\n    into already allocated buffer 'dst' of size 'targetDestSize'.\n    This function either compresses the entire 'src' content into 'dst' if it's large enough,\n    or fill 'dst' buffer completely with as much data as possible from 'src'.\n        *srcSizePtr : will be modified to indicate how many bytes where read from 'src' to fill 'dst'.\n                      New value is necessarily <= old value.\n        return : Nb bytes written into 'dst' (necessarily <= targetDestSize)\n                 or 0 if compression fails\n*/\nLZ4LIB_API int LZ4_compress_destSize (const char* src, char* dst, int* srcSizePtr, int targetDstSize);\n\n\n/*!\nLZ4_decompress_fast() : **unsafe!**\nThis function is a bit faster than LZ4_decompress_safe(),\nbut doesn't provide any security guarantee.\n    originalSize : is the uncompressed size to regenerate\n                   Destination buffer must be already allocated, and its size must be >= 'originalSize' bytes.\n    return : number of bytes read from source buffer (== compressed size).\n             If the source stream is detected malformed, the function stops decoding and return a negative result.\n    note : This function respects memory boundaries for *properly formed* compressed data.\n           However, it does not provide any protection against malicious input.\n           It also doesn't know 'src' size, and implies it's >= compressed size.\n           Use this function in trusted environment **only**.\n*/\nLZ4LIB_API int LZ4_decompress_fast (const char* src, char* dst, int originalSize);\n\n/*!\nLZ4_decompress_safe_partial() :\n    This function decompress a compressed block of size 'srcSize' at position 'src'\n    into destination buffer 'dst' of size 'dstCapacity'.\n    The function will decompress a minimum of 'targetOutputSize' bytes, and stop after that.\n    However, it's not accurate, and may write more than 'targetOutputSize' (but always <= dstCapacity).\n   @return : the number of bytes decoded in the destination buffer (necessarily <= dstCapacity)\n        Note : this number can also be < targetOutputSize, if compressed block contains less data.\n            Therefore, always control how many bytes were decoded.\n            If source stream is detected malformed, function returns a negative result.\n            This function is protected against malicious data packets.\n*/\nLZ4LIB_API int LZ4_decompress_safe_partial (const char* src, char* dst, int srcSize, int targetOutputSize, int dstCapacity);\n\n\n/*-*********************************************\n*  Streaming Compression Functions\n***********************************************/\ntypedef union LZ4_stream_u LZ4_stream_t;  /* incomplete type (defined later) */\n\n/*! LZ4_createStream() and LZ4_freeStream() :\n *  LZ4_createStream() will allocate and initialize an `LZ4_stream_t` structure.\n *  LZ4_freeStream() releases its memory.\n */\nLZ4LIB_API LZ4_stream_t* LZ4_createStream(void);\nLZ4LIB_API int           LZ4_freeStream (LZ4_stream_t* streamPtr);\n\n/*! LZ4_resetStream() :\n *  An LZ4_stream_t structure can be allocated once and re-used multiple times.\n *  Use this function to start compressing a new stream.\n */\nLZ4LIB_API void LZ4_resetStream (LZ4_stream_t* streamPtr);\n\n/*! LZ4_loadDict() :\n *  Use this function to load a static dictionary into LZ4_stream_t.\n *  Any previous data will be forgotten, only 'dictionary' will remain in memory.\n *  Loading a size of 0 is allowed, and is the same as reset.\n * @return : dictionary size, in bytes (necessarily <= 64 KB)\n */\nLZ4LIB_API int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize);\n\n/*! LZ4_compress_fast_continue() :\n *  Compress 'src' content using data from previously compressed blocks, for better compression ratio.\n *  'dst' buffer must be already allocated.\n *  If dstCapacity >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster.\n *\n *  Important : The previous 64KB of compressed data is assumed to remain present and unmodified in memory!\n *\n *  Special 1 : When input is a double-buffer, they can have any size, including < 64 KB.\n *              Make sure that buffers are separated by at least one byte.\n *              This way, each block only depends on previous block.\n *  Special 2 : If input buffer is a ring-buffer, it can have any size, including < 64 KB.\n *\n * @return : size of compressed block\n *           or 0 if there is an error (typically, cannot fit into 'dst').\n *  After an error, the stream status is invalid, it can only be reset or freed.\n */\nLZ4LIB_API int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);\n\n/*! LZ4_saveDict() :\n *  If last 64KB data cannot be guaranteed to remain available at its current memory location,\n *  save it into a safer place (char* safeBuffer).\n *  This is schematically equivalent to a memcpy() followed by LZ4_loadDict(),\n *  but is much faster, because LZ4_saveDict() doesn't need to rebuild tables.\n * @return : saved dictionary size in bytes (necessarily <= maxDictSize), or 0 if error.\n */\nLZ4LIB_API int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int maxDictSize);\n\n\n/*-**********************************************\n*  Streaming Decompression Functions\n*  Bufferless synchronous API\n************************************************/\ntypedef union LZ4_streamDecode_u LZ4_streamDecode_t;   /* incomplete type (defined later) */\n\n/*! LZ4_createStreamDecode() and LZ4_freeStreamDecode() :\n *  creation / destruction of streaming decompression tracking structure.\n *  A tracking structure can be re-used multiple times sequentially. */\nLZ4LIB_API LZ4_streamDecode_t* LZ4_createStreamDecode(void);\nLZ4LIB_API int                 LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream);\n\n/*! LZ4_setStreamDecode() :\n *  An LZ4_streamDecode_t structure can be allocated once and re-used multiple times.\n *  Use this function to start decompression of a new stream of blocks.\n *  A dictionary can optionnally be set. Use NULL or size 0 for a reset order.\n * @return : 1 if OK, 0 if error\n */\nLZ4LIB_API int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize);\n\n/*! LZ4_decompress_*_continue() :\n *  These decoding functions allow decompression of consecutive blocks in \"streaming\" mode.\n *  A block is an unsplittable entity, it must be presented entirely to a decompression function.\n *  Decompression functions only accept one block at a time.\n *  The last 64KB of previously decoded data *must* remain available and unmodified at the memory position where they were decoded.\n *  If less than 64KB of data has been decoded all the data must be present.\n *\n *  Special : if application sets a ring buffer for decompression, it must respect one of the following conditions :\n *  - Exactly same size as encoding buffer, with same update rule (block boundaries at same positions)\n *    In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB).\n *  - Larger than encoding buffer, by a minimum of maxBlockSize more bytes.\n *    maxBlockSize is implementation dependent. It's the maximum size of any single block.\n *    In which case, encoding and decoding buffers do not need to be synchronized,\n *    and encoding ring buffer can have any size, including small ones ( < 64 KB).\n *  - _At least_ 64 KB + 8 bytes + maxBlockSize.\n *    In which case, encoding and decoding buffers do not need to be synchronized,\n *    and encoding ring buffer can have any size, including larger than decoding buffer.\n *  Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer,\n *  and indicate where it is saved using LZ4_setStreamDecode() before decompressing next block.\n*/\nLZ4LIB_API int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int srcSize, int dstCapacity);\nLZ4LIB_API int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int originalSize);\n\n\n/*! LZ4_decompress_*_usingDict() :\n *  These decoding functions work the same as\n *  a combination of LZ4_setStreamDecode() followed by LZ4_decompress_*_continue()\n *  They are stand-alone, and don't need an LZ4_streamDecode_t structure.\n */\nLZ4LIB_API int LZ4_decompress_safe_usingDict (const char* src, char* dst, int srcSize, int dstCapcity, const char* dictStart, int dictSize);\nLZ4LIB_API int LZ4_decompress_fast_usingDict (const char* src, char* dst, int originalSize, const char* dictStart, int dictSize);\n\n\n/*^**********************************************\n * !!!!!!   STATIC LINKING ONLY   !!!!!!\n ***********************************************/\n\n/*-************************************\n *  Unstable declarations\n **************************************\n * Declarations in this section should be considered unstable.\n * Use at your own peril, etc., etc.\n * They may be removed in the future.\n * Their signatures may change.\n **************************************/\n\n#ifdef LZ4_STATIC_LINKING_ONLY\n\n/*! LZ4_resetStream_fast() :\n *  When an LZ4_stream_t is known to be in a internally coherent state,\n *  it can often be prepared for a new compression with almost no work, only\n *  sometimes falling back to the full, expensive reset that is always required\n *  when the stream is in an indeterminate state (i.e., the reset performed by\n *  LZ4_resetStream()).\n *\n *  LZ4_streams are guaranteed to be in a valid state when:\n *  - returned from LZ4_createStream()\n *  - reset by LZ4_resetStream()\n *  - memset(stream, 0, sizeof(LZ4_stream_t))\n *  - the stream was in a valid state and was reset by LZ4_resetStream_fast()\n *  - the stream was in a valid state and was then used in any compression call\n *    that returned success\n *  - the stream was in an indeterminate state and was used in a compression\n *    call that fully reset the state (LZ4_compress_fast_extState()) and that\n *    returned success\n */\nLZ4LIB_API void LZ4_resetStream_fast (LZ4_stream_t* streamPtr);\n\n/*! LZ4_compress_fast_extState_fastReset() :\n *  A variant of LZ4_compress_fast_extState().\n *\n *  Using this variant avoids an expensive initialization step. It is only safe\n *  to call if the state buffer is known to be correctly initialized already\n *  (see above comment on LZ4_resetStream_fast() for a definition of \"correctly\n *  initialized\"). From a high level, the difference is that this function\n *  initializes the provided state with a call to LZ4_resetStream_fast() while\n *  LZ4_compress_fast_extState() starts with a call to LZ4_resetStream().\n */\nLZ4LIB_API int LZ4_compress_fast_extState_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);\n\n/*! LZ4_attach_dictionary() :\n *  This is an experimental API that allows for the efficient use of a\n *  static dictionary many times.\n *\n *  Rather than re-loading the dictionary buffer into a working context before\n *  each compression, or copying a pre-loaded dictionary's LZ4_stream_t into a\n *  working LZ4_stream_t, this function introduces a no-copy setup mechanism,\n *  in which the working stream references the dictionary stream in-place.\n *\n *  Several assumptions are made about the state of the dictionary stream.\n *  Currently, only streams which have been prepared by LZ4_loadDict() should\n *  be expected to work.\n *\n *  Alternatively, the provided dictionary stream pointer may be NULL, in which\n *  case any existing dictionary stream is unset.\n *\n *  If a dictionary is provided, it replaces any pre-existing stream history.\n *  The dictionary contents are the only history that can be referenced and\n *  logically immediately precede the data compressed in the first subsequent\n *  compression call.\n *\n *  The dictionary will only remain attached to the working stream through the\n *  first compression call, at the end of which it is cleared. The dictionary\n *  stream (and source buffer) must remain in-place / accessible / unchanged\n *  through the completion of the first compression call on the stream.\n */\nLZ4LIB_API void LZ4_attach_dictionary(LZ4_stream_t *working_stream, const LZ4_stream_t *dictionary_stream);\n\n#endif\n\n/*-************************************\n *  Private definitions\n **************************************\n * Do not use these definitions.\n * They are exposed to allow static allocation of `LZ4_stream_t` and `LZ4_streamDecode_t`.\n * Using these definitions will expose code to API and/or ABI break in future versions of the library.\n **************************************/\n#define LZ4_HASHLOG   (LZ4_MEMORY_USAGE-2)\n#define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE)\n#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG)       /* required as macro for static allocation */\n\n#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)\n#include <stdint.h>\n\ntypedef struct LZ4_stream_t_internal LZ4_stream_t_internal;\nstruct LZ4_stream_t_internal {\n    uint32_t hashTable[LZ4_HASH_SIZE_U32];\n    uint32_t currentOffset;\n    uint16_t initCheck;\n    uint16_t tableType;\n    const uint8_t* dictionary;\n    const LZ4_stream_t_internal* dictCtx;\n    uint32_t dictSize;\n};\n\ntypedef struct {\n    const uint8_t* externalDict;\n    size_t extDictSize;\n    const uint8_t* prefixEnd;\n    size_t prefixSize;\n} LZ4_streamDecode_t_internal;\n\n#else\n\ntypedef struct LZ4_stream_t_internal LZ4_stream_t_internal;\nstruct LZ4_stream_t_internal {\n    unsigned int hashTable[LZ4_HASH_SIZE_U32];\n    unsigned int currentOffset;\n    unsigned short initCheck;\n    unsigned short tableType;\n    const unsigned char* dictionary;\n    const LZ4_stream_t_internal* dictCtx;\n    unsigned int dictSize;\n};\n\ntypedef struct {\n    const unsigned char* externalDict;\n    size_t extDictSize;\n    const unsigned char* prefixEnd;\n    size_t prefixSize;\n} LZ4_streamDecode_t_internal;\n\n#endif\n\n/*!\n * LZ4_stream_t :\n * information structure to track an LZ4 stream.\n * init this structure before first use.\n * note : only use in association with static linking !\n *        this definition is not API/ABI safe,\n *        it may change in a future version !\n */\n#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4)\n#define LZ4_STREAMSIZE     (LZ4_STREAMSIZE_U64 * sizeof(unsigned long long))\nunion LZ4_stream_u {\n    unsigned long long table[LZ4_STREAMSIZE_U64];\n    LZ4_stream_t_internal internal_donotuse;\n} ;  /* previously typedef'd to LZ4_stream_t */\n\n\n/*!\n * LZ4_streamDecode_t :\n * information structure to track an LZ4 stream during decompression.\n * init this structure  using LZ4_setStreamDecode (or memset()) before first use\n * note : only use in association with static linking !\n *        this definition is not API/ABI safe,\n *        and may change in a future version !\n */\n#define LZ4_STREAMDECODESIZE_U64  4\n#define LZ4_STREAMDECODESIZE     (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long))\nunion LZ4_streamDecode_u {\n    unsigned long long table[LZ4_STREAMDECODESIZE_U64];\n    LZ4_streamDecode_t_internal internal_donotuse;\n} ;   /* previously typedef'd to LZ4_streamDecode_t */\n\n\n/*-************************************\n*  Obsolete Functions\n**************************************/\n\n/*! Deprecation warnings\n   Should deprecation warnings be a problem,\n   it is generally possible to disable them,\n   typically with -Wno-deprecated-declarations for gcc\n   or _CRT_SECURE_NO_WARNINGS in Visual.\n   Otherwise, it's also possible to define LZ4_DISABLE_DEPRECATE_WARNINGS */\n#ifdef LZ4_DISABLE_DEPRECATE_WARNINGS\n#  define LZ4_DEPRECATED(message)   /* disable deprecation warnings */\n#else\n#  define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)\n#  if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */\n#    define LZ4_DEPRECATED(message) [[deprecated(message)]]\n#  elif (LZ4_GCC_VERSION >= 405) || defined(__clang__)\n#    define LZ4_DEPRECATED(message) __attribute__((deprecated(message)))\n#  elif (LZ4_GCC_VERSION >= 301)\n#    define LZ4_DEPRECATED(message) __attribute__((deprecated))\n#  elif defined(_MSC_VER)\n#    define LZ4_DEPRECATED(message) __declspec(deprecated(message))\n#  else\n#    pragma message(\"WARNING: You need to implement LZ4_DEPRECATED for this compiler\")\n#    define LZ4_DEPRECATED(message)\n#  endif\n#endif /* LZ4_DISABLE_DEPRECATE_WARNINGS */\n\n/* Obsolete compression functions */\nLZ4_DEPRECATED(\"use LZ4_compress_default() instead\") LZ4LIB_API int LZ4_compress               (const char* source, char* dest, int sourceSize);\nLZ4_DEPRECATED(\"use LZ4_compress_default() instead\") LZ4LIB_API int LZ4_compress_limitedOutput (const char* source, char* dest, int sourceSize, int maxOutputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_fast_extState() instead\") LZ4LIB_API int LZ4_compress_withState               (void* state, const char* source, char* dest, int inputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_fast_extState() instead\") LZ4LIB_API int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_fast_continue() instead\") LZ4LIB_API int LZ4_compress_continue                (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_fast_continue() instead\") LZ4LIB_API int LZ4_compress_limitedOutput_continue  (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize);\n\n/* Obsolete decompression functions */\nLZ4_DEPRECATED(\"use LZ4_decompress_fast() instead\") LZ4LIB_API int LZ4_uncompress (const char* source, char* dest, int outputSize);\nLZ4_DEPRECATED(\"use LZ4_decompress_safe() instead\") LZ4LIB_API int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize);\n\n/* Obsolete streaming functions; degraded functionality; do not use!\n *\n * In order to perform streaming compression, these functions depended on data\n * that is no longer tracked in the state. They have been preserved as well as\n * possible: using them will still produce a correct output. However, they don't\n * actually retain any history between compression calls. The compression ratio\n * achieved will therefore be no better than compressing each chunk\n * independently.\n */\nLZ4_DEPRECATED(\"Use LZ4_createStream() instead\") LZ4LIB_API void* LZ4_create (char* inputBuffer);\nLZ4_DEPRECATED(\"Use LZ4_createStream() instead\") LZ4LIB_API int   LZ4_sizeofStreamState(void);\nLZ4_DEPRECATED(\"Use LZ4_resetStream() instead\") LZ4LIB_API  int   LZ4_resetStreamState(void* state, char* inputBuffer);\nLZ4_DEPRECATED(\"Use LZ4_saveDict() instead\") LZ4LIB_API     char* LZ4_slideInputBuffer (void* state);\n\n/* Obsolete streaming decoding functions */\nLZ4_DEPRECATED(\"use LZ4_decompress_safe_usingDict() instead\") LZ4LIB_API int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize);\nLZ4_DEPRECATED(\"use LZ4_decompress_fast_usingDict() instead\") LZ4LIB_API int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize);\n\n#endif /* LZ4_H_2983827168210 */\n\n\n#if defined (__cplusplus)\n}\n#endif\n"
  },
  {
    "path": "bdk/libs/fatfs/diskio.h",
    "content": "/*-----------------------------------------------------------------------/\n/  Low level disk interface modlue include file   (C)ChaN, 2014          /\n/-----------------------------------------------------------------------*/\n\n#ifndef _DISKIO_DEFINED\n#define _DISKIO_DEFINED\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <utils/types.h>\n\n/* Status of Disk Functions */\ntypedef BYTE\tDSTATUS;\n\n/* Results of Disk Functions */\ntypedef enum {\n\tRES_OK = 0,\t\t/* 0: Successful */\n\tRES_ERROR,\t\t/* 1: R/W Error */\n\tRES_WRPRT,\t\t/* 2: Write Protected */\n\tRES_NOTRDY,\t\t/* 3: Not Ready */\n\tRES_PARERR\t\t/* 4: Invalid Parameter */\n} DRESULT;\n\ntypedef enum {\n\tDRIVE_SD   = 0,\n\tDRIVE_RAM  = 1,\n\tDRIVE_EMMC = 2,\n\tDRIVE_BIS  = 3,\n\tDRIVE_EMU  = 4\n} DDRIVE;\n\n\n/*---------------------------------------*/\n/* Prototypes for disk control functions */\n\n\nDSTATUS disk_initialize (BYTE pdrv);\nDSTATUS disk_status (BYTE pdrv);\nDRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);\nDRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);\nDRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);\nDRESULT disk_set_info (BYTE pdrv, BYTE cmd, void *buff);\n\n\n/* Disk Status Bits (DSTATUS) */\n\n#define STA_NOINIT\t\t0x01\t/* Drive not initialized */\n#define STA_NODISK\t\t0x02\t/* No medium in the drive */\n#define STA_PROTECT\t\t0x04\t/* Write protected */\n\n\n/* Command code for disk_ioctrl fucntion */\n\n/* Generic command (Used by FatFs) */\n#define CTRL_SYNC\t\t\t0\t/* Complete pending write process (needed at FF_FS_READONLY == 0) */\n#define GET_SECTOR_COUNT\t1\t/* Get media size (needed at FF_USE_MKFS == 1) */\n#define SET_SECTOR_COUNT\t1\t/* Set media size (needed at FF_USE_MKFS == 1) */\n#define GET_SECTOR_SIZE\t\t2\t/* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */\n#define GET_BLOCK_SIZE\t\t3\t/* Get erase block size (needed at FF_USE_MKFS == 1) */\n#define CTRL_TRIM\t\t\t4\t/* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */\n#define SET_SECTOR_OFFSET\t5\t/* Set media logical offset */\n#define SET_WRITE_PROTECT\t6\t/* Lock/Unlock media removal */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "bdk/libs/fatfs/ff.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/*----------------------------------------------------------------------------/\n/  FatFs - Generic FAT Filesystem Module  R0.13c (p4)                         /\n/-----------------------------------------------------------------------------/\n/\n/ Copyright (C) 2018, ChaN, all right reserved.\n/\n/ FatFs module is an open source software. Redistribution and use of FatFs in\n/ source and binary forms, with or without modification, are permitted provided\n/ that the following condition is met:\n/\n/ 1. Redistributions of source code must retain the above copyright notice,\n/    this condition and the following disclaimer.\n/\n/ This software is provided by the copyright holder and contributors \"AS IS\"\n/ and any warranties related to this software are DISCLAIMED.\n/ The copyright owner or contributors be NOT LIABLE for any damages caused\n/ by use of this software.\n/\n/----------------------------------------------------------------------------*/\n\n\n#include \"ff.h\"\t\t\t/* Declarations of FatFs API */\n#include \"diskio.h\"\t\t/* Declarations of device I/O functions */\n#include <storage/mbr_gpt.h>\n#include <utils/util.h>\n#include <gfx_utils.h>\n\n#define EFSPRINTF(text, ...) print_error(); gfx_printf(\"%k\"text\"%k\\n\", 0xFFFFFF00, 0xFFFFFFFF);\n//#define EFSPRINTF(...)\n\n/*--------------------------------------------------------------------------\n\n   Module Private Definitions\n\n---------------------------------------------------------------------------*/\n\n#if FF_DEFINED != 86604\t/* Revision ID */\n#error Wrong include file (ff.h).\n#endif\n\n\n/* Limits and boundaries */\n#define MAX_DIR\t\t0x200000\t\t/* Max size of FAT directory */\n#define MAX_DIR_EX\t0x10000000\t\t/* Max size of exFAT directory */\n#define MAX_FAT12\t0xFF5\t\t\t/* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */\n#define MAX_FAT16\t0xFFF5\t\t\t/* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */\n#define MAX_FAT32\t0x0FFFFFF5\t\t/* Max FAT32 clusters (not specified, practical limit) */\n#define MAX_EXFAT\t0x7FFFFFFD\t\t/* Max exFAT clusters (differs from specs, implementation limit) */\n\n\n/* Character code support macros */\n#define IsUpper(c)\t\t((c) >= 'A' && (c) <= 'Z')\n#define IsLower(c)\t\t((c) >= 'a' && (c) <= 'z')\n#define IsDigit(c)\t\t((c) >= '0' && (c) <= '9')\n#define IsSurrogate(c)\t((c) >= 0xD800 && (c) <= 0xDFFF)\n#define IsSurrogateH(c)\t((c) >= 0xD800 && (c) <= 0xDBFF)\n#define IsSurrogateL(c)\t((c) >= 0xDC00 && (c) <= 0xDFFF)\n\n\n/* Additional file access control and file status flags for internal use */\n#define FA_SEEKEND\t0x20\t/* Seek to end of the file on file open */\n#define FA_MODIFIED\t0x40\t/* File has been modified */\n#define FA_DIRTY\t0x80\t/* FIL.buf[] needs to be written-back */\n\n\n/* Additional file attribute bits for internal use */\n#define AM_VOL\t\t0x08\t/* Volume label */\n#define AM_LFN\t\t0x0F\t/* LFN entry */\n#define AM_MASK\t\t0x3F\t/* Mask of defined bits */\n\n\n/* Name status flags in fn[11] */\n#define NSFLAG\t\t11\t\t/* Index of the name status byte */\n#define NS_LOSS\t\t0x01\t/* Out of 8.3 format */\n#define NS_LFN\t\t0x02\t/* Force to create LFN entry */\n#define NS_LAST\t\t0x04\t/* Last segment */\n#define NS_BODY\t\t0x08\t/* Lower case flag (body) */\n#define NS_EXT\t\t0x10\t/* Lower case flag (ext) */\n#define NS_DOT\t\t0x20\t/* Dot entry */\n#define NS_NOLFN\t0x40\t/* Do not find LFN */\n#define NS_NONAME\t0x80\t/* Not followed */\n\n\n/* exFAT directory entry types */\n#define\tET_BITMAP\t0x81\t/* Allocation bitmap */\n#define\tET_UPCASE\t0x82\t/* Up-case table */\n#define\tET_VLABEL\t0x83\t/* Volume label */\n#define\tET_FILEDIR\t0x85\t/* File and directory */\n#define\tET_STREAM\t0xC0\t/* Stream extension */\n#define\tET_FILENAME\t0xC1\t/* Name extension */\n\n\n/* FatFs refers the FAT structure as simple byte array instead of structure member\n/ because the C structure is not binary compatible between different platforms */\n\n#define BS_JmpBoot\t\t\t0\t\t/* x86 jump instruction (3-byte) */\n#define BS_OEMName\t\t\t3\t\t/* OEM name (8-byte) */\n#define BPB_BytsPerSec\t\t11\t\t/* Sector size [byte] (WORD) */\n#define BPB_SecPerClus\t\t13\t\t/* Cluster size [sector] (BYTE) */\n#define BPB_RsvdSecCnt\t\t14\t\t/* Size of reserved area [sector] (WORD) */\n#define BPB_NumFATs\t\t\t16\t\t/* Number of FATs (BYTE) */\n#define BPB_RootEntCnt\t\t17\t\t/* Size of root directory area for FAT [entry] (WORD) */\n#define BPB_TotSec16\t\t19\t\t/* Volume size (16-bit) [sector] (WORD) */\n#define BPB_Media\t\t\t21\t\t/* Media descriptor byte (BYTE) */\n#define BPB_FATSz16\t\t\t22\t\t/* FAT size (16-bit) [sector] (WORD) */\n#define BPB_SecPerTrk\t\t24\t\t/* Number of sectors per track for int13h [sector] (WORD) */\n#define BPB_NumHeads\t\t26\t\t/* Number of heads for int13h (WORD) */\n#define BPB_HiddSec\t\t\t28\t\t/* Volume offset from top of the drive (DWORD) */\n#define BPB_TotSec32\t\t32\t\t/* Volume size (32-bit) [sector] (DWORD) */\n#define BS_DrvNum\t\t\t36\t\t/* Physical drive number for int13h (BYTE) */\n#define BS_NTres\t\t\t37\t\t/* WindowsNT error flag (BYTE) */\n#define BS_BootSig\t\t\t38\t\t/* Extended boot signature (BYTE) */\n#define BS_VolID\t\t\t39\t\t/* Volume serial number (DWORD) */\n#define BS_VolLab\t\t\t43\t\t/* Volume label string (8-byte) */\n#define BS_FilSysType\t\t54\t\t/* Filesystem type string (8-byte) */\n#define BS_BootCode\t\t\t62\t\t/* Boot code (448-byte) */\n#define BS_55AA\t\t\t\t510\t\t/* Signature word (WORD) */\n\n#define BPB_FATSz32\t\t\t36\t\t/* FAT32: FAT size [sector] (DWORD) */\n#define BPB_ExtFlags32\t\t40\t\t/* FAT32: Extended flags (WORD) */\n#define BPB_FSVer32\t\t\t42\t\t/* FAT32: Filesystem version (WORD) */\n#define BPB_RootClus32\t\t44\t\t/* FAT32: Root directory cluster (DWORD) */\n#define BPB_FSInfo32\t\t48\t\t/* FAT32: Offset of FSINFO sector (WORD) */\n#define BPB_BkBootSec32\t\t50\t\t/* FAT32: Offset of backup boot sector (WORD) */\n#define BS_DrvNum32\t\t\t64\t\t/* FAT32: Physical drive number for int13h (BYTE) */\n#define BS_NTres32\t\t\t65\t\t/* FAT32: Error flag (BYTE) */\n#define BS_BootSig32\t\t66\t\t/* FAT32: Extended boot signature (BYTE) */\n#define BS_VolID32\t\t\t67\t\t/* FAT32: Volume serial number (DWORD) */\n#define BS_VolLab32\t\t\t71\t\t/* FAT32: Volume label string (8-byte) */\n#define BS_FilSysType32\t\t82\t\t/* FAT32: Filesystem type string (8-byte) */\n#define BS_BootCode32\t\t90\t\t/* FAT32: Boot code (420-byte) */\n\n#define BPB_ZeroedEx\t\t11\t\t/* exFAT: MBZ field (53-byte) */\n#define BPB_VolOfsEx\t\t64\t\t/* exFAT: Volume offset from top of the drive [sector] (QWORD) */\n#define BPB_TotSecEx\t\t72\t\t/* exFAT: Volume size [sector] (QWORD) */\n#define BPB_FatOfsEx\t\t80\t\t/* exFAT: FAT offset from top of the volume [sector] (DWORD) */\n#define BPB_FatSzEx\t\t\t84\t\t/* exFAT: FAT size [sector] (DWORD) */\n#define BPB_DataOfsEx\t\t88\t\t/* exFAT: Data offset from top of the volume [sector] (DWORD) */\n#define BPB_NumClusEx\t\t92\t\t/* exFAT: Number of clusters (DWORD) */\n#define BPB_RootClusEx\t\t96\t\t/* exFAT: Root directory start cluster (DWORD) */\n#define BPB_VolIDEx\t\t\t100\t\t/* exFAT: Volume serial number (DWORD) */\n#define BPB_FSVerEx\t\t\t104\t\t/* exFAT: Filesystem version (WORD) */\n#define BPB_VolFlagEx\t\t106\t\t/* exFAT: Volume flags (WORD) */\n#define BPB_BytsPerSecEx\t108\t\t/* exFAT: Log2 of sector size in unit of byte (BYTE) */\n#define BPB_SecPerClusEx\t109\t\t/* exFAT: Log2 of cluster size in unit of sector (BYTE) */\n#define BPB_NumFATsEx\t\t110\t\t/* exFAT: Number of FATs (BYTE) */\n#define BPB_DrvNumEx\t\t111\t\t/* exFAT: Physical drive number for int13h (BYTE) */\n#define BPB_PercInUseEx\t\t112\t\t/* exFAT: Percent in use (BYTE) */\n#define BPB_RsvdEx\t\t\t113\t\t/* exFAT: Reserved (7-byte) */\n#define BS_BootCodeEx\t\t120\t\t/* exFAT: Boot code (390-byte) */\n\n#define DIR_Name\t\t\t0\t\t/* Short file name (11-byte) */\n#define DIR_Attr\t\t\t11\t\t/* Attribute (BYTE) */\n#define DIR_NTres\t\t\t12\t\t/* Lower case flag (BYTE) */\n#define DIR_CrtTime10\t\t13\t\t/* Created time sub-second (BYTE) */\n#define DIR_CrtTime\t\t\t14\t\t/* Created time (DWORD) */\n#define DIR_LstAccDate\t\t18\t\t/* Last accessed date (WORD) */\n#define DIR_FstClusHI\t\t20\t\t/* Higher 16-bit of first cluster (WORD) */\n#define DIR_ModTime\t\t\t22\t\t/* Modified time (DWORD) */\n#define DIR_FstClusLO\t\t26\t\t/* Lower 16-bit of first cluster (WORD) */\n#define DIR_FileSize\t\t28\t\t/* File size (DWORD) */\n#define LDIR_Ord\t\t\t0\t\t/* LFN: LFN order and LLE flag (BYTE) */\n#define LDIR_Attr\t\t\t11\t\t/* LFN: LFN attribute (BYTE) */\n#define LDIR_Type\t\t\t12\t\t/* LFN: Entry type (BYTE) */\n#define LDIR_Chksum\t\t\t13\t\t/* LFN: Checksum of the SFN (BYTE) */\n#define LDIR_FstClusLO\t\t26\t\t/* LFN: MBZ field (WORD) */\n#define XDIR_Type\t\t\t0\t\t/* exFAT: Type of exFAT directory entry (BYTE) */\n#define XDIR_NumLabel\t\t1\t\t/* exFAT: Number of volume label characters (BYTE) */\n#define XDIR_Label\t\t\t2\t\t/* exFAT: Volume label (11-WORD) */\n#define XDIR_CaseSum\t\t4\t\t/* exFAT: Sum of case conversion table (DWORD) */\n#define XDIR_NumSec\t\t\t1\t\t/* exFAT: Number of secondary entries (BYTE) */\n#define XDIR_SetSum\t\t\t2\t\t/* exFAT: Sum of the set of directory entries (WORD) */\n#define XDIR_Attr\t\t\t4\t\t/* exFAT: File attribute (WORD) */\n#define XDIR_CrtTime\t\t8\t\t/* exFAT: Created time (DWORD) */\n#define XDIR_ModTime\t\t12\t\t/* exFAT: Modified time (DWORD) */\n#define XDIR_AccTime\t\t16\t\t/* exFAT: Last accessed time (DWORD) */\n#define XDIR_CrtTime10\t\t20\t\t/* exFAT: Created time subsecond (BYTE) */\n#define XDIR_ModTime10\t\t21\t\t/* exFAT: Modified time subsecond (BYTE) */\n#define XDIR_CrtTZ\t\t\t22\t\t/* exFAT: Created timezone (BYTE) */\n#define XDIR_ModTZ\t\t\t23\t\t/* exFAT: Modified timezone (BYTE) */\n#define XDIR_AccTZ\t\t\t24\t\t/* exFAT: Last accessed timezone (BYTE) */\n#define XDIR_GenFlags\t\t33\t\t/* exFAT: General secondary flags (BYTE) */\n#define XDIR_NumName\t\t35\t\t/* exFAT: Number of file name characters (BYTE) */\n#define XDIR_NameHash\t\t36\t\t/* exFAT: Hash of file name (WORD) */\n#define XDIR_ValidFileSize\t40\t\t/* exFAT: Valid file size (QWORD) */\n#define XDIR_FstClus\t\t52\t\t/* exFAT: First cluster of the file data (DWORD) */\n#define XDIR_FileSize\t\t56\t\t/* exFAT: File/Directory size (QWORD) */\n\n#define SZDIRE\t\t\t\t32\t\t/* Size of a directory entry */\n#define DDEM\t\t\t\t0xE5\t/* Deleted directory entry mark set to DIR_Name[0] */\n#define RDDEM\t\t\t\t0x05\t/* Replacement of the character collides with DDEM */\n#define LLEF\t\t\t\t0x40\t/* Last long entry flag in LDIR_Ord */\n\n#define FSI_LeadSig\t\t\t0\t\t/* FAT32 FSI: Leading signature (DWORD) */\n#define FSI_StrucSig\t\t484\t\t/* FAT32 FSI: Structure signature (DWORD) */\n#define FSI_Free_Count\t\t488\t\t/* FAT32 FSI: Number of free clusters (DWORD) */\n#define FSI_Nxt_Free\t\t492\t\t/* FAT32 FSI: Last allocated cluster (DWORD) */\n\n#define MBR_Table\t\t\t446\t\t/* MBR: Offset of partition table in the MBR */\n#define SZ_PTE\t\t\t\t16\t\t/* MBR: Size of a partition table entry */\n#define PTE_Boot\t\t\t0\t\t/* MBR PTE: Boot indicator */\n#define PTE_StHead\t\t\t1\t\t/* MBR PTE: Start head */\n#define PTE_StSec\t\t\t2\t\t/* MBR PTE: Start sector */\n#define PTE_StCyl\t\t\t3\t\t/* MBR PTE: Start cylinder */\n#define PTE_System\t\t\t4\t\t/* MBR PTE: System ID */\n#define PTE_EdHead\t\t\t5\t\t/* MBR PTE: End head */\n#define PTE_EdSec\t\t\t6\t\t/* MBR PTE: End sector */\n#define PTE_EdCyl\t\t\t7\t\t/* MBR PTE: End cylinder */\n#define PTE_StLba\t\t\t8\t\t/* MBR PTE: Start in LBA */\n#define PTE_SizLba\t\t\t12\t\t/* MBR PTE: Size in LBA */\n\n\n/* Post process on fatal error in the file operations */\n#define ABORT(fs, res)\t\t{ fp->err = (BYTE)(res); LEAVE_FF(fs, res); }\n\n\n/* Re-entrancy related */\n#if FF_FS_REENTRANT\n#if FF_USE_LFN == 1\n#error Static LFN work area cannot be used at thread-safe configuration\n#endif\n#define LEAVE_FF(fs, res)\t{ unlock_fs(fs, res); return res; }\n#else\n#define LEAVE_FF(fs, res)\treturn res\n#endif\n\n\n/* Definitions of volume - physical location conversion */\n#if FF_MULTI_PARTITION\n#define LD2PD(vol) VolToPart[vol].pd\t/* Get physical drive number */\n#define LD2PT(vol) VolToPart[vol].pt\t/* Get partition index */\n#else\n#define LD2PD(vol) (BYTE)(vol)\t/* Each logical drive is bound to the same physical drive number */\n#define LD2PT(vol) 0\t\t\t/* Find first valid partition or in SFD */\n#endif\n\n\n/* Definitions of sector size */\n#if (FF_MAX_SS < FF_MIN_SS) || (FF_MAX_SS != 512 && FF_MAX_SS != 1024 && FF_MAX_SS != 2048 && FF_MAX_SS != 4096) || (FF_MIN_SS != 512 && FF_MIN_SS != 1024 && FF_MIN_SS != 2048 && FF_MIN_SS != 4096)\n#error Wrong sector size configuration\n#endif\n#if FF_MAX_SS == FF_MIN_SS\n#define SS(fs)\t((UINT)FF_MAX_SS)\t/* Fixed sector size */\n#else\n#define SS(fs)\t((fs)->ssize)\t/* Variable sector size */\n#endif\n\n\n/* Timestamp */\n#if FF_FS_NORTC == 1\n#if FF_NORTC_YEAR < 1980 || FF_NORTC_YEAR > 2107 || FF_NORTC_MON < 1 || FF_NORTC_MON > 12 || FF_NORTC_MDAY < 1 || FF_NORTC_MDAY > 31\n#error Invalid FF_FS_NORTC settings\n#endif\n#define GET_FATTIME()\t((DWORD)(FF_NORTC_YEAR - 1980) << 25 | (DWORD)FF_NORTC_MON << 21 | (DWORD)FF_NORTC_MDAY << 16)\n#else\n#define GET_FATTIME()\tget_fattime()\n#endif\n\n\n/* File lock controls */\n#if FF_FS_LOCK != 0\n#if FF_FS_READONLY\n#error FF_FS_LOCK must be 0 at read-only configuration\n#endif\ntypedef struct {\n\tFATFS *fs;\t\t/* Object ID 1, volume (NULL:blank entry) */\n\tDWORD clu;\t\t/* Object ID 2, containing directory (0:root) */\n\tDWORD ofs;\t\t/* Object ID 3, offset in the directory */\n\tWORD ctr;\t\t/* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */\n} FILESEM;\n#endif\n\n\n/* SBCS up-case tables (\\x80-\\xFF) */\n#define TBL_CT437  {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \\\n\t\t\t\t\t0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \\\n\t\t\t\t\t0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n\t\t\t\t\t0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n\t\t\t\t\t0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n\t\t\t\t\t0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n\t\t\t\t\t0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \\\n\t\t\t\t\t0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n#define TBL_CT720  {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \\\n\t\t\t\t\t0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \\\n\t\t\t\t\t0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n\t\t\t\t\t0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n\t\t\t\t\t0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n\t\t\t\t\t0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n\t\t\t\t\t0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \\\n\t\t\t\t\t0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n#define TBL_CT737  {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \\\n\t\t\t\t\t0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \\\n\t\t\t\t\t0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96, \\\n\t\t\t\t\t0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n\t\t\t\t\t0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n\t\t\t\t\t0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n\t\t\t\t\t0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xEF,0xF5,0xF0,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \\\n\t\t\t\t\t0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n#define TBL_CT771  {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \\\n\t\t\t\t\t0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \\\n\t\t\t\t\t0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \\\n\t\t\t\t\t0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n\t\t\t\t\t0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n\t\t\t\t\t0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDC,0xDE,0xDE, \\\n\t\t\t\t\t0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \\\n\t\t\t\t\t0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFE,0xFF}\n#define TBL_CT775  {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F, \\\n\t\t\t\t\t0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \\\n\t\t\t\t\t0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n\t\t\t\t\t0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n\t\t\t\t\t0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n\t\t\t\t\t0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n\t\t\t\t\t0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF, \\\n\t\t\t\t\t0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n#define TBL_CT850  {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \\\n\t\t\t\t\t0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \\\n\t\t\t\t\t0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n\t\t\t\t\t0xB0,0xB1,0xB2,0xB3,0xB4,0x41,0x41,0x41,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n\t\t\t\t\t0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0x41,0x41,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n\t\t\t\t\t0xD1,0xD1,0x45,0x45,0x45,0x49,0x49,0x49,0x49,0xD9,0xDA,0xDB,0xDC,0xDD,0x49,0xDF, \\\n\t\t\t\t\t0x4F,0xE1,0x4F,0x4F,0x4F,0x4F,0xE6,0xE8,0xE8,0x55,0x55,0x55,0x59,0x59,0xEE,0xEF, \\\n\t\t\t\t\t0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n#define TBL_CT852  {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F, \\\n\t\t\t\t\t0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0xAC, \\\n\t\t\t\t\t0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF, \\\n\t\t\t\t\t0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \\\n\t\t\t\t\t0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n\t\t\t\t\t0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n\t\t\t\t\t0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF, \\\n\t\t\t\t\t0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF}\n#define TBL_CT855  {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F, \\\n\t\t\t\t\t0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \\\n\t\t\t\t\t0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF, \\\n\t\t\t\t\t0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \\\n\t\t\t\t\t0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n\t\t\t\t\t0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \\\n\t\t\t\t\t0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF, \\\n\t\t\t\t\t0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF}\n#define TBL_CT857  {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,0x8E,0x8F, \\\n\t\t\t\t\t0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \\\n\t\t\t\t\t0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n\t\t\t\t\t0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n\t\t\t\t\t0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n\t\t\t\t\t0xD0,0xD1,0xD2,0xD3,0xD4,0x49,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n\t\t\t\t\t0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0xED,0xEE,0xEF, \\\n\t\t\t\t\t0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n#define TBL_CT860  {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \\\n\t\t\t\t\t0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \\\n\t\t\t\t\t0x86,0x8B,0x9F,0x96,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n\t\t\t\t\t0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n\t\t\t\t\t0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n\t\t\t\t\t0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n\t\t\t\t\t0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \\\n\t\t\t\t\t0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n#define TBL_CT861  {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \\\n\t\t\t\t\t0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \\\n\t\t\t\t\t0xA4,0xA5,0xA6,0xA7,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n\t\t\t\t\t0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n\t\t\t\t\t0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n\t\t\t\t\t0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n\t\t\t\t\t0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \\\n\t\t\t\t\t0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n#define TBL_CT862  {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \\\n\t\t\t\t\t0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \\\n\t\t\t\t\t0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n\t\t\t\t\t0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n\t\t\t\t\t0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n\t\t\t\t\t0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n\t\t\t\t\t0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \\\n\t\t\t\t\t0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n#define TBL_CT863  {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,0x8F, \\\n\t\t\t\t\t0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \\\n\t\t\t\t\t0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n\t\t\t\t\t0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n\t\t\t\t\t0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n\t\t\t\t\t0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n\t\t\t\t\t0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \\\n\t\t\t\t\t0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n#define TBL_CT864  {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \\\n\t\t\t\t\t0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \\\n\t\t\t\t\t0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n\t\t\t\t\t0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n\t\t\t\t\t0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n\t\t\t\t\t0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n\t\t\t\t\t0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \\\n\t\t\t\t\t0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n#define TBL_CT865  {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \\\n\t\t\t\t\t0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \\\n\t\t\t\t\t0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n\t\t\t\t\t0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n\t\t\t\t\t0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n\t\t\t\t\t0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n\t\t\t\t\t0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \\\n\t\t\t\t\t0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n#define TBL_CT866  {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \\\n\t\t\t\t\t0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \\\n\t\t\t\t\t0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \\\n\t\t\t\t\t0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n\t\t\t\t\t0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n\t\t\t\t\t0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \\\n\t\t\t\t\t0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \\\n\t\t\t\t\t0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}\n#define TBL_CT869  {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \\\n\t\t\t\t\t0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x86,0x9C,0x8D,0x8F,0x90, \\\n\t\t\t\t\t0x91,0x90,0x92,0x95,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \\\n\t\t\t\t\t0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \\\n\t\t\t\t\t0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \\\n\t\t\t\t\t0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \\\n\t\t\t\t\t0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \\\n\t\t\t\t\t0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF}\n\n\n/* DBCS code range |----- 1st byte -----|  |----------- 2nd byte -----------| */\n#define TBL_DC932 {0x81, 0x9F, 0xE0, 0xFC, 0x40, 0x7E, 0x80, 0xFC, 0x00, 0x00}\n#define TBL_DC936 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0x80, 0xFE, 0x00, 0x00}\n#define TBL_DC949 {0x81, 0xFE, 0x00, 0x00, 0x41, 0x5A, 0x61, 0x7A, 0x81, 0xFE}\n#define TBL_DC950 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0xA1, 0xFE, 0x00, 0x00}\n\n\n/* Macros for table definitions */\n#define MERGE_2STR(a, b) a ## b\n#define MKCVTBL(hd, cp) MERGE_2STR(hd, cp)\n\n\n\n\n/*--------------------------------------------------------------------------\n\n   Module Private Work Area\n\n---------------------------------------------------------------------------*/\n/* Remark: Variables defined here without initial value shall be guaranteed\n/  zero/null at start-up. If not, the linker option or start-up routine is\n/  not compliance with C standard. */\n\n/*--------------------------------*/\n/* File/Volume controls           */\n/*--------------------------------*/\n\n#if FF_VOLUMES < 1 || FF_VOLUMES > 10\n#error Wrong FF_VOLUMES setting\n#endif\nstatic FATFS* FatFs[FF_VOLUMES];\t/* Pointer to the filesystem objects (logical drives) */\nstatic WORD Fsid;\t\t\t\t\t/* Filesystem mount ID */\n\n#if FF_FS_RPATH != 0\nstatic BYTE CurrVol;\t\t\t\t/* Current drive */\n#endif\n\n#if FF_FS_LOCK != 0\nstatic FILESEM Files[FF_FS_LOCK];\t/* Open object lock semaphores */\n#endif\n\n#if FF_STR_VOLUME_ID\n#ifdef FF_VOLUME_STRS\nstatic const char* const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS};\t/* Pre-defined volume ID */\n#endif\n#endif\n\n\n/*--------------------------------*/\n/* LFN/Directory working buffer   */\n/*--------------------------------*/\n\n#if FF_USE_LFN == 0\t\t/* Non-LFN configuration */\n#if FF_FS_EXFAT\n#error LFN must be enabled when enable exFAT\n#endif\n#define DEF_NAMBUF\n#define INIT_NAMBUF(fs)\n#define FREE_NAMBUF()\n#define LEAVE_MKFS(res)\treturn res\n\n#else\t\t\t\t\t/* LFN configurations */\n#if FF_MAX_LFN < 12 || FF_MAX_LFN > 255\n#error Wrong setting of FF_MAX_LFN\n#endif\n#if FF_LFN_BUF < FF_SFN_BUF || FF_SFN_BUF < 12\n#error Wrong setting of FF_LFN_BUF or FF_SFN_BUF\n#endif\n#if FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3\n#error Wrong setting of FF_LFN_UNICODE\n#endif\nstatic const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30};\t/* FAT: Offset of LFN characters in the directory entry */\n#define MAXDIRB(nc)\t((nc + 44U) / 15 * SZDIRE)\t/* exFAT: Size of directory entry block scratchpad buffer needed for the name length */\n\n#if FF_USE_LFN == 1\t\t/* LFN enabled with static working buffer */\n#if FF_FS_EXFAT\nstatic BYTE\tDirBuf[MAXDIRB(FF_MAX_LFN)];\t/* Directory entry block scratchpad buffer */\n#endif\nstatic WCHAR LfnBuf[FF_MAX_LFN + 1];\t\t/* LFN working buffer */\n#define DEF_NAMBUF\n#define INIT_NAMBUF(fs)\n#define FREE_NAMBUF()\n#define LEAVE_MKFS(res)\treturn res\n\n#elif FF_USE_LFN == 2 \t/* LFN enabled with dynamic working buffer on the stack */\n#if FF_FS_EXFAT\n#define DEF_NAMBUF\t\tWCHAR lbuf[FF_MAX_LFN+1]; BYTE dbuf[MAXDIRB(FF_MAX_LFN)];\t/* LFN working buffer and directory entry block scratchpad buffer */\n#define INIT_NAMBUF(fs)\t{ (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; }\n#define FREE_NAMBUF()\n#else\n#define DEF_NAMBUF\t\tWCHAR lbuf[FF_MAX_LFN+1];\t/* LFN working buffer */\n#define INIT_NAMBUF(fs)\t{ (fs)->lfnbuf = lbuf; }\n#define FREE_NAMBUF()\n#endif\n#define LEAVE_MKFS(res)\treturn res\n\n#elif FF_USE_LFN == 3 \t/* LFN enabled with dynamic working buffer on the heap */\n#if FF_FS_EXFAT\n#define DEF_NAMBUF\t\tWCHAR *lfn;\t/* Pointer to LFN working buffer and directory entry block scratchpad buffer */\n#define INIT_NAMBUF(fs)\t{ lfn = ff_memalloc((FF_MAX_LFN+1)*2 + MAXDIRB(FF_MAX_LFN)); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+FF_MAX_LFN+1); }\n#define FREE_NAMBUF()\tff_memfree(lfn)\n#else\n#define DEF_NAMBUF\t\tWCHAR *lfn;\t/* Pointer to LFN working buffer */\n#define INIT_NAMBUF(fs)\t{ lfn = ff_memalloc((FF_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; }\n#define FREE_NAMBUF()\tff_memfree(lfn)\n#endif\n#define LEAVE_MKFS(res)\t{ if (!work) ff_memfree(buf); return res; }\n#define MAX_MALLOC\t0x8000\t/* Must be >=FF_MAX_SS */\n\n#else\n#error Wrong setting of FF_USE_LFN\n\n#endif\t/* FF_USE_LFN == 1 */\n#endif\t/* FF_USE_LFN == 0 */\n\n\n\n/*--------------------------------*/\n/* Code conversion tables         */\n/*--------------------------------*/\n\n#if FF_CODE_PAGE == 0\t\t/* Run-time code page configuration */\n#define CODEPAGE CodePage\nstatic WORD CodePage;\t/* Current code page */\nstatic const BYTE *ExCvt, *DbcTbl;\t/* Pointer to current SBCS up-case table and DBCS code range table below */\n\nstatic const BYTE Ct437[] = TBL_CT437;\nstatic const BYTE Ct720[] = TBL_CT720;\nstatic const BYTE Ct737[] = TBL_CT737;\nstatic const BYTE Ct771[] = TBL_CT771;\nstatic const BYTE Ct775[] = TBL_CT775;\nstatic const BYTE Ct850[] = TBL_CT850;\nstatic const BYTE Ct852[] = TBL_CT852;\nstatic const BYTE Ct855[] = TBL_CT855;\nstatic const BYTE Ct857[] = TBL_CT857;\nstatic const BYTE Ct860[] = TBL_CT860;\nstatic const BYTE Ct861[] = TBL_CT861;\nstatic const BYTE Ct862[] = TBL_CT862;\nstatic const BYTE Ct863[] = TBL_CT863;\nstatic const BYTE Ct864[] = TBL_CT864;\nstatic const BYTE Ct865[] = TBL_CT865;\nstatic const BYTE Ct866[] = TBL_CT866;\nstatic const BYTE Ct869[] = TBL_CT869;\nstatic const BYTE Dc932[] = TBL_DC932;\nstatic const BYTE Dc936[] = TBL_DC936;\nstatic const BYTE Dc949[] = TBL_DC949;\nstatic const BYTE Dc950[] = TBL_DC950;\n\n#elif FF_CODE_PAGE < 900\t/* Static code page configuration (SBCS) */\n#define CODEPAGE FF_CODE_PAGE\nstatic const BYTE ExCvt[] = MKCVTBL(TBL_CT, FF_CODE_PAGE);\n\n#else\t\t\t\t\t/* Static code page configuration (DBCS) */\n#define CODEPAGE FF_CODE_PAGE\nstatic const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE);\n\n#endif\n\n\n\n\n/*--------------------------------------------------------------------------\n\n   Module Private Functions\n\n---------------------------------------------------------------------------*/\n\n/*-----------------------------------------------------------------------*/\n/* Print error header                                                    */\n/*-----------------------------------------------------------------------*/\n\nvoid print_error()\n{\n\tgfx_printf(\"\\n\\n\\n%k[FatFS] Error: %k\", 0xFFFFFF00, 0xFFFFFFFF);\n}\n\n\n/*-----------------------------------------------------------------------*/\n/* Load/Store multi-byte word in the FAT structure                       */\n/*-----------------------------------------------------------------------*/\n\nstatic WORD ld_word (const BYTE* ptr)\t/*\t Load a 2-byte little-endian word */\n{\n\tWORD rv;\n\n\trv = ptr[1];\n\trv = rv << 8 | ptr[0];\n\treturn rv;\n}\n\nstatic DWORD ld_dword (const BYTE* ptr)\t/* Load a 4-byte little-endian word */\n{\n\tDWORD rv;\n\n\trv = ptr[3];\n\trv = rv << 8 | ptr[2];\n\trv = rv << 8 | ptr[1];\n\trv = rv << 8 | ptr[0];\n\treturn rv;\n}\n\n#if FF_FS_EXFAT\nstatic QWORD ld_qword (const BYTE* ptr)\t/* Load an 8-byte little-endian word */\n{\n\tQWORD rv;\n\n\trv = ptr[7];\n\trv = rv << 8 | ptr[6];\n\trv = rv << 8 | ptr[5];\n\trv = rv << 8 | ptr[4];\n\trv = rv << 8 | ptr[3];\n\trv = rv << 8 | ptr[2];\n\trv = rv << 8 | ptr[1];\n\trv = rv << 8 | ptr[0];\n\treturn rv;\n}\n#endif\n\n#if !FF_FS_READONLY\nstatic void st_word (BYTE* ptr, WORD val)\t/* Store a 2-byte word in little-endian */\n{\n\t*ptr++ = (BYTE)val; val >>= 8;\n\t*ptr++ = (BYTE)val;\n}\n\nstatic void st_dword (BYTE* ptr, DWORD val)\t/* Store a 4-byte word in little-endian */\n{\n\t*ptr++ = (BYTE)val; val >>= 8;\n\t*ptr++ = (BYTE)val; val >>= 8;\n\t*ptr++ = (BYTE)val; val >>= 8;\n\t*ptr++ = (BYTE)val;\n}\n\n#if FF_FS_EXFAT\nstatic void st_qword (BYTE* ptr, QWORD val)\t/* Store an 8-byte word in little-endian */\n{\n\t*ptr++ = (BYTE)val; val >>= 8;\n\t*ptr++ = (BYTE)val; val >>= 8;\n\t*ptr++ = (BYTE)val; val >>= 8;\n\t*ptr++ = (BYTE)val; val >>= 8;\n\t*ptr++ = (BYTE)val; val >>= 8;\n\t*ptr++ = (BYTE)val; val >>= 8;\n\t*ptr++ = (BYTE)val; val >>= 8;\n\t*ptr++ = (BYTE)val;\n}\n#endif\n#endif\t/* !FF_FS_READONLY */\n\n\n\n/*-----------------------------------------------------------------------*/\n/* String functions                                                      */\n/*-----------------------------------------------------------------------*/\n\n/* Copy memory to memory */\nstatic void mem_cpy (void* dst, const void* src, UINT cnt)\n{\n\tBYTE *d = (BYTE*)dst;\n\tconst BYTE *s = (const BYTE*)src;\n\n\tif (cnt != 0) {\n\t\tdo {\n\t\t\t*d++ = *s++;\n\t\t} while (--cnt);\n\t}\n}\n\n\n/* Fill memory block */\nstatic void mem_set (void* dst, int val, UINT cnt)\n{\n\tBYTE *d = (BYTE*)dst;\n\n\tdo {\n\t\t*d++ = (BYTE)val;\n\t} while (--cnt);\n}\n\n\n/* Compare memory block */\nstatic int mem_cmp (const void* dst, const void* src, UINT cnt)\t/* ZR:same, NZ:different */\n{\n\tconst BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src;\n\tint r = 0;\n\n\tdo {\n\t\tr = *d++ - *s++;\n\t} while (--cnt && r == 0);\n\n\treturn r;\n}\n\n\n/* Check if chr is contained in the string */\nstatic int chk_chr (const char* str, int chr)\t/* NZ:contained, ZR:not contained */\n{\n\twhile (*str && *str != chr) str++;\n\treturn *str;\n}\n\n\n/* Test if the character is DBC 1st byte */\nstatic int dbc_1st (BYTE c)\n{\n#if FF_CODE_PAGE == 0\t\t/* Variable code page */\n\tif (DbcTbl && c >= DbcTbl[0]) {\n\t\tif (c <= DbcTbl[1]) return 1;\t\t\t\t\t/* 1st byte range 1 */\n\t\tif (c >= DbcTbl[2] && c <= DbcTbl[3]) return 1;\t/* 1st byte range 2 */\n\t}\n#elif FF_CODE_PAGE >= 900\t/* DBCS fixed code page */\n\tif (c >= DbcTbl[0]) {\n\t\tif (c <= DbcTbl[1]) return 1;\n\t\tif (c >= DbcTbl[2] && c <= DbcTbl[3]) return 1;\n\t}\n#else\t\t\t\t\t\t/* SBCS fixed code page */\n\tif (c != 0) return 0;\t/* Always false */\n#endif\n\treturn 0;\n}\n\n\n/* Test if the character is DBC 2nd byte */\nstatic int dbc_2nd (BYTE c)\n{\n#if FF_CODE_PAGE == 0\t\t/* Variable code page */\n\tif (DbcTbl && c >= DbcTbl[4]) {\n\t\tif (c <= DbcTbl[5]) return 1;\t\t\t\t\t/* 2nd byte range 1 */\n\t\tif (c >= DbcTbl[6] && c <= DbcTbl[7]) return 1;\t/* 2nd byte range 2 */\n\t\tif (c >= DbcTbl[8] && c <= DbcTbl[9]) return 1;\t/* 2nd byte range 3 */\n\t}\n#elif FF_CODE_PAGE >= 900\t/* DBCS fixed code page */\n\tif (c >= DbcTbl[4]) {\n\t\tif (c <= DbcTbl[5]) return 1;\n\t\tif (c >= DbcTbl[6] && c <= DbcTbl[7]) return 1;\n\t\tif (c >= DbcTbl[8] && c <= DbcTbl[9]) return 1;\n\t}\n#else\t\t\t\t\t\t/* SBCS fixed code page */\n\tif (c != 0) return 0;\t/* Always false */\n#endif\n\treturn 0;\n}\n\n\n#if FF_USE_LFN\n\n/* Get a character from TCHAR string in defined API encodeing */\nstatic DWORD tchar2uni (\t/* Returns character in UTF-16 encoding (>=0x10000 on double encoding unit, 0xFFFFFFFF on decode error) */\n\tconst TCHAR** str\t\t/* Pointer to pointer to TCHAR string in configured encoding */\n)\n{\n\tDWORD uc;\n\tconst TCHAR *p = *str;\n\n#if FF_LFN_UNICODE == 1\t\t/* UTF-16 input */\n\tWCHAR wc;\n\n\tuc = *p++;\t/* Get a unit */\n\tif (IsSurrogate(uc)) {\t/* Surrogate? */\n\t\twc = *p++;\t\t/* Get low surrogate */\n\t\tif (!IsSurrogateH(uc) || !IsSurrogateL(wc)) return 0xFFFFFFFF;\t/* Wrong surrogate? */\n\t\tuc = uc << 16 | wc;\n\t}\n\n#elif FF_LFN_UNICODE == 2\t/* UTF-8 input */\n\tBYTE b;\n\tint nf;\n\n\tuc = (BYTE)*p++;\t/* Get a unit */\n\tif (uc & 0x80) {\t/* Multiple byte code? */\n\t\tif ((uc & 0xE0) == 0xC0) {\t/* 2-byte sequence? */\n\t\t\tuc &= 0x1F; nf = 1;\n\t\t} else {\n\t\t\tif ((uc & 0xF0) == 0xE0) {\t/* 3-byte sequence? */\n\t\t\t\tuc &= 0x0F; nf = 2;\n\t\t\t} else {\n\t\t\t\tif ((uc & 0xF8) == 0xF0) {\t/* 4-byte sequence? */\n\t\t\t\t\tuc &= 0x07; nf = 3;\n\t\t\t\t} else {\t\t\t\t\t/* Wrong sequence */\n\t\t\t\t\treturn 0xFFFFFFFF;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdo {\t/* Get trailing bytes */\n\t\t\tb = (BYTE)*p++;\n\t\t\tif ((b & 0xC0) != 0x80) return 0xFFFFFFFF;\t/* Wrong sequence? */\n\t\t\tuc = uc << 6 | (b & 0x3F);\n\t\t} while (--nf != 0);\n\t\tif (uc < 0x80 || IsSurrogate(uc) || uc >= 0x110000) return 0xFFFFFFFF;\t/* Wrong code? */\n\t\tif (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF);\t/* Make a surrogate pair if needed */\n\t}\n\n#elif FF_LFN_UNICODE == 3\t/* UTF-32 input */\n\tuc = (TCHAR)*p++;\t/* Get a unit */\n\tif (uc >= 0x110000) return 0xFFFFFFFF;\t/* Wrong code? */\n\tif (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF);\t/* Make a surrogate pair if needed */\n\n#else\t\t/* ANSI/OEM input */\n\tBYTE b;\n\tWCHAR wc;\n\n\twc = (BYTE)*p++;\t\t\t/* Get a byte */\n\tif (dbc_1st((BYTE)wc)) {\t/* Is it a DBC 1st byte? */\n\t\tb = (BYTE)*p++;\t\t\t/* Get 2nd byte */\n\t\tif (!dbc_2nd(b)) return 0xFFFFFFFF;\t/* Invalid code? */\n\t\twc = (wc << 8) + b;\t\t/* Make a DBC */\n\t}\n\tif (wc != 0) {\n\t\twc = ff_oem2uni(wc, CODEPAGE);\t/* ANSI/OEM ==> Unicode */\n\t\tif (wc == 0) return 0xFFFFFFFF;\t/* Invalid code? */\n\t}\n\tuc = wc;\n\n#endif\n\t*str = p;\t/* Next read pointer */\n\treturn uc;\n}\n\n\n/* Output a TCHAR string in defined API encoding */\nstatic BYTE put_utf (\t/* Returns number of encoding units written (0:buffer overflow or wrong encoding) */\n\tDWORD chr,\t/* UTF-16 encoded character (Double encoding unit char if >=0x10000) */\n\tTCHAR* buf,\t/* Output buffer */\n\tUINT szb\t/* Size of the buffer */\n)\n{\n#if FF_LFN_UNICODE == 1\t/* UTF-16 output */\n\tWCHAR hs, wc;\n\n\ths = (WCHAR)(chr >> 16);\n\twc = (WCHAR)chr;\n\tif (hs == 0) {\t/* Single encoding unit? */\n\t\tif (szb < 1 || IsSurrogate(wc)) return 0;\t/* Buffer overflow or wrong code? */\n\t\t*buf = wc;\n\t\treturn 1;\n\t}\n\tif (szb < 2 || !IsSurrogateH(hs) || !IsSurrogateL(wc)) return 0;\t/* Buffer overflow or wrong surrogate? */\n\t*buf++ = hs;\n\t*buf++ = wc;\n\treturn 2;\n\n#elif FF_LFN_UNICODE == 2\t/* UTF-8 output */\n\tDWORD hc;\n\n\tif (chr < 0x80) {\t/* Single byte code? */\n\t\tif (szb < 1) return 0;\t/* Buffer overflow? */\n\t\t*buf = (TCHAR)chr;\n\t\treturn 1;\n\t}\n\tif (chr < 0x800) {\t/* 2-byte sequence? */\n\t\tif (szb < 2) return 0;\t/* Buffer overflow? */\n\t\t*buf++ = (TCHAR)(0xC0 | (chr >> 6 & 0x1F));\n\t\t*buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F));\n\t\treturn 2;\n\t}\n\tif (chr < 0x10000) {\t/* 3-byte sequence? */\n\t\tif (szb < 3 || IsSurrogate(chr)) return 0;\t/* Buffer overflow or wrong code? */\n\t\t*buf++ = (TCHAR)(0xE0 | (chr >> 12 & 0x0F));\n\t\t*buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F));\n\t\t*buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F));\n\t\treturn 3;\n\t}\n\t/* 4-byte sequence */\n\tif (szb < 4) return 0;\t/* Buffer overflow? */\n\thc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6;\t/* Get high 10 bits */\n\tchr = (chr & 0xFFFF) - 0xDC00;\t\t\t\t\t/* Get low 10 bits */\n\tif (hc >= 0x100000 || chr >= 0x400) return 0;\t/* Wrong surrogate? */\n\tchr = (hc | chr) + 0x10000;\n\t*buf++ = (TCHAR)(0xF0 | (chr >> 18 & 0x07));\n\t*buf++ = (TCHAR)(0x80 | (chr >> 12 & 0x3F));\n\t*buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F));\n\t*buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F));\n\treturn 4;\n\n#elif FF_LFN_UNICODE == 3\t/* UTF-32 output */\n\tDWORD hc;\n\n\tif (szb < 1) return 0;\t/* Buffer overflow? */\n\tif (chr >= 0x10000) {\t/* Out of BMP? */\n\t\thc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6;\t/* Get high 10 bits */\n\t\tchr = (chr & 0xFFFF) - 0xDC00;\t\t\t\t\t/* Get low 10 bits */\n\t\tif (hc >= 0x100000 || chr >= 0x400) return 0;\t/* Wrong surrogate? */\n\t\tchr = (hc | chr) + 0x10000;\n\t}\n\t*buf++ = (TCHAR)chr;\n\treturn 1;\n\n#else\t\t\t\t\t\t/* ANSI/OEM output */\n\tWCHAR wc;\n\n\twc = ff_uni2oem(chr, CODEPAGE);\n\tif (wc >= 0x100) {\t/* Is this a DBC? */\n\t\tif (szb < 2) return 0;\n\t\t*buf++ = (char)(wc >> 8);\t/* Store DBC 1st byte */\n\t\t*buf++ = (TCHAR)wc;\t\t\t/* Store DBC 2nd byte */\n\t\treturn 2;\n\t}\n\tif (wc == 0 || szb < 1) return 0;\t/* Invalid char or buffer overflow? */\n\t*buf++ = (TCHAR)wc;\t\t\t\t\t/* Store the character */\n\treturn 1;\n#endif\n}\n#endif\t/* FF_USE_LFN */\n\n\n#if FF_FS_REENTRANT\n/*-----------------------------------------------------------------------*/\n/* Request/Release grant to access the volume                            */\n/*-----------------------------------------------------------------------*/\nstatic int lock_fs (\t\t/* 1:Ok, 0:timeout */\n\tFATFS* fs\t\t/* Filesystem object */\n)\n{\n\treturn ff_req_grant(fs->sobj);\n}\n\n\nstatic void unlock_fs (\n\tFATFS* fs,\t\t/* Filesystem object */\n\tFRESULT res\t\t/* Result code to be returned */\n)\n{\n\tif (fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_TIMEOUT) {\n\t\tff_rel_grant(fs->sobj);\n\t}\n}\n\n#endif\n\n\n\n#if FF_FS_LOCK != 0\n/*-----------------------------------------------------------------------*/\n/* File lock control functions                                           */\n/*-----------------------------------------------------------------------*/\n\nstatic FRESULT chk_lock (\t/* Check if the file can be accessed */\n\tDIR* dp,\t\t/* Directory object pointing the file to be checked */\n\tint acc\t\t\t/* Desired access type (0:Read mode open, 1:Write mode open, 2:Delete or rename) */\n)\n{\n\tUINT i, be;\n\n\t/* Search open object table for the object */\n\tbe = 0;\n\tfor (i = 0; i < FF_FS_LOCK; i++) {\n\t\tif (Files[i].fs) {\t/* Existing entry */\n\t\t\tif (Files[i].fs == dp->obj.fs &&\t \t/* Check if the object matches with an open object */\n\t\t\t\tFiles[i].clu == dp->obj.sclust &&\n\t\t\t\tFiles[i].ofs == dp->dptr) break;\n\t\t} else {\t\t\t/* Blank entry */\n\t\t\tbe = 1;\n\t\t}\n\t}\n\tif (i == FF_FS_LOCK) {\t/* The object has not been opened */\n\t\treturn (!be && acc != 2) ? FR_TOO_MANY_OPEN_FILES : FR_OK;\t/* Is there a blank entry for new object? */\n\t}\n\n\t/* The object was opened. Reject any open against writing file and all write mode open */\n\treturn (acc != 0 || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK;\n}\n\n\nstatic int enq_lock (void)\t/* Check if an entry is available for a new object */\n{\n\tUINT i;\n\n\tfor (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ;\n\treturn (i == FF_FS_LOCK) ? 0 : 1;\n}\n\n\nstatic UINT inc_lock (\t/* Increment object open counter and returns its index (0:Internal error) */\n\tDIR* dp,\t/* Directory object pointing the file to register or increment */\n\tint acc\t\t/* Desired access (0:Read, 1:Write, 2:Delete/Rename) */\n)\n{\n\tUINT i;\n\n\n\tfor (i = 0; i < FF_FS_LOCK; i++) {\t/* Find the object */\n\t\tif (Files[i].fs == dp->obj.fs &&\n\t\t\tFiles[i].clu == dp->obj.sclust &&\n\t\t\tFiles[i].ofs == dp->dptr) break;\n\t}\n\n\tif (i == FF_FS_LOCK) {\t\t\t\t/* Not opened. Register it as new. */\n\t\tfor (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ;\n\t\tif (i == FF_FS_LOCK) return 0;\t/* No free entry to register (int err) */\n\t\tFiles[i].fs = dp->obj.fs;\n\t\tFiles[i].clu = dp->obj.sclust;\n\t\tFiles[i].ofs = dp->dptr;\n\t\tFiles[i].ctr = 0;\n\t}\n\n\tif (acc >= 1 && Files[i].ctr) return 0;\t/* Access violation (int err) */\n\n\tFiles[i].ctr = acc ? 0x100 : Files[i].ctr + 1;\t/* Set semaphore value */\n\n\treturn i + 1;\t/* Index number origin from 1 */\n}\n\n\nstatic FRESULT dec_lock (\t/* Decrement object open counter */\n\tUINT i\t\t\t/* Semaphore index (1..) */\n)\n{\n\tWORD n;\n\tFRESULT res;\n\n\n\tif (--i < FF_FS_LOCK) {\t/* Index number origin from 0 */\n\t\tn = Files[i].ctr;\n\t\tif (n == 0x100) n = 0;\t\t/* If write mode open, delete the entry */\n\t\tif (n > 0) n--;\t\t\t\t/* Decrement read mode open count */\n\t\tFiles[i].ctr = n;\n\t\tif (n == 0) Files[i].fs = 0;\t/* Delete the entry if open count gets zero */\n\t\tres = FR_OK;\n\t} else {\n\t\tres = FR_INT_ERR;\t\t\t/* Invalid index nunber */\n\t}\n\treturn res;\n}\n\n\nstatic void clear_lock (\t/* Clear lock entries of the volume */\n\tFATFS *fs\n)\n{\n\tUINT i;\n\n\tfor (i = 0; i < FF_FS_LOCK; i++) {\n\t\tif (Files[i].fs == fs) Files[i].fs = 0;\n\t}\n}\n\n#endif\t/* FF_FS_LOCK != 0 */\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Move/Flush disk access window in the filesystem object                */\n/*-----------------------------------------------------------------------*/\n#if !FF_FS_READONLY\nstatic FRESULT sync_window (\t/* Returns FR_OK or FR_DISK_ERR */\n\tFATFS* fs\t\t\t/* Filesystem object */\n)\n{\n\tFRESULT res = FR_OK;\n\n\n\tif (fs->wflag) {\t/* Is the disk access window dirty */\n\t\tif (disk_write(fs->pdrv, fs->win, fs->winsect, 1) == RES_OK) {\t/* Write back the window */\n\t\t\tfs->wflag = 0;\t/* Clear window dirty flag */\n\t\t\tif (fs->winsect - fs->fatbase < fs->fsize) {\t/* Is it in the 1st FAT? */\n\t\t\t\tif (fs->n_fats == 2) disk_write(fs->pdrv, fs->win, fs->winsect + fs->fsize, 1);\t/* Reflect it to 2nd FAT if needed */\n\t\t\t}\n\t\t} else {\n\t\t\tres = FR_DISK_ERR;\n\t\t}\n\t}\n\treturn res;\n}\n#endif\n\n\nstatic FRESULT move_window (\t/* Returns FR_OK or FR_DISK_ERR */\n\tFATFS* fs,\t\t\t/* Filesystem object */\n\tDWORD sector\t\t/* Sector number to make appearance in the fs->win[] */\n)\n{\n\tFRESULT res = FR_OK;\n\n\n\tif (sector != fs->winsect) {\t/* Window offset changed? */\n#if !FF_FS_READONLY\n\t\tres = sync_window(fs);\t\t/* Write-back changes */\n#endif\n\t\tif (res == FR_OK) {\t\t\t/* Fill sector window with new data */\n\t\t\tif (disk_read(fs->pdrv, fs->win, sector, 1) != RES_OK) {\n\t\t\t\tsector = 0xFFFFFFFF;\t/* Invalidate window if read data is not valid */\n\t\t\t\tres = FR_DISK_ERR;\n\t\t\t}\n\t\t\tfs->winsect = sector;\n\t\t}\n\t}\n\treturn res;\n}\n\n\n\n\n#if !FF_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* Synchronize filesystem and data on the storage                        */\n/*-----------------------------------------------------------------------*/\n\nstatic FRESULT sync_fs (\t/* Returns FR_OK or FR_DISK_ERR */\n\tFATFS* fs\t\t/* Filesystem object */\n)\n{\n\tFRESULT res;\n\n\n\tres = sync_window(fs);\n\tif (res == FR_OK) {\n\t\tif (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) {\t/* FAT32: Update FSInfo sector if needed */\n\t\t\t/* Create FSInfo structure */\n\t\t\tmem_set(fs->win, 0, sizeof fs->win);\n\t\t\tst_word(fs->win + BS_55AA, 0xAA55);\n\t\t\tst_dword(fs->win + FSI_LeadSig, 0x41615252);\n\t\t\tst_dword(fs->win + FSI_StrucSig, 0x61417272);\n\t\t\tst_dword(fs->win + FSI_Free_Count, fs->free_clst);\n\t\t\tst_dword(fs->win + FSI_Nxt_Free, fs->last_clst);\n\t\t\t/* Write it into the FSInfo sector */\n\t\t\tfs->winsect = fs->volbase + 1;\n\t\t\tdisk_write(fs->pdrv, fs->win, fs->winsect, 1);\n\t\t\tfs->fsi_flag = 0;\n\t\t}\n\t\t/* Make sure that no pending write process in the lower layer */\n\t\tif (disk_ioctl(fs->pdrv, CTRL_SYNC, 0) != RES_OK) res = FR_DISK_ERR;\n\t}\n\n\treturn res;\n}\n\n#endif\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Get physical sector number from cluster number                        */\n/*-----------------------------------------------------------------------*/\n\nstatic DWORD clst2sect (\t/* !=0:Sector number, 0:Failed (invalid cluster#) */\n\tFATFS* fs,\t\t/* Filesystem object */\n\tDWORD clst\t\t/* Cluster# to be converted */\n)\n{\n\tclst -= 2;\t\t/* Cluster number is origin from 2 */\n\tif (clst >= fs->n_fatent - 2) return 0;\t\t/* Is it invalid cluster number? */\n\treturn fs->database + fs->csize * clst;\t\t/* Start sector number of the cluster */\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* FAT access - Read value of a FAT entry                                */\n/*-----------------------------------------------------------------------*/\n\nstatic DWORD get_fat (\t\t/* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluster status */\n\tFFOBJID* obj,\t/* Corresponding object */\n\tDWORD clst\t\t/* Cluster number to get the value */\n)\n{\n\tUINT wc, bc;\n\tDWORD val;\n\tFATFS *fs = obj->fs;\n\n\n\tif (clst < 2 || clst >= fs->n_fatent) {\t/* Check if in valid range */\n\t\tval = 1;\t/* Internal error */\n\n\t} else {\n\t\tval = 0xFFFFFFFF;\t/* Default value falls on disk error */\n\n\t\tswitch (fs->fs_type) {\n\t\tcase FS_FAT12 :\n\t\t\tbc = (UINT)clst; bc += bc / 2;\n\t\t\tif (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break;\n\t\t\twc = fs->win[bc++ % SS(fs)];\t\t/* Get 1st byte of the entry */\n\t\t\tif (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break;\n\t\t\twc |= fs->win[bc % SS(fs)] << 8;\t/* Merge 2nd byte of the entry */\n\t\t\tval = (clst & 1) ? (wc >> 4) : (wc & 0xFFF);\t/* Adjust bit position */\n\t\t\tbreak;\n\n\t\tcase FS_FAT16 :\n\t\t\tif (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break;\n\t\t\tval = ld_word(fs->win + clst * 2 % SS(fs));\t\t/* Simple WORD array */\n\t\t\tbreak;\n\n\t\tcase FS_FAT32 :\n\t\t\tif (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break;\n\t\t\tval = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF;\t/* Simple DWORD array but mask out upper 4 bits */\n\t\t\tbreak;\n#if FF_FS_EXFAT\n\t\tcase FS_EXFAT :\n\t\t\tif ((obj->objsize != 0 && obj->sclust != 0) || obj->stat == 0) {\t/* Object except root dir must have valid data length */\n\t\t\t\tDWORD cofs = clst - obj->sclust;\t/* Offset from start cluster */\n\t\t\t\tDWORD clen = (DWORD)((obj->objsize - 1) / SS(fs)) / fs->csize;\t/* Number of clusters - 1 */\n\n\t\t\t\tif (obj->stat == 2 && cofs <= clen) {\t/* Is it a contiguous chain? */\n\t\t\t\t\tval = (cofs == clen) ? 0x7FFFFFFF : clst + 1;\t/* No data on the FAT, generate the value */\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (obj->stat == 3 && cofs < obj->n_cont) {\t/* Is it in the 1st fragment? */\n\t\t\t\t\tval = clst + 1; \t/* Generate the value */\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (obj->stat != 2) {\t/* Get value from FAT if FAT chain is valid */\n\t\t\t\t\tif (obj->n_frag != 0) {\t/* Is it on the growing edge? */\n\t\t\t\t\t\tval = 0x7FFFFFFF;\t/* Generate EOC */\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break;\n\t\t\t\t\t\tval = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t/* go to default */\n#endif\n\t\tdefault:\n\t\t\tval = 1;\t/* Internal error */\n\t\t}\n\t}\n\n\treturn val;\n}\n\n\n\n\n#if !FF_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* FAT access - Change value of a FAT entry                              */\n/*-----------------------------------------------------------------------*/\n\nstatic FRESULT put_fat (\t/* FR_OK(0):succeeded, !=0:error */\n\tFATFS* fs,\t\t/* Corresponding filesystem object */\n\tDWORD clst,\t\t/* FAT index number (cluster number) to be changed */\n\tDWORD val\t\t/* New value to be set to the entry */\n)\n{\n\tUINT bc;\n\tBYTE *p;\n\tFRESULT res = FR_INT_ERR;\n\n\n\tif (clst >= 2 && clst < fs->n_fatent) {\t/* Check if in valid range */\n\t\tswitch (fs->fs_type) {\n\t\tcase FS_FAT12 :\n\t\t\tbc = (UINT)clst; bc += bc / 2;\t/* bc: byte offset of the entry */\n\t\t\tres = move_window(fs, fs->fatbase + (bc / SS(fs)));\n\t\t\tif (res != FR_OK) break;\n\t\t\tp = fs->win + bc++ % SS(fs);\n\t\t\t*p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;\t\t/* Put 1st byte */\n\t\t\tfs->wflag = 1;\n\t\t\tres = move_window(fs, fs->fatbase + (bc / SS(fs)));\n\t\t\tif (res != FR_OK) break;\n\t\t\tp = fs->win + bc % SS(fs);\n\t\t\t*p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));\t/* Put 2nd byte */\n\t\t\tfs->wflag = 1;\n\t\t\tbreak;\n\n\t\tcase FS_FAT16 :\n\t\t\tres = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)));\n\t\t\tif (res != FR_OK) break;\n\t\t\tst_word(fs->win + clst * 2 % SS(fs), (WORD)val);\t/* Simple WORD array */\n\t\t\tfs->wflag = 1;\n\t\t\tbreak;\n\n\t\tcase FS_FAT32 :\n#if FF_FS_EXFAT\n\t\tcase FS_EXFAT :\n#endif\n\t\t\tres = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)));\n\t\t\tif (res != FR_OK) break;\n\t\t\tif (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) {\n\t\t\t\tval = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000);\n\t\t\t}\n\t\t\tst_dword(fs->win + clst * 4 % SS(fs), val);\n\t\t\tfs->wflag = 1;\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn res;\n}\n\n#endif /* !FF_FS_READONLY */\n\n\n\n\n#if FF_FS_EXFAT && !FF_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* exFAT: Accessing FAT and Allocation Bitmap                            */\n/*-----------------------------------------------------------------------*/\n\n/*--------------------------------------*/\n/* Find a contiguous free cluster block */\n/*--------------------------------------*/\n\nstatic DWORD find_bitmap (\t/* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:Disk error */\n\tFATFS* fs,\t/* Filesystem object */\n\tDWORD clst,\t/* Cluster number to scan from */\n\tDWORD ncl\t/* Number of contiguous clusters to find (1..) */\n)\n{\n\tBYTE bm, bv;\n\tUINT i;\n\tDWORD val, scl, ctr;\n\n\n\tclst -= 2;\t/* The first bit in the bitmap corresponds to cluster #2 */\n\tif (clst >= fs->n_fatent - 2) clst = 0;\n\tscl = val = clst; ctr = 0;\n\tfor (;;) {\n\t\tif (move_window(fs, fs->bitbase + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF;\n\t\ti = val / 8 % SS(fs); bm = 1 << (val % 8);\n\t\tdo {\n\t\t\tdo {\n\t\t\t\tbv = fs->win[i] & bm; bm <<= 1;\t\t/* Get bit value */\n\t\t\t\tif (++val >= fs->n_fatent - 2) {\t/* Next cluster (with wrap-around) */\n\t\t\t\t\tval = 0; bm = 0; i = SS(fs);\n\t\t\t\t}\n\t\t\t\tif (bv == 0) {\t/* Is it a free cluster? */\n\t\t\t\t\tif (++ctr == ncl) return scl + 2;\t/* Check if run length is sufficient for required */\n\t\t\t\t} else {\n\t\t\t\t\tscl = val; ctr = 0;\t\t/* Encountered a cluster in-use, restart to scan */\n\t\t\t\t}\n\t\t\t\tif (val == clst) return 0;\t/* All cluster scanned? */\n\t\t\t} while (bm != 0);\n\t\t\tbm = 1;\n\t\t} while (++i < SS(fs));\n\t}\n}\n\n\n/*----------------------------------------*/\n/* Set/Clear a block of allocation bitmap */\n/*----------------------------------------*/\n\nstatic FRESULT change_bitmap (\n\tFATFS* fs,\t/* Filesystem object */\n\tDWORD clst,\t/* Cluster number to change from */\n\tDWORD ncl,\t/* Number of clusters to be changed */\n\tint bv\t\t/* bit value to be set (0 or 1) */\n)\n{\n\tBYTE bm;\n\tUINT i;\n\tDWORD sect;\n\n\n\tclst -= 2;\t/* The first bit corresponds to cluster #2 */\n\tsect = fs->bitbase + clst / 8 / SS(fs);\t/* Sector address */\n\ti = clst / 8 % SS(fs);\t\t\t\t\t/* Byte offset in the sector */\n\tbm = 1 << (clst % 8);\t\t\t\t\t/* Bit mask in the byte */\n\tfor (;;) {\n\t\tif (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR;\n\t\tdo {\n\t\t\tdo {\n\t\t\t\tif (bv == (int)((fs->win[i] & bm) != 0)) return FR_INT_ERR;\t/* Is the bit expected value? */\n\t\t\t\tfs->win[i] ^= bm;\t/* Flip the bit */\n\t\t\t\tfs->wflag = 1;\n\t\t\t\tif (--ncl == 0) return FR_OK;\t/* All bits processed? */\n\t\t\t} while (bm <<= 1);\t\t/* Next bit */\n\t\t\tbm = 1;\n\t\t} while (++i < SS(fs));\t\t/* Next byte */\n\t\ti = 0;\n\t}\n}\n\n\n/*---------------------------------------------*/\n/* Fill the first fragment of the FAT chain    */\n/*---------------------------------------------*/\n\nstatic FRESULT fill_first_frag (\n\tFFOBJID* obj\t/* Pointer to the corresponding object */\n)\n{\n\tFRESULT res;\n\tDWORD cl, n;\n\n\n\tif (obj->stat == 3) {\t/* Has the object been changed 'fragmented' in this session? */\n\t\tfor (cl = obj->sclust, n = obj->n_cont; n; cl++, n--) {\t/* Create cluster chain on the FAT */\n\t\t\tres = put_fat(obj->fs, cl, cl + 1);\n\t\t\tif (res != FR_OK) return res;\n\t\t}\n\t\tobj->stat = 0;\t/* Change status 'FAT chain is valid' */\n\t}\n\treturn FR_OK;\n}\n\n\n/*---------------------------------------------*/\n/* Fill the last fragment of the FAT chain     */\n/*---------------------------------------------*/\n\nstatic FRESULT fill_last_frag (\n\tFFOBJID* obj,\t/* Pointer to the corresponding object */\n\tDWORD lcl,\t\t/* Last cluster of the fragment */\n\tDWORD term\t\t/* Value to set the last FAT entry */\n)\n{\n\tFRESULT res;\n\n\n\twhile (obj->n_frag > 0) {\t/* Create the chain of last fragment */\n\t\tres = put_fat(obj->fs, lcl - obj->n_frag + 1, (obj->n_frag > 1) ? lcl - obj->n_frag + 2 : term);\n\t\tif (res != FR_OK) return res;\n\t\tobj->n_frag--;\n\t}\n\treturn FR_OK;\n}\n\n#endif\t/* FF_FS_EXFAT && !FF_FS_READONLY */\n\n\n\n#if !FF_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* FAT handling - Remove a cluster chain                                 */\n/*-----------------------------------------------------------------------*/\n\nstatic FRESULT remove_chain (\t/* FR_OK(0):succeeded, !=0:error */\n\tFFOBJID* obj,\t\t/* Corresponding object */\n\tDWORD clst,\t\t\t/* Cluster to remove a chain from */\n\tDWORD pclst\t\t\t/* Previous cluster of clst (0 if entire chain) */\n)\n{\n\tFRESULT res = FR_OK;\n\tDWORD nxt;\n\tFATFS *fs = obj->fs;\n#if FF_FS_EXFAT || FF_USE_TRIM\n\tDWORD scl = clst, ecl = clst;\n#endif\n#if FF_USE_TRIM\n\tDWORD rt[2];\n#endif\n\n\tif (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR;\t/* Check if in valid range */\n\n\t/* Mark the previous cluster 'EOC' on the FAT if it exists */\n\tif (pclst != 0 && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT || obj->stat != 2)) {\n\t\tres = put_fat(fs, pclst, 0xFFFFFFFF);\n\t\tif (res != FR_OK) return res;\n\t}\n\n\t/* Remove the chain */\n\tdo {\n\t\tnxt = get_fat(obj, clst);\t\t\t/* Get cluster status */\n\t\tif (nxt == 0) break;\t\t\t\t/* Empty cluster? */\n\t\tif (nxt == 1) return FR_INT_ERR;\t/* Internal error? */\n\t\tif (nxt == 0xFFFFFFFF) return FR_DISK_ERR;\t/* Disk error? */\n\t\tif (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) {\n\t\t\tres = put_fat(fs, clst, 0);\t\t/* Mark the cluster 'free' on the FAT */\n\t\t\tif (res != FR_OK) return res;\n\t\t}\n\t\tif (fs->free_clst < fs->n_fatent - 2) {\t/* Update FSINFO */\n\t\t\tfs->free_clst++;\n\t\t\tfs->fsi_flag |= 1;\n\t\t}\n#if FF_FS_EXFAT || FF_USE_TRIM\n\t\tif (ecl + 1 == nxt) {\t/* Is next cluster contiguous? */\n\t\t\tecl = nxt;\n\t\t} else {\t\t\t\t/* End of contiguous cluster block */\n#if FF_FS_EXFAT\n\t\t\tif (fs->fs_type == FS_EXFAT) {\n\t\t\t\tres = change_bitmap(fs, scl, ecl - scl + 1, 0);\t/* Mark the cluster block 'free' on the bitmap */\n\t\t\t\tif (res != FR_OK) return res;\n\t\t\t}\n#endif\n#if FF_USE_TRIM\n\t\t\trt[0] = clst2sect(fs, scl);\t\t\t\t\t/* Start of data area freed */\n\t\t\trt[1] = clst2sect(fs, ecl) + fs->csize - 1;\t/* End of data area freed */\n\t\t\tdisk_ioctl(fs->pdrv, CTRL_TRIM, rt);\t\t/* Inform device the data in the block is no longer needed */\n#endif\n\t\t\tscl = ecl = nxt;\n\t\t}\n#endif\n\t\tclst = nxt;\t\t\t\t\t/* Next cluster */\n\t} while (clst < fs->n_fatent);\t/* Repeat while not the last link */\n\n#if FF_FS_EXFAT\n\t/* Some post processes for chain status */\n\tif (fs->fs_type == FS_EXFAT) {\n\t\tif (pclst == 0) {\t/* Has the entire chain been removed? */\n\t\t\tobj->stat = 0;\t\t/* Change the chain status 'initial' */\n\t\t} else {\n\t\t\tif (obj->stat == 0) {\t/* Is it a fragmented chain from the beginning of this session? */\n\t\t\t\tclst = obj->sclust;\t\t/* Follow the chain to check if it gets contiguous */\n\t\t\t\twhile (clst != pclst) {\n\t\t\t\t\tnxt = get_fat(obj, clst);\n\t\t\t\t\tif (nxt < 2) return FR_INT_ERR;\n\t\t\t\t\tif (nxt == 0xFFFFFFFF) return FR_DISK_ERR;\n\t\t\t\t\tif (nxt != clst + 1) break;\t/* Not contiguous? */\n\t\t\t\t\tclst++;\n\t\t\t\t}\n\t\t\t\tif (clst == pclst) {\t/* Has the chain got contiguous again? */\n\t\t\t\t\tobj->stat = 2;\t\t/* Change the chain status 'contiguous' */\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) {\t/* Was the chain fragmented in this session and got contiguous again? */\n\t\t\t\t\tobj->stat = 2;\t/* Change the chain status 'contiguous' */\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n#endif\n\treturn FR_OK;\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* FAT handling - Stretch a chain or Create a new chain                  */\n/*-----------------------------------------------------------------------*/\n\nstatic DWORD create_chain (\t/* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */\n\tFFOBJID* obj,\t\t/* Corresponding object */\n\tDWORD clst\t\t\t/* Cluster# to stretch, 0:Create a new chain */\n)\n{\n\tDWORD cs, ncl, scl;\n\tFRESULT res;\n\tFATFS *fs = obj->fs;\n\n\n\tif (clst == 0) {\t/* Create a new chain */\n\t\tscl = fs->last_clst;\t\t\t\t/* Suggested cluster to start to find */\n\t\tif (scl == 0 || scl >= fs->n_fatent) scl = 1;\n\t}\n\telse {\t\t\t\t/* Stretch a chain */\n\t\tcs = get_fat(obj, clst);\t\t\t/* Check the cluster status */\n\t\tif (cs < 2) return 1;\t\t\t\t/* Test for insanity */\n\t\tif (cs == 0xFFFFFFFF) return cs;\t/* Test for disk error */\n\t\tif (cs < fs->n_fatent) return cs;\t/* It is already followed by next cluster */\n\t\tscl = clst;\t\t\t\t\t\t\t/* Cluster to start to find */\n\t}\n\tif (fs->free_clst == 0) return 0;\t\t/* No free cluster */\n\n#if FF_FS_EXFAT\n\tif (fs->fs_type == FS_EXFAT) {\t/* On the exFAT volume */\n\t\tncl = find_bitmap(fs, scl, 1);\t\t\t\t/* Find a free cluster */\n\t\tif (ncl == 0 || ncl == 0xFFFFFFFF) return ncl;\t/* No free cluster or hard error? */\n\t\tres = change_bitmap(fs, ncl, 1, 1);\t\t\t/* Mark the cluster 'in use' */\n\t\tif (res == FR_INT_ERR) return 1;\n\t\tif (res == FR_DISK_ERR) return 0xFFFFFFFF;\n\t\tif (clst == 0) {\t\t\t\t\t\t\t/* Is it a new chain? */\n\t\t\tobj->stat = 2;\t\t\t\t\t\t\t/* Set status 'contiguous' */\n\t\t} else {\t\t\t\t\t\t\t\t\t/* It is a stretched chain */\n\t\t\tif (obj->stat == 2 && ncl != scl + 1) {\t/* Is the chain got fragmented? */\n\t\t\t\tobj->n_cont = scl - obj->sclust;\t/* Set size of the contiguous part */\n\t\t\t\tobj->stat = 3;\t\t\t\t\t\t/* Change status 'just fragmented' */\n\t\t\t}\n\t\t}\n\t\tif (obj->stat != 2) {\t/* Is the file non-contiguous? */\n\t\t\tif (ncl == clst + 1) {\t/* Is the cluster next to previous one? */\n\t\t\t\tobj->n_frag = obj->n_frag ? obj->n_frag + 1 : 2;\t/* Increment size of last framgent */\n\t\t\t} else {\t\t\t\t/* New fragment */\n\t\t\t\tif (obj->n_frag == 0) obj->n_frag = 1;\n\t\t\t\tres = fill_last_frag(obj, clst, ncl);\t/* Fill last fragment on the FAT and link it to new one */\n\t\t\t\tif (res == FR_OK) obj->n_frag = 1;\n\t\t\t}\n\t\t}\n\t} else\n#endif\n\t{\t/* On the FAT/FAT32 volume */\n\t\tncl = 0;\n\t\tif (scl == clst) {\t\t\t\t\t\t/* Stretching an existing chain? */\n\t\t\tncl = scl + 1;\t\t\t\t\t\t/* Test if next cluster is free */\n\t\t\tif (ncl >= fs->n_fatent) ncl = 2;\n\t\t\tcs = get_fat(obj, ncl);\t\t\t\t/* Get next cluster status */\n\t\t\tif (cs == 1 || cs == 0xFFFFFFFF) return cs;\t/* Test for error */\n\t\t\tif (cs != 0) {\t\t\t\t\t\t/* Not free? */\n\t\t\t\tcs = fs->last_clst;\t\t\t\t/* Start at suggested cluster if it is valid */\n\t\t\t\tif (cs >= 2 && cs < fs->n_fatent) scl = cs;\n\t\t\t\tncl = 0;\n\t\t\t}\n\t\t}\n\t\tif (ncl == 0) {\t/* The new cluster cannot be contiguous and find another fragment */\n\t\t\tncl = scl;\t/* Start cluster */\n\t\t\tfor (;;) {\n\t\t\t\tncl++;\t\t\t\t\t\t\t/* Next cluster */\n\t\t\t\tif (ncl >= fs->n_fatent) {\t\t/* Check wrap-around */\n\t\t\t\t\tncl = 2;\n\t\t\t\t\tif (ncl > scl) return 0;\t/* No free cluster found? */\n\t\t\t\t}\n\t\t\t\tcs = get_fat(obj, ncl);\t\t\t/* Get the cluster status */\n\t\t\t\tif (cs == 0) break;\t\t\t\t/* Found a free cluster? */\n\t\t\t\tif (cs == 1 || cs == 0xFFFFFFFF) return cs;\t/* Test for error */\n\t\t\t\tif (ncl == scl) return 0;\t\t/* No free cluster found? */\n\t\t\t}\n\t\t}\n\t\tres = put_fat(fs, ncl, 0xFFFFFFFF);\t\t/* Mark the new cluster 'EOC' */\n\t\tif (res == FR_OK && clst != 0) {\n\t\t\tres = put_fat(fs, clst, ncl);\t\t/* Link it from the previous one if needed */\n\t\t}\n\t}\n\n\tif (res == FR_OK) {\t\t\t/* Update FSINFO if function succeeded. */\n\t\tfs->last_clst = ncl;\n\t\tif (fs->free_clst <= fs->n_fatent - 2) fs->free_clst--;\n\t\tfs->fsi_flag |= 1;\n\t} else {\n\t\tncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1;\t/* Failed. Generate error status */\n\t}\n\n\treturn ncl;\t\t/* Return new cluster number or error status */\n}\n\n#endif /* !FF_FS_READONLY */\n\n\n\n\n#if FF_USE_FASTSEEK\n/*-----------------------------------------------------------------------*/\n/* FAT handling - Convert offset into cluster with link map table        */\n/*-----------------------------------------------------------------------*/\n\nstatic DWORD clmt_clust (\t/* <2:Error, >=2:Cluster number */\n\tFIL* fp,\t\t/* Pointer to the file object */\n\tFSIZE_t ofs\t\t/* File offset to be converted to cluster# */\n)\n{\n\tDWORD cl, ncl, *tbl;\n\tFATFS *fs = fp->obj.fs;\n\n\n\ttbl = fp->cltbl + 1;\t/* Top of CLMT */\n\tcl = (DWORD)(ofs / SS(fs) / fs->csize);\t/* Cluster order from top of the file */\n\tfor (;;) {\n\t\tncl = *tbl++;\t\t\t/* Number of cluters in the fragment */\n\t\tif (ncl == 0) return 0;\t/* End of table? (error) */\n\t\tif (cl < ncl) break;\t/* In this fragment? */\n\t\tcl -= ncl; tbl++;\t\t/* Next fragment */\n\t}\n\treturn cl + *tbl;\t/* Return the cluster number */\n}\n\n#endif\t/* FF_USE_FASTSEEK */\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Directory handling - Fill a cluster with zeros                        */\n/*-----------------------------------------------------------------------*/\n\n#if !FF_FS_READONLY\nstatic FRESULT dir_clear (\t/* Returns FR_OK or FR_DISK_ERR */\n\tFATFS *fs,\t\t/* Filesystem object */\n\tDWORD clst\t\t/* Directory table to clear */\n)\n{\n\tDWORD sect;\n\tUINT n, szb;\n\tBYTE *ibuf;\n\n\n\tif (sync_window(fs) != FR_OK) return FR_DISK_ERR;\t/* Flush disk access window */\n\tsect = clst2sect(fs, clst);\t\t/* Top of the cluster */\n\tfs->winsect = sect;\t\t\t\t/* Set window to top of the cluster */\n\tmem_set(fs->win, 0, sizeof fs->win);\t/* Clear window buffer */\n#if FF_USE_LFN == 3\t\t/* Quick table clear by using multi-secter write */\n\t/* Allocate a temporary buffer */\n\tfor (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs), ibuf = 0; szb > SS(fs) && (ibuf = ff_memalloc(szb)) == 0; szb /= 2) ;\n\tif (szb > SS(fs)) {\t\t/* Buffer allocated? */\n\t\tmem_set(ibuf, 0, szb);\n\t\tszb /= SS(fs);\t\t/* Bytes -> Sectors */\n\t\tfor (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ;\t/* Fill the cluster with 0 */\n\t\tff_memfree(ibuf);\n\t} else\n#endif\n\t{\n\t\tibuf = fs->win; szb = 1;\t/* Use window buffer (many single-sector writes may take a time) */\n\t\tfor (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ;\t/* Fill the cluster with 0 */\n\t}\n\treturn (n == fs->csize) ? FR_OK : FR_DISK_ERR;\n}\n#endif\t/* !FF_FS_READONLY */\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Directory handling - Set directory index                              */\n/*-----------------------------------------------------------------------*/\n\nstatic FRESULT dir_sdi (\t/* FR_OK(0):succeeded, !=0:error */\n\tDIR* dp,\t\t/* Pointer to directory object */\n\tDWORD ofs\t\t/* Offset of directory table */\n)\n{\n\tDWORD csz, clst;\n\tFATFS *fs = dp->obj.fs;\n\n\n\tif (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR) || ofs % SZDIRE) {\t/* Check range of offset and alignment */\n\t\treturn FR_INT_ERR;\n\t}\n\tdp->dptr = ofs;\t\t\t\t/* Set current offset */\n\tclst = dp->obj.sclust;\t\t/* Table start cluster (0:root) */\n\tif (clst == 0 && fs->fs_type >= FS_FAT32) {\t/* Replace cluster# 0 with root cluster# */\n\t\tclst = fs->dirbase;\n\t\tif (FF_FS_EXFAT) dp->obj.stat = 0;\t/* exFAT: Root dir has an FAT chain */\n\t}\n\n\tif (clst == 0) {\t/* Static table (root-directory on the FAT volume) */\n\t\tif (ofs / SZDIRE >= fs->n_rootdir) return FR_INT_ERR;\t/* Is index out of range? */\n\t\tdp->sect = fs->dirbase;\n\n\t} else {\t\t\t/* Dynamic table (sub-directory or root-directory on the FAT32/exFAT volume) */\n\t\tcsz = (DWORD)fs->csize * SS(fs);\t/* Bytes per cluster */\n\t\twhile (ofs >= csz) {\t\t\t\t/* Follow cluster chain */\n\t\t\tclst = get_fat(&dp->obj, clst);\t\t\t\t/* Get next cluster */\n\t\t\tif (clst == 0xFFFFFFFF) return FR_DISK_ERR;\t/* Disk error */\n\t\t\tif (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR;\t/* Reached to end of table or internal error */\n\t\t\tofs -= csz;\n\t\t}\n\t\tdp->sect = clst2sect(fs, clst);\n\t}\n\tdp->clust = clst;\t\t\t\t\t/* Current cluster# */\n\tif (dp->sect == 0) return FR_INT_ERR;\n\tdp->sect += ofs / SS(fs);\t\t\t/* Sector# of the directory entry */\n\tdp->dir = fs->win + (ofs % SS(fs));\t/* Pointer to the entry in the win[] */\n\n\treturn FR_OK;\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Directory handling - Move directory table index next                  */\n/*-----------------------------------------------------------------------*/\n\nstatic FRESULT dir_next (\t/* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */\n\tDIR* dp,\t\t\t\t/* Pointer to the directory object */\n\tint stretch\t\t\t\t/* 0: Do not stretch table, 1: Stretch table if needed */\n)\n{\n\tDWORD ofs, clst;\n\tFATFS *fs = dp->obj.fs;\n\n\n\tofs = dp->dptr + SZDIRE;\t/* Next entry */\n\tif (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) dp->sect = 0;\t/* Disable it if the offset reached the max value */\n\tif (dp->sect == 0) return FR_NO_FILE;\t/* Report EOT if it has been disabled */\n\n\tif (ofs % SS(fs) == 0) {\t/* Sector changed? */\n\t\tdp->sect++;\t\t\t\t/* Next sector */\n\n\t\tif (dp->clust == 0) {\t/* Static table */\n\t\t\tif (ofs / SZDIRE >= fs->n_rootdir) {\t/* Report EOT if it reached end of static table */\n\t\t\t\tdp->sect = 0; return FR_NO_FILE;\n\t\t\t}\n\t\t}\n\t\telse {\t\t\t\t\t/* Dynamic table */\n\t\t\tif ((ofs / SS(fs) & (fs->csize - 1)) == 0) {\t/* Cluster changed? */\n\t\t\t\tclst = get_fat(&dp->obj, dp->clust);\t\t/* Get next cluster */\n\t\t\t\tif (clst <= 1) return FR_INT_ERR;\t\t\t/* Internal error */\n\t\t\t\tif (clst == 0xFFFFFFFF) return FR_DISK_ERR;\t/* Disk error */\n\t\t\t\tif (clst >= fs->n_fatent) {\t\t\t\t\t/* It reached end of dynamic table */\n#if !FF_FS_READONLY\n\t\t\t\t\tif (!stretch) {\t\t\t\t\t\t\t\t/* If no stretch, report EOT */\n\t\t\t\t\t\tdp->sect = 0; return FR_NO_FILE;\n\t\t\t\t\t}\n\t\t\t\t\tclst = create_chain(&dp->obj, dp->clust);\t/* Allocate a cluster */\n\t\t\t\t\tif (clst == 0) return FR_DENIED;\t\t\t/* No free cluster */\n\t\t\t\t\tif (clst == 1) return FR_INT_ERR;\t\t\t/* Internal error */\n\t\t\t\t\tif (clst == 0xFFFFFFFF) return FR_DISK_ERR;\t/* Disk error */\n\t\t\t\t\tif (dir_clear(fs, clst) != FR_OK) return FR_DISK_ERR;\t/* Clean up the stretched table */\n\t\t\t\t\tif (FF_FS_EXFAT) dp->obj.stat |= 4;\t\t\t/* exFAT: The directory has been stretched */\n#else\n\t\t\t\t\tif (!stretch) dp->sect = 0;\t\t\t\t\t/* (this line is to suppress compiler warning) */\n\t\t\t\t\tdp->sect = 0; return FR_NO_FILE;\t\t\t/* Report EOT */\n#endif\n\t\t\t\t}\n\t\t\t\tdp->clust = clst;\t\t/* Initialize data for new cluster */\n\t\t\t\tdp->sect = clst2sect(fs, clst);\n\t\t\t}\n\t\t}\n\t}\n\tdp->dptr = ofs;\t\t\t\t\t\t/* Current entry */\n\tdp->dir = fs->win + ofs % SS(fs);\t/* Pointer to the entry in the win[] */\n\n\treturn FR_OK;\n}\n\n\n\n\n#if !FF_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* Directory handling - Reserve a block of directory entries             */\n/*-----------------------------------------------------------------------*/\n\nstatic FRESULT dir_alloc (\t/* FR_OK(0):succeeded, !=0:error */\n\tDIR* dp,\t\t\t\t/* Pointer to the directory object */\n\tUINT nent\t\t\t\t/* Number of contiguous entries to allocate */\n)\n{\n\tFRESULT res;\n\tUINT n;\n\tFATFS *fs = dp->obj.fs;\n\n\n\tres = dir_sdi(dp, 0);\n\tif (res == FR_OK) {\n\t\tn = 0;\n\t\tdo {\n\t\t\tres = move_window(fs, dp->sect);\n\t\t\tif (res != FR_OK) break;\n#if FF_FS_EXFAT\n\t\t\tif ((fs->fs_type == FS_EXFAT) ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) {\n#else\n\t\t\tif (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) {\n#endif\n\t\t\t\tif (++n == nent) break;\t/* A block of contiguous free entries is found */\n\t\t\t} else {\n\t\t\t\tn = 0;\t\t\t\t\t/* Not a blank entry. Restart to search */\n\t\t\t}\n\t\t\tres = dir_next(dp, 1);\n\t\t} while (res == FR_OK);\t/* Next entry with table stretch enabled */\n\t}\n\n\tif (res == FR_NO_FILE) res = FR_DENIED;\t/* No directory entry to allocate */\n\treturn res;\n}\n\n#endif\t/* !FF_FS_READONLY */\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* FAT: Directory handling - Load/Store start cluster number             */\n/*-----------------------------------------------------------------------*/\n\nstatic DWORD ld_clust (\t/* Returns the top cluster value of the SFN entry */\n\tFATFS* fs,\t\t\t/* Pointer to the fs object */\n\tconst BYTE* dir\t\t/* Pointer to the key entry */\n)\n{\n\tDWORD cl;\n\n\tcl = ld_word(dir + DIR_FstClusLO);\n\tif (fs->fs_type == FS_FAT32) {\n\t\tcl |= (DWORD)ld_word(dir + DIR_FstClusHI) << 16;\n\t}\n\n\treturn cl;\n}\n\n\n#if !FF_FS_READONLY\nstatic void st_clust (\n\tFATFS* fs,\t/* Pointer to the fs object */\n\tBYTE* dir,\t/* Pointer to the key entry */\n\tDWORD cl\t/* Value to be set */\n)\n{\n\tst_word(dir + DIR_FstClusLO, (WORD)cl);\n\tif (fs->fs_type == FS_FAT32) {\n\t\tst_word(dir + DIR_FstClusHI, (WORD)(cl >> 16));\n\t}\n}\n#endif\n\n\n\n#if FF_USE_LFN\n/*--------------------------------------------------------*/\n/* FAT-LFN: Compare a part of file name with an LFN entry */\n/*--------------------------------------------------------*/\n\nstatic int cmp_lfn (\t\t/* 1:matched, 0:not matched */\n\tconst WCHAR* lfnbuf,\t/* Pointer to the LFN working buffer to be compared */\n\tBYTE* dir\t\t\t\t/* Pointer to the directory entry containing the part of LFN */\n)\n{\n\tUINT i, s;\n\tWCHAR wc, uc;\n\n\n\tif (ld_word(dir + LDIR_FstClusLO) != 0) return 0;\t/* Check LDIR_FstClusLO */\n\n\ti = ((dir[LDIR_Ord] & 0x3F) - 1) * 13;\t/* Offset in the LFN buffer */\n\n\tfor (wc = 1, s = 0; s < 13; s++) {\t\t/* Process all characters in the entry */\n\t\tuc = ld_word(dir + LfnOfs[s]);\t\t/* Pick an LFN character */\n\t\tif (wc != 0) {\n\t\t\tif (i >= FF_MAX_LFN + 1 || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) {\t/* Compare it */\n\t\t\t\treturn 0;\t\t\t\t\t/* Not matched */\n\t\t\t}\n\t\t\twc = uc;\n\t\t} else {\n\t\t\tif (uc != 0xFFFF) return 0;\t\t/* Check filler */\n\t\t}\n\t}\n\n\tif ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) return 0;\t/* Last segment matched but different length */\n\n\treturn 1;\t\t/* The part of LFN matched */\n}\n\n\n#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT\n/*-----------------------------------------------------*/\n/* FAT-LFN: Pick a part of file name from an LFN entry */\n/*-----------------------------------------------------*/\n\nstatic int pick_lfn (\t/* 1:succeeded, 0:buffer overflow or invalid LFN entry */\n\tWCHAR* lfnbuf,\t\t/* Pointer to the LFN working buffer */\n\tBYTE* dir\t\t\t/* Pointer to the LFN entry */\n)\n{\n\tUINT i, s;\n\tWCHAR wc, uc;\n\n\n\tif (ld_word(dir + LDIR_FstClusLO) != 0) return 0;\t/* Check LDIR_FstClusLO is 0 */\n\n\ti = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13;\t/* Offset in the LFN buffer */\n\n\tfor (wc = 1, s = 0; s < 13; s++) {\t\t/* Process all characters in the entry */\n\t\tuc = ld_word(dir + LfnOfs[s]);\t\t/* Pick an LFN character */\n\t\tif (wc != 0) {\n\t\t\tif (i >= FF_MAX_LFN + 1) return 0;\t/* Buffer overflow? */\n\t\t\tlfnbuf[i++] = wc = uc;\t\t\t/* Store it */\n\t\t} else {\n\t\t\tif (uc != 0xFFFF) return 0;\t\t/* Check filler */\n\t\t}\n\t}\n\n\tif (dir[LDIR_Ord] & LLEF && wc != 0) {\t/* Put terminator if it is the last LFN part and not terminated */\n\t\tif (i >= FF_MAX_LFN + 1) return 0;\t/* Buffer overflow? */\n\t\tlfnbuf[i] = 0;\n\t}\n\n\treturn 1;\t\t/* The part of LFN is valid */\n}\n#endif\n\n\n#if !FF_FS_READONLY\n/*-----------------------------------------*/\n/* FAT-LFN: Create an entry of LFN entries */\n/*-----------------------------------------*/\n\nstatic void put_lfn (\n\tconst WCHAR* lfn,\t/* Pointer to the LFN */\n\tBYTE* dir,\t\t\t/* Pointer to the LFN entry to be created */\n\tBYTE ord,\t\t\t/* LFN order (1-20) */\n\tBYTE sum\t\t\t/* Checksum of the corresponding SFN */\n)\n{\n\tUINT i, s;\n\tWCHAR wc;\n\n\n\tdir[LDIR_Chksum] = sum;\t\t\t/* Set checksum */\n\tdir[LDIR_Attr] = AM_LFN;\t\t/* Set attribute. LFN entry */\n\tdir[LDIR_Type] = 0;\n\tst_word(dir + LDIR_FstClusLO, 0);\n\n\ti = (ord - 1) * 13;\t\t\t\t/* Get offset in the LFN working buffer */\n\ts = wc = 0;\n\tdo {\n\t\tif (wc != 0xFFFF) wc = lfn[i++];\t/* Get an effective character */\n\t\tst_word(dir + LfnOfs[s], wc);\t\t/* Put it */\n\t\tif (wc == 0) wc = 0xFFFF;\t\t/* Padding characters for left locations */\n\t} while (++s < 13);\n\tif (wc == 0xFFFF || !lfn[i]) ord |= LLEF;\t/* Last LFN part is the start of LFN sequence */\n\tdir[LDIR_Ord] = ord;\t\t\t/* Set the LFN order */\n}\n\n#endif\t/* !FF_FS_READONLY */\n#endif\t/* FF_USE_LFN */\n\n\n\n#if FF_USE_LFN && !FF_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* FAT-LFN: Create a Numbered SFN                                        */\n/*-----------------------------------------------------------------------*/\n\nstatic void gen_numname (\n\tBYTE* dst,\t\t\t/* Pointer to the buffer to store numbered SFN */\n\tconst BYTE* src,\t/* Pointer to SFN */\n\tconst WCHAR* lfn,\t/* Pointer to LFN */\n\tUINT seq\t\t\t/* Sequence number */\n)\n{\n\tBYTE ns[8], c;\n\tUINT i, j;\n\tWCHAR wc;\n\tDWORD sr;\n\n\n\tmem_cpy(dst, src, 11);\n\n\tif (seq > 5) {\t/* In case of many collisions, generate a hash number instead of sequential number */\n\t\tsr = seq;\n\t\twhile (*lfn) {\t/* Create a CRC as hash value */\n\t\t\twc = *lfn++;\n\t\t\tfor (i = 0; i < 16; i++) {\n\t\t\t\tsr = (sr << 1) + (wc & 1);\n\t\t\t\twc >>= 1;\n\t\t\t\tif (sr & 0x10000) sr ^= 0x11021;\n\t\t\t}\n\t\t}\n\t\tseq = (UINT)sr;\n\t}\n\n\t/* itoa (hexdecimal) */\n\ti = 7;\n\tdo {\n\t\tc = (BYTE)((seq % 16) + '0');\n\t\tif (c > '9') c += 7;\n\t\tns[i--] = c;\n\t\tseq /= 16;\n\t} while (seq);\n\tns[i] = '~';\n\n\t/* Append the number to the SFN body */\n\tfor (j = 0; j < i && dst[j] != ' '; j++) {\n\t\tif (dbc_1st(dst[j])) {\n\t\t\tif (j == i - 1) break;\n\t\t\tj++;\n\t\t}\n\t}\n\tdo {\n\t\tdst[j++] = (i < 8) ? ns[i++] : ' ';\n\t} while (j < 8);\n}\n#endif\t/* FF_USE_LFN && !FF_FS_READONLY */\n\n\n\n#if FF_USE_LFN\n/*-----------------------------------------------------------------------*/\n/* FAT-LFN: Calculate checksum of an SFN entry                           */\n/*-----------------------------------------------------------------------*/\n\nstatic BYTE sum_sfn (\n\tconst BYTE* dir\t\t/* Pointer to the SFN entry */\n)\n{\n\tBYTE sum = 0;\n\tUINT n = 11;\n\n\tdo {\n\t\tsum = (sum >> 1) + (sum << 7) + *dir++;\n\t} while (--n);\n\treturn sum;\n}\n\n#endif\t/* FF_USE_LFN */\n\n\n\n#if FF_FS_EXFAT\n/*-----------------------------------------------------------------------*/\n/* exFAT: Checksum                                                       */\n/*-----------------------------------------------------------------------*/\n\nstatic WORD xdir_sum (\t/* Get checksum of the directoly entry block */\n\tconst BYTE* dir\t\t/* Directory entry block to be calculated */\n)\n{\n\tUINT i, szblk;\n\tWORD sum;\n\n\n\tszblk = (dir[XDIR_NumSec] + 1) * SZDIRE;\t/* Number of bytes of the entry block */\n\tfor (i = sum = 0; i < szblk; i++) {\n\t\tif (i == XDIR_SetSum) {\t/* Skip 2-byte sum field */\n\t\t\ti++;\n\t\t} else {\n\t\t\tsum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + dir[i];\n\t\t}\n\t}\n\treturn sum;\n}\n\n\n\nstatic WORD xname_sum (\t/* Get check sum (to be used as hash) of the file name */\n\tconst WCHAR* name\t/* File name to be calculated */\n)\n{\n\tWCHAR chr;\n\tWORD sum = 0;\n\n\n\twhile ((chr = *name++) != 0) {\n\t\tchr = (WCHAR)ff_wtoupper(chr);\t\t/* File name needs to be up-case converted */\n\t\tsum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr & 0xFF);\n\t\tsum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr >> 8);\n\t}\n\treturn sum;\n}\n\n\n#if !FF_FS_READONLY && FF_USE_MKFS\nstatic DWORD xsum32 (\t/* Returns 32-bit checksum */\n\tBYTE  dat,\t\t\t/* Byte to be calculated (byte-by-byte processing) */\n\tDWORD sum\t\t\t/* Previous sum value */\n)\n{\n\tsum = ((sum & 1) ? 0x80000000 : 0) + (sum >> 1) + dat;\n\treturn sum;\n}\n#endif\n\n\n#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2\n/*------------------------------------------------------*/\n/* exFAT: Get object information from a directory block */\n/*------------------------------------------------------*/\n\nstatic void get_xfileinfo (\n\tBYTE* dirb,\t\t\t/* Pointer to the direcotry entry block 85+C0+C1s */\n\tFILINFO* fno\t\t/* Buffer to store the extracted file information */\n)\n{\n\tWCHAR wc, hs;\n\tUINT di, si, nc;\n\n\t/* Get file name from the entry block */\n\tsi = SZDIRE * 2;\t/* 1st C1 entry */\n\tnc = 0; hs = 0; di = 0;\n\twhile (nc < dirb[XDIR_NumName]) {\n\t\tif (si >= MAXDIRB(FF_MAX_LFN)) { di = 0; break; }\t/* Truncated directory block? */\n\t\tif ((si % SZDIRE) == 0) si += 2;\t\t/* Skip entry type field */\n\t\twc = ld_word(dirb + si); si += 2; nc++;\t/* Get a character */\n\t\tif (hs == 0 && IsSurrogate(wc)) {\t/* Is it a surrogate? */\n\t\t\ths = wc; continue;\t/* Get low surrogate */\n\t\t}\n\t\twc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di);\t/* Store it in API encoding */\n\t\tif (wc == 0) { di = 0; break; }\t/* Buffer overflow or wrong encoding? */\n\t\tdi += wc;\n\t\ths = 0;\n\t}\n\tif (hs != 0) di = 0;\t\t\t\t\t/* Broken surrogate pair? */\n\tif (di == 0) fno->fname[di++] = '?';\t/* Inaccessible object name? */\n\tfno->fname[di] = 0;\t\t\t\t\t\t/* Terminate the name */\n\tfno->altname[0] = 0;\t\t\t\t\t/* exFAT does not support SFN */\n\n\tfno->fattrib = dirb[XDIR_Attr];\t\t\t/* Attribute */\n\tfno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(dirb + XDIR_FileSize);\t/* Size */\n\tfno->ftime = ld_word(dirb + XDIR_ModTime + 0);\t/* Time */\n\tfno->fdate = ld_word(dirb + XDIR_ModTime + 2);\t/* Date */\n}\n\n#endif\t/* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */\n\n\n/*-----------------------------------*/\n/* exFAT: Get a directry entry block */\n/*-----------------------------------*/\n\nstatic FRESULT load_xdir (\t/* FR_INT_ERR: invalid entry block */\n\tDIR* dp\t\t\t\t\t/* Reading direcotry object pointing top of the entry block to load */\n)\n{\n\tFRESULT res;\n\tUINT i, sz_ent;\n\tBYTE* dirb = dp->obj.fs->dirbuf;\t/* Pointer to the on-memory direcotry entry block 85+C0+C1s */\n\n\n\t/* Load file-directory entry */\n\tres = move_window(dp->obj.fs, dp->sect);\n\tif (res != FR_OK) return res;\n\tif (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR;\t/* Invalid order */\n\tmem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE);\n\tsz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE;\n\tif (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR;\n\n\t/* Load stream-extension entry */\n\tres = dir_next(dp, 0);\n\tif (res == FR_NO_FILE) res = FR_INT_ERR;\t/* It cannot be */\n\tif (res != FR_OK) return res;\n\tres = move_window(dp->obj.fs, dp->sect);\n\tif (res != FR_OK) return res;\n\tif (dp->dir[XDIR_Type] != ET_STREAM) return FR_INT_ERR;\t/* Invalid order */\n\tmem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE);\n\tif (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR;\n\n\t/* Load file-name entries */\n\ti = 2 * SZDIRE;\t/* Name offset to load */\n\tdo {\n\t\tres = dir_next(dp, 0);\n\t\tif (res == FR_NO_FILE) res = FR_INT_ERR;\t/* It cannot be */\n\t\tif (res != FR_OK) return res;\n\t\tres = move_window(dp->obj.fs, dp->sect);\n\t\tif (res != FR_OK) return res;\n\t\tif (dp->dir[XDIR_Type] != ET_FILENAME) return FR_INT_ERR;\t/* Invalid order */\n\t\tif (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE);\n\t} while ((i += SZDIRE) < sz_ent);\n\n\t/* Sanity check (do it for only accessible object) */\n\tif (i <= MAXDIRB(FF_MAX_LFN)) {\n\t\tif (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR;\n\t}\n\treturn FR_OK;\n}\n\n\n/*------------------------------------------------------------------*/\n/* exFAT: Initialize object allocation info with loaded entry block */\n/*------------------------------------------------------------------*/\n\nstatic void init_alloc_info (\n\tFATFS* fs,\t\t/* Filesystem object */\n\tFFOBJID* obj\t/* Object allocation information to be initialized */\n)\n{\n\tobj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus);\t\t/* Start cluster */\n\tobj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize);\t/* Size */\n\tobj->stat = fs->dirbuf[XDIR_GenFlags] & 2;\t\t\t\t/* Allocation status */\n\tobj->n_frag = 0;\t\t\t\t\t\t\t\t\t\t/* No last fragment info */\n}\n\n\n\n#if !FF_FS_READONLY || FF_FS_RPATH != 0\n/*------------------------------------------------*/\n/* exFAT: Load the object's directory entry block */\n/*------------------------------------------------*/\n\nstatic FRESULT load_obj_xdir (\n\tDIR* dp,\t\t\t/* Blank directory object to be used to access containing direcotry */\n\tconst FFOBJID* obj\t/* Object with its containing directory information */\n)\n{\n\tFRESULT res;\n\n\t/* Open object containing directory */\n\tdp->obj.fs = obj->fs;\n\tdp->obj.sclust = obj->c_scl;\n\tdp->obj.stat = (BYTE)obj->c_size;\n\tdp->obj.objsize = obj->c_size & 0xFFFFFF00;\n\tdp->obj.n_frag = 0;\n\tdp->blk_ofs = obj->c_ofs;\n\n\tres = dir_sdi(dp, dp->blk_ofs);\t/* Goto object's entry block */\n\tif (res == FR_OK) {\n\t\tres = load_xdir(dp);\t\t/* Load the object's entry block */\n\t}\n\treturn res;\n}\n#endif\n\n\n#if !FF_FS_READONLY\n/*----------------------------------------*/\n/* exFAT: Store the directory entry block */\n/*----------------------------------------*/\n\nstatic FRESULT store_xdir (\n\tDIR* dp\t\t\t\t/* Pointer to the direcotry object */\n)\n{\n\tFRESULT res;\n\tUINT nent;\n\tBYTE* dirb = dp->obj.fs->dirbuf;\t/* Pointer to the direcotry entry block 85+C0+C1s */\n\n\t/* Create set sum */\n\tst_word(dirb + XDIR_SetSum, xdir_sum(dirb));\n\tnent = dirb[XDIR_NumSec] + 1;\n\n\t/* Store the direcotry entry block to the directory */\n\tres = dir_sdi(dp, dp->blk_ofs);\n\twhile (res == FR_OK) {\n\t\tres = move_window(dp->obj.fs, dp->sect);\n\t\tif (res != FR_OK) break;\n\t\tmem_cpy(dp->dir, dirb, SZDIRE);\n\t\tdp->obj.fs->wflag = 1;\n\t\tif (--nent == 0) break;\n\t\tdirb += SZDIRE;\n\t\tres = dir_next(dp, 0);\n\t}\n\treturn (res == FR_OK || res == FR_DISK_ERR) ? res : FR_INT_ERR;\n}\n\n\n\n/*-------------------------------------------*/\n/* exFAT: Create a new directory enrty block */\n/*-------------------------------------------*/\n\nstatic void create_xdir (\n\tBYTE* dirb,\t\t\t/* Pointer to the direcotry entry block buffer */\n\tconst WCHAR* lfn\t/* Pointer to the object name */\n)\n{\n\tUINT i;\n\tBYTE nc1, nlen;\n\tWCHAR wc;\n\n\n\t/* Create file-directory and stream-extension entry */\n\tmem_set(dirb, 0, 2 * SZDIRE);\n\tdirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR;\n\tdirb[1 * SZDIRE + XDIR_Type] = ET_STREAM;\n\n\t/* Create file-name entries */\n\ti = SZDIRE * 2;\t/* Top of file_name entries */\n\tnlen = nc1 = 0; wc = 1;\n\tdo {\n\t\tdirb[i++] = ET_FILENAME; dirb[i++] = 0;\n\t\tdo {\t/* Fill name field */\n\t\t\tif (wc != 0 && (wc = lfn[nlen]) != 0) nlen++;\t/* Get a character if exist */\n\t\t\tst_word(dirb + i, wc); \t\t/* Store it */\n\t\t\ti += 2;\n\t\t} while (i % SZDIRE != 0);\n\t\tnc1++;\n\t} while (lfn[nlen]);\t/* Fill next entry if any char follows */\n\n\tdirb[XDIR_NumName] = nlen;\t\t/* Set name length */\n\tdirb[XDIR_NumSec] = 1 + nc1;\t/* Set secondary count (C0 + C1s) */\n\tst_word(dirb + XDIR_NameHash, xname_sum(lfn));\t/* Set name hash */\n}\n\n#endif\t/* !FF_FS_READONLY */\n#endif\t/* FF_FS_EXFAT */\n\n\n\n#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT\n/*-----------------------------------------------------------------------*/\n/* Read an object from the directory                                     */\n/*-----------------------------------------------------------------------*/\n\n#define DIR_READ_FILE(dp) dir_read(dp, 0)\n#define DIR_READ_LABEL(dp) dir_read(dp, 1)\n\nstatic FRESULT dir_read (\n\tDIR* dp,\t\t/* Pointer to the directory object */\n\tint vol\t\t\t/* Filtered by 0:file/directory or 1:volume label */\n)\n{\n\tFRESULT res = FR_NO_FILE;\n\tFATFS *fs = dp->obj.fs;\n\tBYTE attr, b;\n#if FF_USE_LFN\n\tBYTE ord = 0xFF, sum = 0xFF;\n#endif\n\n\twhile (dp->sect) {\n\t\tres = move_window(fs, dp->sect);\n\t\tif (res != FR_OK) break;\n\t\tb = dp->dir[DIR_Name];\t/* Test for the entry type */\n\t\tif (b == 0) {\n\t\t\tres = FR_NO_FILE; break; /* Reached to end of the directory */\n\t\t}\n#if FF_FS_EXFAT\n\t\tif (fs->fs_type == FS_EXFAT) {\t/* On the exFAT volume */\n\t\t\tif (FF_USE_LABEL && vol) {\n\t\t\t\tif (b == ET_VLABEL) break;\t/* Volume label entry? */\n\t\t\t} else {\n\t\t\t\tif (b == ET_FILEDIR) {\t\t/* Start of the file entry block? */\n\t\t\t\t\tdp->blk_ofs = dp->dptr;\t/* Get location of the block */\n\t\t\t\t\tres = load_xdir(dp);\t/* Load the entry block */\n\t\t\t\t\tif (res == FR_OK) {\n\t\t\t\t\t\tdp->obj.attr = fs->dirbuf[XDIR_Attr] & AM_MASK;\t/* Get attribute */\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else\n#endif\n\t\t{\t/* On the FAT/FAT32 volume */\n\t\t\tdp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK;\t/* Get attribute */\n#if FF_USE_LFN\t\t/* LFN configuration */\n\t\t\tif (b == DDEM || b == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) {\t/* An entry without valid data */\n\t\t\t\tord = 0xFF;\n\t\t\t} else {\n\t\t\t\tif (attr == AM_LFN) {\t\t\t/* An LFN entry is found */\n\t\t\t\t\tif (b & LLEF) {\t\t\t/* Is it start of an LFN sequence? */\n\t\t\t\t\t\tsum = dp->dir[LDIR_Chksum];\n\t\t\t\t\t\tb &= (BYTE)~LLEF; ord = b;\n\t\t\t\t\t\tdp->blk_ofs = dp->dptr;\n\t\t\t\t\t}\n\t\t\t\t\t/* Check LFN validity and capture it */\n\t\t\t\t\tord = (b == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF;\n\t\t\t\t} else {\t\t\t\t\t/* An SFN entry is found */\n\t\t\t\t\tif (ord != 0 || sum != sum_sfn(dp->dir)) {\t/* Is there a valid LFN? */\n\t\t\t\t\t\tdp->blk_ofs = 0xFFFFFFFF;\t\t\t/* It has no LFN. */\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n#else\t\t/* Non LFN configuration */\n\t\t\tif (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol) {\t/* Is it a valid entry? */\n\t\t\t\tbreak;\n\t\t\t}\n#endif\n\t\t}\n\t\tres = dir_next(dp, 0);\t\t/* Next entry */\n\t\tif (res != FR_OK) break;\n\t}\n\n\tif (res != FR_OK) dp->sect = 0;\t\t/* Terminate the read operation on error or EOT */\n\treturn res;\n}\n\n#endif\t/* FF_FS_MINIMIZE <= 1 || FF_USE_LABEL || FF_FS_RPATH >= 2 */\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Directory handling - Find an object in the directory                  */\n/*-----------------------------------------------------------------------*/\n\nstatic FRESULT dir_find (\t/* FR_OK(0):succeeded, !=0:error */\n\tDIR* dp\t\t\t\t\t/* Pointer to the directory object with the file name */\n)\n{\n\tFRESULT res;\n\tFATFS *fs = dp->obj.fs;\n\tBYTE c;\n#if FF_USE_LFN\n\tBYTE a, ord, sum;\n#endif\n\n\tres = dir_sdi(dp, 0);\t\t\t/* Rewind directory object */\n\tif (res != FR_OK) return res;\n#if FF_FS_EXFAT\n\tif (fs->fs_type == FS_EXFAT) {\t/* On the exFAT volume */\n\t\tBYTE nc;\n\t\tUINT di, ni;\n\t\tWORD hash = xname_sum(fs->lfnbuf);\t\t/* Hash value of the name to find */\n\n\t\twhile ((res = DIR_READ_FILE(dp)) == FR_OK) {\t/* Read an item */\n#if FF_MAX_LFN < 255\n\t\t\tif (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue;\t\t\t/* Skip comparison if inaccessible object name */\n#endif\n\t\t\tif (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue;\t/* Skip comparison if hash mismatched */\n\t\t\tfor (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) {\t/* Compare the name */\n\t\t\t\tif ((di % SZDIRE) == 0) di += 2;\n\t\t\t\tif (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break;\n\t\t\t}\n\t\t\tif (nc == 0 && !fs->lfnbuf[ni]) break;\t/* Name matched? */\n\t\t}\n\t\treturn res;\n\t}\n#endif\n\t/* On the FAT/FAT32 volume */\n#if FF_USE_LFN\n\tord = sum = 0xFF; dp->blk_ofs = 0xFFFFFFFF;\t/* Reset LFN sequence */\n#endif\n\tdo {\n\t\tres = move_window(fs, dp->sect);\n\t\tif (res != FR_OK) break;\n\t\tc = dp->dir[DIR_Name];\n\t\tif (c == 0) { res = FR_NO_FILE; break; }\t/* Reached to end of table */\n#if FF_USE_LFN\t\t/* LFN configuration */\n\t\tdp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK;\n\t\tif (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) {\t/* An entry without valid data */\n\t\t\tord = 0xFF; dp->blk_ofs = 0xFFFFFFFF;\t/* Reset LFN sequence */\n\t\t} else {\n\t\t\tif (a == AM_LFN) {\t\t\t/* An LFN entry is found */\n\t\t\t\tif (!(dp->fn[NSFLAG] & NS_NOLFN)) {\n\t\t\t\t\tif (c & LLEF) {\t\t/* Is it start of LFN sequence? */\n\t\t\t\t\t\tsum = dp->dir[LDIR_Chksum];\n\t\t\t\t\t\tc &= (BYTE)~LLEF; ord = c;\t/* LFN start order */\n\t\t\t\t\t\tdp->blk_ofs = dp->dptr;\t/* Start offset of LFN */\n\t\t\t\t\t}\n\t\t\t\t\t/* Check validity of the LFN entry and compare it with given name */\n\t\t\t\t\tord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF;\n\t\t\t\t}\n\t\t\t} else {\t\t\t\t\t/* An SFN entry is found */\n\t\t\t\tif (ord == 0 && sum == sum_sfn(dp->dir)) break;\t/* LFN matched? */\n\t\t\t\tif (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dp->dir, dp->fn, 11)) break;\t/* SFN matched? */\n\t\t\t\tord = 0xFF; dp->blk_ofs = 0xFFFFFFFF;\t/* Reset LFN sequence */\n\t\t\t}\n\t\t}\n#else\t\t/* Non LFN configuration */\n\t\tdp->obj.attr = dp->dir[DIR_Attr] & AM_MASK;\n\t\tif (!(dp->dir[DIR_Attr] & AM_VOL) && !mem_cmp(dp->dir, dp->fn, 11)) break;\t/* Is it a valid entry? */\n#endif\n\t\tres = dir_next(dp, 0);\t/* Next entry */\n\t} while (res == FR_OK);\n\n\treturn res;\n}\n\n\n\n\n#if !FF_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* Register an object to the directory                                   */\n/*-----------------------------------------------------------------------*/\n\nstatic FRESULT dir_register (\t/* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */\n\tDIR* dp\t\t\t\t\t\t/* Target directory with object name to be created */\n)\n{\n\tFRESULT res;\n\tFATFS *fs = dp->obj.fs;\n#if FF_USE_LFN\t\t/* LFN configuration */\n\tUINT n, nlen, nent;\n\tBYTE sn[12], sum;\n\n\n\tif (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME;\t/* Check name validity */\n\tfor (nlen = 0; fs->lfnbuf[nlen]; nlen++) ;\t/* Get lfn length */\n\n#if FF_FS_EXFAT\n\tif (fs->fs_type == FS_EXFAT) {\t/* On the exFAT volume */\n\t\tnent = (nlen + 14) / 15 + 2;\t/* Number of entries to allocate (85+C0+C1s) */\n\t\tres = dir_alloc(dp, nent);\t\t/* Allocate directory entries */\n\t\tif (res != FR_OK) return res;\n\t\tdp->blk_ofs = dp->dptr - SZDIRE * (nent - 1);\t/* Set the allocated entry block offset */\n\n\t\tif (dp->obj.stat & 4) {\t\t\t/* Has the directory been stretched by new allocation? */\n\t\t\tdp->obj.stat &= ~4;\n\t\t\tres = fill_first_frag(&dp->obj);\t/* Fill the first fragment on the FAT if needed */\n\t\t\tif (res != FR_OK) return res;\n\t\t\tres = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF);\t/* Fill the last fragment on the FAT if needed */\n\t\t\tif (res != FR_OK) return res;\n\t\t\tif (dp->obj.sclust != 0) {\t\t/* Is it a sub-directory? */\n\t\t\t\tDIR dj;\n\n\t\t\t\tres = load_obj_xdir(&dj, &dp->obj);\t/* Load the object status */\n\t\t\t\tif (res != FR_OK) return res;\n\t\t\t\tdp->obj.objsize += (DWORD)fs->csize * SS(fs);\t\t\t/* Increase the directory size by cluster size */\n\t\t\t\tst_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize);\t/* Update the allocation status */\n\t\t\t\tst_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize);\n\t\t\t\tfs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1;\n\t\t\t\tres = store_xdir(&dj);\t\t\t\t/* Store the object status */\n\t\t\t\tif (res != FR_OK) return res;\n\t\t\t}\n\t\t}\n\n\t\tcreate_xdir(fs->dirbuf, fs->lfnbuf);\t/* Create on-memory directory block to be written later */\n\t\treturn FR_OK;\n\t}\n#endif\n\t/* On the FAT/FAT32 volume */\n\tmem_cpy(sn, dp->fn, 12);\n\tif (sn[NSFLAG] & NS_LOSS) {\t\t\t/* When LFN is out of 8.3 format, generate a numbered name */\n\t\tdp->fn[NSFLAG] = NS_NOLFN;\t\t/* Find only SFN */\n\t\tfor (n = 1; n < 100; n++) {\n\t\t\tgen_numname(dp->fn, sn, fs->lfnbuf, n);\t/* Generate a numbered name */\n\t\t\tres = dir_find(dp);\t\t\t\t/* Check if the name collides with existing SFN */\n\t\t\tif (res != FR_OK) break;\n\t\t}\n\t\tif (n == 100) return FR_DENIED;\t\t/* Abort if too many collisions */\n\t\tif (res != FR_NO_FILE) return res;\t/* Abort if the result is other than 'not collided' */\n\t\tdp->fn[NSFLAG] = sn[NSFLAG];\n\t}\n\n\t/* Create an SFN with/without LFNs. */\n\tnent = (sn[NSFLAG] & NS_LFN) ? (nlen + 12) / 13 + 1 : 1;\t/* Number of entries to allocate */\n\tres = dir_alloc(dp, nent);\t\t/* Allocate entries */\n\tif (res == FR_OK && --nent) {\t/* Set LFN entry if needed */\n\t\tres = dir_sdi(dp, dp->dptr - nent * SZDIRE);\n\t\tif (res == FR_OK) {\n\t\t\tsum = sum_sfn(dp->fn);\t/* Checksum value of the SFN tied to the LFN */\n\t\t\tdo {\t\t\t\t\t/* Store LFN entries in bottom first */\n\t\t\t\tres = move_window(fs, dp->sect);\n\t\t\t\tif (res != FR_OK) break;\n\t\t\t\tput_lfn(fs->lfnbuf, dp->dir, (BYTE)nent, sum);\n\t\t\t\tfs->wflag = 1;\n\t\t\t\tres = dir_next(dp, 0);\t/* Next entry */\n\t\t\t} while (res == FR_OK && --nent);\n\t\t}\n\t}\n\n#else\t/* Non LFN configuration */\n\tres = dir_alloc(dp, 1);\t\t/* Allocate an entry for SFN */\n\n#endif\n\n\t/* Set SFN entry */\n\tif (res == FR_OK) {\n\t\tres = move_window(fs, dp->sect);\n\t\tif (res == FR_OK) {\n\t\t\tmem_set(dp->dir, 0, SZDIRE);\t/* Clean the entry */\n\t\t\tmem_cpy(dp->dir + DIR_Name, dp->fn, 11);\t/* Put SFN */\n#if FF_USE_LFN\n\t\t\tdp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT);\t/* Put NT flag */\n#endif\n\t\t\tfs->wflag = 1;\n\t\t}\n\t}\n\n\treturn res;\n}\n\n#endif /* !FF_FS_READONLY */\n\n\n\n#if !FF_FS_READONLY && FF_FS_MINIMIZE == 0\n/*-----------------------------------------------------------------------*/\n/* Remove an object from the directory                                   */\n/*-----------------------------------------------------------------------*/\n\nstatic FRESULT dir_remove (\t/* FR_OK:Succeeded, FR_DISK_ERR:A disk error */\n\tDIR* dp\t\t\t\t\t/* Directory object pointing the entry to be removed */\n)\n{\n\tFRESULT res;\n\tFATFS *fs = dp->obj.fs;\n#if FF_USE_LFN\t\t/* LFN configuration */\n\tDWORD last = dp->dptr;\n\n\tres = (dp->blk_ofs == 0xFFFFFFFF) ? FR_OK : dir_sdi(dp, dp->blk_ofs);\t/* Goto top of the entry block if LFN is exist */\n\tif (res == FR_OK) {\n\t\tdo {\n\t\t\tres = move_window(fs, dp->sect);\n\t\t\tif (res != FR_OK) break;\n\t\t\tif (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {\t/* On the exFAT volume */\n\t\t\t\tdp->dir[XDIR_Type] &= 0x7F;\t/* Clear the entry InUse flag. */\n\t\t\t} else {\t\t\t\t\t\t\t\t\t/* On the FAT/FAT32 volume */\n\t\t\t\tdp->dir[DIR_Name] = DDEM;\t/* Mark the entry 'deleted'. */\n\t\t\t}\n\t\t\tfs->wflag = 1;\n\t\t\tif (dp->dptr >= last) break;\t/* If reached last entry then all entries of the object has been deleted. */\n\t\t\tres = dir_next(dp, 0);\t/* Next entry */\n\t\t} while (res == FR_OK);\n\t\tif (res == FR_NO_FILE) res = FR_INT_ERR;\n\t}\n#else\t\t\t/* Non LFN configuration */\n\n\tres = move_window(fs, dp->sect);\n\tif (res == FR_OK) {\n\t\tdp->dir[DIR_Name] = DDEM;\t/* Mark the entry 'deleted'.*/\n\t\tfs->wflag = 1;\n\t}\n#endif\n\n\treturn res;\n}\n\n#endif /* !FF_FS_READONLY && FF_FS_MINIMIZE == 0 */\n\n\n\n#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2\n/*-----------------------------------------------------------------------*/\n/* Get file information from directory entry                             */\n/*-----------------------------------------------------------------------*/\n\nstatic void get_fileinfo (\n\tDIR* dp,\t\t\t/* Pointer to the directory object */\n\tFILINFO* fno\t\t/* Pointer to the file information to be filled */\n)\n{\n\tUINT si, di;\n#if FF_USE_LFN\n\tBYTE lcf;\n\tWCHAR wc, hs;\n\tFATFS *fs = dp->obj.fs;\n#else\n\tTCHAR c;\n#endif\n\n\n\tfno->fname[0] = 0;\t\t\t/* Invaidate file info */\n\tif (dp->sect == 0) return;\t/* Exit if read pointer has reached end of directory */\n\n#if FF_USE_LFN\t\t/* LFN configuration */\n#if FF_FS_EXFAT\n\tif (fs->fs_type == FS_EXFAT) {\t/* On the exFAT volume */\n\t\tget_xfileinfo(fs->dirbuf, fno);\n\t\treturn;\n\t} else\n#endif\n\t{\t/* On the FAT/FAT32 volume */\n\t\tif (dp->blk_ofs != 0xFFFFFFFF) {\t/* Get LFN if available */\n\t\t\tsi = di = hs = 0;\n\t\t\twhile (fs->lfnbuf[si] != 0) {\n\t\t\t\twc = fs->lfnbuf[si++];\t\t/* Get an LFN character (UTF-16) */\n\t\t\t\tif (hs == 0 && IsSurrogate(wc)) {\t/* Is it a surrogate? */\n\t\t\t\t\ths = wc; continue;\t\t/* Get low surrogate */\n\t\t\t\t}\n\t\t\t\twc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di);\t/* Store it in UTF-16 or UTF-8 encoding */\n\t\t\t\tif (wc == 0) { di = 0; break; }\t/* Invalid char or buffer overflow? */\n\t\t\t\tdi += wc;\n\t\t\t\ths = 0;\n\t\t\t}\n\t\t\tif (hs != 0) di = 0;\t/* Broken surrogate pair? */\n\t\t\tfno->fname[di] = 0;\t\t/* Terminate the LFN (null string means LFN is invalid) */\n\t\t}\n\t}\n\n\tsi = di = 0;\n\twhile (si < 11) {\t\t/* Get SFN from SFN entry */\n\t\twc = dp->dir[si++];\t\t\t/* Get a char */\n\t\tif (wc == ' ') continue;\t/* Skip padding spaces */\n\t\tif (wc == RDDEM) wc = DDEM;\t/* Restore replaced DDEM character */\n\t\tif (si == 9 && di < FF_SFN_BUF) fno->altname[di++] = '.';\t/* Insert a . if extension is exist */\n#if FF_LFN_UNICODE >= 1\t/* Unicode output */\n\t\tif (dbc_1st((BYTE)wc) && si != 8 && si != 11 && dbc_2nd(dp->dir[si])) {\t/* Make a DBC if needed */\n\t\t\twc = wc << 8 | dp->dir[si++];\n\t\t}\n\t\twc = ff_oem2uni(wc, CODEPAGE);\t\t/* ANSI/OEM -> Unicode */\n\t\tif (wc == 0) { di = 0; break; }\t\t/* Wrong char in the current code page? */\n\t\twc = put_utf(wc, &fno->altname[di], FF_SFN_BUF - di);\t/* Store it in Unicode */\n\t\tif (wc == 0) { di = 0; break; }\t\t/* Buffer overflow? */\n\t\tdi += wc;\n#else\t\t\t\t\t/* ANSI/OEM output */\n\t\tfno->altname[di++] = (TCHAR)wc;\t/* Store it without any conversion */\n#endif\n\t}\n\tfno->altname[di] = 0;\t/* Terminate the SFN  (null string means SFN is invalid) */\n\n\tif (fno->fname[0] == 0) {\t/* If LFN is invalid, altname[] needs to be copied to fname[] */\n\t\tif (di == 0) {\t/* If LFN and SFN both are invalid, this object is inaccesible */\n\t\t\tfno->fname[di++] = '?';\n\t\t} else {\n\t\t\tfor (si = di = 0, lcf = NS_BODY; fno->altname[si]; si++, di++) {\t/* Copy altname[] to fname[] with case information */\n\t\t\t\twc = (WCHAR)fno->altname[si];\n\t\t\t\tif (wc == '.') lcf = NS_EXT;\n\t\t\t\tif (IsUpper(wc) && (dp->dir[DIR_NTres] & lcf)) wc += 0x20;\n\t\t\t\tfno->fname[di] = (TCHAR)wc;\n\t\t\t}\n\t\t}\n\t\tfno->fname[di] = 0;\t/* Terminate the LFN */\n\t\tif (!dp->dir[DIR_NTres]) fno->altname[0] = 0;\t/* Altname is not needed if neither LFN nor case info is exist. */\n\t}\n\n#else\t/* Non-LFN configuration */\n\tsi = di = 0;\n\twhile (si < 11) {\t\t/* Copy name body and extension */\n\t\tc = (TCHAR)dp->dir[si++];\n\t\tif (c == ' ') continue;\t\t/* Skip padding spaces */\n\t\tif (c == RDDEM) c = DDEM;\t/* Restore replaced DDEM character */\n\t\tif (si == 9) fno->fname[di++] = '.';/* Insert a . if extension is exist */\n\t\tfno->fname[di++] = c;\n\t}\n\tfno->fname[di] = 0;\n#endif\n\n\tfno->fattrib = dp->dir[DIR_Attr];\t\t\t\t\t/* Attribute */\n\tfno->fsize = ld_dword(dp->dir + DIR_FileSize);\t\t/* Size */\n\tfno->ftime = ld_word(dp->dir + DIR_ModTime + 0);\t/* Time */\n\tfno->fdate = ld_word(dp->dir + DIR_ModTime + 2);\t/* Date */\n}\n\n#endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */\n\n\n\n#if FF_USE_FIND && FF_FS_MINIMIZE <= 1\n/*-----------------------------------------------------------------------*/\n/* Pattern matching                                                      */\n/*-----------------------------------------------------------------------*/\n\nstatic DWORD get_achar (\t/* Get a character and advances ptr */\n\tconst TCHAR** ptr\t\t/* Pointer to pointer to the ANSI/OEM or Unicode string */\n)\n{\n\tDWORD chr;\n\n\n#if FF_USE_LFN && FF_LFN_UNICODE >= 1\t/* Unicode input */\n\tchr = tchar2uni(ptr);\n\tif (chr == 0xFFFFFFFF) chr = 0;\t\t/* Wrong UTF encoding is recognized as end of the string */\n\tchr = ff_wtoupper(chr);\n\n#else\t\t\t\t\t\t\t\t\t/* ANSI/OEM input */\n\tchr = (BYTE)*(*ptr)++;\t\t\t\t/* Get a byte */\n\tif (IsLower(chr)) chr -= 0x20;\t\t/* To upper ASCII char */\n#if FF_CODE_PAGE == 0\n\tif (ExCvt && chr >= 0x80) chr = ExCvt[chr - 0x80];\t/* To upper SBCS extended char */\n#elif FF_CODE_PAGE < 900\n\tif (chr >= 0x80) chr = ExCvt[chr - 0x80];\t/* To upper SBCS extended char */\n#endif\n#if FF_CODE_PAGE == 0 || FF_CODE_PAGE >= 900\n\tif (dbc_1st((BYTE)chr)) {\t/* Get DBC 2nd byte if needed */\n\t\tchr = dbc_2nd((BYTE)**ptr) ? chr << 8 | (BYTE)*(*ptr)++ : 0;\n\t}\n#endif\n\n#endif\n\treturn chr;\n}\n\n\nstatic int pattern_matching (\t/* 0:not matched, 1:matched */\n\tconst TCHAR* pat,\t/* Matching pattern */\n\tconst TCHAR* nam,\t/* String to be tested */\n\tint skip,\t\t\t/* Number of pre-skip chars (number of ?s) */\n\tint inf\t\t\t\t/* Infinite search (* specified) */\n)\n{\n\tconst TCHAR *pp, *np;\n\tDWORD pc, nc;\n\tint nm, nx;\n\n\n\twhile (skip--) {\t\t\t\t/* Pre-skip name chars */\n\t\tif (!get_achar(&nam)) return 0;\t/* Branch mismatched if less name chars */\n\t}\n\tif (*pat == 0 && inf) return 1;\t/* (short circuit) */\n\n\tdo {\n\t\tpp = pat; np = nam;\t\t\t/* Top of pattern and name to match */\n\t\tfor (;;) {\n\t\t\tif (*pp == '?' || *pp == '*') {\t/* Wildcard? */\n\t\t\t\tnm = nx = 0;\n\t\t\t\tdo {\t\t\t\t/* Analyze the wildcard block */\n\t\t\t\t\tif (*pp++ == '?') nm++; else nx = 1;\n\t\t\t\t} while (*pp == '?' || *pp == '*');\n\t\t\t\tif (pattern_matching(pp, np, nm, nx)) return 1;\t/* Test new branch (recurs upto number of wildcard blocks in the pattern) */\n\t\t\t\tnc = *np; break;\t/* Branch mismatched */\n\t\t\t}\n\t\t\tpc = get_achar(&pp);\t/* Get a pattern char */\n\t\t\tnc = get_achar(&np);\t/* Get a name char */\n\t\t\tif (pc != nc) break;\t/* Branch mismatched? */\n\t\t\tif (pc == 0) return 1;\t/* Branch matched? (matched at end of both strings) */\n\t\t}\n\t\tget_achar(&nam);\t\t\t/* nam++ */\n\t} while (inf && nc);\t\t\t/* Retry until end of name if infinite search is specified */\n\n\treturn 0;\n}\n\n#endif /* FF_USE_FIND && FF_FS_MINIMIZE <= 1 */\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Pick a top segment and create the object name in directory form       */\n/*-----------------------------------------------------------------------*/\n\nstatic FRESULT create_name (\t/* FR_OK: successful, FR_INVALID_NAME: could not create */\n\tDIR* dp,\t\t\t\t\t/* Pointer to the directory object */\n\tconst TCHAR** path\t\t\t/* Pointer to pointer to the segment in the path string */\n)\n{\n#if FF_USE_LFN\t\t/* LFN configuration */\n\tBYTE b, cf;\n\tWCHAR wc, *lfn;\n\tDWORD uc;\n\tUINT i, ni, si, di;\n\tconst TCHAR *p;\n\n\n\t/* Create LFN into LFN working buffer */\n\tp = *path; lfn = dp->obj.fs->lfnbuf; di = 0;\n\tfor (;;) {\n\t\tuc = tchar2uni(&p);\t\t\t/* Get a character */\n\t\tif (uc == 0xFFFFFFFF) return FR_INVALID_NAME;\t\t/* Invalid code or UTF decode error */\n\t\tif (uc >= 0x10000) lfn[di++] = (WCHAR)(uc >> 16);\t/* Store high surrogate if needed */\n\t\twc = (WCHAR)uc;\n\t\tif (wc < ' ' || wc == '/' || wc == '\\\\') break;\t/* Break if end of the path or a separator is found */\n\t\tif (wc < 0x80 && chk_chr(\"\\\"*:<>\\?|\\x7F\", wc)) return FR_INVALID_NAME;\t/* Reject illegal characters for LFN */\n\t\tif (di >= FF_MAX_LFN) return FR_INVALID_NAME;\t/* Reject too long name */\n\t\tlfn[di++] = wc;\t\t\t\t\t/* Store the Unicode character */\n\t}\n\twhile (*p == '/' || *p == '\\\\') p++;\t/* Skip duplicated separators if exist */\n\t*path = p;\t\t\t\t\t\t\t/* Return pointer to the next segment */\n\tcf = (wc < ' ') ? NS_LAST : 0;\t\t/* Set last segment flag if end of the path */\n\n#if FF_FS_RPATH != 0\n\tif ((di == 1 && lfn[di - 1] == '.') ||\n\t\t(di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) {\t/* Is this segment a dot name? */\n\t\tlfn[di] = 0;\n\t\tfor (i = 0; i < 11; i++) {\t\t/* Create dot name for SFN entry */\n\t\t\tdp->fn[i] = (i < di) ? '.' : ' ';\n\t\t}\n\t\tdp->fn[i] = cf | NS_DOT;\t\t/* This is a dot entry */\n\t\treturn FR_OK;\n\t}\n#endif\n\twhile (di) {\t\t\t\t\t\t/* Snip off trailing spaces and dots if exist */\n\t\twc = lfn[di - 1];\n\t\tif (wc != ' ' && wc != '.') break;\n\t\tdi--;\n\t}\n\tlfn[di] = 0;\t\t\t\t\t\t\t/* LFN is created into the working buffer */\n\tif (di == 0) return FR_INVALID_NAME;\t/* Reject null name */\n\n\t/* Create SFN in directory form */\n\tfor (si = 0; lfn[si] == ' '; si++) ;\t/* Remove leading spaces */\n\tif (si > 0 || lfn[si] == '.') cf |= NS_LOSS | NS_LFN;\t/* Is there any leading space or dot? */\n\twhile (di > 0 && lfn[di - 1] != '.') di--;\t/* Find last dot (di<=si: no extension) */\n\n\tmem_set(dp->fn, ' ', 11);\n\ti = b = 0; ni = 8;\n\tfor (;;) {\n\t\twc = lfn[si++];\t\t\t\t\t/* Get an LFN character */\n\t\tif (wc == 0) break;\t\t\t\t/* Break on end of the LFN */\n\t\tif (wc == ' ' || (wc == '.' && si != di)) {\t/* Remove embedded spaces and dots */\n\t\t\tcf |= NS_LOSS | NS_LFN;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (i >= ni || si == di) {\t\t/* End of field? */\n\t\t\tif (ni == 11) {\t\t\t\t/* Name extension overflow? */\n\t\t\t\tcf |= NS_LOSS | NS_LFN;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (si != di) cf |= NS_LOSS | NS_LFN;\t/* Name body overflow? */\n\t\t\tif (si > di) break;\t\t\t\t\t\t/* No name extension? */\n\t\t\tsi = di; i = 8; ni = 11; b <<= 2;\t\t/* Enter name extension */\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (wc >= 0x80) {\t/* Is this a non-ASCII character? */\n\t\t\tcf |= NS_LFN;\t/* LFN entry needs to be created */\n#if FF_CODE_PAGE == 0\n\t\t\tif (ExCvt) {\t/* At SBCS */\n\t\t\t\twc = ff_uni2oem(wc, CODEPAGE);\t\t\t/* Unicode ==> ANSI/OEM code */\n\t\t\t\tif (wc & 0x80) wc = ExCvt[wc & 0x7F];\t/* Convert extended character to upper (SBCS) */\n\t\t\t} else {\t\t/* At DBCS */\n\t\t\t\twc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE);\t/* Unicode ==> Upper convert ==> ANSI/OEM code */\n\t\t\t}\n#elif FF_CODE_PAGE < 900\t/* SBCS cfg */\n\t\t\twc = ff_uni2oem(wc, CODEPAGE);\t\t\t/* Unicode ==> ANSI/OEM code */\n\t\t\tif (wc & 0x80) wc = ExCvt[wc & 0x7F];\t/* Convert extended character to upper (SBCS) */\n#else\t\t\t\t\t\t/* DBCS cfg */\n\t\t\twc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE);\t/* Unicode ==> Upper convert ==> ANSI/OEM code */\n#endif\n\t\t}\n\n\t\tif (wc >= 0x100) {\t\t\t\t/* Is this a DBC? */\n\t\t\tif (i >= ni - 1) {\t\t\t/* Field overflow? */\n\t\t\t\tcf |= NS_LOSS | NS_LFN;\n\t\t\t\ti = ni; continue;\t\t/* Next field */\n\t\t\t}\n\t\t\tdp->fn[i++] = (BYTE)(wc >> 8);\t/* Put 1st byte */\n\t\t} else {\t\t\t\t\t\t/* SBC */\n\t\t\tif (wc == 0 || chk_chr(\"+,;=[]\", wc)) {\t/* Replace illegal characters for SFN if needed */\n\t\t\t\twc = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */\n\t\t\t} else {\n\t\t\t\tif (IsUpper(wc)) {\t\t/* ASCII upper case? */\n\t\t\t\t\tb |= 2;\n\t\t\t\t}\n\t\t\t\tif (IsLower(wc)) {\t\t/* ASCII lower case? */\n\t\t\t\t\tb |= 1; wc -= 0x20;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdp->fn[i++] = (BYTE)wc;\n\t}\n\n\tif (dp->fn[0] == DDEM) dp->fn[0] = RDDEM;\t/* If the first character collides with DDEM, replace it with RDDEM */\n\n\tif (ni == 8) b <<= 2;\t\t\t\t/* Shift capital flags if no extension */\n\tif ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) cf |= NS_LFN;\t/* LFN entry needs to be created if composite capitals */\n\tif (!(cf & NS_LFN)) {\t\t\t\t/* When LFN is in 8.3 format without extended character, NT flags are created */\n\t\tif (b & 0x01) cf |= NS_EXT;\t\t/* NT flag (Extension has small capital letters only) */\n\t\tif (b & 0x04) cf |= NS_BODY;\t/* NT flag (Body has small capital letters only) */\n\t}\n\n\tdp->fn[NSFLAG] = cf;\t/* SFN is created into dp->fn[] */\n\n\treturn FR_OK;\n\n\n#else\t/* FF_USE_LFN : Non-LFN configuration */\n\tBYTE c, d, *sfn;\n\tUINT ni, si, i;\n\tconst char *p;\n\n\t/* Create file name in directory form */\n\tp = *path; sfn = dp->fn;\n\tmem_set(sfn, ' ', 11);\n\tsi = i = 0; ni = 8;\n#if FF_FS_RPATH != 0\n\tif (p[si] == '.') { /* Is this a dot entry? */\n\t\tfor (;;) {\n\t\t\tc = (BYTE)p[si++];\n\t\t\tif (c != '.' || si >= 3) break;\n\t\t\tsfn[i++] = c;\n\t\t}\n\t\tif (c != '/' && c != '\\\\' && c > ' ') return FR_INVALID_NAME;\n\t\t*path = p + si;\t\t\t\t\t\t\t\t/* Return pointer to the next segment */\n\t\tsfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT;\t/* Set last segment flag if end of the path */\n\t\treturn FR_OK;\n\t}\n#endif\n\tfor (;;) {\n\t\tc = (BYTE)p[si++];\t\t\t\t/* Get a byte */\n\t\tif (c <= ' ') break; \t\t\t/* Break if end of the path name */\n\t\tif (c == '/' || c == '\\\\') {\t/* Break if a separator is found */\n\t\t\twhile (p[si] == '/' || p[si] == '\\\\') si++;\t/* Skip duplicated separator if exist */\n\t\t\tbreak;\n\t\t}\n\t\tif (c == '.' || i >= ni) {\t\t/* End of body or field overflow? */\n\t\t\tif (ni == 11 || c != '.') return FR_INVALID_NAME;\t/* Field overflow or invalid dot? */\n\t\t\ti = 8; ni = 11;\t\t\t\t/* Enter file extension field */\n\t\t\tcontinue;\n\t\t}\n#if FF_CODE_PAGE == 0\n\t\tif (ExCvt && c >= 0x80) {\t\t/* Is SBC extended character? */\n\t\t\tc = ExCvt[c & 0x7F];\t\t/* To upper SBC extended character */\n\t\t}\n#elif FF_CODE_PAGE < 900\n\t\tif (c >= 0x80) {\t\t\t\t/* Is SBC extended character? */\n\t\t\tc = ExCvt[c & 0x7F];\t\t/* To upper SBC extended character */\n\t\t}\n#endif\n\t\tif (dbc_1st(c)) {\t\t\t\t/* Check if it is a DBC 1st byte */\n\t\t\td = (BYTE)p[si++];\t\t\t/* Get 2nd byte */\n\t\t\tif (!dbc_2nd(d) || i >= ni - 1) return FR_INVALID_NAME;\t/* Reject invalid DBC */\n\t\t\tsfn[i++] = c;\n\t\t\tsfn[i++] = d;\n\t\t} else {\t\t\t\t\t\t/* SBC */\n\t\t\tif (chk_chr(\"\\\"*+,:;<=>\\?[]|\\x7F\", c)) return FR_INVALID_NAME;\t/* Reject illegal chrs for SFN */\n\t\t\tif (IsLower(c)) c -= 0x20;\t/* To upper */\n\t\t\tsfn[i++] = c;\n\t\t}\n\t}\n\t*path = p + si;\t\t\t\t\t\t/* Return pointer to the next segment */\n\tif (i == 0) return FR_INVALID_NAME;\t/* Reject nul string */\n\n\tif (sfn[0] == DDEM) sfn[0] = RDDEM;\t/* If the first character collides with DDEM, replace it with RDDEM */\n\tsfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0;\t\t/* Set last segment flag if end of the path */\n\n\treturn FR_OK;\n#endif /* FF_USE_LFN */\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Follow a file path                                                    */\n/*-----------------------------------------------------------------------*/\n\nstatic FRESULT follow_path (\t/* FR_OK(0): successful, !=0: error code */\n\tDIR* dp,\t\t\t\t\t/* Directory object to return last directory and found object */\n\tconst TCHAR* path\t\t\t/* Full-path string to find a file or directory */\n)\n{\n\tFRESULT res;\n\tBYTE ns;\n\tFATFS *fs = dp->obj.fs;\n\n\n#if FF_FS_RPATH != 0\n\tif (*path != '/' && *path != '\\\\') {\t/* Without heading separator */\n\t\tdp->obj.sclust = fs->cdir;\t\t\t\t/* Start from current directory */\n\t} else\n#endif\n\t{\t\t\t\t\t\t\t\t\t\t/* With heading separator */\n\t\twhile (*path == '/' || *path == '\\\\') path++;\t/* Strip heading separator */\n\t\tdp->obj.sclust = 0;\t\t\t\t\t/* Start from root directory */\n\t}\n#if FF_FS_EXFAT\n\tdp->obj.n_frag = 0;\t/* Invalidate last fragment counter of the object */\n#if FF_FS_RPATH != 0\n\tif (fs->fs_type == FS_EXFAT && dp->obj.sclust) {\t/* exFAT: Retrieve the sub-directory's status */\n\t\tDIR dj;\n\n\t\tdp->obj.c_scl = fs->cdc_scl;\n\t\tdp->obj.c_size = fs->cdc_size;\n\t\tdp->obj.c_ofs = fs->cdc_ofs;\n\t\tres = load_obj_xdir(&dj, &dp->obj);\n\t\tif (res != FR_OK) return res;\n\t\tdp->obj.objsize = ld_dword(fs->dirbuf + XDIR_FileSize);\n\t\tdp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2;\n\t}\n#endif\n#endif\n\n\tif ((UINT)*path < ' ') {\t\t\t\t/* Null path name is the origin directory itself */\n\t\tdp->fn[NSFLAG] = NS_NONAME;\n\t\tres = dir_sdi(dp, 0);\n\n\t} else {\t\t\t\t\t\t\t\t/* Follow path */\n\t\tfor (;;) {\n\t\t\tres = create_name(dp, &path);\t/* Get a segment name of the path */\n\t\t\tif (res != FR_OK) break;\n\t\t\tres = dir_find(dp);\t\t\t\t/* Find an object with the segment name */\n\t\t\tns = dp->fn[NSFLAG];\n\t\t\tif (res != FR_OK) {\t\t\t\t/* Failed to find the object */\n\t\t\t\tif (res == FR_NO_FILE) {\t/* Object is not found */\n\t\t\t\t\tif (FF_FS_RPATH && (ns & NS_DOT)) {\t/* If dot entry is not exist, stay there */\n\t\t\t\t\t\tif (!(ns & NS_LAST)) continue;\t/* Continue to follow if not last segment */\n\t\t\t\t\t\tdp->fn[NSFLAG] = NS_NONAME;\n\t\t\t\t\t\tres = FR_OK;\n\t\t\t\t\t} else {\t\t\t\t\t\t\t/* Could not find the object */\n\t\t\t\t\t\tif (!(ns & NS_LAST)) res = FR_NO_PATH;\t/* Adjust error code if not last segment */\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (ns & NS_LAST) break;\t\t\t/* Last segment matched. Function completed. */\n\t\t\t/* Get into the sub-directory */\n\t\t\tif (!(dp->obj.attr & AM_DIR)) {\t\t/* It is not a sub-directory and cannot follow */\n\t\t\t\tres = FR_NO_PATH; break;\n\t\t\t}\n#if FF_FS_EXFAT\n\t\t\tif (fs->fs_type == FS_EXFAT) {\t\t/* Save containing directory information for next dir */\n\t\t\t\tdp->obj.c_scl = dp->obj.sclust;\n\t\t\t\tdp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat;\n\t\t\t\tdp->obj.c_ofs = dp->blk_ofs;\n\t\t\t\tinit_alloc_info(fs, &dp->obj);\t/* Open next directory */\n\t\t\t} else\n#endif\n\t\t\t{\n\t\t\t\tdp->obj.sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs));\t/* Open next directory */\n\t\t\t}\n\t\t}\n\t}\n\n\treturn res;\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Get logical drive number from path name                               */\n/*-----------------------------------------------------------------------*/\n\nstatic int get_ldnumber (\t/* Returns logical drive number (-1:invalid drive number or null pointer) */\n\tconst TCHAR** path\t\t/* Pointer to pointer to the path name */\n)\n{\n\tconst TCHAR *tp, *tt;\n\tTCHAR tc;\n\tint i, vol = -1;\n#if FF_STR_VOLUME_ID\t\t/* Find string volume ID */\n\tconst char *sp;\n\tchar c;\n#endif\n\n\ttt = tp = *path;\n\tif (!tp) return vol;\t/* Invalid path name? */\n\tdo tc = *tt++; while ((UINT)tc >= (FF_USE_LFN ? ' ' : '!') && tc != ':');\t/* Find a colon in the path */\n\n\tif (tc == ':') {\t/* DOS/Windows style volume ID? */\n\t\ti = FF_VOLUMES;\n\t\tif (IsDigit(*tp) && tp + 2 == tt) {\t/* Is there a numeric volume ID + colon? */\n\t\t\ti = (int)*tp - '0';\t/* Get the LD number */\n\t\t}\n#if FF_STR_VOLUME_ID == 1\t/* Arbitrary string is enabled */\n\t\telse {\n\t\t\ti = 0;\n\t\t\tdo {\n\t\t\t\tsp = VolumeStr[i]; tp = *path;\t/* This string volume ID and path name */\n\t\t\t\tdo {\t/* Compare the volume ID with path name */\n\t\t\t\t\tc = *sp++; tc = *tp++;\n\t\t\t\t\tif (IsLower(c)) c -= 0x20;\n\t\t\t\t\tif (IsLower(tc)) tc -= 0x20;\n\t\t\t\t} while (c && (TCHAR)c == tc);\n\t\t\t} while ((c || tp != tt) && ++i < FF_VOLUMES);\t/* Repeat for each id until pattern match */\n\t\t}\n#endif\n\t\tif (i < FF_VOLUMES) {\t/* If a volume ID is found, get the drive number and strip it */\n\t\t\tvol = i;\t\t/* Drive number */\n\t\t\t*path = tt;\t\t/* Snip the drive prefix off */\n\t\t}\n\t\treturn vol;\n\t}\n#if FF_STR_VOLUME_ID == 2\t\t/* Unix style volume ID is enabled */\n\tif (*tp == '/') {\n\t\ti = 0;\n\t\tdo {\n\t\t\tsp = VolumeStr[i]; tp = *path;\t/* This string volume ID and path name */\n\t\t\tdo {\t/* Compare the volume ID with path name */\n\t\t\t\tc = *sp++; tc = *(++tp);\n\t\t\t\tif (IsLower(c)) c -= 0x20;\n\t\t\t\tif (IsLower(tc)) tc -= 0x20;\n\t\t\t} while (c && (TCHAR)c == tc);\n\t\t} while ((c || (tc != '/' && (UINT)tc >= (FF_USE_LFN ? ' ' : '!'))) && ++i < FF_VOLUMES);\t/* Repeat for each ID until pattern match */\n\t\tif (i < FF_VOLUMES) {\t/* If a volume ID is found, get the drive number and strip it */\n\t\t\tvol = i;\t\t/* Drive number */\n\t\t\t*path = tp;\t\t/* Snip the drive prefix off */\n\t\t\treturn vol;\n\t\t}\n\t}\n#endif\n\t/* No drive prefix is found */\n#if FF_FS_RPATH != 0\n\tvol = CurrVol;\t/* Default drive is current drive */\n#else\n\tvol = 0;\t\t/* Default drive is 0 */\n#endif\n\treturn vol;\t\t/* Return the default drive */\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Load a sector and check if it is an FAT VBR                           */\n/*-----------------------------------------------------------------------*/\n\nstatic BYTE check_fs (\t/* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */\n\tFATFS* fs,\t\t\t/* Filesystem object */\n\tDWORD sect\t\t\t/* Sector# (lba) to load and check if it is an FAT-VBR or not */\n)\n{\n\tfs->wflag = 0; fs->winsect = 0xFFFFFFFF;\t\t/* Invaidate window */\n\tif (move_window(fs, sect) != FR_OK) return 4;\t/* Load boot record */\n\n\tif (ld_word(fs->win + BS_55AA) != 0xAA55) return 3;\t/* Check boot record signature (always here regardless of the sector size) */\n\n#if FF_FS_EXFAT\n\tif (!mem_cmp(fs->win + BS_JmpBoot, \"\\xEB\\x76\\x90\" \"EXFAT   \", 11)) return 1;\t/* Check if exFAT VBR */\n#endif\n\tif (fs->win[BS_JmpBoot] == 0xE9 || fs->win[BS_JmpBoot] == 0xEB || fs->win[BS_JmpBoot] == 0xE8) {\t/* Valid JumpBoot code? */\n\t\tif (!mem_cmp(fs->win + BS_FilSysType, \"FAT\", 3)) return 0;\t\t/* Is it an FAT VBR? */\n\t\tif (!mem_cmp(fs->win + BS_FilSysType32, \"FAT32\", 5)) return 0;\t/* Is it an FAT32 VBR? */\n\t}\n\treturn 2;\t/* Valid BS but not FAT */\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Determine logical drive number and mount the volume if needed         */\n/*-----------------------------------------------------------------------*/\n\nstatic FRESULT find_volume (\t/* FR_OK(0): successful, !=0: an error occurred */\n\tconst TCHAR** path,\t\t\t/* Pointer to pointer to the path name (drive number) */\n\tFATFS** rfs,\t\t\t\t/* Pointer to pointer to the found filesystem object */\n\tBYTE mode\t\t\t\t\t/* !=0: Check write protection for write access */\n)\n{\n\tBYTE fmt, *pt;\n\tint vol;\n\tDSTATUS stat;\n\tDWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4];\n\tWORD nrsv;\n\tFATFS *fs;\n\tUINT i;\n\n\n\t/* Get logical drive number */\n\t*rfs = 0;\n\tvol = get_ldnumber(path);\n\tif (vol < 0) return FR_INVALID_DRIVE;\n\n\t/* Check if the filesystem object is valid or not */\n\tfs = FatFs[vol];\t\t\t\t\t/* Get pointer to the filesystem object */\n\tif (!fs) return FR_NOT_ENABLED;\t\t/* Is the filesystem object available? */\n#if FF_FS_REENTRANT\n\tif (!lock_fs(fs)) return FR_TIMEOUT;\t/* Lock the volume */\n#endif\n\t*rfs = fs;\t\t\t\t\t\t\t/* Return pointer to the filesystem object */\n\n\tmode &= (BYTE)~FA_READ;\t\t\t\t/* Desired access mode, write access or not */\n\tif (fs->fs_type != 0) {\t\t\t\t/* If the volume has been mounted */\n\t\tstat = disk_status(fs->pdrv);\n\t\tif (!(stat & STA_NOINIT)) {\t\t/* and the physical drive is kept initialized */\n\t\t\tif (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) {\t/* Check write protection if needed */\n\t\t\t\treturn FR_WRITE_PROTECTED;\n\t\t\t}\n\t\t\treturn FR_OK;\t\t\t\t/* The filesystem object is valid */\n\t\t}\n\t}\n\n\t/* The filesystem object is not valid. */\n\t/* Following code attempts to mount the volume. (analyze BPB and initialize the filesystem object) */\n\n\tfs->fs_type = 0;\t\t\t\t\t/* Clear the filesystem object */\n\tfs->part_type = 0;\t\t\t\t\t/* Clear the Partition object */\n\tfs->pdrv = LD2PD(vol);\t\t\t\t/* Bind the logical drive and a physical drive */\n\tstat = disk_initialize(fs->pdrv);\t/* Initialize the physical drive */\n\tif (stat & STA_NOINIT) { \t\t\t/* Check if the initialization succeeded */\n\t\treturn FR_NOT_READY;\t\t\t/* Failed to initialize due to no medium or hard error */\n\t}\n\tif (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */\n\t\treturn FR_WRITE_PROTECTED;\n\t}\n#if FF_MAX_SS != FF_MIN_SS\t\t\t\t/* Get sector size (multiple sector size cfg only) */\n\tif (disk_ioctl(fs->pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR;\n\tif (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR;\n#endif\n\n\t/* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK (MBR) and SFD (w/o partition). */\n\tbsect = 0;\n\tfmt = check_fs(fs, bsect);\t\t\t/* Load sector 0 and check if it is an FAT-VBR as SFD */\n\tif (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) {\t/* Not an FAT-VBR or forced partition number */\n\t\tfor (i = 0; i < 4; i++) {\t\t/* Get partition offset */\n\t\t\tpt = fs->win + (MBR_Table + i * SZ_PTE);\n\t\t\tbr[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0;\n\t\t}\n\t\ti = LD2PT(vol);\t\t\t\t\t/* Partition number: 0:auto, 1-4:forced */\n\t\tif (i != 0) i--;\n\t\tdo {\t\t\t\t\t\t\t/* Find an FAT volume */\n\t\t\tbsect = br[i];\n\t\t\tfmt = bsect ? check_fs(fs, bsect) : 3;\t/* Check the partition */\n\t\t} while (LD2PT(vol) == 0 && fmt >= 2 && ++i < 4);\n\t}\n\tif (fmt == 4) {\n\t\tEFSPRINTF(\"BRNL\");\n\t\treturn FR_DISK_ERR;\t\t/* An error occured in the disk I/O layer */\n\t}\n#if FF_SIMPLE_GPT\n\tif (fmt >= 2) {\n\t\t/* If GPT Check the first partition */\n\t\tgpt_header_t *gpt_header = (gpt_header_t *)fs->win;\n\t\tif (move_window(fs, 1) != FR_OK) return FR_DISK_ERR;\n\t\tif (!mem_cmp(&gpt_header->signature, \"EFI PART\", 8)) {\n\t\t\tif (move_window(fs, gpt_header->part_ent_lba) != FR_OK) return FR_DISK_ERR;\n\t\t\tgpt_entry_t *gpt_entry = (gpt_entry_t *)fs->win;\n\t\t\tfs->part_type = 1;\n\t\t\tbsect = gpt_entry->lba_start;\n\t\t\tfmt = bsect ? check_fs(fs, bsect) : 3;\t/* Check the partition */\n\t\t}\n\t}\n#endif\n\tif (fmt >= 2) {\n\t\tEFSPRINTF(\"NOFAT\");\n\t\treturn FR_NO_FILESYSTEM;\t/* No FAT volume is found */\n\t}\n\n\t/* An FAT volume is found (bsect). Following code initializes the filesystem object */\n\n#if FF_FS_EXFAT\n\tif (fmt == 1) {\n\t\tQWORD maxlba;\n\t\tDWORD so, cv, bcl;\n\n\t\tfor (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ;\t/* Check zero filler */\n\t\tif (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM;\n\n\t\tif (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM;\t/* Check exFAT version (must be version 1.0) */\n\n\t\tif (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) {\t/* (BPB_BytsPerSecEx must be equal to the physical sector size) */\n\t\t\tEFSPRINTF(\"EXSPS\");\n\t\t\treturn FR_NO_FILESYSTEM;\n\t\t}\n\n\t\tmaxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect;\t/* Last LBA + 1 of the volume */\n\t\tif (maxlba >= 0x100000000) return FR_NO_FILESYSTEM;\t/* (It cannot be handled in 32-bit LBA) */\n\n\t\tfs->fsize = ld_dword(fs->win + BPB_FatSzEx);\t/* Number of sectors per FAT */\n\n\t\tfs->n_fats = fs->win[BPB_NumFATsEx];\t\t\t/* Number of FATs */\n\t\tif (fs->n_fats != 1) {\n\t\t\tEFSPRINTF(\"EXFNF\");\n\t\t\treturn FR_NO_FILESYSTEM;\t/* (Supports only 1 FAT) */\n\t\t}\n\n\t\tfs->csize = 1 << fs->win[BPB_SecPerClusEx];\t\t/* Cluster size */\n\t\tif (fs->csize == 0)\treturn FR_NO_FILESYSTEM;\t/* (Must be 1..32768) */\n\n\t\tnclst = ld_dword(fs->win + BPB_NumClusEx);\t\t/* Number of clusters */\n\t\tif (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM;\t/* (Too many clusters) */\n\t\tfs->n_fatent = nclst + 2;\n\n\t\t/* Boundaries and Limits */\n\t\tfs->volbase = bsect;\n\t\tfs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx);\n\t\tfs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx);\n\t\tif (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM;\t/* (Volume size must not be smaller than the size requiered) */\n\t\tfs->dirbase = ld_dword(fs->win + BPB_RootClusEx);\n\n\t\t/* Get bitmap location and check if it is contiguous (implementation assumption) */\n\t\tso = i = 0;\n\t\tfor (;;) {\t/* Find the bitmap entry in the root directory (in only first cluster) */\n\t\t\tif (i == 0) {\n\t\t\t\tif (so >= fs->csize) return FR_NO_FILESYSTEM;\t/* Not found? */\n\t\t\t\tif (move_window(fs, clst2sect(fs, fs->dirbase) + so) != FR_OK) {\n\t\t\t\t\tEFSPRINTF(\"EXBM1C\");\n\t\t\t\t\treturn FR_DISK_ERR;\n\t\t\t\t}\n\t\t\t\tso++;\n\t\t\t}\n\t\t\tif (fs->win[i] == ET_BITMAP) break;\t\t\t\t/* Is it a bitmap entry? */\n\t\t\ti = (i + SZDIRE) % SS(fs);\t/* Next entry */\n\t\t}\n\t\tbcl = ld_dword(fs->win + i + 20);\t\t\t\t\t/* Bitmap cluster */\n\t\tif (bcl < 2 || bcl >= fs->n_fatent) {\n\t\t\tEFSPRINTF(\"EXBMM\");\n\t\t\treturn FR_NO_FILESYSTEM;\n\t\t}\n\t\tfs->bitbase = fs->database + fs->csize * (bcl - 2);\t/* Bitmap sector */\n\t\tfor (;;) {\t/* Check if bitmap is contiguous */\n\t\t\tif (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR;\n\t\t\tcv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4);\n\t\t\tif (cv == 0xFFFFFFFF) break;\t\t\t\t/* Last link? */\n\t\t\tif (cv != ++bcl) {\n\t\t\t\tEFSPRINTF(\"EXBMM\");\n\t\t\t\treturn FR_NO_FILESYSTEM;\t/* Fragmented? */\n\t\t\t}\n\t\t}\n\n#if !FF_FS_READONLY\n\t\tfs->last_clst = fs->free_clst = 0xFFFFFFFF;\t\t/* Initialize cluster allocation information */\n#endif\n\t\tfmt = FS_EXFAT;\t\t\t/* FAT sub-type */\n\t} else\n#endif\t/* FF_FS_EXFAT */\n\t{\n\t\tif (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) {\n\t\t\tEFSPRINTF(\"32SPS\");\n\t\t\treturn FR_NO_FILESYSTEM;\t/* (BPB_BytsPerSec must be equal to the physical sector size) */\n\t\t}\n\n\t\tfasize = ld_word(fs->win + BPB_FATSz16);\t\t/* Number of sectors per FAT */\n\t\tif (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32);\n\t\tfs->fsize = fasize;\n\n\t\tfs->n_fats = fs->win[BPB_NumFATs];\t\t\t\t/* Number of FATs */\n\t\tif (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM;\t/* (Must be 1 or 2) */\n\t\tfasize *= fs->n_fats;\t\t\t\t\t\t\t/* Number of sectors for FAT area */\n\n\t\tfs->csize = fs->win[BPB_SecPerClus];\t\t\t/* Cluster size */\n\t\tif (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM;\t/* (Must be power of 2) */\n\n\t\tfs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt);\t/* Number of root directory entries */\n\t\tif (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM;\t/* (Must be sector aligned) */\n\n\t\ttsect = ld_word(fs->win + BPB_TotSec16);\t\t/* Number of sectors on the volume */\n\t\tif (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32);\n\n\t\tnrsv = ld_word(fs->win + BPB_RsvdSecCnt);\t\t/* Number of reserved sectors */\n\t\tif (nrsv == 0) return FR_NO_FILESYSTEM;\t\t\t/* (Must not be 0) */\n\n\t\t/* Determine the FAT sub type */\n\t\tsysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE);\t/* RSV + FAT + DIR */\n\t\tif (tsect < sysect) return FR_NO_FILESYSTEM;\t/* (Invalid volume size) */\n\t\tnclst = (tsect - sysect) / fs->csize;\t\t\t/* Number of clusters */\n\t\tif (nclst == 0) return FR_NO_FILESYSTEM;\t\t/* (Invalid volume size) */\n\t\tfmt = 0;\n\t\tif (nclst <= MAX_FAT32) fmt = FS_FAT32;\n\t\tif (nclst <= MAX_FAT16) fmt = FS_FAT16;\n\t\tif (nclst <= MAX_FAT12) fmt = FS_FAT12;\n\t\tif (fmt == 0) return FR_NO_FILESYSTEM;\n\n\t\t/* Boundaries and Limits */\n\t\tfs->n_fatent = nclst + 2;\t\t\t\t\t\t/* Number of FAT entries */\n\t\tfs->volbase = bsect;\t\t\t\t\t\t\t/* Volume start sector */\n\t\tfs->fatbase = bsect + nrsv; \t\t\t\t\t/* FAT start sector */\n\t\tfs->database = bsect + sysect;\t\t\t\t\t/* Data start sector */\n\t\tif (fmt == FS_FAT32) {\n\t\t\tif (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM;\t/* (Must be FAT32 revision 0.0) */\n\t\t\tif (fs->n_rootdir != 0) return FR_NO_FILESYSTEM;\t/* (BPB_RootEntCnt must be 0) */\n\t\t\tfs->dirbase = ld_dword(fs->win + BPB_RootClus32);\t/* Root directory start cluster */\n\t\t\tszbfat = fs->n_fatent * 4;\t\t\t\t\t/* (Needed FAT size) */\n\t\t} else {\n\t\t\tif (fs->n_rootdir == 0)\treturn FR_NO_FILESYSTEM;\t/* (BPB_RootEntCnt must not be 0) */\n\t\t\tfs->dirbase = fs->fatbase + fasize;\t\t\t/* Root directory start sector */\n\t\t\tszbfat = (fmt == FS_FAT16) ?\t\t\t\t/* (Needed FAT size) */\n\t\t\t\tfs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);\n\t\t}\n\t\tif (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM;\t/* (BPB_FATSz must not be less than the size needed) */\n\n#if !FF_FS_READONLY\n\t\t/* Get FSInfo if available */\n\t\tfs->last_clst = fs->free_clst = 0xFFFFFFFF;\t\t/* Initialize cluster allocation information */\n\t\tfs->fsi_flag = 0x80;\n#if (FF_FS_NOFSINFO & 3) != 3\n\t\tif (fmt == FS_FAT32\t\t\t\t/* Allow to update FSInfo only if BPB_FSInfo32 == 1 */\n\t\t\t&& ld_word(fs->win + BPB_FSInfo32) == 1\n\t\t\t&& move_window(fs, bsect + 1) == FR_OK)\n\t\t{\n\t\t\tfs->fsi_flag = 0;\n\t\t\tif (ld_word(fs->win + BS_55AA) == 0xAA55\t/* Load FSInfo data if available */\n\t\t\t\t&& ld_dword(fs->win + FSI_LeadSig) == 0x41615252\n\t\t\t\t&& ld_dword(fs->win + FSI_StrucSig) == 0x61417272)\n\t\t\t{\n#if (FF_FS_NOFSINFO & 1) == 0\n\t\t\t\tfs->free_clst = ld_dword(fs->win + FSI_Free_Count);\n#endif\n#if (FF_FS_NOFSINFO & 2) == 0\n\t\t\t\tfs->last_clst = ld_dword(fs->win + FSI_Nxt_Free);\n#endif\n\t\t\t}\n\t\t}\n#endif\t/* (FF_FS_NOFSINFO & 3) != 3 */\n#endif\t/* !FF_FS_READONLY */\n\t}\n\n\tfs->fs_type = fmt;\t\t/* FAT sub-type */\n\tfs->id = ++Fsid;\t\t/* Volume mount ID */\n#if FF_USE_LFN == 1\n\tfs->lfnbuf = LfnBuf;\t/* Static LFN working buffer */\n#if FF_FS_EXFAT\n\tfs->dirbuf = DirBuf;\t/* Static directory block scratchpad buffer */\n#endif\n#endif\n#if FF_FS_RPATH != 0\n\tfs->cdir = 0;\t\t\t/* Initialize current directory */\n#endif\n#if FF_FS_LOCK != 0\t\t\t/* Clear file lock semaphores */\n\tclear_lock(fs);\n#endif\n\treturn FR_OK;\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Check if the file/directory object is valid or not                    */\n/*-----------------------------------------------------------------------*/\n\nstatic FRESULT validate (\t/* Returns FR_OK or FR_INVALID_OBJECT */\n\tFFOBJID* obj,\t\t\t/* Pointer to the FFOBJID, the 1st member in the FIL/DIR object, to check validity */\n\tFATFS** rfs\t\t\t\t/* Pointer to pointer to the owner filesystem object to return */\n)\n{\n\tFRESULT res = FR_INVALID_OBJECT;\n\n\n\tif (obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id) {\t/* Test if the object is valid */\n#if FF_FS_REENTRANT\n\t\tif (lock_fs(obj->fs)) {\t/* Obtain the filesystem object */\n\t\t\tif (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */\n\t\t\t\tres = FR_OK;\n\t\t\t} else {\n\t\t\t\tunlock_fs(obj->fs, FR_OK);\n\t\t\t}\n\t\t} else {\n\t\t\tres = FR_TIMEOUT;\n\t\t}\n#else\n\t\tif (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */\n\t\t\tres = FR_OK;\n\t\t}\n#endif\n\t}\n\t*rfs = (res == FR_OK) ? obj->fs : 0;\t/* Corresponding filesystem object */\n\treturn res;\n}\n\n\n\n\n/*---------------------------------------------------------------------------\n\n   Public Functions (FatFs API)\n\n----------------------------------------------------------------------------*/\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Mount/Unmount a Logical Drive                                         */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_mount (\n\tFATFS* fs,\t\t\t/* Pointer to the filesystem object (NULL:unmount)*/\n\tconst TCHAR* path,\t/* Logical drive number to be mounted/unmounted */\n\tBYTE opt\t\t\t/* Mode option 0:Do not mount (delayed mount), 1:Mount immediately */\n)\n{\n\tFATFS *cfs;\n\tint vol;\n\tFRESULT res;\n\tconst TCHAR *rp = path;\n\n\n\t/* Get logical drive number */\n\tvol = get_ldnumber(&rp);\n\tif (vol < 0) {\n\t\tEFSPRINTF(\"IDRIVE!\");\n\t\treturn FR_INVALID_DRIVE;\n\t}\n\tcfs = FatFs[vol];\t\t\t\t\t/* Pointer to fs object */\n\n\tif (cfs) {\n#if FF_FS_LOCK != 0\n\t\tclear_lock(cfs);\n#endif\n#if FF_FS_REENTRANT\t\t\t\t\t\t/* Discard sync object of the current volume */\n\t\tif (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR;\n#endif\n\t\tcfs->fs_type = 0;\t\t\t\t/* Clear old fs object */\n\t}\n\n\tif (fs) {\n\t\tfs->fs_type = 0;\t\t\t\t/* Clear new fs object */\n#if FF_FS_REENTRANT\t\t\t\t\t\t/* Create sync object for the new volume */\n\t\tif (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR;\n#endif\n\t}\n\tFatFs[vol] = fs;\t\t\t\t\t/* Register new fs object */\n\n\tif (opt == 0) return FR_OK;\t\t\t/* Do not mount now, it will be mounted later */\n\n\tres = find_volume(&path, &fs, 0);\t/* Force mounted the volume */\n\tLEAVE_FF(fs, res);\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Open or Create a File                                                 */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_open (\n\tFIL* fp,\t\t\t/* Pointer to the blank file object */\n\tconst TCHAR* path,\t/* Pointer to the file name */\n\tBYTE mode\t\t\t/* Access mode and file open mode flags */\n)\n{\n\tFRESULT res;\n\tDIR dj;\n\tFATFS *fs;\n#if !FF_FS_READONLY\n\tDWORD dw, cl, bcs, clst, sc;\n\tFSIZE_t ofs;\n#endif\n\tDEF_NAMBUF\n\n\n\tif (!fp) return FR_INVALID_OBJECT;\n\n\t/* Get logical drive number */\n\tmode &= FF_FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND;\n\tres = find_volume(&path, &fs, mode);\n\tif (res == FR_OK) {\n\t\tdj.obj.fs = fs;\n\t\tINIT_NAMBUF(fs);\n\t\tres = follow_path(&dj, path);\t/* Follow the file path */\n#if !FF_FS_READONLY\t/* Read/Write configuration */\n\t\tif (res == FR_OK) {\n\t\t\tif (dj.fn[NSFLAG] & NS_NONAME) {\t/* Origin directory itself? */\n\t\t\t\tres = FR_INVALID_NAME;\n\t\t\t}\n#if FF_FS_LOCK != 0\n\t\t\telse {\n\t\t\t\tres = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0);\t\t/* Check if the file can be used */\n\t\t\t}\n#endif\n\t\t}\n\t\t/* Create or Open a file */\n\t\tif (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {\n\t\t\tif (res != FR_OK) {\t\t\t\t\t/* No file, create new */\n\t\t\t\tif (res == FR_NO_FILE) {\t\t/* There is no file to open, create a new entry */\n#if FF_FS_LOCK != 0\n\t\t\t\t\tres = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES;\n#else\n\t\t\t\t\tres = dir_register(&dj);\n#endif\n\t\t\t\t}\n\t\t\t\tmode |= FA_CREATE_ALWAYS;\t\t/* File is created */\n\t\t\t}\n\t\t\telse {\t\t\t\t\t\t\t\t/* Any object with the same name is already existing */\n\t\t\t\tif (dj.obj.attr & (AM_RDO | AM_DIR)) {\t/* Cannot overwrite it (R/O or DIR) */\n\t\t\t\t\tres = FR_DENIED;\n\t\t\t\t} else {\n\t\t\t\t\tif (mode & FA_CREATE_NEW) res = FR_EXIST;\t/* Cannot create as new file */\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (res == FR_OK && (mode & FA_CREATE_ALWAYS)) {\t/* Truncate the file if overwrite mode */\n#if FF_FS_EXFAT\n\t\t\t\tif (fs->fs_type == FS_EXFAT) {\n\t\t\t\t\t/* Get current allocation info */\n\t\t\t\t\tfp->obj.fs = fs;\n\t\t\t\t\tinit_alloc_info(fs, &fp->obj);\n\t\t\t\t\t/* Set directory entry block initial state */\n\t\t\t\t\tmem_set(fs->dirbuf + 2, 0, 30);\t\t/* Clear 85 entry except for NumSec */\n\t\t\t\t\tmem_set(fs->dirbuf + 38, 0, 26);\t/* Clear C0 entry except for NumName and NameHash */\n\t\t\t\t\tfs->dirbuf[XDIR_Attr] = AM_ARC;\n\t\t\t\t\tst_dword(fs->dirbuf + XDIR_CrtTime, GET_FATTIME());\n\t\t\t\t\tfs->dirbuf[XDIR_GenFlags] = 1;\n\t\t\t\t\tres = store_xdir(&dj);\n\t\t\t\t\tif (res == FR_OK && fp->obj.sclust != 0) {\t/* Remove the cluster chain if exist */\n\t\t\t\t\t\tres = remove_chain(&fp->obj, fp->obj.sclust, 0);\n\t\t\t\t\t\tfs->last_clst = fp->obj.sclust - 1;\t\t/* Reuse the cluster hole */\n\t\t\t\t\t}\n\t\t\t\t} else\n#endif\n\t\t\t\t{\n\t\t\t\t\t/* Set directory entry initial state */\n\t\t\t\t\tcl = ld_clust(fs, dj.dir);\t\t\t/* Get current cluster chain */\n\t\t\t\t\tst_dword(dj.dir + DIR_CrtTime, GET_FATTIME());\t/* Set created time */\n\t\t\t\t\tdj.dir[DIR_Attr] = AM_ARC;\t\t\t/* Reset attribute */\n\t\t\t\t\tst_clust(fs, dj.dir, 0);\t\t\t/* Reset file allocation info */\n\t\t\t\t\tst_dword(dj.dir + DIR_FileSize, 0);\n\t\t\t\t\tfs->wflag = 1;\n\t\t\t\t\tif (cl != 0) {\t\t\t\t\t\t/* Remove the cluster chain if exist */\n\t\t\t\t\t\tdw = fs->winsect;\n\t\t\t\t\t\tres = remove_chain(&dj.obj, cl, 0);\n\t\t\t\t\t\tif (res == FR_OK) {\n\t\t\t\t\t\t\tres = move_window(fs, dw);\n\t\t\t\t\t\t\tfs->last_clst = cl - 1;\t\t/* Reuse the cluster hole */\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\t/* Open an existing file */\n\t\t\tif (res == FR_OK) {\t\t\t\t\t/* Is the object exsiting? */\n\t\t\t\tif (dj.obj.attr & AM_DIR) {\t\t/* File open against a directory */\n\t\t\t\t\tres = FR_NO_FILE;\n\t\t\t\t} else {\n\t\t\t\t\tif ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) { /* Write mode open against R/O file */\n\t\t\t\t\t\tres = FR_DENIED;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (res == FR_OK) {\n\t\t\tif (mode & FA_CREATE_ALWAYS) mode |= FA_MODIFIED;\t/* Set file change flag if created or overwritten */\n\t\t\tfp->dir_sect = fs->winsect;\t\t\t/* Pointer to the directory entry */\n\t\t\tfp->dir_ptr = dj.dir;\n#if FF_FS_LOCK != 0\n\t\t\tfp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0);\t/* Lock the file for this session */\n\t\t\tif (fp->obj.lockid == 0) res = FR_INT_ERR;\n#endif\n\t\t}\n#else\t\t/* R/O configuration */\n\t\tif (res == FR_OK) {\n\t\t\tif (dj.fn[NSFLAG] & NS_NONAME) {\t/* Is it origin directory itself? */\n\t\t\t\tres = FR_INVALID_NAME;\n\t\t\t} else {\n\t\t\t\tif (dj.obj.attr & AM_DIR) {\t\t/* Is it a directory? */\n\t\t\t\t\tres = FR_NO_FILE;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n#endif\n\n\t\tif (res == FR_OK) {\n#if FF_FS_EXFAT\n\t\t\tif (fs->fs_type == FS_EXFAT) {\n\t\t\t\tfp->obj.c_scl = dj.obj.sclust;\t\t\t\t\t\t\t/* Get containing directory info */\n\t\t\t\tfp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat;\n\t\t\t\tfp->obj.c_ofs = dj.blk_ofs;\n\t\t\t\tinit_alloc_info(fs, &fp->obj);\n\t\t\t} else\n#endif\n\t\t\t{\n\t\t\t\tfp->obj.sclust = ld_clust(fs, dj.dir);\t\t\t\t\t/* Get object allocation info */\n\t\t\t\tfp->obj.objsize = ld_dword(dj.dir + DIR_FileSize);\n\t\t\t}\n#if FF_USE_FASTSEEK\n\t\t\tfp->cltbl = 0;\t\t\t/* Disable fast seek mode */\n#endif\n\t\t\tfp->obj.fs = fs;\t \t/* Validate the file object */\n\t\t\tfp->obj.id = fs->id;\n\t\t\tfp->flag = mode;\t\t/* Set file access mode */\n\t\t\tfp->err = 0;\t\t\t/* Clear error flag */\n\t\t\tfp->sect = 0;\t\t\t/* Invalidate current data sector */\n\t\t\tfp->fptr = 0;\t\t\t/* Set file pointer top of the file */\n#if !FF_FS_READONLY\n#if !FF_FS_TINY\n\t\t\tmem_set(fp->buf, 0, sizeof fp->buf);\t/* Clear sector buffer */\n#endif\n\t\t\tif ((mode & FA_SEEKEND) && fp->obj.objsize > 0) {\t/* Seek to end of file if FA_OPEN_APPEND is specified */\n\t\t\t\tfp->fptr = fp->obj.objsize;\t\t\t/* Offset to seek */\n\t\t\t\tbcs = (DWORD)fs->csize * SS(fs);\t/* Cluster size in byte */\n\t\t\t\tclst = fp->obj.sclust;\t\t\t\t/* Follow the cluster chain */\n\t\t\t\tfor (ofs = fp->obj.objsize; res == FR_OK && ofs > bcs; ofs -= bcs) {\n\t\t\t\t\tclst = get_fat(&fp->obj, clst);\n\t\t\t\t\tif (clst <= 1) res = FR_INT_ERR;\n\t\t\t\t\tif (clst == 0xFFFFFFFF) res = FR_DISK_ERR;\n\t\t\t\t}\n\t\t\t\tfp->clust = clst;\n\t\t\t\tif (res == FR_OK && ofs % SS(fs)) {\t/* Fill sector buffer if not on the sector boundary */\n\t\t\t\t\tif ((sc = clst2sect(fs, clst)) == 0) {\n\t\t\t\t\t\tres = FR_INT_ERR;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfp->sect = sc + (DWORD)(ofs / SS(fs));\n#if !FF_FS_TINY\n\t\t\t\t\t\tif (disk_read(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR;\n#endif\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n#endif\n\t\t}\n\n\t\tFREE_NAMBUF();\n\t}\n\n\tif (res != FR_OK) fp->obj.fs = 0;\t/* Invalidate file object on error */\n\n\tLEAVE_FF(fs, res);\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Read File                                                             */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_read (\n\tFIL* fp, \t/* Pointer to the file object */\n\tvoid* buff,\t/* Pointer to data buffer */\n\tUINT btr,\t/* Number of bytes to read */\n\tUINT* br\t/* Pointer to number of bytes read */\n)\n{\n\tFRESULT res;\n\tFATFS *fs;\n\tDWORD clst, sect;\n\tFSIZE_t remain;\n\tUINT rcnt, cc, csect;\n\tBYTE *rbuff = (BYTE*)buff;\n\n\tUINT br_tmp;\n\tif (!br)\n\t\tbr = &br_tmp;\n\t*br = 0;\t/* Clear read byte counter */\n\tres = validate(&fp->obj, &fs);\t\t\t\t/* Check validity of the file object */\n\tif (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {\n\t\tEFSPRINTF(\"FOV\");\n\t\tLEAVE_FF(fs, res);\t/* Check validity */\n\t}\n\tif (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */\n\tremain = fp->obj.objsize - fp->fptr;\n\tif (btr > remain) btr = (UINT)remain;\t\t/* Truncate btr by remaining bytes */\n\n\tfor ( ;  btr;\t\t\t\t\t\t\t\t/* Repeat until btr bytes read */\n\t\tbtr -= rcnt, *br += rcnt, rbuff += rcnt, fp->fptr += rcnt) {\n\t\tif (fp->fptr % SS(fs) == 0) {\t\t\t/* On the sector boundary? */\n\t\t\tcsect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1));\t/* Sector offset in the cluster */\n\t\t\tif (csect == 0) {\t\t\t\t\t/* On the cluster boundary? */\n\t\t\t\tif (fp->fptr == 0) {\t\t\t/* On the top of the file? */\n\t\t\t\t\tclst = fp->obj.sclust;\t\t/* Follow cluster chain from the origin */\n\t\t\t\t} else {\t\t\t\t\t\t/* Middle or end of the file */\n#if FF_USE_FASTSEEK\n\t\t\t\t\tif (fp->cltbl) {\n\t\t\t\t\t\tclst = clmt_clust(fp, fp->fptr);\t/* Get cluster# from the CLMT */\n\t\t\t\t\t} else\n#endif\n\t\t\t\t\t{\n\t\t\t\t\t\tclst = get_fat(&fp->obj, fp->clust);\t/* Follow cluster chain on the FAT */\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (clst < 2) {\n\t\t\t\t\tEFSPRINTF(\"CCHK\");\n\t\t\t\t\tABORT(fs, FR_INT_ERR);\n\t\t\t\t}\n\t\t\t\tif (clst == 0xFFFFFFFF) {\n\t\t\t\t\tEFSPRINTF(\"DSKC\");\n\t\t\t\t\tABORT(fs, FR_DISK_ERR);\n\t\t\t\t}\n\t\t\t\tfp->clust = clst;\t\t\t\t/* Update current cluster */\n\t\t\t}\n\t\t\tsect = clst2sect(fs, fp->clust);\t/* Get current sector */\n\t\t\tif (sect == 0) ABORT(fs, FR_INT_ERR);\n\t\t\tsect += csect;\n\t\t\tcc = btr / SS(fs);\t\t\t\t\t/* When remaining bytes >= sector size, */\n\t\t\tif (cc > 0) {\t\t\t\t\t\t/* Read maximum contiguous sectors directly */\n\t\t\t\tif (csect + cc > fs->csize) {\t/* Clip at cluster boundary */\n\t\t\t\t\tcc = fs->csize - csect;\n\t\t\t\t}\n\t\t\t\tif (disk_read(fs->pdrv, rbuff, sect, cc) != RES_OK) {\n\t\t\t\t\tEFSPRINTF(\"RLIO\");\n\t\t\t\t\tABORT(fs, FR_DISK_ERR);\n\t\t\t\t}\n#if !FF_FS_READONLY && FF_FS_MINIMIZE <= 2\t\t/* Replace one of the read sectors with cached data if it contains a dirty sector */\n#if FF_FS_TINY\n\t\t\t\tif (fs->wflag && fs->winsect - sect < cc) {\n\t\t\t\t\tmem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs));\n\t\t\t\t}\n#else\n\t\t\t\tif ((fp->flag & FA_DIRTY) && fp->sect - sect < cc) {\n\t\t\t\t\tmem_cpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs));\n\t\t\t\t}\n#endif\n#endif\n\t\t\t\trcnt = SS(fs) * cc;\t\t\t\t/* Number of bytes transferred */\n\t\t\t\tcontinue;\n\t\t\t}\n#if !FF_FS_TINY\n\t\t\tif (fp->sect != sect) {\t\t\t/* Load data sector if not in cache */\n#if !FF_FS_READONLY\n\t\t\t\tif (fp->flag & FA_DIRTY) {\t\t/* Write-back dirty sector cache */\n\t\t\t\t\tif (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) {\n\t\t\t\t\t\tEFSPRINTF(\"RDC\");\n\t\t\t\t\t\tABORT(fs, FR_DISK_ERR);\n\t\t\t\t\t}\n\t\t\t\t\tfp->flag &= (BYTE)~FA_DIRTY;\n\t\t\t\t}\n#endif\n\t\t\t\tif (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) {\n\t\t\t\t\tEFSPRINTF(\"RSC\");\n\t\t\t\t\tABORT(fs, FR_DISK_ERR);\t/* Fill sector cache */\n\t\t\t\t}\n\t\t\t}\n#endif\n\t\t\tfp->sect = sect;\n\t\t}\n\t\trcnt = SS(fs) - (UINT)fp->fptr % SS(fs);\t/* Number of bytes left in the sector */\n\t\tif (rcnt > btr) rcnt = btr;\t\t\t\t\t/* Clip it by btr if needed */\n#if FF_FS_TINY\n\t\tif (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR);\t/* Move sector window */\n\t\tmem_cpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt);\t/* Extract partial sector */\n#else\n\t\tmem_cpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt);\t/* Extract partial sector */\n#endif\n\t}\n\n\tLEAVE_FF(fs, FR_OK);\n}\n\n\n\n\n#if FF_FASTFS && FF_USE_FASTSEEK\n/*-----------------------------------------------------------------------*/\n/* Fast Read Aligned Sized File Without a Cache                         */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_read_fast (\n\tFIL* fp,\t\t\t/* Pointer to the file object */\n\tconst void* buff,\t/* Pointer to the data to be written */\n\tUINT btr\t\t\t/* Number of bytes to read */\n)\n{\n\tFRESULT res;\n\tFATFS *fs;\n\tUINT csize_bytes, count;\n\tDWORD clst, work_bytes;\n\tFSIZE_t work_sector = 0;\n\tFSIZE_t sector_base = 0;\n\tBYTE *wbuff = (BYTE*)buff;\n\n\tres = validate(&fp->obj, &fs);\t\t\t/* Check validity of the file object */\n\tif (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {\n\t\tEFSPRINTF(\"FOV\");\n\t\tLEAVE_FF(fs, res);\t/* Check validity */\n\t}\n\n\tif (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */\n\tFSIZE_t remain = fp->obj.objsize - fp->fptr;\n\tif (btr > remain) btr = (UINT)remain;\t\t/* Truncate btr by remaining bytes */\n\tif (!btr)\n\t\tgoto out;\n\n\tcsize_bytes = fs->csize * SS(fs);\n\n\t//!TODO: support sector reading inside a cluster\n\tDWORD csect = (UINT)((fp->fptr / SS(fs)) & (fs->csize - 1));\t/* Sector offset in the cluster */\n\tif (csect) { EFSPRINTF(\"ICSR\"); ABORT(fs, FR_INT_ERR); }\n\n\tif (!fp->fptr) {\t/* On the top of the file? */\n\t\tclst = fp->obj.sclust;\t/* Follow from the origin */\n\t} else {\n\t\tif (fp->cltbl) clst = clmt_clust(fp, fp->fptr);\t/* Get cluster# from the CLMT */\n\t\telse { EFSPRINTF(\"CLTBL\"); ABORT(fs, FR_CLTBL_NO_INIT); }\n\t}\n\tif (clst < 2) { EFSPRINTF(\"CCHK\"); ABORT(fs, FR_INT_ERR); }\n\telse if (clst == 0xFFFFFFFF) { EFSPRINTF(\"DSKC\"); ABORT(fs, FR_DISK_ERR); }\n\n\tfp->clust = clst;\t/* Set working cluster */\n\n\tsector_base = clst2sect(fs, fp->clust);\n\twork_bytes = MIN(btr, csize_bytes);\n\tcount = work_bytes / SS(fs);\n\tfp->fptr += work_bytes;\n\tbtr -= work_bytes;\n\n\twhile (btr) {\n\t\tclst = clmt_clust(fp, fp->fptr);\t/* Get cluster# from the CLMT */\n\n\t\tif (clst < 2) { EFSPRINTF(\"CCHK2\"); ABORT(fs, FR_INT_ERR); }\n\t\telse if (clst == 0xFFFFFFFF) { EFSPRINTF(\"DSKC\"); ABORT(fs, FR_DISK_ERR); }\n\n\t\tfp->clust = clst;\n\n\t\twork_sector = clst2sect(fs, fp->clust);\n\t\twork_bytes = MIN(btr, csize_bytes);\n\t\tif ((work_sector - sector_base) == count) count += work_bytes / SS(fs);\n\t\telse {\n\t\t\tif (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR);\n\t\t\twbuff += count * SS(fs);\n\n\t\t\tsector_base = work_sector;\n\t\t\tcount = work_bytes / SS(fs);\n\t\t}\n\n\t\tfp->fptr += work_bytes;\n\t\tbtr -= work_bytes;\n\t}\n\n\tif (!btr) {\t/* Final cluster/sectors read. */\n\t\tif (work_bytes % SS(fs))\n\t\t\tcount++; /* Read an extra block. Expects buffer being big enough. */\n\t\tif (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR);\n\t}\n\nout:\n\tLEAVE_FF(fs, FR_OK);\n}\n#endif\n\n\n\n\n#if !FF_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* Write File                                                            */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_write (\n\tFIL* fp,\t\t\t/* Pointer to the file object */\n\tconst void* buff,\t/* Pointer to the data to be written */\n\tUINT btw,\t\t\t/* Number of bytes to write */\n\tUINT* bw\t\t\t/* Pointer to number of bytes written */\n)\n{\n\tFRESULT res;\n\tFATFS *fs;\n\tDWORD clst, sect;\n\tUINT wcnt, cc, csect;\n\tconst BYTE *wbuff = (const BYTE*)buff;\n\n\tUINT bw_tmp;\n\tif (!bw)\n\t\tbw = &bw_tmp;\n\t*bw = 0;\t/* Clear write byte counter */\n\tres = validate(&fp->obj, &fs);\t\t\t/* Check validity of the file object */\n\tif (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {\n\t\tEFSPRINTF(\"FOV\");\n\t\tLEAVE_FF(fs, res);\t/* Check validity */\n\t}\n\tif (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED);\t/* Check access mode */\n\n\t/* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */\n\tif ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) {\n\t\tbtw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr);\n\t}\n\n\tfor ( ;  btw;\t\t\t\t\t\t\t/* Repeat until all data written */\n\t\tbtw -= wcnt, *bw += wcnt, wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize) {\n\t\tif (fp->fptr % SS(fs) == 0) {\t\t/* On the sector boundary? */\n\t\t\tcsect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1);\t/* Sector offset in the cluster */\n\t\t\tif (csect == 0) {\t\t\t\t/* On the cluster boundary? */\n\t\t\t\tif (fp->fptr == 0) {\t\t/* On the top of the file? */\n\t\t\t\t\tclst = fp->obj.sclust;\t/* Follow from the origin */\n\t\t\t\t\tif (clst == 0) {\t\t/* If no cluster is allocated, */\n\t\t\t\t\t\tclst = create_chain(&fp->obj, 0);\t/* create a new cluster chain */\n\t\t\t\t\t}\n\t\t\t\t} else {\t\t\t\t\t/* On the middle or end of the file */\n#if FF_USE_FASTSEEK\n\t\t\t\t\tif (fp->cltbl) {\n\t\t\t\t\t\tclst = clmt_clust(fp, fp->fptr);\t/* Get cluster# from the CLMT */\n\t\t\t\t\t} else\n#endif\n\t\t\t\t\t{\n\t\t\t\t\t\tclst = create_chain(&fp->obj, fp->clust);\t/* Follow or stretch cluster chain on the FAT */\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (clst == 0) {\n\t\t\t\t\tEFSPRINTF(\"DSKFULL\");\n\t\t\t\t\tbreak;\t\t/* Could not allocate a new cluster (disk full) */\n\t\t\t\t}\n\t\t\t\tif (clst == 1) {\n\t\t\t\t\tEFSPRINTF(\"CCHK\");\n\t\t\t\t\tABORT(fs, FR_INT_ERR);\n\t\t\t\t}\n\t\t\t\tif (clst == 0xFFFFFFFF) {\n\t\t\t\t\tEFSPRINTF(\"DERR\");\n\t\t\t\t\tABORT(fs, FR_DISK_ERR);\n\t\t\t\t}\n\t\t\t\tfp->clust = clst;\t\t\t/* Update current cluster */\n\t\t\t\tif (fp->obj.sclust == 0) fp->obj.sclust = clst;\t/* Set start cluster if the first write */\n\t\t\t}\n#if FF_FS_TINY\n\t\t\tif (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR);\t/* Write-back sector cache */\n#else\n\t\t\tif (fp->flag & FA_DIRTY) {\t\t/* Write-back sector cache */\n\t\t\t\tif (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);\n\t\t\t\tfp->flag &= (BYTE)~FA_DIRTY;\n\t\t\t}\n#endif\n\t\t\tsect = clst2sect(fs, fp->clust);\t/* Get current sector */\n\t\t\tif (sect == 0) ABORT(fs, FR_INT_ERR);\n\t\t\tsect += csect;\n\t\t\tcc = btw / SS(fs);\t\t\t\t/* When remaining bytes >= sector size, */\n\t\t\tif (cc > 0) {\t\t\t\t\t/* Write maximum contiguous sectors directly */\n\t\t\t\tif (csect + cc > fs->csize) {\t/* Clip at cluster boundary */\n\t\t\t\t\tcc = fs->csize - csect;\n\t\t\t\t}\n\t\t\t\tif (disk_write(fs->pdrv, wbuff, sect, cc) != RES_OK) {\n\t\t\t\t\tEFSPRINTF(\"WLIO\");\n\t\t\t\t\tABORT(fs, FR_DISK_ERR);\n\t\t\t\t}\n#if FF_FS_MINIMIZE <= 2\n#if FF_FS_TINY\n\t\t\t\tif (fs->winsect - sect < cc) {\t/* Refill sector cache if it gets invalidated by the direct write */\n\t\t\t\t\tmem_cpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs));\n\t\t\t\t\tfs->wflag = 0;\n\t\t\t\t}\n#else\n\t\t\t\tif (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */\n\t\t\t\t\tmem_cpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs));\n\t\t\t\t\tfp->flag &= (BYTE)~FA_DIRTY;\n\t\t\t\t}\n#endif\n#endif\n\t\t\t\twcnt = SS(fs) * cc;\t\t/* Number of bytes transferred */\n\t\t\t\tcontinue;\n\t\t\t}\n#if FF_FS_TINY\n\t\t\tif (fp->fptr >= fp->obj.objsize) {\t/* Avoid silly cache filling on the growing edge */\n\t\t\t\tif (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR);\n\t\t\t\tfs->winsect = sect;\n\t\t\t}\n#else\n\t\t\tif (fp->sect != sect && \t\t/* Fill sector cache with file data */\n\t\t\t\tfp->fptr < fp->obj.objsize &&\n\t\t\t\tdisk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) {\n\t\t\t\t\tABORT(fs, FR_DISK_ERR);\n\t\t\t}\n#endif\n\t\t\tfp->sect = sect;\n\t\t}\n\t\twcnt = SS(fs) - (UINT)fp->fptr % SS(fs);\t/* Number of bytes left in the sector */\n\t\tif (wcnt > btw) wcnt = btw;\t\t\t\t\t/* Clip it by btw if needed */\n#if FF_FS_TINY\n\t\tif (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR);\t/* Move sector window */\n\t\tmem_cpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt);\t/* Fit data to the sector */\n\t\tfs->wflag = 1;\n#else\n\t\tmem_cpy(fp->buf + fp->fptr % SS(fs), wbuff, wcnt);\t/* Fit data to the sector */\n\t\tfp->flag |= FA_DIRTY;\n#endif\n\t}\n\n\tfp->flag |= FA_MODIFIED;\t\t\t\t/* Set file change flag */\n\n\tLEAVE_FF(fs, FR_OK);\n}\n\n\n\n\n#if FF_FASTFS && FF_USE_FASTSEEK\n/*-----------------------------------------------------------------------*/\n/* Fast Write Aligned Sized File Without a Cache                         */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_write_fast (\n\tFIL* fp,\t\t\t/* Pointer to the file object */\n\tconst void* buff,\t/* Pointer to the data to be written */\n\tUINT btw\t\t\t/* Number of bytes to write */\n)\n{\n\tFRESULT res;\n\tFATFS *fs;\n\tUINT csize_bytes, count;\n\tDWORD clst, work_bytes;\n\tFSIZE_t work_sector = 0;\n\tFSIZE_t sector_base = 0;\n\tconst BYTE *wbuff = (const BYTE*)buff;\n\n\tres = validate(&fp->obj, &fs);\t\t\t/* Check validity of the file object */\n\tif (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {\n\t\tEFSPRINTF(\"FOV\");\n\t\tLEAVE_FF(fs, res);\t/* Check validity */\n\t}\n\n\tif (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED);\t/* Check access mode */\n\tif (!btw)\n\t\tgoto out;\n\n\t/* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */\n\tif ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) {\n\t\tbtw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr);\n\t}\n\n\tcsize_bytes = fs->csize * SS(fs);\n\n\t// TODO support sector writing inside a cluster\n\tDWORD csect = (UINT)((fp->fptr / SS(fs)) & (fs->csize - 1));\t/* Sector offset in the cluster */\n\tif (csect) { EFSPRINTF(\"ICSR\"); ABORT(fs, FR_INT_ERR); }\n\n\tif (!fp->fptr) {\t/* On the top of the file? */\n\t\tclst = fp->obj.sclust;\t/* Follow from the origin */\n\t} else {\n\t\tif (fp->cltbl) clst = clmt_clust(fp, fp->fptr);\t/* Get cluster# from the CLMT */\n\t\telse { EFSPRINTF(\"CLTBL\"); ABORT(fs, FR_CLTBL_NO_INIT); }\n\t}\n\tif (clst < 2) { EFSPRINTF(\"CCHK\"); ABORT(fs, FR_INT_ERR); }\n\telse if (clst == 0xFFFFFFFF) { EFSPRINTF(\"DERR\"); ABORT(fs, FR_DISK_ERR); }\n\n\tfp->clust = clst;\t/* Set working cluster */\n\n\tsector_base = clst2sect(fs, fp->clust);\n\twork_bytes = MIN(btw, csize_bytes);\n\tcount = work_bytes / SS(fs);\n\tfp->fptr += work_bytes;\n\tbtw -= work_bytes;\n\n\twhile (btw) {\n\t\tclst = clmt_clust(fp, fp->fptr);\t/* Get cluster# from the CLMT */\n\n\t\tif (clst < 2) { EFSPRINTF(\"CCHK2\"); ABORT(fs, FR_INT_ERR); }\n\t\telse if (clst == 0xFFFFFFFF) { EFSPRINTF(\"DERR\"); ABORT(fs, FR_DISK_ERR); }\n\n\t\tfp->clust = clst;\n\n\t\twork_sector = clst2sect(fs, fp->clust);\n\t\twork_bytes = MIN(btw, csize_bytes);\n\t\tif ((work_sector - sector_base) == count) count += work_bytes / SS(fs);\n\t\telse {\n\t\t\tif (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR);\n\t\t\twbuff += count * SS(fs);\n\n\t\t\tsector_base = work_sector;\n\t\t\tcount = work_bytes / SS(fs);\n\t\t}\n\n\t\tfp->fptr += work_bytes;\n\t\tbtw -= work_bytes;\n\t}\n\n\tif (!btw) {\t/* Final cluster/sectors write. */\n\t\tif (work_bytes % SS(fs))\n\t\t\tcount++; /* Write an extra block. Cluster is always > storage block. */\n\t\tif (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR);\n\t\tfp->flag &= (BYTE)~FA_DIRTY;\n\t}\n\n\tfp->flag |= FA_MODIFIED;\t/* Set file change flag */\n\nout:\n\tLEAVE_FF(fs, FR_OK);\n}\n#endif\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Synchronize the File                                                  */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_sync (\n\tFIL* fp\t\t/* Pointer to the file object */\n)\n{\n\tFRESULT res;\n\tFATFS *fs;\n\tDWORD tm;\n\tBYTE *dir;\n\n\n\tres = validate(&fp->obj, &fs);\t/* Check validity of the file object */\n\tif (res == FR_OK) {\n\t\tif (fp->flag & FA_MODIFIED) {\t/* Is there any change to the file? */\n#if !FF_FS_TINY\n\t\t\tif (fp->flag & FA_DIRTY) {\t/* Write-back cached data if needed */\n\t\t\t\tif (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR);\n\t\t\t\tfp->flag &= (BYTE)~FA_DIRTY;\n\t\t\t}\n#endif\n\t\t\t/* Update the directory entry */\n\t\t\ttm = GET_FATTIME();\t\t\t\t/* Modified time */\n#if FF_FS_EXFAT\n\t\t\tif (fs->fs_type == FS_EXFAT) {\n\t\t\t\tres = fill_first_frag(&fp->obj);\t/* Fill first fragment on the FAT if needed */\n\t\t\t\tif (res == FR_OK) {\n\t\t\t\t\tres = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF);\t/* Fill last fragment on the FAT if needed */\n\t\t\t\t}\n\t\t\t\tif (res == FR_OK) {\n\t\t\t\t\tDIR dj;\n\t\t\t\t\tDEF_NAMBUF\n\n\t\t\t\t\tINIT_NAMBUF(fs);\n\t\t\t\t\tres = load_obj_xdir(&dj, &fp->obj);\t/* Load directory entry block */\n\t\t\t\t\tif (res == FR_OK) {\n\t\t\t\t\t\tfs->dirbuf[XDIR_Attr] |= AM_ARC;\t\t\t\t/* Set archive attribute to indicate that the file has been changed */\n\t\t\t\t\t\tfs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1;\t/* Update file allocation information */\n\t\t\t\t\t\tst_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust);\n\t\t\t\t\t\tst_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize);\n\t\t\t\t\t\tst_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize);\n\t\t\t\t\t\tst_dword(fs->dirbuf + XDIR_ModTime, tm);\t\t/* Update modified time */\n\t\t\t\t\t\tfs->dirbuf[XDIR_ModTime10] = 0;\n\t\t\t\t\t\tst_dword(fs->dirbuf + XDIR_AccTime, 0);\n\t\t\t\t\t\tres = store_xdir(&dj);\t/* Restore it to the directory */\n\t\t\t\t\t\tif (res == FR_OK) {\n\t\t\t\t\t\t\tres = sync_fs(fs);\n\t\t\t\t\t\t\tfp->flag &= (BYTE)~FA_MODIFIED;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tFREE_NAMBUF();\n\t\t\t\t}\n\t\t\t} else\n#endif\n\t\t\t{\n\t\t\t\tres = move_window(fs, fp->dir_sect);\n\t\t\t\tif (res == FR_OK) {\n\t\t\t\t\tdir = fp->dir_ptr;\n\t\t\t\t\tdir[DIR_Attr] |= AM_ARC;\t\t\t\t\t\t/* Set archive attribute to indicate that the file has been changed */\n\t\t\t\t\tst_clust(fp->obj.fs, dir, fp->obj.sclust);\t\t/* Update file allocation information  */\n\t\t\t\t\tst_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize);\t/* Update file size */\n\t\t\t\t\tst_dword(dir + DIR_ModTime, tm);\t\t\t\t/* Update modified time */\n\t\t\t\t\tst_word(dir + DIR_LstAccDate, 0);\n\t\t\t\t\tfs->wflag = 1;\n\t\t\t\t\tres = sync_fs(fs);\t\t\t\t\t/* Restore it to the directory */\n\t\t\t\t\tfp->flag &= (BYTE)~FA_MODIFIED;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLEAVE_FF(fs, res);\n}\n\n#endif /* !FF_FS_READONLY */\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Close File                                                            */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_close (\n\tFIL* fp\t\t/* Pointer to the file object to be closed */\n)\n{\n\tFRESULT res;\n\tFATFS *fs;\n\n#if !FF_FS_READONLY\n\tres = f_sync(fp);\t\t\t\t\t/* Flush cached data */\n\tif (res == FR_OK)\n#endif\n\t{\n\t\tres = validate(&fp->obj, &fs);\t/* Lock volume */\n\t\tif (res == FR_OK) {\n#if FF_FS_LOCK != 0\n\t\t\tres = dec_lock(fp->obj.lockid);\t\t/* Decrement file open counter */\n\t\t\tif (res == FR_OK) fp->obj.fs = 0;\t/* Invalidate file object */\n#else\n\t\t\tfp->obj.fs = 0;\t/* Invalidate file object */\n#endif\n#if FF_FS_REENTRANT\n\t\t\tunlock_fs(fs, FR_OK);\t\t/* Unlock volume */\n#endif\n\t\t}\n\t}\n\treturn res;\n}\n\n\n\n\n#if FF_FS_RPATH >= 1\n/*-----------------------------------------------------------------------*/\n/* Change Current Directory or Current Drive, Get Current Directory      */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_chdrive (\n\tconst TCHAR* path\t\t/* Drive number to set */\n)\n{\n\tint vol;\n\n\n\t/* Get logical drive number */\n\tvol = get_ldnumber(&path);\n\tif (vol < 0) return FR_INVALID_DRIVE;\n\tCurrVol = (BYTE)vol;\t/* Set it as current volume */\n\n\treturn FR_OK;\n}\n\n\n\nFRESULT f_chdir (\n\tconst TCHAR* path\t/* Pointer to the directory path */\n)\n{\n#if FF_STR_VOLUME_ID == 2\n\tUINT i;\n#endif\n\tFRESULT res;\n\tDIR dj;\n\tFATFS *fs;\n\tDEF_NAMBUF\n\n\n\t/* Get logical drive */\n\tres = find_volume(&path, &fs, 0);\n\tif (res == FR_OK) {\n\t\tdj.obj.fs = fs;\n\t\tINIT_NAMBUF(fs);\n\t\tres = follow_path(&dj, path);\t\t/* Follow the path */\n\t\tif (res == FR_OK) {\t\t\t\t\t/* Follow completed */\n\t\t\tif (dj.fn[NSFLAG] & NS_NONAME) {\t/* Is it the start directory itself? */\n\t\t\t\tfs->cdir = dj.obj.sclust;\n#if FF_FS_EXFAT\n\t\t\t\tif (fs->fs_type == FS_EXFAT) {\n\t\t\t\t\tfs->cdc_scl = dj.obj.c_scl;\n\t\t\t\t\tfs->cdc_size = dj.obj.c_size;\n\t\t\t\t\tfs->cdc_ofs = dj.obj.c_ofs;\n\t\t\t\t}\n#endif\n\t\t\t} else {\n\t\t\t\tif (dj.obj.attr & AM_DIR) {\t/* It is a sub-directory */\n#if FF_FS_EXFAT\n\t\t\t\t\tif (fs->fs_type == FS_EXFAT) {\n\t\t\t\t\t\tfs->cdir = ld_dword(fs->dirbuf + XDIR_FstClus);\t\t/* Sub-directory cluster */\n\t\t\t\t\t\tfs->cdc_scl = dj.obj.sclust;\t\t\t\t\t\t/* Save containing directory information */\n\t\t\t\t\t\tfs->cdc_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat;\n\t\t\t\t\t\tfs->cdc_ofs = dj.blk_ofs;\n\t\t\t\t\t} else\n#endif\n\t\t\t\t\t{\n\t\t\t\t\t\tfs->cdir = ld_clust(fs, dj.dir);\t\t\t\t\t/* Sub-directory cluster */\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tres = FR_NO_PATH;\t\t/* Reached but a file */\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tFREE_NAMBUF();\n\t\tif (res == FR_NO_FILE) res = FR_NO_PATH;\n#if FF_STR_VOLUME_ID == 2\t/* Also current drive is changed at Unix style volume ID */\n\t\tif (res == FR_OK) {\n\t\t\tfor (i = FF_VOLUMES - 1; i && fs != FatFs[i]; i--) ;\t/* Set current drive */\n\t\t\tCurrVol = (BYTE)i;\n\t\t}\n#endif\n\t}\n\n\tLEAVE_FF(fs, res);\n}\n\n\n#if FF_FS_RPATH >= 2\nFRESULT f_getcwd (\n\tTCHAR* buff,\t/* Pointer to the directory path */\n\tUINT len\t\t/* Size of buff in unit of TCHAR */\n)\n{\n\tFRESULT res;\n\tDIR dj;\n\tFATFS *fs;\n\tUINT i, n;\n\tDWORD ccl;\n\tTCHAR *tp = buff;\n#if FF_VOLUMES >= 2\n\tUINT vl;\n#if FF_STR_VOLUME_ID\n\tconst char *vp;\n#endif\n#endif\n\tFILINFO fno;\n\tDEF_NAMBUF\n\n\n\t/* Get logical drive */\n\tbuff[0] = 0;\t/* Set null string to get current volume */\n\tres = find_volume((const TCHAR**)&buff, &fs, 0);\t/* Get current volume */\n\tif (res == FR_OK) {\n\t\tdj.obj.fs = fs;\n\t\tINIT_NAMBUF(fs);\n\n\t\t/* Follow parent directories and create the path */\n\t\ti = len;\t\t\t/* Bottom of buffer (directory stack base) */\n\t\tif (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) {\t/* (Cannot do getcwd on exFAT and returns root path) */\n\t\t\tdj.obj.sclust = fs->cdir;\t\t\t\t/* Start to follow upper directory from current directory */\n\t\t\twhile ((ccl = dj.obj.sclust) != 0) {\t/* Repeat while current directory is a sub-directory */\n\t\t\t\tres = dir_sdi(&dj, 1 * SZDIRE);\t/* Get parent directory */\n\t\t\t\tif (res != FR_OK) break;\n\t\t\t\tres = move_window(fs, dj.sect);\n\t\t\t\tif (res != FR_OK) break;\n\t\t\t\tdj.obj.sclust = ld_clust(fs, dj.dir);\t/* Goto parent directory */\n\t\t\t\tres = dir_sdi(&dj, 0);\n\t\t\t\tif (res != FR_OK) break;\n\t\t\t\tdo {\t\t\t\t\t\t\t/* Find the entry links to the child directory */\n\t\t\t\t\tres = DIR_READ_FILE(&dj);\n\t\t\t\t\tif (res != FR_OK) break;\n\t\t\t\t\tif (ccl == ld_clust(fs, dj.dir)) break;\t/* Found the entry */\n\t\t\t\t\tres = dir_next(&dj, 0);\n\t\t\t\t} while (res == FR_OK);\n\t\t\t\tif (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */\n\t\t\t\tif (res != FR_OK) break;\n\t\t\t\tget_fileinfo(&dj, &fno);\t\t/* Get the directory name and push it to the buffer */\n\t\t\t\tfor (n = 0; fno.fname[n]; n++) ;\t/* Name length */\n\t\t\t\tif (i < n + 1) {\t/* Insufficient space to store the path name? */\n\t\t\t\t\tres = FR_NOT_ENOUGH_CORE; break;\n\t\t\t\t}\n\t\t\t\twhile (n) buff[--i] = fno.fname[--n];\t/* Stack the name */\n\t\t\t\tbuff[--i] = '/';\n\t\t\t}\n\t\t}\n\t\tif (res == FR_OK) {\n\t\t\tif (i == len) buff[--i] = '/';\t/* Is it the root-directory? */\n#if FF_VOLUMES >= 2\t\t\t/* Put drive prefix */\n\t\t\tvl = 0;\n#if FF_STR_VOLUME_ID >= 1\t/* String volume ID */\n\t\t\tfor (n = 0, vp = (const char*)VolumeStr[CurrVol]; vp[n]; n++) ;\n\t\t\tif (i >= n + 2) {\n\t\t\t\tif (FF_STR_VOLUME_ID == 2) *tp++ = (TCHAR)'/';\n\t\t\t\tfor (vl = 0; vl < n; *tp++ = (TCHAR)vp[vl], vl++) ;\n\t\t\t\tif (FF_STR_VOLUME_ID == 1) *tp++ = (TCHAR)':';\n\t\t\t\tvl++;\n\t\t\t}\n#else\t\t\t\t\t\t/* Numeric volume ID */\n\t\t\tif (i >= 3) {\n\t\t\t\t*tp++ = (TCHAR)'0' + CurrVol;\n\t\t\t\t*tp++ = (TCHAR)':';\n\t\t\t\tvl = 2;\n\t\t\t}\n#endif\n\t\t\tif (vl == 0) res = FR_NOT_ENOUGH_CORE;\n#endif\n\t\t\t/* Add current directory path */\n\t\t\tif (res == FR_OK) {\n\t\t\t\tdo *tp++ = buff[i++]; while (i < len);\t/* Copy stacked path string */\n\t\t\t}\n\t\t}\n\t\tFREE_NAMBUF();\n\t}\n\n\t*tp = 0;\n\tLEAVE_FF(fs, res);\n}\n\n#endif /* FF_FS_RPATH >= 2 */\n#endif /* FF_FS_RPATH >= 1 */\n\n\n\n#if FF_FS_MINIMIZE <= 2\n/*-----------------------------------------------------------------------*/\n/* Seek File Read/Write Pointer                                          */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_lseek (\n\tFIL* fp,\t\t/* Pointer to the file object */\n\tFSIZE_t ofs\t\t/* File pointer from top of file */\n)\n{\n\tFRESULT res;\n\tFATFS *fs;\n\tDWORD clst, bcs, nsect;\n\tFSIZE_t ifptr;\n#if FF_USE_FASTSEEK\n\tDWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl;\n#endif\n\n\tres = validate(&fp->obj, &fs);\t\t/* Check validity of the file object */\n\tif (res == FR_OK) res = (FRESULT)fp->err;\n#if FF_FS_EXFAT && !FF_FS_READONLY\n\tif (res == FR_OK && fs->fs_type == FS_EXFAT) {\n\t\tres = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF);\t/* Fill last fragment on the FAT if needed */\n\t}\n#endif\n\tif (res != FR_OK) LEAVE_FF(fs, res);\n\n#if FF_USE_FASTSEEK\n\tif (fp->cltbl) {\t/* Fast seek */\n\t\tif (ofs == CREATE_LINKMAP) {\t/* Create CLMT */\n\t\t\ttbl = fp->cltbl;\n\t\t\ttlen = *tbl++; ulen = 2;\t/* Given table size and required table size */\n\t\t\tcl = fp->obj.sclust;\t\t/* Origin of the chain */\n\t\t\tif (cl != 0) {\n\t\t\t\tdo {\n\t\t\t\t\t/* Get a fragment */\n\t\t\t\t\ttcl = cl; ncl = 0; ulen += 2;\t/* Top, length and used items */\n\t\t\t\t\tdo {\n\t\t\t\t\t\tpcl = cl; ncl++;\n\t\t\t\t\t\tcl = get_fat(&fp->obj, cl);\n\t\t\t\t\t\tif (cl <= 1) ABORT(fs, FR_INT_ERR);\n\t\t\t\t\t\tif (cl == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);\n\t\t\t\t\t} while (cl == pcl + 1);\n\t\t\t\t\tif (ulen <= tlen) {\t\t/* Store the length and top of the fragment */\n\t\t\t\t\t\t*tbl++ = ncl; *tbl++ = tcl;\n\t\t\t\t\t}\n\t\t\t\t} while (cl < fs->n_fatent);\t/* Repeat until end of chain */\n\t\t\t}\n\t\t\t*fp->cltbl = ulen;\t/* Number of items used */\n\t\t\tif (ulen <= tlen) {\n\t\t\t\t*tbl = 0;\t\t/* Terminate table */\n\t\t\t} else {\n\t\t\t\tres = FR_NOT_ENOUGH_CORE;\t/* Given table size is smaller than required */\n\t\t\t}\n\t\t} else {\t\t\t\t\t\t/* Fast seek */\n\t\t\tif (ofs > fp->obj.objsize) ofs = fp->obj.objsize;\t/* Clip offset at the file size */\n\t\t\tfp->fptr = ofs;\t\t\t\t/* Set file pointer */\n\t\t\tif (ofs > 0) {\n\t\t\t\tfp->clust = clmt_clust(fp, ofs - 1);\n\t\t\t\tdsc = clst2sect(fs, fp->clust);\n\t\t\t\tif (dsc == 0) ABORT(fs, FR_INT_ERR);\n\t\t\t\tdsc += (DWORD)((ofs - 1) / SS(fs)) & (fs->csize - 1);\n\t\t\t\tif (fp->fptr % SS(fs) && dsc != fp->sect) {\t/* Refill sector cache if needed */\n#if !FF_FS_TINY\n#if !FF_FS_READONLY\n\t\t\t\t\tif (fp->flag & FA_DIRTY) {\t\t/* Write-back dirty sector cache */\n\t\t\t\t\t\tif (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);\n\t\t\t\t\t\tfp->flag &= (BYTE)~FA_DIRTY;\n\t\t\t\t\t}\n#endif\n\t\t\t\t\tif (disk_read(fs->pdrv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);\t/* Load current sector */\n#endif\n\t\t\t\t\tfp->sect = dsc;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else\n#endif\n\n\t/* Normal Seek */\n\t{\n#if FF_FS_EXFAT\n\t\tif (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF;\t/* Clip at 4 GiB - 1 if at FATxx */\n#endif\n\t\tif (ofs > fp->obj.objsize && (FF_FS_READONLY || !(fp->flag & FA_WRITE))) {\t/* In read-only mode, clip offset with the file size */\n\t\t\tofs = fp->obj.objsize;\n\t\t}\n\t\tifptr = fp->fptr;\n\t\tfp->fptr = nsect = 0;\n\t\tif (ofs > 0) {\n\t\t\tbcs = (DWORD)fs->csize * SS(fs);\t/* Cluster size (byte) */\n\t\t\tif (ifptr > 0 &&\n\t\t\t\t(ofs - 1) / bcs >= (ifptr - 1) / bcs) {\t/* When seek to same or following cluster, */\n\t\t\t\tfp->fptr = (ifptr - 1) & ~(FSIZE_t)(bcs - 1);\t/* start from the current cluster */\n\t\t\t\tofs -= fp->fptr;\n\t\t\t\tclst = fp->clust;\n\t\t\t} else {\t\t\t\t\t\t\t\t\t/* When seek to back cluster, */\n\t\t\t\tclst = fp->obj.sclust;\t\t\t\t\t/* start from the first cluster */\n#if !FF_FS_READONLY\n\t\t\t\tif (clst == 0) {\t\t\t\t\t\t/* If no cluster chain, create a new chain */\n\t\t\t\t\tclst = create_chain(&fp->obj, 0);\n\t\t\t\t\tif (clst == 1) ABORT(fs, FR_INT_ERR);\n\t\t\t\t\tif (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);\n\t\t\t\t\tfp->obj.sclust = clst;\n\t\t\t\t}\n#endif\n\t\t\t\tfp->clust = clst;\n\t\t\t}\n\t\t\tif (clst != 0) {\n\t\t\t\twhile (ofs > bcs) {\t\t\t\t\t\t/* Cluster following loop */\n\t\t\t\t\tofs -= bcs; fp->fptr += bcs;\n#if !FF_FS_READONLY\n\t\t\t\t\tif (fp->flag & FA_WRITE) {\t\t\t/* Check if in write mode or not */\n\t\t\t\t\t\tif (FF_FS_EXFAT && fp->fptr > fp->obj.objsize) {\t/* No FAT chain object needs correct objsize to generate FAT value */\n\t\t\t\t\t\t\tfp->obj.objsize = fp->fptr;\n\t\t\t\t\t\t\tfp->flag |= FA_MODIFIED;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tclst = create_chain(&fp->obj, clst);\t/* Follow chain with forceed stretch */\n\t\t\t\t\t\tif (clst == 0) {\t\t\t\t/* Clip file size in case of disk full */\n\t\t\t\t\t\t\tofs = 0; break;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else\n#endif\n\t\t\t\t\t{\n\t\t\t\t\t\tclst = get_fat(&fp->obj, clst);\t/* Follow cluster chain if not in write mode */\n\t\t\t\t\t}\n\t\t\t\t\tif (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);\n\t\t\t\t\tif (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR);\n\t\t\t\t\tfp->clust = clst;\n\t\t\t\t}\n\t\t\t\tfp->fptr += ofs;\n\t\t\t\tif (ofs % SS(fs)) {\n\t\t\t\t\tnsect = clst2sect(fs, clst);\t/* Current sector */\n\t\t\t\t\tif (nsect == 0) ABORT(fs, FR_INT_ERR);\n\t\t\t\t\tnsect += (DWORD)(ofs / SS(fs));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (!FF_FS_READONLY && fp->fptr > fp->obj.objsize) {\t/* Set file change flag if the file size is extended */\n\t\t\tfp->obj.objsize = fp->fptr;\n\t\t\tfp->flag |= FA_MODIFIED;\n\t\t}\n\t\tif (fp->fptr % SS(fs) && nsect != fp->sect) {\t/* Fill sector cache if needed */\n#if !FF_FS_TINY\n#if !FF_FS_READONLY\n\t\t\tif (fp->flag & FA_DIRTY) {\t\t\t/* Write-back dirty sector cache */\n\t\t\t\tif (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);\n\t\t\t\tfp->flag &= (BYTE)~FA_DIRTY;\n\t\t\t}\n#endif\n\t\t\tif (disk_read(fs->pdrv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);\t/* Fill sector cache */\n#endif\n\t\t\tfp->sect = nsect;\n\t\t}\n\t}\n\n\tLEAVE_FF(fs, res);\n}\n\n\n\n#if FF_FASTFS && FF_USE_FASTSEEK\n/*-----------------------------------------------------------------------*/\n/* Seek File Read/Write Pointer                                          */\n/*-----------------------------------------------------------------------*/\n\nDWORD *f_expand_cltbl (\n\tFIL* fp,\t\t/* Pointer to the file object */\n\tUINT tblsz,\t\t/* Size of table (2 DWORDs + 2 DWORDs per fragment) */\n\tFSIZE_t ofs\t\t/* File pointer from top of file */\n)\n{\n\t/*\n\t * Cluster table structure:\n\t * Size (DWORD)\n\t * Padding (DWORD)\n\t * (Cluster Offset (DWORD) + Sequential clusters (DWORD)) * Fragments\n\t */\n\tif (fp->flag & FA_WRITE) f_lseek(fp, ofs);\t/* Expand file if write is enabled */\n\tif (!fp->cltbl) {\t/* Allocate memory for cluster link table */\n\t\tfp->cltbl = (DWORD *)ff_memalloc(tblsz);\n\t\tif (!fp->cltbl) return (void *)0;\n\t\tfp->cltbl[0] = tblsz;\n\t}\n\tif (f_lseek(fp, CREATE_LINKMAP)) {\t/* Create cluster link table */\n\t\tff_memfree(fp->cltbl);\n\t\tfp->cltbl = (void *)0;\n\t\tEFSPRINTF(\"CLTBLSZ\");\n\t\treturn (void *)0;\n\t}\n\tf_lseek(fp, 0);\n\n\treturn fp->cltbl;\n}\n#endif\n\n\n\n\n#if FF_FS_MINIMIZE <= 1\n/*-----------------------------------------------------------------------*/\n/* Create a Directory Object                                             */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_opendir (\n\tDIR* dp,\t\t\t/* Pointer to directory object to create */\n\tconst TCHAR* path\t/* Pointer to the directory path */\n)\n{\n\tFRESULT res;\n\tFATFS *fs;\n\tDEF_NAMBUF\n\n\n\tif (!dp) return FR_INVALID_OBJECT;\n\n\t/* Get logical drive */\n\tres = find_volume(&path, &fs, 0);\n\tif (res == FR_OK) {\n\t\tdp->obj.fs = fs;\n\t\tINIT_NAMBUF(fs);\n\t\tres = follow_path(dp, path);\t\t\t/* Follow the path to the directory */\n\t\tif (res == FR_OK) {\t\t\t\t\t\t/* Follow completed */\n\t\t\tif (!(dp->fn[NSFLAG] & NS_NONAME)) {\t/* It is not the origin directory itself */\n\t\t\t\tif (dp->obj.attr & AM_DIR) {\t\t/* This object is a sub-directory */\n#if FF_FS_EXFAT\n\t\t\t\t\tif (fs->fs_type == FS_EXFAT) {\n\t\t\t\t\t\tdp->obj.c_scl = dp->obj.sclust;\t\t\t\t\t\t\t/* Get containing directory inforamation */\n\t\t\t\t\t\tdp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat;\n\t\t\t\t\t\tdp->obj.c_ofs = dp->blk_ofs;\n\t\t\t\t\t\tinit_alloc_info(fs, &dp->obj);\t/* Get object allocation info */\n\t\t\t\t\t} else\n#endif\n\t\t\t\t\t{\n\t\t\t\t\t\tdp->obj.sclust = ld_clust(fs, dp->dir);\t/* Get object allocation info */\n\t\t\t\t\t}\n\t\t\t\t} else {\t\t\t\t\t\t/* This object is a file */\n\t\t\t\t\tres = FR_NO_PATH;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (res == FR_OK) {\n\t\t\t\tdp->obj.id = fs->id;\n\t\t\t\tres = dir_sdi(dp, 0);\t\t\t/* Rewind directory */\n#if FF_FS_LOCK != 0\n\t\t\t\tif (res == FR_OK) {\n\t\t\t\t\tif (dp->obj.sclust != 0) {\n\t\t\t\t\t\tdp->obj.lockid = inc_lock(dp, 0);\t/* Lock the sub directory */\n\t\t\t\t\t\tif (!dp->obj.lockid) res = FR_TOO_MANY_OPEN_FILES;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdp->obj.lockid = 0;\t/* Root directory need not to be locked */\n\t\t\t\t\t}\n\t\t\t\t}\n#endif\n\t\t\t}\n\t\t}\n\t\tFREE_NAMBUF();\n\t\tif (res == FR_NO_FILE) res = FR_NO_PATH;\n\t}\n\tif (res != FR_OK) dp->obj.fs = 0;\t\t/* Invalidate the directory object if function faild */\n\n\tLEAVE_FF(fs, res);\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Close Directory                                                       */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_closedir (\n\tDIR *dp\t\t/* Pointer to the directory object to be closed */\n)\n{\n\tFRESULT res;\n\tFATFS *fs;\n\n\n\tres = validate(&dp->obj, &fs);\t/* Check validity of the file object */\n\tif (res == FR_OK) {\n#if FF_FS_LOCK != 0\n\t\tif (dp->obj.lockid) res = dec_lock(dp->obj.lockid);\t/* Decrement sub-directory open counter */\n\t\tif (res == FR_OK) dp->obj.fs = 0;\t/* Invalidate directory object */\n#else\n\t\tdp->obj.fs = 0;\t/* Invalidate directory object */\n#endif\n#if FF_FS_REENTRANT\n\t\tunlock_fs(fs, FR_OK);\t\t/* Unlock volume */\n#endif\n\t}\n\treturn res;\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Read Directory Entries in Sequence                                    */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_readdir (\n\tDIR* dp,\t\t\t/* Pointer to the open directory object */\n\tFILINFO* fno\t\t/* Pointer to file information to return */\n)\n{\n\tFRESULT res;\n\tFATFS *fs;\n\tDEF_NAMBUF\n\n\n\tres = validate(&dp->obj, &fs);\t/* Check validity of the directory object */\n\tif (res == FR_OK) {\n\t\tif (!fno) {\n\t\t\tres = dir_sdi(dp, 0);\t\t\t/* Rewind the directory object */\n\t\t} else {\n\t\t\tINIT_NAMBUF(fs);\n\t\t\tres = DIR_READ_FILE(dp);\t\t/* Read an item */\n\t\t\tif (res == FR_NO_FILE) res = FR_OK;\t/* Ignore end of directory */\n\t\t\tif (res == FR_OK) {\t\t\t\t/* A valid entry is found */\n\t\t\t\tget_fileinfo(dp, fno);\t\t/* Get the object information */\n\t\t\t\tres = dir_next(dp, 0);\t\t/* Increment index for next */\n\t\t\t\tif (res == FR_NO_FILE) res = FR_OK;\t/* Ignore end of directory now */\n\t\t\t}\n\t\t\tFREE_NAMBUF();\n\t\t}\n\t}\n\tLEAVE_FF(fs, res);\n}\n\n\n\n#if FF_USE_FIND\n/*-----------------------------------------------------------------------*/\n/* Find Next File                                                        */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_findnext (\n\tDIR* dp,\t\t/* Pointer to the open directory object */\n\tFILINFO* fno\t/* Pointer to the file information structure */\n)\n{\n\tFRESULT res;\n\n\n\tfor (;;) {\n\t\tres = f_readdir(dp, fno);\t\t/* Get a directory item */\n\t\tif (res != FR_OK || !fno || !fno->fname[0]) break;\t/* Terminate if any error or end of directory */\n\t\tif (pattern_matching(dp->pat, fno->fname, 0, 0)) break;\t\t/* Test for the file name */\n#if FF_USE_LFN && FF_USE_FIND == 2\n\t\tif (pattern_matching(dp->pat, fno->altname, 0, 0)) break;\t/* Test for alternative name if exist */\n#endif\n\t}\n\treturn res;\n}\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Find First File                                                       */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_findfirst (\n\tDIR* dp,\t\t\t\t/* Pointer to the blank directory object */\n\tFILINFO* fno,\t\t\t/* Pointer to the file information structure */\n\tconst TCHAR* path,\t\t/* Pointer to the directory to open */\n\tconst TCHAR* pattern\t/* Pointer to the matching pattern */\n)\n{\n\tFRESULT res;\n\n\n\tdp->pat = pattern;\t\t/* Save pointer to pattern string */\n\tres = f_opendir(dp, path);\t\t/* Open the target directory */\n\tif (res == FR_OK) {\n\t\tres = f_findnext(dp, fno);\t/* Find the first item */\n\t}\n\treturn res;\n}\n\n#endif\t/* FF_USE_FIND */\n\n\n\n#if FF_FS_MINIMIZE == 0\n/*-----------------------------------------------------------------------*/\n/* Get File Status                                                       */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_stat (\n\tconst TCHAR* path,\t/* Pointer to the file path */\n\tFILINFO* fno\t\t/* Pointer to file information to return */\n)\n{\n\tFRESULT res;\n\tDIR dj;\n\tDEF_NAMBUF\n\n\n\t/* Get logical drive */\n\tres = find_volume(&path, &dj.obj.fs, 0);\n\tif (res == FR_OK) {\n\t\tINIT_NAMBUF(dj.obj.fs);\n\t\tres = follow_path(&dj, path);\t/* Follow the file path */\n\t\tif (res == FR_OK) {\t\t\t\t/* Follow completed */\n\t\t\tif (dj.fn[NSFLAG] & NS_NONAME) {\t/* It is origin directory */\n\t\t\t\tres = FR_INVALID_NAME;\n\t\t\t} else {\t\t\t\t\t\t\t/* Found an object */\n\t\t\t\tif (fno) get_fileinfo(&dj, fno);\n\t\t\t}\n\t\t}\n\t\tFREE_NAMBUF();\n\t}\n\n\tLEAVE_FF(dj.obj.fs, res);\n}\n\n\n\n#if !FF_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* Get Number of Free Clusters                                           */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_getfree (\n\tconst TCHAR* path,\t/* Logical drive number */\n\tDWORD* nclst,\t\t/* Pointer to a variable to return number of free clusters */\n\tFATFS** fatfs\t\t/* Pointer to return pointer to corresponding filesystem object */\n)\n{\n\tFRESULT res;\n\tFATFS *fs;\n\tDWORD nfree, clst, sect, stat;\n\tUINT i;\n\tFFOBJID obj;\n\n\n\t/* Get logical drive */\n\tres = find_volume(&path, &fs, 0);\n\tif (res == FR_OK) {\n\t\tif (fatfs) *fatfs = fs;\t/* Return ptr to the fs object */\n\t\t/* If free_clst is valid, return it without full FAT scan */\n\t\tif (fs->free_clst <= fs->n_fatent - 2) {\n\t\t\t*nclst = fs->free_clst;\n\t\t} else {\n\t\t\t/* Scan FAT to obtain number of free clusters */\n\t\t\tnfree = 0;\n\t\t\tif (fs->fs_type == FS_FAT12) {\t/* FAT12: Scan bit field FAT entries */\n\t\t\t\tclst = 2; obj.fs = fs;\n\t\t\t\tdo {\n\t\t\t\t\tstat = get_fat(&obj, clst);\n\t\t\t\t\tif (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }\n\t\t\t\t\tif (stat == 1) { res = FR_INT_ERR; break; }\n\t\t\t\t\tif (stat == 0) nfree++;\n\t\t\t\t} while (++clst < fs->n_fatent);\n\t\t\t} else {\n#if FF_FS_EXFAT\n\t\t\t\tif (fs->fs_type == FS_EXFAT) {\t/* exFAT: Scan allocation bitmap */\n\t\t\t\t\tBYTE bm;\n\t\t\t\t\tUINT b;\n\n\t\t\t\t\tclst = fs->n_fatent - 2;\t/* Number of clusters */\n\t\t\t\t\tsect = fs->bitbase;\t\t\t/* Bitmap sector */\n\t\t\t\t\ti = 0;\t\t\t\t\t\t/* Offset in the sector */\n\t\t\t\t\tdo {\t/* Counts numbuer of bits with zero in the bitmap */\n\t\t\t\t\t\tif (i == 0) {\n\t\t\t\t\t\t\tres = move_window(fs, sect++);\n\t\t\t\t\t\t\tif (res != FR_OK) break;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (b = 8, bm = fs->win[i]; b && clst; b--, clst--) {\n\t\t\t\t\t\t\tif (!(bm & 1)) nfree++;\n\t\t\t\t\t\t\tbm >>= 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\ti = (i + 1) % SS(fs);\n\t\t\t\t\t} while (clst);\n\t\t\t\t} else\n#endif\n\t\t\t\t{\t/* FAT16/32: Scan WORD/DWORD FAT entries */\n\t\t\t\t\tclst = fs->n_fatent;\t/* Number of entries */\n\t\t\t\t\tsect = fs->fatbase;\t\t/* Top of the FAT */\n\t\t\t\t\ti = 0;\t\t\t\t\t/* Offset in the sector */\n\t\t\t\t\tdo {\t/* Counts numbuer of entries with zero in the FAT */\n\t\t\t\t\t\tif (i == 0) {\n\t\t\t\t\t\t\tres = move_window(fs, sect++);\n\t\t\t\t\t\t\tif (res != FR_OK) break;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (fs->fs_type == FS_FAT16) {\n\t\t\t\t\t\t\tif (ld_word(fs->win + i) == 0) nfree++;\n\t\t\t\t\t\t\ti += 2;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif ((ld_dword(fs->win + i) & 0x0FFFFFFF) == 0) nfree++;\n\t\t\t\t\t\t\ti += 4;\n\t\t\t\t\t\t}\n\t\t\t\t\t\ti %= SS(fs);\n\t\t\t\t\t} while (--clst);\n\t\t\t\t}\n\t\t\t}\n\t\t\t*nclst = nfree;\t\t\t/* Return the free clusters */\n\t\t\tfs->free_clst = nfree;\t/* Now free_clst is valid */\n\t\t\tfs->fsi_flag |= 1;\t\t/* FAT32: FSInfo is to be updated */\n\t\t}\n\t}\n\n\tLEAVE_FF(fs, res);\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Truncate File                                                         */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_truncate (\n\tFIL* fp\t\t/* Pointer to the file object */\n)\n{\n\tFRESULT res;\n\tFATFS *fs;\n\tDWORD ncl;\n\n\n\tres = validate(&fp->obj, &fs);\t/* Check validity of the file object */\n\tif (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);\n\tif (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED);\t/* Check access mode */\n\n\tif (fp->fptr < fp->obj.objsize) {\t/* Process when fptr is not on the eof */\n\t\tif (fp->fptr == 0) {\t/* When set file size to zero, remove entire cluster chain */\n\t\t\tres = remove_chain(&fp->obj, fp->obj.sclust, 0);\n\t\t\tfp->obj.sclust = 0;\n\t\t} else {\t\t\t\t/* When truncate a part of the file, remove remaining clusters */\n\t\t\tncl = get_fat(&fp->obj, fp->clust);\n\t\t\tres = FR_OK;\n\t\t\tif (ncl == 0xFFFFFFFF) res = FR_DISK_ERR;\n\t\t\tif (ncl == 1) res = FR_INT_ERR;\n\t\t\tif (res == FR_OK && ncl < fs->n_fatent) {\n\t\t\t\tres = remove_chain(&fp->obj, ncl, fp->clust);\n\t\t\t}\n\t\t}\n\t\tfp->obj.objsize = fp->fptr;\t/* Set file size to current read/write point */\n\t\tfp->flag |= FA_MODIFIED;\n#if !FF_FS_TINY\n\t\tif (res == FR_OK && (fp->flag & FA_DIRTY)) {\n\t\t\tif (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) {\n\t\t\t\tres = FR_DISK_ERR;\n\t\t\t} else {\n\t\t\t\tfp->flag &= (BYTE)~FA_DIRTY;\n\t\t\t}\n\t\t}\n#endif\n\t\tif (res != FR_OK) ABORT(fs, res);\n\t}\n\n\tLEAVE_FF(fs, res);\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Delete a File/Directory                                               */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_unlink (\n\tconst TCHAR* path\t\t/* Pointer to the file or directory path */\n)\n{\n\tFRESULT res;\n\tDIR dj, sdj;\n\tDWORD dclst = 0;\n\tFATFS *fs;\n#if FF_FS_EXFAT\n\tFFOBJID obj;\n#endif\n\tDEF_NAMBUF\n\n\n\t/* Get logical drive */\n\tres = find_volume(&path, &fs, FA_WRITE);\n\tif (res == FR_OK) {\n\t\tdj.obj.fs = fs;\n\t\tINIT_NAMBUF(fs);\n\t\tres = follow_path(&dj, path);\t\t/* Follow the file path */\n\t\tif (FF_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) {\n\t\t\tres = FR_INVALID_NAME;\t\t\t/* Cannot remove dot entry */\n\t\t}\n#if FF_FS_LOCK != 0\n\t\tif (res == FR_OK) res = chk_lock(&dj, 2);\t/* Check if it is an open object */\n#endif\n\t\tif (res == FR_OK) {\t\t\t\t\t/* The object is accessible */\n\t\t\tif (dj.fn[NSFLAG] & NS_NONAME) {\n\t\t\t\tres = FR_INVALID_NAME;\t\t/* Cannot remove the origin directory */\n\t\t\t} else {\n\t\t\t\tif (dj.obj.attr & AM_RDO) {\n\t\t\t\t\tres = FR_DENIED;\t\t/* Cannot remove R/O object */\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (res == FR_OK) {\n#if FF_FS_EXFAT\n\t\t\t\tobj.fs = fs;\n\t\t\t\tif (fs->fs_type == FS_EXFAT) {\n\t\t\t\t\tinit_alloc_info(fs, &obj);\n\t\t\t\t\tdclst = obj.sclust;\n\t\t\t\t} else\n#endif\n\t\t\t\t{\n\t\t\t\t\tdclst = ld_clust(fs, dj.dir);\n\t\t\t\t}\n\t\t\t\tif (dj.obj.attr & AM_DIR) {\t\t\t/* Is it a sub-directory? */\n#if FF_FS_RPATH != 0\n\t\t\t\t\tif (dclst == fs->cdir) {\t\t \t/* Is it the current directory? */\n\t\t\t\t\t\tres = FR_DENIED;\n\t\t\t\t\t} else\n#endif\n\t\t\t\t\t{\n\t\t\t\t\t\tsdj.obj.fs = fs;\t\t\t\t/* Open the sub-directory */\n\t\t\t\t\t\tsdj.obj.sclust = dclst;\n#if FF_FS_EXFAT\n\t\t\t\t\t\tif (fs->fs_type == FS_EXFAT) {\n\t\t\t\t\t\t\tsdj.obj.objsize = obj.objsize;\n\t\t\t\t\t\t\tsdj.obj.stat = obj.stat;\n\t\t\t\t\t\t}\n#endif\n\t\t\t\t\t\tres = dir_sdi(&sdj, 0);\n\t\t\t\t\t\tif (res == FR_OK) {\n\t\t\t\t\t\t\tres = DIR_READ_FILE(&sdj);\t\t\t/* Test if the directory is empty */\n\t\t\t\t\t\t\tif (res == FR_OK) res = FR_DENIED;\t/* Not empty? */\n\t\t\t\t\t\t\tif (res == FR_NO_FILE) res = FR_OK;\t/* Empty? */\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (res == FR_OK) {\n\t\t\t\tres = dir_remove(&dj);\t\t\t/* Remove the directory entry */\n\t\t\t\tif (res == FR_OK && dclst != 0) {\t/* Remove the cluster chain if exist */\n#if FF_FS_EXFAT\n\t\t\t\t\tres = remove_chain(&obj, dclst, 0);\n#else\n\t\t\t\t\tres = remove_chain(&dj.obj, dclst, 0);\n#endif\n\t\t\t\t}\n\t\t\t\tif (res == FR_OK) res = sync_fs(fs);\n\t\t\t}\n\t\t}\n\t\tFREE_NAMBUF();\n\t}\n\n\tLEAVE_FF(fs, res);\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Create a Directory                                                    */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_mkdir (\n\tconst TCHAR* path\t\t/* Pointer to the directory path */\n)\n{\n\tFRESULT res;\n\tDIR dj;\n\tFFOBJID sobj;\n\tFATFS *fs;\n\tDWORD dcl, pcl, tm;\n\tDEF_NAMBUF\n\n\n\tres = find_volume(&path, &fs, FA_WRITE);\t/* Get logical drive */\n\tif (res == FR_OK) {\n\t\tdj.obj.fs = fs;\n\t\tINIT_NAMBUF(fs);\n\t\tres = follow_path(&dj, path);\t\t\t/* Follow the file path */\n\t\tif (res == FR_OK) res = FR_EXIST;\t\t/* Name collision? */\n\t\tif (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) {\t/* Invalid name? */\n\t\t\tres = FR_INVALID_NAME;\n\t\t}\n\t\tif (res == FR_NO_FILE) {\t\t\t\t/* It is clear to create a new directory */\n\t\t\tsobj.fs = fs;\t\t\t\t\t\t/* New object id to create a new chain */\n\t\t\tdcl = create_chain(&sobj, 0);\t\t/* Allocate a cluster for the new directory */\n\t\t\tres = FR_OK;\n\t\t\tif (dcl == 0) res = FR_DENIED;\t\t/* No space to allocate a new cluster? */\n\t\t\tif (dcl == 1) res = FR_INT_ERR;\t\t/* Any insanity? */\n\t\t\tif (dcl == 0xFFFFFFFF) res = FR_DISK_ERR;\t/* Disk error? */\n\t\t\ttm = GET_FATTIME();\n\t\t\tif (res == FR_OK) {\n\t\t\t\tres = dir_clear(fs, dcl);\t\t/* Clean up the new table */\n\t\t\t\tif (res == FR_OK) {\n\t\t\t\t\tif (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) {\t/* Create dot entries (FAT only) */\n\t\t\t\t\t\tmem_set(fs->win + DIR_Name, ' ', 11);\t/* Create \".\" entry */\n\t\t\t\t\t\tfs->win[DIR_Name] = '.';\n\t\t\t\t\t\tfs->win[DIR_Attr] = AM_DIR;\n\t\t\t\t\t\tst_dword(fs->win + DIR_ModTime, tm);\n\t\t\t\t\t\tst_clust(fs, fs->win, dcl);\n\t\t\t\t\t\tmem_cpy(fs->win + SZDIRE, fs->win, SZDIRE); /* Create \"..\" entry */\n\t\t\t\t\t\tfs->win[SZDIRE + 1] = '.'; pcl = dj.obj.sclust;\n\t\t\t\t\t\tst_clust(fs, fs->win + SZDIRE, pcl);\n\t\t\t\t\t\tfs->wflag = 1;\n\t\t\t\t\t}\n\t\t\t\t\tres = dir_register(&dj);\t/* Register the object to the parent directoy */\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (res == FR_OK) {\n#if FF_FS_EXFAT\n\t\t\t\tif (fs->fs_type == FS_EXFAT) {\t/* Initialize directory entry block */\n\t\t\t\t\tst_dword(fs->dirbuf + XDIR_ModTime, tm);\t/* Created time */\n\t\t\t\t\tst_dword(fs->dirbuf + XDIR_FstClus, dcl);\t/* Table start cluster */\n\t\t\t\t\tst_dword(fs->dirbuf + XDIR_FileSize, (DWORD)fs->csize * SS(fs));\t/* File size needs to be valid */\n\t\t\t\t\tst_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)fs->csize * SS(fs));\n\t\t\t\t\tfs->dirbuf[XDIR_GenFlags] = 3;\t\t\t\t/* Initialize the object flag */\n\t\t\t\t\tfs->dirbuf[XDIR_Attr] = AM_DIR;\t\t\t\t/* Attribute */\n\t\t\t\t\tres = store_xdir(&dj);\n\t\t\t\t} else\n#endif\n\t\t\t\t{\n\t\t\t\t\tst_dword(dj.dir + DIR_ModTime, tm);\t/* Created time */\n\t\t\t\t\tst_clust(fs, dj.dir, dcl);\t\t\t/* Table start cluster */\n\t\t\t\t\tdj.dir[DIR_Attr] = AM_DIR;\t\t\t/* Attribute */\n\t\t\t\t\tfs->wflag = 1;\n\t\t\t\t}\n\t\t\t\tif (res == FR_OK) {\n\t\t\t\t\tres = sync_fs(fs);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tremove_chain(&sobj, dcl, 0);\t\t/* Could not register, remove the allocated cluster */\n\t\t\t}\n\t\t}\n\t\tFREE_NAMBUF();\n\t}\n\n\tLEAVE_FF(fs, res);\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Rename a File/Directory                                               */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_rename (\n\tconst TCHAR* path_old,\t/* Pointer to the object name to be renamed */\n\tconst TCHAR* path_new\t/* Pointer to the new name */\n)\n{\n\tFRESULT res;\n\tDIR djo, djn;\n\tFATFS *fs;\n\tBYTE buf[FF_FS_EXFAT ? SZDIRE * 2 : SZDIRE], *dir;\n\tDWORD dw;\n\tDEF_NAMBUF\n\n\n\tget_ldnumber(&path_new);\t\t\t\t\t\t/* Snip the drive number of new name off */\n\tres = find_volume(&path_old, &fs, FA_WRITE);\t/* Get logical drive of the old object */\n\tif (res == FR_OK) {\n\t\tdjo.obj.fs = fs;\n\t\tINIT_NAMBUF(fs);\n\t\tres = follow_path(&djo, path_old);\t\t/* Check old object */\n\t\tif (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME;\t/* Check validity of name */\n#if FF_FS_LOCK != 0\n\t\tif (res == FR_OK) {\n\t\t\tres = chk_lock(&djo, 2);\n\t\t}\n#endif\n\t\tif (res == FR_OK) {\t\t\t\t\t\t/* Object to be renamed is found */\n#if FF_FS_EXFAT\n\t\t\tif (fs->fs_type == FS_EXFAT) {\t/* At exFAT volume */\n\t\t\t\tBYTE nf, nn;\n\t\t\t\tWORD nh;\n\n\t\t\t\tmem_cpy(buf, fs->dirbuf, SZDIRE * 2);\t/* Save 85+C0 entry of old object */\n\t\t\t\tmem_cpy(&djn, &djo, sizeof djo);\n\t\t\t\tres = follow_path(&djn, path_new);\t\t/* Make sure if new object name is not in use */\n\t\t\t\tif (res == FR_OK) {\t\t\t\t\t\t/* Is new name already in use by any other object? */\n\t\t\t\t\tres = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST;\n\t\t\t\t}\n\t\t\t\tif (res == FR_NO_FILE) { \t\t\t\t/* It is a valid path and no name collision */\n\t\t\t\t\tres = dir_register(&djn);\t\t\t/* Register the new entry */\n\t\t\t\t\tif (res == FR_OK) {\n\t\t\t\t\t\tnf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName];\n\t\t\t\t\t\tnh = ld_word(fs->dirbuf + XDIR_NameHash);\n\t\t\t\t\t\tmem_cpy(fs->dirbuf, buf, SZDIRE * 2);\t/* Restore 85+C0 entry */\n\t\t\t\t\t\tfs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn;\n\t\t\t\t\t\tst_word(fs->dirbuf + XDIR_NameHash, nh);\n\t\t\t\t\t\tif (!(fs->dirbuf[XDIR_Attr] & AM_DIR)) fs->dirbuf[XDIR_Attr] |= AM_ARC;\t/* Set archive attribute if it is a file */\n/* Start of critical section where an interruption can cause a cross-link */\n\t\t\t\t\t\tres = store_xdir(&djn);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else\n#endif\n\t\t\t{\t/* At FAT/FAT32 volume */\n\t\t\t\tmem_cpy(buf, djo.dir, SZDIRE);\t\t\t/* Save directory entry of the object */\n\t\t\t\tmem_cpy(&djn, &djo, sizeof (DIR));\t\t/* Duplicate the directory object */\n\t\t\t\tres = follow_path(&djn, path_new);\t\t/* Make sure if new object name is not in use */\n\t\t\t\tif (res == FR_OK) {\t\t\t\t\t\t/* Is new name already in use by any other object? */\n\t\t\t\t\tres = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST;\n\t\t\t\t}\n\t\t\t\tif (res == FR_NO_FILE) { \t\t\t\t/* It is a valid path and no name collision */\n\t\t\t\t\tres = dir_register(&djn);\t\t\t/* Register the new entry */\n\t\t\t\t\tif (res == FR_OK) {\n\t\t\t\t\t\tdir = djn.dir;\t\t\t\t\t/* Copy directory entry of the object except name */\n\t\t\t\t\t\tmem_cpy(dir + 13, buf + 13, SZDIRE - 13);\n\t\t\t\t\t\tdir[DIR_Attr] = buf[DIR_Attr];\n\t\t\t\t\t\tif (!(dir[DIR_Attr] & AM_DIR)) dir[DIR_Attr] |= AM_ARC;\t/* Set archive attribute if it is a file */\n\t\t\t\t\t\tfs->wflag = 1;\n\t\t\t\t\t\tif ((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) {\t/* Update .. entry in the sub-directory if needed */\n\t\t\t\t\t\t\tdw = clst2sect(fs, ld_clust(fs, dir));\n\t\t\t\t\t\t\tif (dw == 0) {\n\t\t\t\t\t\t\t\tres = FR_INT_ERR;\n\t\t\t\t\t\t\t} else {\n/* Start of critical section where an interruption can cause a cross-link */\n\t\t\t\t\t\t\t\tres = move_window(fs, dw);\n\t\t\t\t\t\t\t\tdir = fs->win + SZDIRE * 1;\t/* Ptr to .. entry */\n\t\t\t\t\t\t\t\tif (res == FR_OK && dir[1] == '.') {\n\t\t\t\t\t\t\t\t\tst_clust(fs, dir, djn.obj.sclust);\n\t\t\t\t\t\t\t\t\tfs->wflag = 1;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (res == FR_OK) {\n\t\t\t\tres = dir_remove(&djo);\t\t/* Remove old entry */\n\t\t\t\tif (res == FR_OK) {\n\t\t\t\t\tres = sync_fs(fs);\n\t\t\t\t}\n\t\t\t}\n/* End of the critical section */\n\t\t}\n\t\tFREE_NAMBUF();\n\t}\n\n\tLEAVE_FF(fs, res);\n}\n\n#endif /* !FF_FS_READONLY */\n#endif /* FF_FS_MINIMIZE == 0 */\n#endif /* FF_FS_MINIMIZE <= 1 */\n#endif /* FF_FS_MINIMIZE <= 2 */\n\n\n\n#if FF_USE_CHMOD && !FF_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* Change Attribute                                                      */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_chmod (\n\tconst TCHAR* path,\t/* Pointer to the file path */\n\tBYTE attr,\t\t\t/* Attribute bits */\n\tBYTE mask\t\t\t/* Attribute mask to change */\n)\n{\n\tFRESULT res;\n\tDIR dj;\n\tFATFS *fs;\n\tDEF_NAMBUF\n\n\n\tres = find_volume(&path, &fs, FA_WRITE);\t/* Get logical drive */\n\tif (res == FR_OK) {\n\t\tdj.obj.fs = fs;\n\t\tINIT_NAMBUF(fs);\n\t\tres = follow_path(&dj, path);\t/* Follow the file path */\n\t\tif (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME;\t/* Check object validity */\n\t\tif (res == FR_OK) {\n\t\t\tmask &= AM_RDO|AM_HID|AM_SYS|AM_ARC;\t/* Valid attribute mask */\n#if FF_FS_EXFAT\n\t\t\tif (fs->fs_type == FS_EXFAT) {\n\t\t\t\tfs->dirbuf[XDIR_Attr] = (attr & mask) | (fs->dirbuf[XDIR_Attr] & (BYTE)~mask);\t/* Apply attribute change */\n\t\t\t\tres = store_xdir(&dj);\n\t\t\t} else\n#endif\n\t\t\t{\n\t\t\t\tdj.dir[DIR_Attr] = (attr & mask) | (dj.dir[DIR_Attr] & (BYTE)~mask);\t/* Apply attribute change */\n\t\t\t\tfs->wflag = 1;\n\t\t\t}\n\t\t\tif (res == FR_OK) {\n\t\t\t\tres = sync_fs(fs);\n\t\t\t}\n\t\t}\n\t\tFREE_NAMBUF();\n\t}\n\n\tLEAVE_FF(fs, res);\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Change Timestamp                                                      */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_utime (\n\tconst TCHAR* path,\t/* Pointer to the file/directory name */\n\tconst FILINFO* fno\t/* Pointer to the timestamp to be set */\n)\n{\n\tFRESULT res;\n\tDIR dj;\n\tFATFS *fs;\n\tDEF_NAMBUF\n\n\n\tres = find_volume(&path, &fs, FA_WRITE);\t/* Get logical drive */\n\tif (res == FR_OK) {\n\t\tdj.obj.fs = fs;\n\t\tINIT_NAMBUF(fs);\n\t\tres = follow_path(&dj, path);\t/* Follow the file path */\n\t\tif (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME;\t/* Check object validity */\n\t\tif (res == FR_OK) {\n#if FF_FS_EXFAT\n\t\t\tif (fs->fs_type == FS_EXFAT) {\n\t\t\t\tst_dword(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime);\n\t\t\t\tres = store_xdir(&dj);\n\t\t\t} else\n#endif\n\t\t\t{\n\t\t\t\tst_dword(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime);\n\t\t\t\tfs->wflag = 1;\n\t\t\t}\n\t\t\tif (res == FR_OK) {\n\t\t\t\tres = sync_fs(fs);\n\t\t\t}\n\t\t}\n\t\tFREE_NAMBUF();\n\t}\n\n\tLEAVE_FF(fs, res);\n}\n\n#endif\t/* FF_USE_CHMOD && !FF_FS_READONLY */\n\n\n\n#if FF_USE_LABEL\n/*-----------------------------------------------------------------------*/\n/* Get Volume Label                                                      */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_getlabel (\n\tconst TCHAR* path,\t/* Logical drive number */\n\tTCHAR* label,\t\t/* Buffer to store the volume label */\n\tDWORD* vsn\t\t\t/* Variable to store the volume serial number */\n)\n{\n\tFRESULT res;\n\tDIR dj;\n\tFATFS *fs;\n\tUINT si, di;\n\tWCHAR wc;\n\n\t/* Get logical drive */\n\tres = find_volume(&path, &fs, 0);\n\n\t/* Get volume label */\n\tif (res == FR_OK && label) {\n\t\tdj.obj.fs = fs; dj.obj.sclust = 0;\t/* Open root directory */\n\t\tres = dir_sdi(&dj, 0);\n\t\tif (res == FR_OK) {\n\t\t \tres = DIR_READ_LABEL(&dj);\t\t/* Find a volume label entry */\n\t\t \tif (res == FR_OK) {\n#if FF_FS_EXFAT\n\t\t\t\tif (fs->fs_type == FS_EXFAT) {\n\t\t\t\t\tWCHAR hs;\n\n\t\t\t\t\tfor (si = di = hs = 0; si < dj.dir[XDIR_NumLabel]; si++) {\t/* Extract volume label from 83 entry */\n\t\t\t\t\t\twc = ld_word(dj.dir + XDIR_Label + si * 2);\n\t\t\t\t\t\tif (hs == 0 && IsSurrogate(wc)) {\t/* Is the code a surrogate? */\n\t\t\t\t\t\t\ths = wc; continue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\twc = put_utf((DWORD)hs << 16 | wc, &label[di], 4);\n\t\t\t\t\t\tif (wc == 0) { di = 0; break; }\n\t\t\t\t\t\tdi += wc;\n\t\t\t\t\t\ths = 0;\n\t\t\t\t\t}\n\t\t\t\t\tif (hs != 0) di = 0;\t/* Broken surrogate pair? */\n\t\t\t\t\tlabel[di] = 0;\n\t\t\t\t} else\n#endif\n\t\t\t\t{\n\t\t\t\t\tsi = di = 0;\t\t/* Extract volume label from AM_VOL entry */\n\t\t\t\t\twhile (si < 11) {\n\t\t\t\t\t\twc = dj.dir[si++];\n#if FF_USE_LFN && FF_LFN_UNICODE >= 1 \t/* Unicode output */\n\t\t\t\t\t\tif (dbc_1st((BYTE)wc) && si < 11) wc = wc << 8 | dj.dir[si++];\t/* Is it a DBC? */\n\t\t\t\t\t\twc = ff_oem2uni(wc, CODEPAGE);\t\t\t\t\t/* Convert it into Unicode */\n\t\t\t\t\t\tif (wc != 0) wc = put_utf(wc, &label[di], 4);\t/* Put it in Unicode */\n\t\t\t\t\t\tif (wc == 0) { di = 0; break; }\n\t\t\t\t\t\tdi += wc;\n#else\t\t\t\t\t\t\t\t\t/* ANSI/OEM output */\n\t\t\t\t\t\tlabel[di++] = (TCHAR)wc;\n#endif\n\t\t\t\t\t}\n\t\t\t\t\tdo {\t\t\t\t/* Truncate trailing spaces */\n\t\t\t\t\t\tlabel[di] = 0;\n\t\t\t\t\t\tif (di == 0) break;\n\t\t\t\t\t} while (label[--di] == ' ');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (res == FR_NO_FILE) {\t/* No label entry and return nul string */\n\t\t\tlabel[0] = 0;\n\t\t\tres = FR_OK;\n\t\t}\n\t}\n\n\t/* Get volume serial number */\n\tif (res == FR_OK && vsn) {\n\t\tres = move_window(fs, fs->volbase);\n\t\tif (res == FR_OK) {\n\t\t\tswitch (fs->fs_type) {\n\t\t\tcase FS_EXFAT:\n\t\t\t\tdi = BPB_VolIDEx; break;\n\n\t\t\tcase FS_FAT32:\n\t\t\t\tdi = BS_VolID32; break;\n\n\t\t\tdefault:\n\t\t\t\tdi = BS_VolID;\n\t\t\t}\n\t\t\t*vsn = ld_dword(fs->win + di);\n\t\t}\n\t}\n\n\tLEAVE_FF(fs, res);\n}\n\n\n\n#if !FF_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* Set Volume Label                                                      */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_setlabel (\n\tconst TCHAR* label\t/* Volume label to set with heading logical drive number */\n)\n{\n\tFRESULT res;\n\tDIR dj;\n\tFATFS *fs;\n\tBYTE dirvn[22];\n\tUINT di;\n\tWCHAR wc;\n\tstatic const char badchr[] = \"+.,;=[]/\\\\\\\"*:<>\\?|\\x7F\";\t/* [0..] for FAT, [7..] for exFAT */\n#if FF_USE_LFN\n\tDWORD dc;\n#endif\n\n\t/* Get logical drive */\n\tres = find_volume(&label, &fs, FA_WRITE);\n\tif (res != FR_OK) LEAVE_FF(fs, res);\n\n#if FF_FS_EXFAT\n\tif (fs->fs_type == FS_EXFAT) {\t/* On the exFAT volume */\n\t\tmem_set(dirvn, 0, 22);\n\t\tdi = 0;\n\t\twhile ((UINT)*label >= ' ') {\t/* Create volume label */\n\t\t\tdc = tchar2uni(&label);\t/* Get a Unicode character */\n\t\t\tif (dc >= 0x10000) {\n\t\t\t\tif (dc == 0xFFFFFFFF || di >= 10) {\t/* Wrong surrogate or buffer overflow */\n\t\t\t\t\tdc = 0;\n\t\t\t\t} else {\n\t\t\t\t\tst_word(dirvn + di * 2, (WCHAR)(dc >> 16)); di++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (dc == 0 || chk_chr(badchr + 7, (int)dc) || di >= 11) {\t/* Check validity of the volume label */\n\t\t\t\tLEAVE_FF(fs, FR_INVALID_NAME);\n\t\t\t}\n\t\t\tst_word(dirvn + di * 2, (WCHAR)dc); di++;\n\t\t}\n\t} else\n#endif\n\t{\t/* On the FAT/FAT32 volume */\n\t\tmem_set(dirvn, ' ', 11);\n\t\tdi = 0;\n\t\twhile ((UINT)*label >= ' ') {\t/* Create volume label */\n#if FF_USE_LFN\n\t\t\tdc = tchar2uni(&label);\n\t\t\twc = (dc < 0x10000) ? ff_uni2oem(ff_wtoupper(dc), CODEPAGE) : 0;\n#else\t\t\t\t\t\t\t\t\t/* ANSI/OEM input */\n\t\t\twc = (BYTE)*label++;\n\t\t\tif (dbc_1st((BYTE)wc)) wc = dbc_2nd((BYTE)*label) ? wc << 8 | (BYTE)*label++ : 0;\n\t\t\tif (IsLower(wc)) wc -= 0x20;\t\t/* To upper ASCII characters */\n#if FF_CODE_PAGE == 0\n\t\t\tif (ExCvt && wc >= 0x80) wc = ExCvt[wc - 0x80];\t/* To upper extended characters (SBCS cfg) */\n#elif FF_CODE_PAGE < 900\n\t\t\tif (wc >= 0x80) wc = ExCvt[wc - 0x80];\t/* To upper extended characters (SBCS cfg) */\n#endif\n#endif\n\t\t\tif (wc == 0 || chk_chr(badchr + 0, (int)wc) || di >= (UINT)((wc >= 0x100) ? 10 : 11)) {\t/* Reject invalid characters for volume label */\n\t\t\t\tLEAVE_FF(fs, FR_INVALID_NAME);\n\t\t\t}\n\t\t\tif (wc >= 0x100) dirvn[di++] = (BYTE)(wc >> 8);\n\t\t\tdirvn[di++] = (BYTE)wc;\n\t\t}\n\t\tif (dirvn[0] == DDEM) LEAVE_FF(fs, FR_INVALID_NAME);\t/* Reject illegal name (heading DDEM) */\n\t\twhile (di && dirvn[di - 1] == ' ') di--;\t\t\t\t/* Snip trailing spaces */\n\t}\n\n\t/* Set volume label */\n\tdj.obj.fs = fs; dj.obj.sclust = 0;\t/* Open root directory */\n\tres = dir_sdi(&dj, 0);\n\tif (res == FR_OK) {\n\t\tres = DIR_READ_LABEL(&dj);\t/* Get volume label entry */\n\t\tif (res == FR_OK) {\n\t\t\tif (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {\n\t\t\t\tdj.dir[XDIR_NumLabel] = (BYTE)di;\t/* Change the volume label */\n\t\t\t\tmem_cpy(dj.dir + XDIR_Label, dirvn, 22);\n\t\t\t} else {\n\t\t\t\tif (di != 0) {\n\t\t\t\t\tmem_cpy(dj.dir, dirvn, 11);\t/* Change the volume label */\n\t\t\t\t} else {\n\t\t\t\t\tdj.dir[DIR_Name] = DDEM;\t/* Remove the volume label */\n\t\t\t\t}\n\t\t\t}\n\t\t\tfs->wflag = 1;\n\t\t\tres = sync_fs(fs);\n\t\t} else {\t\t\t/* No volume label entry or an error */\n\t\t\tif (res == FR_NO_FILE) {\n\t\t\t\tres = FR_OK;\n\t\t\t\tif (di != 0) {\t/* Create a volume label entry */\n\t\t\t\t\tres = dir_alloc(&dj, 1);\t/* Allocate an entry */\n\t\t\t\t\tif (res == FR_OK) {\n\t\t\t\t\t\tmem_set(dj.dir, 0, SZDIRE);\t/* Clean the entry */\n\t\t\t\t\t\tif (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {\n\t\t\t\t\t\t\tdj.dir[XDIR_Type] = ET_VLABEL;\t/* Create volume label entry */\n\t\t\t\t\t\t\tdj.dir[XDIR_NumLabel] = (BYTE)di;\n\t\t\t\t\t\t\tmem_cpy(dj.dir + XDIR_Label, dirvn, 22);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tdj.dir[DIR_Attr] = AM_VOL;\t\t/* Create volume label entry */\n\t\t\t\t\t\t\tmem_cpy(dj.dir, dirvn, 11);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfs->wflag = 1;\n\t\t\t\t\t\tres = sync_fs(fs);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLEAVE_FF(fs, res);\n}\n\n#endif /* !FF_FS_READONLY */\n#endif /* FF_USE_LABEL */\n\n\n\n#if FF_USE_EXPAND && !FF_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* Allocate a Contiguous Blocks to the File                              */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_expand (\n\tFIL* fp,\t\t/* Pointer to the file object */\n\tFSIZE_t fsz,\t/* File size to be expanded to */\n\tBYTE opt\t\t/* Operation mode 0:Find and prepare or 1:Find and allocate */\n)\n{\n\tFRESULT res;\n\tFATFS *fs;\n\tDWORD n, clst, stcl, scl, ncl, tcl, lclst;\n\n\n\tres = validate(&fp->obj, &fs);\t\t/* Check validity of the file object */\n\tif (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);\n\tif (fsz == 0 || fp->obj.objsize != 0 || !(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED);\n#if FF_FS_EXFAT\n\tif (fs->fs_type != FS_EXFAT && fsz >= 0x100000000) LEAVE_FF(fs, FR_DENIED);\t/* Check if in size limit */\n#endif\n\tn = (DWORD)fs->csize * SS(fs);\t/* Cluster size */\n\ttcl = (DWORD)(fsz / n) + ((fsz & (n - 1)) ? 1 : 0);\t/* Number of clusters required */\n\tstcl = fs->last_clst; lclst = 0;\n\tif (stcl < 2 || stcl >= fs->n_fatent) stcl = 2;\n\n#if FF_FS_EXFAT\n\tif (fs->fs_type == FS_EXFAT) {\n\t\tscl = find_bitmap(fs, stcl, tcl);\t\t\t/* Find a contiguous cluster block */\n\t\tif (scl == 0) res = FR_DENIED;\t\t\t\t/* No contiguous cluster block was found */\n\t\tif (scl == 0xFFFFFFFF) res = FR_DISK_ERR;\n\t\tif (res == FR_OK) {\t/* A contiguous free area is found */\n\t\t\tif (opt) {\t\t/* Allocate it now */\n\t\t\t\tres = change_bitmap(fs, scl, tcl, 1);\t/* Mark the cluster block 'in use' */\n\t\t\t\tlclst = scl + tcl - 1;\n\t\t\t} else {\t\t/* Set it as suggested point for next allocation */\n\t\t\t\tlclst = scl - 1;\n\t\t\t}\n\t\t}\n\t} else\n#endif\n\t{\n\t\tscl = clst = stcl; ncl = 0;\n\t\tfor (;;) {\t/* Find a contiguous cluster block */\n\t\t\tn = get_fat(&fp->obj, clst);\n\t\t\tif (++clst >= fs->n_fatent) clst = 2;\n\t\t\tif (n == 1) { res = FR_INT_ERR; break; }\n\t\t\tif (n == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }\n\t\t\tif (n == 0) {\t/* Is it a free cluster? */\n\t\t\t\tif (++ncl == tcl) break;\t/* Break if a contiguous cluster block is found */\n\t\t\t} else {\n\t\t\t\tscl = clst; ncl = 0;\t\t/* Not a free cluster */\n\t\t\t}\n\t\t\tif (clst == stcl) { res = FR_DENIED; break; }\t/* No contiguous cluster? */\n\t\t}\n\t\tif (res == FR_OK) {\t/* A contiguous free area is found */\n\t\t\tif (opt) {\t\t/* Allocate it now */\n\t\t\t\tfor (clst = scl, n = tcl; n; clst++, n--) {\t/* Create a cluster chain on the FAT */\n\t\t\t\t\tres = put_fat(fs, clst, (n == 1) ? 0xFFFFFFFF : clst + 1);\n\t\t\t\t\tif (res != FR_OK) break;\n\t\t\t\t\tlclst = clst;\n\t\t\t\t}\n\t\t\t} else {\t\t/* Set it as suggested point for next allocation */\n\t\t\t\tlclst = scl - 1;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (res == FR_OK) {\n\t\tfs->last_clst = lclst;\t\t/* Set suggested start cluster to start next */\n\t\tif (opt) {\t/* Is it allocated now? */\n\t\t\tfp->obj.sclust = scl;\t\t/* Update object allocation information */\n\t\t\tfp->obj.objsize = fsz;\n\t\t\tif (FF_FS_EXFAT) fp->obj.stat = 2;\t/* Set status 'contiguous chain' */\n\t\t\tfp->flag |= FA_MODIFIED;\n\t\t\tif (fs->free_clst <= fs->n_fatent - 2) {\t/* Update FSINFO */\n\t\t\t\tfs->free_clst -= tcl;\n\t\t\t\tfs->fsi_flag |= 1;\n\t\t\t}\n\t\t}\n\t}\n\n\tLEAVE_FF(fs, res);\n}\n\n#endif /* FF_USE_EXPAND && !FF_FS_READONLY */\n\n\n\n#if FF_USE_FORWARD\n/*-----------------------------------------------------------------------*/\n/* Forward Data to the Stream Directly                                   */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_forward (\n\tFIL* fp, \t\t\t\t\t\t/* Pointer to the file object */\n\tUINT (*func)(const BYTE*,UINT),\t/* Pointer to the streaming function */\n\tUINT btf,\t\t\t\t\t\t/* Number of bytes to forward */\n\tUINT* bf\t\t\t\t\t\t/* Pointer to number of bytes forwarded */\n)\n{\n\tFRESULT res;\n\tFATFS *fs;\n\tDWORD clst, sect;\n\tFSIZE_t remain;\n\tUINT rcnt, csect;\n\tBYTE *dbuf;\n\n\n\t*bf = 0;\t/* Clear transfer byte counter */\n\tres = validate(&fp->obj, &fs);\t\t/* Check validity of the file object */\n\tif (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);\n\tif (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED);\t/* Check access mode */\n\n\tremain = fp->obj.objsize - fp->fptr;\n\tif (btf > remain) btf = (UINT)remain;\t\t\t/* Truncate btf by remaining bytes */\n\n\tfor ( ;  btf && (*func)(0, 0);\t\t\t\t\t/* Repeat until all data transferred or stream goes busy */\n\t\tfp->fptr += rcnt, *bf += rcnt, btf -= rcnt) {\n\t\tcsect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1));\t/* Sector offset in the cluster */\n\t\tif (fp->fptr % SS(fs) == 0) {\t\t\t\t/* On the sector boundary? */\n\t\t\tif (csect == 0) {\t\t\t\t\t\t/* On the cluster boundary? */\n\t\t\t\tclst = (fp->fptr == 0) ?\t\t\t/* On the top of the file? */\n\t\t\t\t\tfp->obj.sclust : get_fat(&fp->obj, fp->clust);\n\t\t\t\tif (clst <= 1) ABORT(fs, FR_INT_ERR);\n\t\t\t\tif (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);\n\t\t\t\tfp->clust = clst;\t\t\t\t\t/* Update current cluster */\n\t\t\t}\n\t\t}\n\t\tsect = clst2sect(fs, fp->clust);\t\t\t/* Get current data sector */\n\t\tif (sect == 0) ABORT(fs, FR_INT_ERR);\n\t\tsect += csect;\n#if FF_FS_TINY\n\t\tif (move_window(fs, sect) != FR_OK) ABORT(fs, FR_DISK_ERR);\t/* Move sector window to the file data */\n\t\tdbuf = fs->win;\n#else\n\t\tif (fp->sect != sect) {\t\t/* Fill sector cache with file data */\n#if !FF_FS_READONLY\n\t\t\tif (fp->flag & FA_DIRTY) {\t\t/* Write-back dirty sector cache */\n\t\t\t\tif (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);\n\t\t\t\tfp->flag &= (BYTE)~FA_DIRTY;\n\t\t\t}\n#endif\n\t\t\tif (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);\n\t\t}\n\t\tdbuf = fp->buf;\n#endif\n\t\tfp->sect = sect;\n\t\trcnt = SS(fs) - (UINT)fp->fptr % SS(fs);\t/* Number of bytes left in the sector */\n\t\tif (rcnt > btf) rcnt = btf;\t\t\t\t\t/* Clip it by btr if needed */\n\t\trcnt = (*func)(dbuf + ((UINT)fp->fptr % SS(fs)), rcnt);\t/* Forward the file data */\n\t\tif (rcnt == 0) ABORT(fs, FR_INT_ERR);\n\t}\n\n\tLEAVE_FF(fs, FR_OK);\n}\n#endif /* FF_USE_FORWARD */\n\n\n\n#if FF_USE_MKFS && !FF_FS_READONLY\n/*-----------------------------------------------------------------------*/\n/* Create an FAT/exFAT volume                                            */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_mkfs (\n\tconst TCHAR* path,\t/* Logical drive number */\n\tBYTE opt,\t\t\t/* Format option */\n\tDWORD au,\t\t\t/* Size of allocation unit (cluster) [byte] */\n\tvoid* work,\t\t\t/* Pointer to working buffer (null: use heap memory) */\n\tUINT len\t\t\t/* Size of working buffer [byte] */\n)\n{\n\tconst UINT n_fats = 2;\t\t/* Number of FATs for FAT/FAT32 volume (1 or 2) */\n\tconst UINT n_rootdir = 512;\t/* Number of root directory entries for FAT volume */\n\tstatic const WORD cst[] = {1, 4, 16, 64, 256, 512, 0};\t/* Cluster size boundary for FAT volume (4Ks unit) */\n\tstatic const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0};\t/* Cluster size boundary for FAT32 volume (128Ks unit) */\n\tBYTE fmt, sys, *buf, *pte, pdrv, part;\n\tWORD ss;\t/* Sector size */\n\tDWORD szb_buf, sz_buf, sz_blk, n_clst, pau, sect, nsect, n;\n\tDWORD b_vol, b_fat, b_data;\t\t\t\t/* Base LBA for volume, fat, data */\n\tDWORD sz_vol, sz_rsv, sz_fat, sz_dir;\t/* Size for volume, fat, dir, data */\n\tUINT i;\n\tint vol;\n\tDSTATUS stat;\n#if FF_USE_TRIM || FF_FS_EXFAT\n\tDWORD tbl[3];\n#endif\n\n\n\t/* Check mounted drive and clear work area */\n\tvol = get_ldnumber(&path);\t\t\t\t\t/* Get target logical drive */\n\tif (vol < 0) return FR_INVALID_DRIVE;\n\tif (FatFs[vol]) FatFs[vol]->fs_type = 0;\t/* Clear the volume if mounted */\n\tpdrv = LD2PD(vol);\t/* Physical drive */\n\tpart = LD2PT(vol);\t/* Partition (0:create as new, 1-4:get from partition table) */\n\n\t/* Check physical drive status */\n\tstat = disk_initialize(pdrv);\n\tif (stat & STA_NOINIT) return FR_NOT_READY;\n\tif (stat & STA_PROTECT) return FR_WRITE_PROTECTED;\n\tif (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 131072 || (sz_blk & (sz_blk - 1))) sz_blk = 2048;\t/* Erase block to align data area. 1MB minimum */\n#if FF_MAX_SS != FF_MIN_SS\t\t/* Get sector size of the medium if variable sector size cfg. */\n\tif (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR;\n\tif (ss > FF_MAX_SS || ss < FF_MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR;\n#else\n\tss = FF_MAX_SS;\n#endif\n\tif ((au != 0 && au < ss) || au > 0x1000000 || (au & (au - 1))) return FR_INVALID_PARAMETER;\t/* Check if au is valid */\n\tau /= ss;\t/* Cluster size in unit of sector */\n\n\t/* Get working buffer */\n#if FF_USE_LFN == 3\n\tif (!work) {\t/* Use heap memory for working buffer */\n\t\tfor (szb_buf = MAX_MALLOC, buf = 0; szb_buf >= ss && (buf = ff_memalloc(szb_buf)) == 0; szb_buf /= 2) ;\n\t\tsz_buf = szb_buf / ss;\t\t/* Size of working buffer (sector) */\n\t} else\n#endif\n\t{\n\t\tbuf = (BYTE*)work;\t\t/* Working buffer */\n\t\tsz_buf = len / ss;\t\t/* Size of working buffer (sector) */\n\t\tszb_buf = sz_buf * ss;\t/* Size of working buffer (byte) */\n\t}\n\tif (!buf || sz_buf == 0) return FR_NOT_ENOUGH_CORE;\n\n\t/* Determine where the volume to be located (b_vol, sz_vol) */\n\tif (FF_MULTI_PARTITION && part != 0) {\n\t\t/* Get partition information from partition table in the MBR */\n\t\tif (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);\t/* Load MBR */\n\t\tif (ld_word(buf + BS_55AA) != 0xAA55) LEAVE_MKFS(FR_MKFS_ABORTED);\t/* Check if MBR is valid */\n\t\tpte = buf + (MBR_Table + (part - 1) * SZ_PTE);\n\t\tif (pte[PTE_System] == 0) LEAVE_MKFS(FR_MKFS_ABORTED);\t/* No partition? */\n\t\tb_vol = ld_dword(pte + PTE_StLba);\t\t/* Get volume start sector */\n\t\tsz_vol = ld_dword(pte + PTE_SizLba);\t/* Get volume size */\n\t} else {\n\t\t/* Create a single-partition in this function */\n\t\tif (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);\n\t\tb_vol = (opt & FM_SFD) ? 0 : sz_blk;\t\t/* Volume start sector */\n\t\tif (sz_vol < b_vol) LEAVE_MKFS(FR_MKFS_ABORTED);\n\t\tsz_vol -= b_vol;\t\t\t\t\t\t/* Volume size */\n\t}\n\tif (sz_vol < 128) LEAVE_MKFS(FR_MKFS_ABORTED);\t/* Check if volume size is >=128s */\n\n\t/* Pre-determine the FAT type */\n\tdo {\n\t\tif (FF_FS_EXFAT && (opt & FM_EXFAT)) {\t/* exFAT possible? */\n\t\t\tif ((opt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || au > 128) {\t/* exFAT only, vol >= 64Ms or au > 128s ? */\n\t\t\t\tfmt = FS_EXFAT; break;\n\t\t\t}\n\t\t}\n\t\tif (au > 128) LEAVE_MKFS(FR_INVALID_PARAMETER);\t/* Too large au for FAT/FAT32 */\n\t\tif (opt & FM_FAT32) {\t/* FAT32 possible? */\n\t\t\tif ((opt & FM_ANY) == FM_FAT32 || !(opt & FM_FAT)) {\t/* FAT32 only or no-FAT? */\n\t\t\t\tfmt = FS_FAT32; break;\n\t\t\t}\n\t\t}\n\t\tif (!(opt & FM_FAT)) LEAVE_MKFS(FR_INVALID_PARAMETER);\t/* no-FAT? */\n\t\tfmt = FS_FAT16;\n\t} while (0);\n\n#if FF_FS_EXFAT\n\tif (fmt == FS_EXFAT) {\t/* Create an exFAT volume */\n\t\tDWORD szb_bit, szb_case, sum, nb, cl;\n\t\tWCHAR ch, si;\n\t\tUINT j, st;\n\t\tBYTE b;\n\n\t\tif (sz_vol < 0x1000) LEAVE_MKFS(FR_MKFS_ABORTED);\t/* Too small volume? */\n#if FF_USE_TRIM\n\t\ttbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1;\t/* Inform the device the volume area may be erased */\n\t\tdisk_ioctl(pdrv, CTRL_TRIM, tbl);\n#endif\n\t\t/* Determine FAT location, data location and number of clusters */\n\t\tif (au == 0) {\t/* au auto-selection */\n\t\t\tau = 8;\n\t\t\tif (sz_vol >= 0x80000) au = 64;\t\t/* >= 512Ks */\n\t\t\tif (sz_vol >= 0x4000000) au = 256;\t/* >= 64Ms */\n\t\t}\n\t\tb_fat = b_vol + 32;\t\t\t\t\t\t\t\t\t\t/* FAT start at offset 32 */\n\t\tsz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss;\t\t\t/* Number of FAT sectors */\n\t\tb_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1);\t/* Align data area to the erase block boundary */\n\t\tif (b_data - b_vol >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED);\t/* Too small volume? */\n\t\tn_clst = (sz_vol - (b_data - b_vol)) / au;\t\t\t\t/* Number of clusters */\n\t\tif (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED);\t\t\t/* Too few clusters? */\n\t\tif (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED);\t/* Too many clusters? */\n\n\t\tszb_bit = (n_clst + 7) / 8;\t\t\t\t\t\t/* Size of allocation bitmap */\n\t\ttbl[0] = (szb_bit + au * ss - 1) / (au * ss);\t/* Number of allocation bitmap clusters */\n\n\t\t/* Create a compressed up-case table */\n\t\tsect = b_data + au * tbl[0];\t/* Table start sector */\n\t\tsum = 0;\t\t\t\t\t\t/* Table checksum to be stored in the 82 entry */\n\t\tst = 0; si = 0; i = 0; j = 0; szb_case = 0;\n\t\tdo {\n\t\t\tswitch (st) {\n\t\t\tcase 0:\n\t\t\t\tch = (WCHAR)ff_wtoupper(si);\t/* Get an up-case char */\n\t\t\t\tif (ch != si) {\n\t\t\t\t\tsi++; break;\t\t/* Store the up-case char if exist */\n\t\t\t\t}\n\t\t\t\tfor (j = 1; (WCHAR)(si + j) && (WCHAR)(si + j) == ff_wtoupper((WCHAR)(si + j)); j++) ;\t/* Get run length of no-case block */\n\t\t\t\tif (j >= 128) {\n\t\t\t\t\tch = 0xFFFF; st = 2; break;\t/* Compress the no-case block if run is >= 128 */\n\t\t\t\t}\n\t\t\t\tst = 1;\t\t\t/* Do not compress short run */\n\t\t\t\t/* go to next case */\n\t\t\tcase 1:\n\t\t\t\tch = si++;\t\t/* Fill the short run */\n\t\t\t\tif (--j == 0) st = 0;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tch = (WCHAR)j; si += (WCHAR)j;\t/* Number of chars to skip */\n\t\t\t\tst = 0;\n\t\t\t}\n\t\t\tsum = xsum32(buf[i + 0] = (BYTE)ch, sum);\t\t/* Put it into the write buffer */\n\t\t\tsum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum);\n\t\t\ti += 2; szb_case += 2;\n\t\t\tif (si == 0 || i == szb_buf) {\t\t/* Write buffered data when buffer full or end of process */\n\t\t\t\tn = (i + ss - 1) / ss;\n\t\t\t\tif (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);\n\t\t\t\tsect += n; i = 0;\n\t\t\t}\n\t\t} while (si);\n\t\ttbl[1] = (szb_case + au * ss - 1) / (au * ss);\t/* Number of up-case table clusters */\n\t\ttbl[2] = 1;\t\t\t\t\t\t\t\t\t\t/* Number of root dir clusters */\n\n\t\t/* Initialize the allocation bitmap */\n\t\tsect = b_data; nsect = (szb_bit + ss - 1) / ss;\t/* Start of bitmap and number of sectors */\n\t\tnb = tbl[0] + tbl[1] + tbl[2];\t\t\t\t\t/* Number of clusters in-use by system */\n\t\tdo {\n\t\t\tmem_set(buf, 0, szb_buf);\n\t\t\tfor (i = 0; nb >= 8 && i < szb_buf; buf[i++] = 0xFF, nb -= 8) ;\n\t\t\tfor (b = 1; nb != 0 && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ;\n\t\t\tn = (nsect > sz_buf) ? sz_buf : nsect;\t\t/* Write the buffered data */\n\t\t\tif (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);\n\t\t\tsect += n; nsect -= n;\n\t\t} while (nsect);\n\n\t\t/* Initialize the FAT */\n\t\tsect = b_fat; nsect = sz_fat;\t/* Start of FAT and number of FAT sectors */\n\t\tj = nb = cl = 0;\n\t\tdo {\n\t\t\tmem_set(buf, 0, szb_buf); i = 0;\t/* Clear work area and reset write index */\n\t\t\tif (cl == 0) {\t/* Set entry 0 and 1 */\n\t\t\t\tst_dword(buf + i, 0xFFFFFFF8); i += 4; cl++;\n\t\t\t\tst_dword(buf + i, 0xFFFFFFFF); i += 4; cl++;\n\t\t\t}\n\t\t\tdo {\t\t\t/* Create chains of bitmap, up-case and root dir */\n\t\t\t\twhile (nb != 0 && i < szb_buf) {\t\t\t/* Create a chain */\n\t\t\t\t\tst_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF);\n\t\t\t\t\ti += 4; cl++; nb--;\n\t\t\t\t}\n\t\t\t\tif (nb == 0 && j < 3) nb = tbl[j++];\t/* Next chain */\n\t\t\t} while (nb != 0 && i < szb_buf);\n\t\t\tn = (nsect > sz_buf) ? sz_buf : nsect;\t/* Write the buffered data */\n\t\t\tif (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);\n\t\t\tsect += n; nsect -= n;\n\t\t} while (nsect);\n\n\t\t/* Initialize the root directory */\n\t\tmem_set(buf, 0, szb_buf);\n\t\tbuf[SZDIRE * 0 + 0] = ET_VLABEL;\t\t/* Volume label entry */\n\t\tbuf[SZDIRE * 1 + 0] = ET_BITMAP;\t\t/* Bitmap entry */\n\t\tst_dword(buf + SZDIRE * 1 + 20, 2);\t\t\t\t/* cluster */\n\t\tst_dword(buf + SZDIRE * 1 + 24, szb_bit);\t\t/* size */\n\t\tbuf[SZDIRE * 2 + 0] = ET_UPCASE;\t\t/* Up-case table entry */\n\t\tst_dword(buf + SZDIRE * 2 + 4, sum);\t\t\t/* sum */\n\t\tst_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]);\t/* cluster */\n\t\tst_dword(buf + SZDIRE * 2 + 24, szb_case);\t\t/* size */\n\t\tsect = b_data + au * (tbl[0] + tbl[1]);\tnsect = au;\t/* Start of the root directory and number of sectors */\n\t\tdo {\t/* Fill root directory sectors */\n\t\t\tn = (nsect > sz_buf) ? sz_buf : nsect;\n\t\t\tif (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);\n\t\t\tmem_set(buf, 0, ss);\n\t\t\tsect += n; nsect -= n;\n\t\t} while (nsect);\n\n\t\t/* Create two set of the exFAT VBR blocks */\n\t\tsect = b_vol;\n\t\tfor (n = 0; n < 2; n++) {\n\t\t\t/* Main record (+0) */\n\t\t\tmem_set(buf, 0, ss);\n\t\t\tmem_cpy(buf + BS_JmpBoot, \"\\xEB\\x76\\x90\" \"EXFAT   \", 11);\t/* Boot jump code (x86), OEM name */\n\t\t\tst_dword(buf + BPB_VolOfsEx, b_vol);\t\t\t\t\t/* Volume offset in the physical drive [sector] */\n\t\t\tst_dword(buf + BPB_TotSecEx, sz_vol);\t\t\t\t\t/* Volume size [sector] */\n\t\t\tst_dword(buf + BPB_FatOfsEx, b_fat - b_vol);\t\t\t/* FAT offset [sector] */\n\t\t\tst_dword(buf + BPB_FatSzEx, sz_fat);\t\t\t\t\t/* FAT size [sector] */\n\t\t\tst_dword(buf + BPB_DataOfsEx, b_data - b_vol);\t\t\t/* Data offset [sector] */\n\t\t\tst_dword(buf + BPB_NumClusEx, n_clst);\t\t\t\t\t/* Number of clusters */\n\t\t\tst_dword(buf + BPB_RootClusEx, 2 + tbl[0] + tbl[1]);\t/* Root dir cluster # */\n\t\t\tst_dword(buf + BPB_VolIDEx, GET_FATTIME());\t\t\t\t/* VSN */\n\t\t\tst_word(buf + BPB_FSVerEx, 0x100);\t\t\t\t\t\t/* Filesystem version (1.00) */\n\t\t\tfor (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ;\t/* Log2 of sector size [byte] */\n\t\t\tfor (buf[BPB_SecPerClusEx] = 0, i = au; i >>= 1; buf[BPB_SecPerClusEx]++) ;\t/* Log2 of cluster size [sector] */\n\t\t\tbuf[BPB_NumFATsEx] = 1;\t\t\t\t\t/* Number of FATs */\n\t\t\tbuf[BPB_DrvNumEx] = 0x80;\t\t\t\t/* Drive number (for int13) */\n\t\t\tst_word(buf + BS_BootCodeEx, 0xFEEB);\t/* Boot code (x86) */\n\t\t\tst_word(buf + BS_55AA, 0xAA55);\t\t\t/* Signature (placed here regardless of sector size) */\n\t\t\tfor (i = sum = 0; i < ss; i++) {\t\t/* VBR checksum */\n\t\t\t\tif (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum);\n\t\t\t}\n\t\t\tif (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);\n\t\t\t/* Extended bootstrap record (+1..+8) */\n\t\t\tmem_set(buf, 0, ss);\n\t\t\tst_word(buf + ss - 2, 0xAA55);\t/* Signature (placed at end of sector) */\n\t\t\tfor (j = 1; j < 9; j++) {\n\t\t\t\tfor (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ;\t/* VBR checksum */\n\t\t\t\tif (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);\n\t\t\t}\n\t\t\t/* OEM/Reserved record (+9..+10) */\n\t\t\tmem_set(buf, 0, ss);\n\t\t\tfor ( ; j < 11; j++) {\n\t\t\t\tfor (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ;\t/* VBR checksum */\n\t\t\t\tif (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);\n\t\t\t}\n\t\t\t/* Sum record (+11) */\n\t\t\tfor (i = 0; i < ss; i += 4) st_dword(buf + i, sum);\t\t/* Fill with checksum value */\n\t\t\tif (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);\n\t\t}\n\n\t} else\n#endif\t/* FF_FS_EXFAT */\n\t{\t/* Create an FAT/FAT32 volume */\n\t\tdo {\n\t\t\tpau = au;\n\t\t\t/* Pre-determine number of clusters and FAT sub-type */\n\t\t\tif (fmt == FS_FAT32) {\t/* FAT32 volume */\n\t\t\t\tif (pau == 0) {\t/* au auto-selection */\n\t\t\t\t\tn = sz_vol / 0x20000;\t/* Volume size in unit of 128KS */\n\t\t\t\t\tfor (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ;\t/* Get from table */\n\t\t\t\t}\n\t\t\t\tn_clst = sz_vol / pau;\t/* Number of clusters */\n\t\t\t\twhile (1) {\n\t\t\t\t\t/* Do not account for reserved/root cluster on FAT size for better alignment. */\n\t\t\t\t\tsz_fat = (n_clst * 4 + ss - 1) / ss;\t/* FAT size [sector]. */\n\t\t\t\t\tsz_rsv = 2048;\t/* Number of reserved sectors. Use 1MB for better performance (for flash memory media) */\n\t\t\t\t\tsz_dir = 0;\t\t/* No static directory */\n\t\t\t\t\tif (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) LEAVE_MKFS(FR_MKFS_ABORTED);\n\t\t\t\t\tb_fat = b_vol + sz_rsv;\t\t\t\t\t\t/* FAT base */\n\t\t\t\t\tb_data = b_fat + sz_fat * n_fats + sz_dir;\t/* Data base */\n\n\t\t\t\t\t/* Align data base to erase block boundary (for flash memory media) */\n\t\t\t\t\tn = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data;\t/* Next nearest erase block from current data base */\n\t\t\t\t\tb_fat += n;\t\t/* FAT32: Move FAT base */\n\t\t\t\t\t/* Make sure FAT base is aligned to reserved size for performance (PRF2SAFE min cluster alignment) */\n\t\t\t\t\tif ((b_fat & (sz_rsv - 1) || (n_fats == 2 && sz_fat & (sz_rsv - 1)))) {\n\t\t\t\t\t\tn_clst++;\t/* FAT size must always be bigger than real free size */\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tsz_rsv += n;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\t\t\t\t/* FAT volume */\n\t\t\t\tif (pau == 0) {\t/* au auto-selection */\n\t\t\t\t\tn = sz_vol / 0x1000;\t/* Volume size in unit of 4KS */\n\t\t\t\t\tfor (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ;\t/* Get from table */\n\t\t\t\t}\n\t\t\t\tn_clst = sz_vol / pau;\n\t\t\t\tif (n_clst > MAX_FAT12) {\n\t\t\t\t\tn = n_clst * 2 + 4;\t\t/* FAT size [byte] */\n\t\t\t\t} else {\n\t\t\t\t\tfmt = FS_FAT12;\n\t\t\t\t\tn = (n_clst * 3 + 1) / 2 + 3;\t/* FAT size [byte] */\n\t\t\t\t}\n\t\t\t\tsz_fat = (n + ss - 1) / ss;\t\t/* FAT size [sector] */\n\t\t\t\tsz_rsv = 1;\t\t\t\t\t\t/* Number of reserved sectors */\n\t\t\t\tsz_dir = (DWORD)n_rootdir * SZDIRE / ss;\t/* Rootdir size [sector] */\n\t\t\t\tb_fat = b_vol + sz_rsv;\t\t\t\t\t\t/* FAT base */\n\t\t\t\tb_data = b_fat + sz_fat * n_fats + sz_dir;\t/* Data base */\n\n\t\t\t\t/* Align data base to erase block boundary (for flash memory media) */\n\t\t\t\tn = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data;\t/* Next nearest erase block from current data base */\n\t\t\t\tif (n % n_fats) {\t/* Adjust fractional error if needed */\n\t\t\t\t\tn--; sz_rsv++; b_fat++;\t/* FAT: Expand FAT size */\n\t\t\t\t}\n\t\t\t\tsz_fat += n / n_fats;\n\t\t\t}\n\n\t\t\t/* Determine number of clusters and final check of validity of the FAT sub-type */\n\t\t\tif (sz_vol < b_data + pau * 16 - b_vol) LEAVE_MKFS(FR_MKFS_ABORTED);\t/* Too small volume */\n\t\t\tn_clst = (sz_vol - sz_rsv - sz_fat * n_fats - sz_dir) / pau;\n\t\t\tif (fmt == FS_FAT32) {\n\t\t\t\tif (n_clst <= MAX_FAT16) {\t/* Too few clusters for FAT32 */\n\t\t\t\t\tif (au == 0 && (au = pau / 2) != 0) continue;\t/* Adjust cluster size and retry */\n\t\t\t\t\tLEAVE_MKFS(FR_MKFS_ABORTED);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (fmt == FS_FAT16) {\n\t\t\t\tif (n_clst > MAX_FAT16) {\t/* Too many clusters for FAT16 */\n\t\t\t\t\tif (au == 0 && (pau * 2) <= 64) {\n\t\t\t\t\t\tau = pau * 2; continue;\t\t/* Adjust cluster size and retry */\n\t\t\t\t\t}\n\t\t\t\t\tif ((opt & FM_FAT32)) {\n\t\t\t\t\t\tfmt = FS_FAT32; continue;\t/* Switch type to FAT32 and retry */\n\t\t\t\t\t}\n\t\t\t\t\tif (au == 0 && (au = pau * 2) <= 128) continue;\t/* Adjust cluster size and retry */\n\t\t\t\t\tLEAVE_MKFS(FR_MKFS_ABORTED);\n\t\t\t\t}\n\t\t\t\tif  (n_clst <= MAX_FAT12) {\t/* Too few clusters for FAT16 */\n\t\t\t\t\tif (au == 0 && (au = pau * 2) <= 128) continue;\t/* Adjust cluster size and retry */\n\t\t\t\t\tLEAVE_MKFS(FR_MKFS_ABORTED);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (fmt == FS_FAT12 && n_clst > MAX_FAT12) LEAVE_MKFS(FR_MKFS_ABORTED);\t/* Too many clusters for FAT12 */\n\n\t\t\t/* Ok, it is the valid cluster configuration */\n\t\t\tbreak;\n\t\t} while (1);\n\n#if FF_USE_TRIM\n\t\ttbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1;\t/* Inform the device the volume area can be erased */\n\t\tdisk_ioctl(pdrv, CTRL_TRIM, tbl);\n#endif\n\t\t/* Create FAT VBR */\n\t\tmem_set(buf, 0, ss);\n\t\t/* Boot jump code (x86), OEM name */\n\t\tif (!(opt & FM_PRF2)) mem_cpy(buf + BS_JmpBoot, \"\\xEB\\xFE\\x90\" \"NYX1.8.0\", 11);\n\t\telse mem_cpy(buf + BS_JmpBoot, \"\\xEB\\xE9\\x90\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\", 11);\n\t\tst_word(buf + BPB_BytsPerSec, ss);\t\t\t\t/* Sector size [byte] */\n\t\tbuf[BPB_SecPerClus] = (BYTE)pau;\t\t\t\t/* Cluster size [sector] */\n\t\tst_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv);\t/* Size of reserved area */\n\t\tbuf[BPB_NumFATs] = (BYTE)n_fats;\t\t\t\t/* Number of FATs */\n\t\tst_word(buf + BPB_RootEntCnt, (WORD)((fmt == FS_FAT32) ? 0 : n_rootdir));\t/* Number of root directory entries */\n\t\tif (sz_vol < 0x10000) {\n\t\t\tst_word(buf + BPB_TotSec16, (WORD)sz_vol);\t/* Volume size in 16-bit LBA */\n\t\t} else {\n\t\t\tst_dword(buf + BPB_TotSec32, sz_vol);\t\t/* Volume size in 32-bit LBA */\n\t\t}\n\t\tbuf[BPB_Media] = 0xF8;\t\t\t\t\t\t\t/* Media descriptor byte */\n\t\tst_word(buf + BPB_SecPerTrk, 63);\t\t\t\t/* Number of sectors per track (for int13) */\n\t\tst_word(buf + BPB_NumHeads, (opt & FM_PRF2) ? 16 : 255);\t/* Number of heads (for int13) */\n\t\tst_dword(buf + BPB_HiddSec, b_vol);\t\t\t\t/* Volume offset in the physical drive [sector] */\n\t\tif (fmt == FS_FAT32) {\n\t\t\tst_dword(buf + BS_VolID32, (opt & FM_PRF2) ? 0 : GET_FATTIME());\t/* VSN */\n\t\t\tst_dword(buf + BPB_FATSz32, sz_fat);\t\t/* FAT size [sector] */\n\t\t\tst_dword(buf + BPB_RootClus32, 2);\t\t\t/* Root directory cluster # (2) */\n\t\t\tst_word(buf + BPB_FSInfo32, 1);\t\t\t\t/* Offset of FSINFO sector (VBR + 1) */\n\t\t\tst_word(buf + BPB_BkBootSec32, 6);\t\t\t/* Offset of backup VBR (VBR + 6) */\n\t\t\tbuf[BS_DrvNum32] = 0x80;\t\t\t\t\t/* Drive number (for int13) */\n\t\t\tbuf[BS_BootSig32] = 0x29;\t\t\t\t\t/* Extended boot signature */\n\t\t\t/* Volume label, FAT signature */\n\t\t\tif (!(opt & FM_PRF2)) mem_cpy(buf + BS_VolLab32, FF_MKFS_LABEL \"FAT32   \", 19);\n\t\t\telse mem_cpy(buf + BS_VolLab32, \"NO NAME    \" \"FAT32   \", 19);\n\t\t} else {\n\t\t\tst_dword(buf + BS_VolID, GET_FATTIME());\t/* VSN */\n\t\t\tst_word(buf + BPB_FATSz16, (WORD)sz_fat);\t/* FAT size [sector] */\n\t\t\tbuf[BS_DrvNum] = 0x80;\t\t\t\t\t\t/* Drive number (for int13) */\n\t\t\tbuf[BS_BootSig] = 0x29;\t\t\t\t\t\t/* Extended boot signature */\n\t\t\t/* Volume label, FAT signature */\n\t\t\tif (!(opt & FM_PRF2)) mem_cpy(buf + BS_VolLab, FF_MKFS_LABEL \"FAT     \", 19);\n\t\t\telse mem_cpy(buf + BS_VolLab, \"NO NAME    \" \"FAT     \", 19);\n\t\t}\n\t\tst_word(buf + BS_55AA, 0xAA55);\t\t\t\t\t/* Signature (offset is fixed here regardless of sector size) */\n\t\tif (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);\t/* Write it to the VBR sector */\n\n\t\t/* Create FSINFO record if needed */\n\t\tif (fmt == FS_FAT32) {\n\t\t\tdisk_write(pdrv, buf, b_vol + 6, 1);\t\t/* Write backup VBR (VBR + 6) */\n\t\t\tmem_set(buf, 0, ss);\n\t\t\tst_dword(buf + FSI_LeadSig, 0x41615252);\n\t\t\tst_dword(buf + FSI_StrucSig, 0x61417272);\n\t\t\tif (opt & FM_PRF2) {\n\t\t\t\tst_dword(buf + FSI_Free_Count, 0xFFFFFFFF);\t/* Invalidate free count */\n\t\t\t\tst_dword(buf + FSI_Nxt_Free, 0xFFFFFFFF);\t/* Invalidate last allocated cluster */\n\t\t\t} else {\n\t\t\t\tst_dword(buf + FSI_Free_Count, n_clst - 1);\t/* Number of free clusters */\n\t\t\t\tst_dword(buf + FSI_Nxt_Free, 2);\t\t\t/* Last allocated cluster# */\n\t\t\t}\n\t\t\tst_word(buf + BS_55AA, 0xAA55);\n\t\t\tdisk_write(pdrv, buf, b_vol + 7, 1);\t\t/* Write backup FSINFO (VBR + 7) */\n\t\t\tdisk_write(pdrv, buf, b_vol + 1, 1);\t\t/* Write original FSINFO (VBR + 1) */\n\t\t}\n\n\t\t/* Clear PRF2SAFE info so PrFILE2 can recreate it and upgrade it if old */\n\t\tif (fmt == FS_FAT32 && opt & FM_PRF2) {\n\t\t\tmem_set(buf, 0, ss);\n\t\t\tdisk_write(pdrv, buf, b_vol + 3, 1);\t\t\t/* Write PRF2SAFE info (VBR + 3) */\n\t\t}\n\n\t\t/* Initialize FAT area */\n\t\tmem_set(buf, 0, (UINT)szb_buf);\n\t\tsect = b_fat;\t\t/* FAT start sector */\n\t\tfor (i = 0; i < n_fats; i++) {\t\t\t/* Initialize FATs each */\n\t\t\tif (fmt == FS_FAT32) {\n\t\t\t\tst_dword(buf + 0, 0xFFFFFFF8);\t/* Entry 0 */\n\t\t\t\tst_dword(buf + 4, 0xFFFFFFFF);\t/* Entry 1 */\n\t\t\t\tst_dword(buf + 8, 0x0FFFFFFF);\t/* Entry 2 (root directory) */\n\t\t\t} else {\n\t\t\t\tst_dword(buf + 0, (fmt == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8);\t/* Entry 0 and 1 */\n\t\t\t}\n\t\t\tnsect = sz_fat;\t\t/* Number of FAT sectors */\n\t\t\tdo {\t/* Fill FAT sectors */\n\t\t\t\tn = (nsect > sz_buf) ? sz_buf : nsect;\n\t\t\t\tif (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);\n\t\t\t\tmem_set(buf, 0, ss);\n\t\t\t\tsect += n; nsect -= n;\n\t\t\t} while (nsect);\n\t\t}\n\n\t\t/* Initialize root directory (fill with zero) */\n\t\tnsect = (fmt == FS_FAT32) ? pau : sz_dir;\t/* Number of root directory sectors */\n\t\tdo {\n\t\t\tn = (nsect > sz_buf) ? sz_buf : nsect;\n\t\t\tif (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);\n\t\t\tsect += n; nsect -= n;\n\t\t} while (nsect);\n\t}\n\n\t/* Determine system ID in the partition table */\n\tif (FF_FS_EXFAT && fmt == FS_EXFAT) {\n\t\tsys = 0x07;\t\t\t/* HPFS/NTFS/exFAT */\n\t} else {\n\t\tif (fmt == FS_FAT32) {\n\t\t\tsys = 0x0C;\t\t/* FAT32X */\n\t\t} else {\n\t\t\tif (sz_vol >= 0x10000) {\n\t\t\t\tsys = 0x06;\t/* FAT12/16 (large) */\n\t\t\t} else {\n\t\t\t\tsys = (fmt == FS_FAT16) ? 0x04 : 0x01;\t/* FAT16 : FAT12 */\n\t\t\t}\n\t\t}\n\t}\n\n\t/* Update partition information */\n\tif (FF_MULTI_PARTITION && part != 0) {\t/* Created in the existing partition */\n\t\t/* Update system ID in the partition table */\n\t\tif (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);\t/* Read the MBR */\n\t\tbuf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys;\t\t/* Set system ID */\n\t\tif (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);\t/* Write it back to the MBR */\n\t} else {\t\t\t\t\t\t\t\t/* Created as a new single partition */\n\t\tif (!(opt & FM_SFD)) {\t/* Create partition table if in FDISK format */\n\t\t\tmem_set(buf, 0, ss);\n\t\t\tst_word(buf + BS_55AA, 0xAA55);\t\t/* MBR signature */\n\t\t\tpte = buf + MBR_Table;\t\t\t\t/* Create partition table for single partition in the drive */\n\t\t\tpte[PTE_Boot] = 0;\t\t\t\t\t/* Boot indicator */\n\t\t\tpte[PTE_StHead] = 1;\t\t\t\t/* Start head */\n\t\t\tpte[PTE_StSec] = 1;\t\t\t\t\t/* Start sector */\n\t\t\tpte[PTE_StCyl] = 0;\t\t\t\t\t/* Start cylinder */\n\t\t\tpte[PTE_System] = sys;\t\t\t\t/* System type */\n\t\t\tn = (b_vol + sz_vol) / (63 * 255);\t/* (End CHS may be invalid) */\n\t\t\tpte[PTE_EdHead] = 254;\t\t\t\t/* End head */\n\t\t\tpte[PTE_EdSec] = (BYTE)(((n >> 2) & 0xC0) | 63);\t/* End sector */\n\t\t\tpte[PTE_EdCyl] = (BYTE)n;\t\t\t/* End cylinder */\n\t\t\tst_dword(pte + PTE_StLba, b_vol);\t/* Start offset in LBA */\n\t\t\tst_dword(pte + PTE_SizLba, sz_vol);\t/* Size in sectors */\n\t\t\tif (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);\t/* Write it to the MBR */\n\t\t}\n\t}\n\n\tif (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);\n\n\tLEAVE_MKFS(FR_OK);\n}\n\n\n\n#if FF_MULTI_PARTITION\n/*-----------------------------------------------------------------------*/\n/* Create Partition Table on the Physical Drive                          */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_fdisk (\n\tBYTE pdrv,\t\t\t/* Physical drive number */\n\tconst DWORD* szt,\t/* Pointer to the size table for each partitions */\n\tvoid* work\t\t\t/* Pointer to the working buffer (null: use heap memory) */\n)\n{\n\tUINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl;\n\tBYTE s_hd, e_hd, *p, *buf = (BYTE*)work;\n\tDSTATUS stat;\n\tDWORD sz_disk, sz_part, s_part;\n\tFRESULT res;\n\n\n\tstat = disk_initialize(pdrv);\n\tif (stat & STA_NOINIT) return FR_NOT_READY;\n\tif (stat & STA_PROTECT) return FR_WRITE_PROTECTED;\n\tif (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR;\n\n\tbuf = (BYTE*)work;\n#if FF_USE_LFN == 3\n\tif (!buf) buf = ff_memalloc(FF_MAX_SS);\t/* Use heap memory for working buffer */\n#endif\n\tif (!buf) return FR_NOT_ENOUGH_CORE;\n\n\t/* Determine the CHS without any consideration of the drive geometry */\n\tfor (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ;\n\tif (n == 256) n--;\n\te_hd = (BYTE)(n - 1);\n\tsz_cyl = 63 * n;\n\ttot_cyl = sz_disk / sz_cyl;\n\n\t/* Create partition table */\n\tmem_set(buf, 0, FF_MAX_SS);\n\tp = buf + MBR_Table; b_cyl = 0;\n\tfor (i = 0; i < 4; i++, p += SZ_PTE) {\n\t\tp_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl;\t/* Number of cylinders */\n\t\tif (p_cyl == 0) continue;\n\t\ts_part = (DWORD)sz_cyl * b_cyl;\n\t\tsz_part = (DWORD)sz_cyl * p_cyl;\n\t\tif (i == 0) {\t/* Exclude first track of cylinder 0 */\n\t\t\ts_hd = 1;\n\t\t\ts_part += 63; sz_part -= 63;\n\t\t} else {\n\t\t\ts_hd = 0;\n\t\t}\n\t\te_cyl = b_cyl + p_cyl - 1;\t/* End cylinder */\n\t\tif (e_cyl >= tot_cyl) LEAVE_MKFS(FR_INVALID_PARAMETER);\n\n\t\t/* Set partition table */\n\t\tp[1] = s_hd;\t\t\t\t\t\t/* Start head */\n\t\tp[2] = (BYTE)(((b_cyl >> 2) & 0xC0) | 1);\t/* Start sector */\n\t\tp[3] = (BYTE)b_cyl;\t\t\t\t\t/* Start cylinder */\n\t\tp[4] = 0x07;\t\t\t\t\t\t/* System type (temporary setting) */\n\t\tp[5] = e_hd;\t\t\t\t\t\t/* End head */\n\t\tp[6] = (BYTE)(((e_cyl >> 2) & 0xC0) | 63);\t/* End sector */\n\t\tp[7] = (BYTE)e_cyl;\t\t\t\t\t/* End cylinder */\n\t\tst_dword(p + 8, s_part);\t\t\t/* Start sector in LBA */\n\t\tst_dword(p + 12, sz_part);\t\t\t/* Number of sectors */\n\n\t\t/* Next partition */\n\t\tb_cyl += p_cyl;\n\t}\n\tst_word(p, 0xAA55);\t\t/* MBR signature (always at offset 510) */\n\n\t/* Write it to the MBR */\n\tres = (disk_write(pdrv, buf, 0, 1) == RES_OK && disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR;\n\tLEAVE_MKFS(res);\n}\n\n#endif /* FF_MULTI_PARTITION */\n#endif /* FF_USE_MKFS && !FF_FS_READONLY */\n\n\n\n\n#if FF_USE_STRFUNC\n#if FF_USE_LFN && FF_LFN_UNICODE && (FF_STRF_ENCODE < 0 || FF_STRF_ENCODE > 3)\n#error Wrong FF_STRF_ENCODE setting\n#endif\n/*-----------------------------------------------------------------------*/\n/* Get a String from the File                                            */\n/*-----------------------------------------------------------------------*/\n\nTCHAR* f_gets (\n\tTCHAR* buff,\t/* Pointer to the string buffer to read */\n\tint len,\t\t/* Size of string buffer (items) */\n\tFIL* fp\t\t\t/* Pointer to the file object */\n)\n{\n\tint nc = 0;\n\tTCHAR *p = buff;\n\tBYTE s[4];\n\tUINT rc;\n\tDWORD dc;\n#if FF_USE_LFN && FF_LFN_UNICODE && FF_STRF_ENCODE <= 2\n\tWCHAR wc;\n#endif\n#if FF_USE_LFN && FF_LFN_UNICODE && FF_STRF_ENCODE == 3\n\tUINT ct;\n#endif\n\n#if FF_USE_LFN && FF_LFN_UNICODE\t\t\t/* With code conversion (Unicode API) */\n\t/* Make a room for the character and terminator  */\n\tif (FF_LFN_UNICODE == 1) len -= (FF_STRF_ENCODE == 0) ? 1 : 2;\n\tif (FF_LFN_UNICODE == 2) len -= (FF_STRF_ENCODE == 0) ? 3 : 4;\n\tif (FF_LFN_UNICODE == 3) len -= 1;\n\twhile (nc < len) {\n#if FF_STRF_ENCODE == 0\t\t/* Read a character in ANSI/OEM */\n\t\tf_read(fp, s, 1, &rc);\n\t\tif (rc != 1) break;\n\t\twc = s[0];\n\t\tif (dbc_1st((BYTE)wc)) {\n\t\t\tf_read(fp, s, 1, &rc);\n\t\t\tif (rc != 1 || !dbc_2nd(s[0])) continue;\n\t\t\twc = wc << 8 | s[0];\n\t\t}\n\t\tdc = ff_oem2uni(wc, CODEPAGE);\n\t\tif (dc == 0) continue;\n#elif FF_STRF_ENCODE == 1 || FF_STRF_ENCODE == 2 \t/* Read a character in UTF-16LE/BE */\n\t\tf_read(fp, s, 2, &rc);\n\t\tif (rc != 2) break;\n\t\tdc = (FF_STRF_ENCODE == 1) ? ld_word(s) : s[0] << 8 | s[1];\n\t\tif (IsSurrogateL(dc)) continue;\n\t\tif (IsSurrogateH(dc)) {\n\t\t\tf_read(fp, s, 2, &rc);\n\t\t\tif (rc != 2) break;\n\t\t\twc = (FF_STRF_ENCODE == 1) ? ld_word(s) : s[0] << 8 | s[1];\n\t\t\tif (!IsSurrogateL(wc)) continue;\n\t\t\tdc = ((dc & 0x3FF) + 0x40) << 10 | (wc & 0x3FF);\n\t\t}\n#else\t/* Read a character in UTF-8 */\n\t\tf_read(fp, s, 1, &rc);\n\t\tif (rc != 1) break;\n\t\tdc = s[0];\n\t\tif (dc >= 0x80) {\t/* Multi-byte character? */\n\t\t\tct = 0;\n\t\t\tif ((dc & 0xE0) == 0xC0) { dc &= 0x1F; ct = 1; }\t/* 2-byte? */\n\t\t\tif ((dc & 0xF0) == 0xE0) { dc &= 0x0F; ct = 2; }\t/* 3-byte? */\n\t\t\tif ((dc & 0xF8) == 0xF0) { dc &= 0x07; ct = 3; }\t/* 4-byte? */\n\t\t\tif (ct == 0) continue;\n\t\t\tf_read(fp, s, ct, &rc);\t\t/* Get trailing bytes */\n\t\t\tif (rc != ct) break;\n\t\t\trc = 0;\n\t\t\tdo {\t/* Merge trailing bytes */\n\t\t\t\tif ((s[rc] & 0xC0) != 0x80) break;\n\t\t\t\tdc = dc << 6 | (s[rc] & 0x3F);\n\t\t\t} while (++rc < ct);\n\t\t\tif (rc != ct || dc < 0x80 || IsSurrogate(dc) || dc >= 0x110000) continue;\t/* Wrong encoding? */\n\t\t}\n#endif\n\t\tif (FF_USE_STRFUNC == 2 && dc == '\\r') continue;\t/* Strip \\r off if needed */\n#if FF_LFN_UNICODE == 1\t|| FF_LFN_UNICODE == 3\t/* Output it in UTF-16/32 encoding */\n\t\tif (FF_LFN_UNICODE == 1 && dc >= 0x10000) {\t/* Out of BMP at UTF-16? */\n\t\t\t*p++ = (TCHAR)(0xD800 | ((dc >> 10) - 0x40)); nc++;\t/* Make and output high surrogate */\n\t\t\tdc = 0xDC00 | (dc & 0x3FF);\t\t/* Make low surrogate */\n\t\t}\n\t\t*p++ = (TCHAR)dc; nc++;\n\t\tif (dc == '\\n') break;\t/* End of line? */\n#elif FF_LFN_UNICODE == 2\t\t/* Output it in UTF-8 encoding */\n\t\tif (dc < 0x80) {\t/* 1-byte */\n\t\t\t*p++ = (TCHAR)dc;\n\t\t\tnc++;\n\t\t\tif (dc == '\\n') break;\t/* End of line? */\n\t\t} else {\n\t\t\tif (dc < 0x800) {\t\t/* 2-byte */\n\t\t\t\t*p++ = (TCHAR)(0xC0 | (dc >> 6 & 0x1F));\n\t\t\t\t*p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F));\n\t\t\t\tnc += 2;\n\t\t\t} else {\n\t\t\t\tif (dc < 0x10000) {\t/* 3-byte */\n\t\t\t\t\t*p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F));\n\t\t\t\t\t*p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F));\n\t\t\t\t\t*p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F));\n\t\t\t\t\tnc += 3;\n\t\t\t\t} else {\t\t\t/* 4-byte */\n\t\t\t\t\t*p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07));\n\t\t\t\t\t*p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F));\n\t\t\t\t\t*p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F));\n\t\t\t\t\t*p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F));\n\t\t\t\t\tnc += 4;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n#endif\n\t}\n\n#else\t\t\t/* Byte-by-byte without any conversion (ANSI/OEM API) */\n\tlen -= 1;\t/* Make a room for the terminator */\n\twhile (nc < len) {\n\t\tf_read(fp, s, 1, &rc);\n\t\tif (rc != 1) break;\n\t\tdc = s[0];\n\t\tif (FF_USE_STRFUNC == 2 && dc == '\\r') continue;\n\t\t*p++ = (TCHAR)dc; nc++;\n\t\tif (dc == '\\n') break;\n\t}\n#endif\n\n\t*p = 0;\t\t/* Terminate the string */\n\treturn nc ? buff : 0;\t/* When no data read due to EOF or error, return with error. */\n}\n\n\n\n\n#if !FF_FS_READONLY\n#include <stdarg.h>\n/*-----------------------------------------------------------------------*/\n/* Put a Character to the File                                           */\n/*-----------------------------------------------------------------------*/\n\ntypedef struct {\t/* Putchar output buffer and work area */\n\tFIL *fp;\t\t/* Ptr to the writing file */\n\tint idx, nchr;\t/* Write index of buf[] (-1:error), number of encoding units written */\n#if FF_USE_LFN && FF_LFN_UNICODE == 1\n\tWCHAR hs;\n#elif FF_USE_LFN && FF_LFN_UNICODE == 2\n\tBYTE bs[4];\n\tUINT wi, ct;\n#endif\n\tBYTE buf[64];\t/* Write buffer */\n} putbuff;\n\n\nstatic void putc_bfd (\t\t/* Buffered write with code conversion */\n\tputbuff* pb,\n\tTCHAR c\n)\n{\n\tUINT n;\n\tint i, nc;\n#if FF_USE_LFN && FF_LFN_UNICODE\n\tWCHAR hs, wc;\n#if FF_LFN_UNICODE == 2\n\tDWORD dc;\n\tTCHAR *tp;\n#endif\n#endif\n\n\tif (FF_USE_STRFUNC == 2 && c == '\\n') {\t /* LF -> CRLF conversion */\n\t\tputc_bfd(pb, '\\r');\n\t}\n\n\ti = pb->idx;\t\t\t/* Write index of pb->buf[] */\n\tif (i < 0) return;\n\tnc = pb->nchr;\t\t\t/* Write unit counter */\n\n#if FF_USE_LFN && FF_LFN_UNICODE\n#if FF_LFN_UNICODE == 1\t\t/* UTF-16 input */\n\tif (IsSurrogateH(c)) {\n\t\tpb->hs = c; return;\n\t}\n\ths = pb->hs; pb->hs = 0;\n\tif (hs != 0) {\n\t\tif (!IsSurrogateL(c)) hs = 0;\n\t} else {\n\t\tif (IsSurrogateL(c)) return;\n\t}\n\twc = c;\n#elif FF_LFN_UNICODE == 2\t/* UTF-8 input */\n\tfor (;;) {\n\t\tif (pb->ct == 0) {\t/* Out of multi-byte sequence? */\n\t\t\tpb->bs[pb->wi = 0] = (BYTE)c;\t/* Save 1st byte */\n\t\t\tif ((BYTE)c < 0x80) break;\t\t\t\t\t/* 1-byte? */\n\t\t\tif (((BYTE)c & 0xE0) == 0xC0) pb->ct = 1;\t/* 2-byte? */\n\t\t\tif (((BYTE)c & 0xF0) == 0xE0) pb->ct = 2;\t/* 3-byte? */\n\t\t\tif (((BYTE)c & 0xF1) == 0xF0) pb->ct = 3;\t/* 4-byte? */\n\t\t\treturn;\n\t\t} else {\t\t\t\t/* In the multi-byte sequence */\n\t\t\tif (((BYTE)c & 0xC0) != 0x80) {\t/* Broken sequence? */\n\t\t\t\tpb->ct = 0; continue;\n\t\t\t}\n\t\t\tpb->bs[++pb->wi] = (BYTE)c;\t/* Save the trailing byte */\n\t\t\tif (--pb->ct == 0) break;\t/* End of multi-byte sequence? */\n\t\t\treturn;\n\t\t}\n\t}\n\ttp = (TCHAR*)pb->bs;\n\tdc = tchar2uni(&tp);\t/* UTF-8 ==> UTF-16 */\n\tif (dc == 0xFFFFFFFF) return;\n\twc = (WCHAR)dc;\n\ths = (WCHAR)(dc >> 16);\n#elif FF_LFN_UNICODE == 3\t/* UTF-32 input */\n\tif (IsSurrogate(c) || c >= 0x110000) return;\n\tif (c >= 0x10000) {\n\t\ths = (WCHAR)(0xD800 | ((c >> 10) - 0x40)); \t/* Make high surrogate */\n\t\twc = 0xDC00 | (c & 0x3FF);\t\t\t\t\t/* Make low surrogate */\n\t} else {\n\t\ths = 0;\n\t\twc = (WCHAR)c;\n\t}\n#endif\n\n#if FF_STRF_ENCODE == 1\t\t/* Write a character in UTF-16LE */\n\tif (hs != 0) {\n\t\tst_word(&pb->buf[i], hs);\n\t\ti += 2;\n\t\tnc++;\n\t}\n\tst_word(&pb->buf[i], wc);\n\ti += 2;\n#elif FF_STRF_ENCODE == 2\t/* Write a character in UTF-16BE */\n\tif (hs != 0) {\n\t\tpb->buf[i++] = (BYTE)(hs >> 8);\n\t\tpb->buf[i++] = (BYTE)hs;\n\t\tnc++;\n\t}\n\tpb->buf[i++] = (BYTE)(wc >> 8);\n\tpb->buf[i++] = (BYTE)wc;\n#elif FF_STRF_ENCODE == 3\t/* Write it in UTF-8 */\n\tif (hs != 0) {\t\t\t\t/* 4-byte */\n\t\tnc += 3;\n\t\ths = (hs & 0x3FF) + 0x40;\n\t\tpb->buf[i++] = (BYTE)(0xF0 | hs >> 8);\n\t\tpb->buf[i++] = (BYTE)(0x80 | (hs >> 2 & 0x3F));\n\t\tpb->buf[i++] = (BYTE)(0x80 | (hs & 3) << 4 | (wc >> 6 & 0x0F));\n\t\tpb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F));\n\t} else {\n\t\tif (wc < 0x80) {\t\t/* 1-byte */\n\t\t\tpb->buf[i++] = (BYTE)wc;\n\t\t} else {\n\t\t\tif (wc < 0x800) {\t/* 2-byte */\n\t\t\t\tnc += 1;\n\t\t\t\tpb->buf[i++] = (BYTE)(0xC0 | wc >> 6);\n\t\t\t} else {\t\t\t/* 3-byte */\n\t\t\t\tnc += 2;\n\t\t\t\tpb->buf[i++] = (BYTE)(0xE0 | wc >> 12);\n\t\t\t\tpb->buf[i++] = (BYTE)(0x80 | (wc >> 6 & 0x3F));\n\t\t\t}\n\t\t\tpb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F));\n\t\t}\n\t}\n#else\t\t\t\t\t\t/* Write it in ANSI/OEM */\n\tif (hs != 0) return;\n\twc = ff_uni2oem(wc, CODEPAGE);\t/* UTF-16 ==> ANSI/OEM */\n\tif (wc == 0) return;\n\tif (wc >= 0x100) {\n\t\tpb->buf[i++] = (BYTE)(wc >> 8); nc++;\n\t}\n\tpb->buf[i++] = (BYTE)wc;\n#endif\n\n#else\t\t\t\t\t\t\t\t\t/* ANSI/OEM input (without re-encode) */\n\tpb->buf[i++] = (BYTE)c;\n#endif\n\n\tif (i >= (int)(sizeof pb->buf) - 4) {\t/* Write buffered characters to the file */\n\t\tf_write(pb->fp, pb->buf, (UINT)i, &n);\n\t\ti = (n == (UINT)i) ? 0 : -1;\n\t}\n\tpb->idx = i;\n\tpb->nchr = nc + 1;\n}\n\n\nstatic int putc_flush (\t\t/* Flush left characters in the buffer */\n\tputbuff* pb\n)\n{\n\tUINT nw;\n\n\tif (   pb->idx >= 0\t/* Flush buffered characters to the file */\n\t\t&& f_write(pb->fp, pb->buf, (UINT)pb->idx, &nw) == FR_OK\n\t\t&& (UINT)pb->idx == nw) return pb->nchr;\n\treturn EOF;\n}\n\n\nstatic void putc_init (\t\t/* Initialize write buffer */\n\tputbuff* pb,\n\tFIL* fp\n)\n{\n\tmem_set(pb, 0, sizeof (putbuff));\n\tpb->fp = fp;\n}\n\n\n\nint f_putc (\n\tTCHAR c,\t/* A character to be output */\n\tFIL* fp\t\t/* Pointer to the file object */\n)\n{\n\tputbuff pb;\n\n\n\tputc_init(&pb, fp);\n\tputc_bfd(&pb, c);\t/* Put the character */\n\treturn putc_flush(&pb);\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Put a String to the File                                              */\n/*-----------------------------------------------------------------------*/\n\nint f_puts (\n\tconst TCHAR* str,\t/* Pointer to the string to be output */\n\tFIL* fp\t\t\t\t/* Pointer to the file object */\n)\n{\n\tputbuff pb;\n\n\tif (str == (void *)0) return EOF; /* String is NULL */\n\n\tputc_init(&pb, fp);\n\twhile (*str) putc_bfd(&pb, *str++);\t\t/* Put the string */\n\treturn putc_flush(&pb);\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Put a Formatted String to the File                                    */\n/*-----------------------------------------------------------------------*/\n\nint f_printf (\n\tFIL* fp,\t\t\t/* Pointer to the file object */\n\tconst TCHAR* fmt,\t/* Pointer to the format string */\n\t...\t\t\t\t\t/* Optional arguments... */\n)\n{\n\tva_list arp;\n\tputbuff pb;\n\tBYTE f, r;\n\tUINT i, j, w;\n\tDWORD v;\n\tTCHAR c, d, str[32], *p;\n\n\tif (fmt == (void *)0) return EOF; /* String is NULL */\n\n\tputc_init(&pb, fp);\n\n\tva_start(arp, fmt);\n\n\tfor (;;) {\n\t\tc = *fmt++;\n\t\tif (c == 0) break;\t\t\t/* End of string */\n\t\tif (c != '%') {\t\t\t\t/* Non escape character */\n\t\t\tputc_bfd(&pb, c);\n\t\t\tcontinue;\n\t\t}\n\t\tw = f = 0;\n\t\tc = *fmt++;\n\t\tif (c == '0') {\t\t\t\t/* Flag: '0' padding */\n\t\t\tf = 1; c = *fmt++;\n\t\t} else {\n\t\t\tif (c == '-') {\t\t\t/* Flag: left justified */\n\t\t\t\tf = 2; c = *fmt++;\n\t\t\t}\n\t\t}\n\t\tif (c == '*') {\t\t\t\t/* Minimum width by argument */\n\t\t\tw = va_arg(arp, int);\n\t\t\tc = *fmt++;\n\t\t} else {\n\t\t\twhile (IsDigit(c)) {\t/* Minimum width */\n\t\t\t\tw = w * 10 + c - '0';\n\t\t\t\tc = *fmt++;\n\t\t\t}\n\t\t}\n\t\tif (c == 'l' || c == 'L') {\t/* Type prefix: Size is long int */\n\t\t\tf |= 4; c = *fmt++;\n\t\t}\n\t\tif (c == 0) break;\n\t\td = c;\n\t\tif (IsLower(d)) d -= 0x20;\n\t\tswitch (d) {\t\t\t\t/* Atgument type is... */\n\t\tcase 'S' :\t\t\t\t\t/* String */\n\t\t\tp = va_arg(arp, TCHAR*);\n\t\t\tfor (j = 0; p[j]; j++) ;\n\t\t\tif (!(f & 2)) {\t\t\t\t\t\t/* Right padded */\n\t\t\t\twhile (j++ < w) putc_bfd(&pb, ' ') ;\n\t\t\t}\n\t\t\twhile (*p) putc_bfd(&pb, *p++) ;\t\t/* String body */\n\t\t\twhile (j++ < w) putc_bfd(&pb, ' ') ;\t/* Left padded */\n\t\t\tcontinue;\n\n\t\tcase 'C' :\t\t\t\t\t/* Character */\n\t\t\tputc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue;\n\n\t\tcase 'B' :\t\t\t\t\t/* Unsigned binary */\n\t\t\tr = 2; break;\n\n\t\tcase 'O' :\t\t\t\t\t/* Unsigned octal */\n\t\t\tr = 8; break;\n\n\t\tcase 'D' :\t\t\t\t\t/* Signed decimal */\n\t\tcase 'U' :\t\t\t\t\t/* Unsigned decimal */\n\t\t\tr = 10; break;\n\n\t\tcase 'X' :\t\t\t\t\t/* Unsigned hexdecimal */\n\t\t\tr = 16; break;\n\n\t\tdefault:\t\t\t\t\t/* Unknown type (pass-through) */\n\t\t\tputc_bfd(&pb, c); continue;\n\t\t}\n\n\t\t/* Get an argument and put it in numeral */\n\t\tv = (f & 4) ? (DWORD)va_arg(arp, long) : ((d == 'D') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int));\n\t\tif (d == 'D' && (v & 0x80000000)) {\n\t\t\tv = 0 - v;\n\t\t\tf |= 8;\n\t\t}\n\t\ti = 0;\n\t\tdo {\n\t\t\td = (TCHAR)(v % r); v /= r;\n\t\t\tif (d > 9) d += (c == 'x') ? 0x27 : 0x07;\n\t\t\tstr[i++] = d + '0';\n\t\t} while (v && i < sizeof str / sizeof *str);\n\t\tif (f & 8) str[i++] = '-';\n\t\tj = i; d = (f & 1) ? '0' : ' ';\n\t\tif (!(f & 2)) {\n\t\t\twhile (j++ < w) putc_bfd(&pb, d);\t/* Right pad */\n\t\t}\n\t\tdo {\n\t\t\tputc_bfd(&pb, str[--i]);\t\t\t/* Number body */\n\t\t} while (i);\n\t\twhile (j++ < w) putc_bfd(&pb, d);\t\t/* Left pad */\n\t}\n\n\tva_end(arp);\n\n\treturn putc_flush(&pb);\n}\n\n#endif /* !FF_FS_READONLY */\n#endif /* FF_USE_STRFUNC */\n\n\n\n#if FF_CODE_PAGE == 0\n/*-----------------------------------------------------------------------*/\n/* Set Active Codepage for the Path Name                                 */\n/*-----------------------------------------------------------------------*/\n\nFRESULT f_setcp (\n\tWORD cp\t\t/* Value to be set as active code page */\n)\n{\n\tstatic const WORD       validcp[] = {  437,   720,   737,   771,   775,   850,   852,   857,   860,   861,   862,   863,   864,   865,   866,   869,   932,   936,   949,   950, 0};\n\tstatic const BYTE* const tables[] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0};\n\tUINT i;\n\n\n\tfor (i = 0; validcp[i] != 0 && validcp[i] != cp; i++) ;\t/* Find the code page */\n\tif (validcp[i] != cp) return FR_INVALID_PARAMETER;\t/* Not found? */\n\n\tCodePage = cp;\n\tif (cp >= 900) {\t/* DBCS */\n\t\tExCvt = 0;\n\t\tDbcTbl = tables[i];\n\t} else {\t\t\t/* SBCS */\n\t\tExCvt = tables[i];\n\t\tDbcTbl = 0;\n\t}\n\treturn FR_OK;\n}\n#endif\t/* FF_CODE_PAGE == 0 */\n"
  },
  {
    "path": "bdk/libs/fatfs/ff.h",
    "content": "/*----------------------------------------------------------------------------/\n/  FatFs - Generic FAT Filesystem module  R0.13c                              /\n/-----------------------------------------------------------------------------/\n/\n/ Copyright (C) 2018, ChaN, all right reserved.\n/\n/ FatFs module is an open source software. Redistribution and use of FatFs in\n/ source and binary forms, with or without modification, are permitted provided\n/ that the following condition is met:\n\n/ 1. Redistributions of source code must retain the above copyright notice,\n/    this condition and the following disclaimer.\n/\n/ This software is provided by the copyright holder and contributors \"AS IS\"\n/ and any warranties related to this software are DISCLAIMED.\n/ The copyright owner or contributors be NOT LIABLE for any damages caused\n/ by use of this software.\n/\n/----------------------------------------------------------------------------*/\n\n\n#ifndef FF_DEFINED\n#define FF_DEFINED\t86604\t/* Revision ID */\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <utils/types.h>\t/* Basic integer types */\n#include <fatfs_cfg.h>\t/* FatFs configuration options */\n\n#if FF_DEFINED != FFCONF_DEF\n#error Wrong configuration file (ffconf.h).\n#endif\n\n\n\n/* Definitions of volume management */\n\n#if FF_MULTI_PARTITION\t\t/* Multiple partition configuration */\ntypedef struct {\n\tBYTE pd;\t/* Physical drive number */\n\tBYTE pt;\t/* Partition: 0:Auto detect, 1-4:Forced partition) */\n} PARTITION;\nextern PARTITION VolToPart[];\t/* Volume - Partition resolution table */\n#endif\n\n#if FF_STR_VOLUME_ID\n#ifndef FF_VOLUME_STRS\nextern const char* VolumeStr[FF_VOLUMES];\t/* User defied volume ID */\n#endif\n#endif\n\n\n\n/* Type of path name strings on FatFs API */\n\n#ifndef _INC_TCHAR\n#define _INC_TCHAR\n\n#if FF_USE_LFN && FF_LFN_UNICODE == 1 \t/* Unicode in UTF-16 encoding */\ntypedef WCHAR TCHAR;\n#define _T(x) L ## x\n#define _TEXT(x) L ## x\n#elif FF_USE_LFN && FF_LFN_UNICODE == 2\t/* Unicode in UTF-8 encoding */\ntypedef char TCHAR;\n#define _T(x) u8 ## x\n#define _TEXT(x) u8 ## x\n#elif FF_USE_LFN && FF_LFN_UNICODE == 3\t/* Unicode in UTF-32 encoding */\ntypedef DWORD TCHAR;\n#define _T(x) U ## x\n#define _TEXT(x) U ## x\n#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3)\n#error Wrong FF_LFN_UNICODE setting\n#else\t\t\t\t\t\t\t\t\t/* ANSI/OEM code in SBCS/DBCS */\ntypedef char TCHAR;\n#define _T(x) x\n#define _TEXT(x) x\n#endif\n\n#endif\n\n\n\n/* Type of file size variables */\n\n#if FF_FS_EXFAT\ntypedef QWORD FSIZE_t;\n#else\ntypedef DWORD FSIZE_t;\n#endif\n\n\n\n/* Filesystem object structure (FATFS) */\n\ntypedef struct {\n\tBYTE\tfs_type;\t\t/* Filesystem type (0:not mounted) */\n\tBYTE\tpart_type;\t\t/* Partition type (0:MBR, 1:GPT) */\n\tBYTE\tpdrv;\t\t\t/* Associated physical drive */\n\tBYTE\tn_fats;\t\t\t/* Number of FATs (1 or 2) */\n\tBYTE\twflag;\t\t\t/* win[] flag (b0:dirty) */\n\tBYTE\tfsi_flag;\t\t/* FSINFO flags (b7:disabled, b0:dirty) */\n\tWORD\tid;\t\t\t\t/* Volume mount ID */\n\tWORD\tn_rootdir;\t\t/* Number of root directory entries (FAT12/16) */\n\tWORD\tcsize;\t\t\t/* Cluster size [sectors] */\n#if FF_MAX_SS != FF_MIN_SS\n\tWORD\tssize;\t\t\t/* Sector size (512, 1024, 2048 or 4096) */\n#endif\n#if FF_USE_LFN\n\tWCHAR*\tlfnbuf;\t\t\t/* LFN working buffer */\n#endif\n#if FF_FS_EXFAT\n\tBYTE*\tdirbuf;\t\t\t/* Directory entry block scratchpad buffer for exFAT */\n#endif\n#if FF_FS_REENTRANT\n\tFF_SYNC_t\tsobj;\t\t/* Identifier of sync object */\n#endif\n#if !FF_FS_READONLY\n\tDWORD\tlast_clst;\t\t/* Last allocated cluster */\n\tDWORD\tfree_clst;\t\t/* Number of free clusters */\n#endif\n#if FF_FS_RPATH\n\tDWORD\tcdir;\t\t\t/* Current directory start cluster (0:root) */\n#if FF_FS_EXFAT\n\tDWORD\tcdc_scl;\t\t/* Containing directory start cluster (invalid when cdir is 0) */\n\tDWORD\tcdc_size;\t\t/* b31-b8:Size of containing directory, b7-b0: Chain status */\n\tDWORD\tcdc_ofs;\t\t/* Offset in the containing directory (invalid when cdir is 0) */\n#endif\n#endif\n\tDWORD\tn_fatent;\t\t/* Number of FAT entries (number of clusters + 2) */\n\tDWORD\tfsize;\t\t\t/* Size of an FAT [sectors] */\n\tDWORD\tvolbase;\t\t/* Volume base sector */\n\tDWORD\tfatbase;\t\t/* FAT base sector */\n\tDWORD\tdirbase;\t\t/* Root directory base sector/cluster */\n\tDWORD\tdatabase;\t\t/* Data base sector */\n#if FF_FS_EXFAT\n\tDWORD\tbitbase;\t\t/* Allocation bitmap base sector */\n#endif\n\tDWORD\twinsect;\t\t/* Current sector appearing in the win[] */\n\tBYTE\twin[FF_MAX_SS] __attribute__((aligned(8)));\t/* Disk access window for Directory, FAT (and file data at tiny cfg). DMA aligned. */\n} FATFS;\n\n\n\n/* Object ID and allocation information (FFOBJID) */\n\ntypedef struct {\n\tFATFS*\tfs;\t\t\t\t/* Pointer to the hosting volume of this object */\n\tWORD\tid;\t\t\t\t/* Hosting volume mount ID */\n\tBYTE\tattr;\t\t\t/* Object attribute */\n\tBYTE\tstat;\t\t\t/* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */\n\tDWORD\tsclust;\t\t\t/* Object data start cluster (0:no cluster or root directory) */\n\tFSIZE_t\tobjsize;\t\t/* Object size (valid when sclust != 0) */\n#if FF_FS_EXFAT\n\tDWORD\tn_cont;\t\t\t/* Size of first fragment - 1 (valid when stat == 3) */\n\tDWORD\tn_frag;\t\t\t/* Size of last fragment needs to be written to FAT (valid when not zero) */\n\tDWORD\tc_scl;\t\t\t/* Containing directory start cluster (valid when sclust != 0) */\n\tDWORD\tc_size;\t\t\t/* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */\n\tDWORD\tc_ofs;\t\t\t/* Offset in the containing directory (valid when file object and sclust != 0) */\n#endif\n#if FF_FS_LOCK\n\tUINT\tlockid;\t\t\t/* File lock ID origin from 1 (index of file semaphore table Files[]) */\n#endif\n} FFOBJID;\n\n\n\n/* File object structure (FIL) */\n\ntypedef struct {\n\tFFOBJID\tobj;\t\t\t/* Object identifier (must be the 1st member to detect invalid object pointer) */\n\tBYTE\tflag;\t\t\t/* File status flags */\n\tBYTE\terr;\t\t\t/* Abort flag (error code) */\n\tFSIZE_t\tfptr;\t\t\t/* File read/write pointer (Zeroed on file open) */\n\tDWORD\tclust;\t\t\t/* Current cluster of fpter (invalid when fptr is 0) */\n\tDWORD\tsect;\t\t\t/* Sector number appearing in buf[] (0:invalid) */\n#if !FF_FS_READONLY\n\tDWORD\tdir_sect;\t\t/* Sector number containing the directory entry (not used at exFAT) */\n\tBYTE*\tdir_ptr;\t\t/* Pointer to the directory entry in the win[] (not used at exFAT) */\n#endif\n#if FF_USE_FASTSEEK\n\tDWORD*\tcltbl;\t\t\t/* Pointer to the cluster link map table (nulled on open, set by application) */\n#endif\n#if !FF_FS_TINY\n\tBYTE\tbuf[FF_MAX_SS] __attribute__((aligned(8)));\t/* File private data read/write window. DMA aligned. */\n#endif\n} FIL;\n\n\n\n/* Directory object structure (DIR) */\n\ntypedef struct {\n\tFFOBJID\tobj;\t\t\t/* Object identifier */\n\tDWORD\tdptr;\t\t\t/* Current read/write offset */\n\tDWORD\tclust;\t\t\t/* Current cluster */\n\tDWORD\tsect;\t\t\t/* Current sector (0:Read operation has terminated) */\n\tBYTE*\tdir;\t\t\t/* Pointer to the directory item in the win[] */\n\tBYTE\tfn[12];\t\t\t/* SFN (in/out) {body[8],ext[3],status[1]} */\n#if FF_USE_LFN\n\tDWORD\tblk_ofs;\t\t/* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */\n#endif\n#if FF_USE_FIND\n\tconst TCHAR* pat;\t\t/* Pointer to the name matching pattern */\n#endif\n} DIR;\n\n\n\n/* File information structure (FILINFO) */\n\ntypedef struct {\n\tFSIZE_t\tfsize;\t\t\t/* File size */\n\tWORD\tfdate;\t\t\t/* Modified date */\n\tWORD\tftime;\t\t\t/* Modified time */\n\tBYTE\tfattrib;\t\t/* File attribute */\n#if FF_USE_LFN\n\tTCHAR\taltname[FF_SFN_BUF + 1];/* Altenative file name */\n\tTCHAR\tfname[FF_LFN_BUF + 1];\t/* Primary file name */\n#else\n\tTCHAR\tfname[12 + 1];\t/* File name */\n#endif\n} FILINFO;\n\n\n\n/* File function return code (FRESULT) */\n\ntypedef enum {\n\tFR_OK = 0,\t\t\t\t/* (0) Succeeded */\n\tFR_DISK_ERR,\t\t\t/* (1) A hard error occurred in the low level disk I/O layer */\n\tFR_INT_ERR,\t\t\t\t/* (2) Assertion failed */\n\tFR_NOT_READY,\t\t\t/* (3) The physical drive cannot work */\n\tFR_NO_FILE,\t\t\t\t/* (4) Could not find the file */\n\tFR_NO_PATH,\t\t\t\t/* (5) Could not find the path */\n\tFR_INVALID_NAME,\t\t/* (6) The path name format is invalid */\n\tFR_DENIED,\t\t\t\t/* (7) Access denied due to prohibited access or directory full */\n\tFR_EXIST,\t\t\t\t/* (8) Access denied due to prohibited access */\n\tFR_INVALID_OBJECT,\t\t/* (9) The file/directory object is invalid */\n\tFR_WRITE_PROTECTED,\t\t/* (10) The physical drive is write protected */\n\tFR_INVALID_DRIVE,\t\t/* (11) The logical drive number is invalid */\n\tFR_NOT_ENABLED,\t\t\t/* (12) The volume has no work area */\n\tFR_NO_FILESYSTEM,\t\t/* (13) There is no valid FAT volume */\n\tFR_MKFS_ABORTED,\t\t/* (14) The f_mkfs() aborted due to any problem */\n\tFR_TIMEOUT,\t\t\t\t/* (15) Could not get a grant to access the volume within defined period */\n\tFR_LOCKED,\t\t\t\t/* (16) The operation is rejected according to the file sharing policy */\n\tFR_NOT_ENOUGH_CORE,\t\t/* (17) LFN working buffer could not be allocated */\n\tFR_TOO_MANY_OPEN_FILES,\t/* (18) Number of open files > FF_FS_LOCK */\n#if FF_FASTFS\n\tFR_INVALID_PARAMETER,\t/* (19) Given parameter is invalid */\n\tFR_CLTBL_NO_INIT\t    /* (20) The cluster table for fast seek/read/write was not created */\n#else\n\tFR_INVALID_PARAMETER\t/* (19) Given parameter is invalid */\n#endif\n} FRESULT;\n\n\n\n/*--------------------------------------------------------------*/\n/* FatFs module application interface                           */\n\nFRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode);\t\t\t\t/* Open or create a file */\nFRESULT f_close (FIL* fp);\t\t\t\t\t\t\t\t\t\t\t/* Close an open file object */\nFRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br);\t\t\t/* Read data from the file */\nFRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw);\t/* Write data to the file */\n#if FF_FASTFS /* buff needs to be block aligned. Intercluster data access is not supported. */\nFRESULT f_read_fast (FIL* fp, const void* buff, UINT btr);\t\t\t/* Fast read data from the file */\nFRESULT f_write_fast (FIL* fp, const void* buff, UINT btw);         /* Fast write data to the file */\n#endif\nFRESULT f_lseek (FIL* fp, FSIZE_t ofs);\t\t\t\t\t\t\t\t/* Move file pointer of the file object */\nFRESULT f_truncate (FIL* fp);\t\t\t\t\t\t\t\t\t\t/* Truncate the file */\nFRESULT f_sync (FIL* fp);\t\t\t\t\t\t\t\t\t\t\t/* Flush cached data of the writing file */\nFRESULT f_opendir (DIR* dp, const TCHAR* path);\t\t\t\t\t\t/* Open a directory */\nFRESULT f_closedir (DIR* dp);\t\t\t\t\t\t\t\t\t\t/* Close an open directory */\nFRESULT f_readdir (DIR* dp, FILINFO* fno);\t\t\t\t\t\t\t/* Read a directory item */\nFRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern);\t/* Find first file */\nFRESULT f_findnext (DIR* dp, FILINFO* fno);\t\t\t\t\t\t\t/* Find next file */\nFRESULT f_mkdir (const TCHAR* path);\t\t\t\t\t\t\t\t/* Create a sub directory */\nFRESULT f_unlink (const TCHAR* path);\t\t\t\t\t\t\t\t/* Delete an existing file or directory */\nFRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new);\t/* Rename/Move a file or directory */\nFRESULT f_stat (const TCHAR* path, FILINFO* fno);\t\t\t\t\t/* Get file status */\nFRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask);\t\t\t/* Change attribute of a file/dir */\nFRESULT f_utime (const TCHAR* path, const FILINFO* fno);\t\t\t/* Change timestamp of a file/dir */\nFRESULT f_chdir (const TCHAR* path);\t\t\t\t\t\t\t\t/* Change current directory */\nFRESULT f_chdrive (const TCHAR* path);\t\t\t\t\t\t\t\t/* Change current drive */\nFRESULT f_getcwd (TCHAR* buff, UINT len);\t\t\t\t\t\t\t/* Get current directory */\nFRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs);\t/* Get number of free clusters on the drive */\nFRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn);\t/* Get volume label */\nFRESULT f_setlabel (const TCHAR* label);\t\t\t\t\t\t\t/* Set volume label */\nFRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf);\t/* Forward data to the stream */\n#if FF_FASTFS\nDWORD  *f_expand_cltbl (FIL* fp, UINT tblsz, FSIZE_t ofs);\t\t\t/* Expand file and populate cluster table */\n#endif\nFRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt);\t\t\t\t\t/* Allocate a contiguous block to the file */\nFRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt);\t\t\t/* Mount/Unmount a logical drive */\nFRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len);\t/* Create a FAT volume */\nFRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work);\t\t\t/* Divide a physical drive into some partitions */\nFRESULT f_setcp (WORD cp);\t\t\t\t\t\t\t\t\t\t\t/* Set current code page */\nint f_putc (TCHAR c, FIL* fp);\t\t\t\t\t\t\t\t\t\t/* Put a character to the file */\nint f_puts (const TCHAR* str, FIL* cp);\t\t\t\t\t\t\t\t/* Put a string to the file */\nint f_printf (FIL* fp, const TCHAR* str, ...);\t\t\t\t\t\t/* Put a formatted string to the file */\nTCHAR* f_gets (TCHAR* buff, int len, FIL* fp);\t\t\t\t\t\t/* Get a string from the file */\n\n#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))\n#define f_error(fp) ((fp)->err)\n#define f_tell(fp) ((fp)->fptr)\n#define f_size(fp) ((fp)->obj.objsize)\n#define f_rewind(fp) f_lseek((fp), 0)\n#define f_rewinddir(dp) f_readdir((dp), 0)\n#define f_rmdir(path) f_unlink(path)\n#define f_unmount(path) f_mount(0, path, 0)\n\n#ifndef EOF\n#define EOF (-1)\n#endif\n\n\n\n\n/*--------------------------------------------------------------*/\n/* Additional user defined functions                            */\n\n/* RTC function */\n#if !FF_FS_READONLY && !FF_FS_NORTC\nDWORD get_fattime (void);\n#endif\n\n/* LFN support functions */\n#if FF_USE_LFN >= 1\t\t\t\t\t\t/* Code conversion (defined in unicode.c) */\nWCHAR ff_oem2uni (WCHAR oem, WORD cp);\t/* OEM code to Unicode conversion */\nWCHAR ff_uni2oem (DWORD uni, WORD cp);\t/* Unicode to OEM code conversion */\nDWORD ff_wtoupper (DWORD uni);\t\t\t/* Unicode upper-case conversion */\n#endif\n#if FF_USE_LFN == 3\t\t\t\t\t\t/* Dynamic memory allocation */\nvoid* ff_memalloc (UINT msize);\t\t\t/* Allocate memory block */\nvoid ff_memfree (void* mblock);\t\t\t/* Free memory block */\n#endif\n\n/* Sync functions */\n#if FF_FS_REENTRANT\nint ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj);\t/* Create a sync object */\nint ff_req_grant (FF_SYNC_t sobj);\t\t/* Lock sync object */\nvoid ff_rel_grant (FF_SYNC_t sobj);\t\t/* Unlock sync object */\nint ff_del_syncobj (FF_SYNC_t sobj);\t/* Delete a sync object */\n#endif\n\n\n\n\n/*--------------------------------------------------------------*/\n/* Flags and offset address                                     */\n\n\n/* File access mode and open method flags (3rd argument of f_open) */\n#define\tFA_READ\t\t\t\t0x01\n#define\tFA_WRITE\t\t\t0x02\n#define\tFA_OPEN_EXISTING\t0x00\n#define\tFA_CREATE_NEW\t\t0x04\n#define\tFA_CREATE_ALWAYS\t0x08\n#define\tFA_OPEN_ALWAYS\t\t0x10\n#define\tFA_OPEN_APPEND\t\t0x30\n\n/* Fast seek controls (2nd argument of f_lseek) */\n#define CREATE_LINKMAP\t((FSIZE_t)0 - 1)\n\n/* Format options (2nd argument of f_mkfs) */\n#define FM_FAT\t\t0x01\n#define FM_FAT32\t0x02\n#define FM_EXFAT\t0x04\n#define FM_ANY\t\t0x07\n#define FM_SFD\t\t0x08\n#define FM_PRF2\t\t0x10\n\n/* Filesystem type (FATFS.fs_type) */\n#define FS_FAT12\t1\n#define FS_FAT16\t2\n#define FS_FAT32\t3\n#define FS_EXFAT\t4\n\n/* File attribute bits for directory entry (FILINFO.fattrib) */\n#define\tAM_RDO\t0x01\t/* Read only */\n#define\tAM_HID\t0x02\t/* Hidden */\n#define\tAM_SYS\t0x04\t/* System */\n#define\tAM_VOL\t0x08\t/* Volume */\n#define AM_DIR\t0x10\t/* Directory */\n#define AM_ARC\t0x20\t/* Archive */\n#define AM_DEV\t0x40\t/* Device */\n#define AM_RVD\t0x80\t/* Reserved */\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* FF_DEFINED */\n"
  },
  {
    "path": "bdk/libs/fatfs/ffsystem.c",
    "content": "/*------------------------------------------------------------------------*/\n/* Sample Code of OS Dependent Functions for FatFs                        */\n/* (C) ChaN, 2018                                                         */\n/* (C) CTCaer, 2018-2024                                                  */\n/*------------------------------------------------------------------------*/\n\n#include <bdk.h>\n\n#include <libs/fatfs/ff.h>\n\n#if FF_USE_LFN == 3\t/* Dynamic memory allocation */\n\n/*------------------------------------------------------------------------*/\n/* Allocate a memory block                                                */\n/*------------------------------------------------------------------------*/\n\nvoid* ff_memalloc (\t/* Returns pointer to the allocated memory block (null if not enough core) */\n\tUINT msize\t\t/* Number of bytes to allocate */\n)\n{\n\t// Ensure size is aligned to SDMMC block size.\n\treturn malloc(ALIGN(msize, SDMMC_DAT_BLOCKSIZE));\t/* Allocate a new memory block with POSIX API */\n}\n\n\n/*------------------------------------------------------------------------*/\n/* Free a memory block                                                    */\n/*------------------------------------------------------------------------*/\n\nvoid ff_memfree (\n\tvoid* mblock\t/* Pointer to the memory block to free (nothing to do if null) */\n)\n{\n\tfree(mblock);\t/* Free the memory block with POSIX API */\n}\n\n#endif\n\n#if FF_FS_NORTC == 0\n\n/*------------------------------------------------------------------------*/\n/* Get real time clock                                                    */\n/*------------------------------------------------------------------------*/\n\nDWORD get_fattime (\n\tvoid\n)\n{\n\trtc_time_t time;\n\n\tmax77620_rtc_get_time_adjusted(&time);\n\n\treturn (((DWORD)(time.year - 1980) << 25) | ((DWORD)time.month << 21) | ((DWORD)time.day << 16) |\n\t\t((DWORD)time.hour << 11) | ((DWORD)time.min << 5) | (time.sec >> 1));\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/fatfs/ffunicode.c",
    "content": "/*------------------------------------------------------------------------*/\n/* Unicode handling functions for FatFs R0.13c                            */\n/*------------------------------------------------------------------------*/\n/* This module will occupy a huge memory in the .const section when the    /\n/  FatFs is configured for LFN with DBCS. If the system has any Unicode    /\n/  utilitiy for the code conversion, this module should be modified to use /\n/  that function to avoid silly memory consumption.                        /\n/-------------------------------------------------------------------------*/\n/*\n/ Copyright (C) 2018, ChaN, all right reserved.\n/\n/ FatFs module is an open source software. Redistribution and use of FatFs in\n/ source and binary forms, with or without modification, are permitted provided\n/ that the following condition is met:\n/\n/ 1. Redistributions of source code must retain the above copyright notice,\n/    this condition and the following disclaimer.\n/\n/ This software is provided by the copyright holder and contributors \"AS IS\"\n/ and any warranties related to this software are DISCLAIMED.\n/ The copyright owner or contributors be NOT LIABLE for any damages caused\n/ by use of this software.\n*/\n\n\n#include \"ff.h\"\n\n#if FF_USE_LFN\t/* This module will be blanked at non-LFN configuration */\n\n#if FF_DEFINED != 86604\t/* Revision ID */\n#error Wrong include file (ff.h).\n#endif\n\n#define MERGE2(a, b) a ## b\n#define CVTBL(tbl, cp) MERGE2(tbl, cp)\n\n/*------------------------------------------------------------------------*/\n/* Code Conversion Tables                                                 */\n/*------------------------------------------------------------------------*/\n\n#if FF_CODE_PAGE == 437 || FF_CODE_PAGE == 0\nstatic const WCHAR uc437[] = {\t/*  CP437(U.S.) to Unicode conversion table */\n\t0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,\n\t0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,\n\t0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,\n\t0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,\n\t0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n\t0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n\t0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,\n\t0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0\n};\n#endif\n#if FF_CODE_PAGE == 720 || FF_CODE_PAGE == 0\nstatic const WCHAR uc720[] = {\t/*  CP720(Arabic) to Unicode conversion table */\n\t0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000,\n\t0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627,\n\t0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB,\n\t0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,\n\t0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n\t0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n\t0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A,\n\t0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0\n};\n#endif\n#if FF_CODE_PAGE == 737 || FF_CODE_PAGE == 0\nstatic const WCHAR uc737[] = {\t/*  CP737(Greek) to Unicode conversion table */\n\t0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0,\n\t0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,\n\t0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,\n\t0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,\n\t0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n\t0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n\t0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E,\n\t0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0\n};\n#endif\n#if FF_CODE_PAGE == 771 || FF_CODE_PAGE == 0\nstatic const WCHAR uc771[] = {\t/*  CP771(KBL) to Unicode conversion table */\n\t0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,\n\t0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,\n\t0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,\n\t0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,\n\t0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n\t0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x0104, 0x0105, 0x010C, 0x010D,\n\t0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,\n\t0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0\n};\n#endif\n#if FF_CODE_PAGE == 775 || FF_CODE_PAGE == 0\nstatic const WCHAR uc775[] = {\t/*  CP775(Baltic) to Unicode conversion table */\n\t0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5,\n\t0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4,\n\t0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB,\n\t0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510,\n\t0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D,\n\t0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n\t0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019,\n\t0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0\n};\n#endif\n#if FF_CODE_PAGE == 850 || FF_CODE_PAGE == 0\nstatic const WCHAR uc850[] = {\t/*  CP850(Latin 1) to Unicode conversion table */\n\t0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,\n\t0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,\n\t0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,\n\t0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,\n\t0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,\n\t0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,\n\t0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,\n\t0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0\n};\n#endif\n#if FF_CODE_PAGE == 852 || FF_CODE_PAGE == 0\nstatic const WCHAR uc852[] = {\t/*  CP852(Latin 2) to Unicode conversion table */\n\t0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106,\n\t0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D,\n\t0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB,\n\t0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510,\n\t0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,\n\t0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580,\n\t0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4,\n\t0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0\n};\n#endif\n#if FF_CODE_PAGE == 855 || FF_CODE_PAGE == 0\nstatic const WCHAR uc855[] = {\t/*  CP855(Cyrillic) to Unicode conversion table */\n\t0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408,\n\t0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A,\n\t0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB,\n\t0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510,\n\t0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,\n\t0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580,\n\t0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116,\n\t0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0\n};\n#endif\n#if FF_CODE_PAGE == 857 || FF_CODE_PAGE == 0\nstatic const WCHAR uc857[] = {\t/*  CP857(Turkish) to Unicode conversion table */\n\t0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5,\n\t0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F,\n\t0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,\n\t0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,\n\t0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,\n\t0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,\n\t0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4,\n\t0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0\n};\n#endif\n#if FF_CODE_PAGE == 860 || FF_CODE_PAGE == 0\nstatic const WCHAR uc860[] = {\t/*  CP860(Portuguese) to Unicode conversion table */\n\t0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2,\n\t0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3,\n\t0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,\n\t0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,\n\t0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n\t0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n\t0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,\n\t0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0\n};\n#endif\n#if FF_CODE_PAGE == 861 || FF_CODE_PAGE == 0\nstatic const WCHAR uc861[] = {\t/*  CP861(Icelandic) to Unicode conversion table */\n\t0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5,\n\t0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,\n\t0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,\n\t0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,\n\t0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n\t0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n\t0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,\n\t0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0\n};\n#endif\n#if FF_CODE_PAGE == 862 || FF_CODE_PAGE == 0\nstatic const WCHAR uc862[] = {\t/*  CP862(Hebrew) to Unicode conversion table */\n\t0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,\n\t0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,\n\t0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,\n\t0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,\n\t0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n\t0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n\t0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,\n\t0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0\n};\n#endif\n#if FF_CODE_PAGE == 863 || FF_CODE_PAGE == 0\nstatic const WCHAR uc863[] = {\t/*  CP863(Canadian French) to Unicode conversion table */\n\t0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0,\n\t0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192,\n\t0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB,\n\t0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,\n\t0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n\t0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n\t0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2219,\n\t0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0\n};\n#endif\n#if FF_CODE_PAGE == 864 || FF_CODE_PAGE == 0\nstatic const WCHAR uc864[] = {\t/*  CP864(Arabic) to Unicode conversion table */\n\t0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518,\n\t0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000,\n\t0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5,\n\t0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F,\n\t0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9,\n\t0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9,\n\t0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1,\n\t0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000\n};\n#endif\n#if FF_CODE_PAGE == 865 || FF_CODE_PAGE == 0\nstatic const WCHAR uc865[] = {\t/*  CP865(Nordic) to Unicode conversion table */\n\t0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,\n\t0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,\n\t0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4,\n\t0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,\n\t0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n\t0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n\t0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,\n\t0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0\n};\n#endif\n#if FF_CODE_PAGE == 866 || FF_CODE_PAGE == 0\nstatic const WCHAR uc866[] = {\t/*  CP866(Russian) to Unicode conversion table */\n\t0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,\n\t0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,\n\t0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,\n\t0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,\n\t0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,\n\t0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,\n\t0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,\n\t0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0\n};\n#endif\n#if FF_CODE_PAGE == 869 || FF_CODE_PAGE == 0\nstatic const WCHAR uc869[] = {\t/*  CP869(Greek 2) to Unicode conversion table */\n\t0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389,\n\t0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF,\n\t0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB,\n\t0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C, 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510,\n\t0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0A30, 0x03A1, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3,\n\t0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580,\n\t0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384,\n\t0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0\n};\n#endif\n\n\n\n\n/*------------------------------------------------------------------------*/\n/* OEM <==> Unicode conversions for static code page configuration        */\n/* SBCS fixed code page                                                   */\n/*------------------------------------------------------------------------*/\n\n#if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900\nWCHAR ff_uni2oem (\t/* Returns OEM code character, zero on error */\n\tDWORD\tuni,\t/* UTF-16 encoded character to be converted */\n\tWORD\tcp\t\t/* Code page for the conversion */\n)\n{\n\tWCHAR c = 0;\n\tconst WCHAR *p = CVTBL(uc, FF_CODE_PAGE);\n\n\n\tif (uni < 0x80) {\t/* ASCII? */\n\t\tc = (WCHAR)uni;\n\n\t} else {\t\t\t/* Non-ASCII */\n\t\tif (uni < 0x10000 && cp == FF_CODE_PAGE) {\t/* Is it in BMP and valid code page? */\n\t\t\tfor (c = 0; c < 0x80 && uni != p[c]; c++) ;\n\t\t\tc = (c + 0x80) & 0xFF;\n\t\t}\n\t}\n\n\treturn c;\n}\n\nWCHAR ff_oem2uni (\t/* Returns Unicode character, zero on error */\n\tWCHAR\toem,\t/* OEM code to be converted */\n\tWORD\tcp\t\t/* Code page for the conversion */\n)\n{\n\tWCHAR c = 0;\n\tconst WCHAR *p = CVTBL(uc, FF_CODE_PAGE);\n\n\n\tif (oem < 0x80) {\t/* ASCII? */\n\t\tc = oem;\n\n\t} else {\t\t\t/* Extended char */\n\t\tif (cp == FF_CODE_PAGE) {\t/* Is it a valid code page? */\n\t\t\tif (oem < 0x100) c = p[oem - 0x80];\n\t\t}\n\t}\n\n\treturn c;\n}\n\n#endif\n\n\n\n/*------------------------------------------------------------------------*/\n/* OEM <==> Unicode conversions for static code page configuration        */\n/* DBCS fixed code page                                                   */\n/*------------------------------------------------------------------------*/\n\n#if FF_CODE_PAGE >= 900\nWCHAR ff_uni2oem (\t/* Returns OEM code character, zero on error */\n\tDWORD\tuni,\t/* UTF-16 encoded character to be converted */\n\tWORD\tcp\t\t/* Code page for the conversion */\n)\n{\n\tconst WCHAR *p;\n\tWCHAR c = 0, uc;\n\tUINT i = 0, n, li, hi;\n\n\n\tif (uni < 0x80) {\t/* ASCII? */\n\t\tc = (WCHAR)uni;\n\n\t} else {\t\t\t/* Non-ASCII */\n\t\tif (uni < 0x10000 && cp == FF_CODE_PAGE) {\t/* Is it in BMP and valid code page? */\n\t\t\tuc = (WCHAR)uni;\n\t\t\tp = CVTBL(uni2oem, FF_CODE_PAGE);\n\t\t\thi = sizeof CVTBL(uni2oem, FF_CODE_PAGE) / 4 - 1;\n\t\t\tli = 0;\n\t\t\tfor (n = 16; n; n--) {\n\t\t\t\ti = li + (hi - li) / 2;\n\t\t\t\tif (uc == p[i * 2]) break;\n\t\t\t\tif (uc > p[i * 2]) {\n\t\t\t\t\tli = i;\n\t\t\t\t} else {\n\t\t\t\t\thi = i;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (n != 0) c = p[i * 2 + 1];\n\t\t}\n\t}\n\n\treturn c;\n}\n\n\nWCHAR ff_oem2uni (\t/* Returns Unicode character, zero on error */\n\tWCHAR\toem,\t/* OEM code to be converted */\n\tWORD\tcp\t\t/* Code page for the conversion */\n)\n{\n\tconst WCHAR *p;\n\tWCHAR c = 0;\n\tUINT i = 0, n, li, hi;\n\n\n\tif (oem < 0x80) {\t/* ASCII? */\n\t\tc = oem;\n\n\t} else {\t\t\t/* Extended char */\n\t\tif (cp == FF_CODE_PAGE) {\t/* Is it valid code page? */\n\t\t\tp = CVTBL(oem2uni, FF_CODE_PAGE);\n\t\t\thi = sizeof CVTBL(oem2uni, FF_CODE_PAGE) / 4 - 1;\n\t\t\tli = 0;\n\t\t\tfor (n = 16; n; n--) {\n\t\t\t\ti = li + (hi - li) / 2;\n\t\t\t\tif (oem == p[i * 2]) break;\n\t\t\t\tif (oem > p[i * 2]) {\n\t\t\t\t\tli = i;\n\t\t\t\t} else {\n\t\t\t\t\thi = i;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (n != 0) c = p[i * 2 + 1];\n\t\t}\n\t}\n\n\treturn c;\n}\n#endif\n\n\n\n/*------------------------------------------------------------------------*/\n/* OEM <==> Unicode conversions for dynamic code page configuration       */\n/*------------------------------------------------------------------------*/\n\n#if FF_CODE_PAGE == 0\n\nstatic const WORD cp_code[]          = {  437,   720,   737,   771,   775,   850,   852,   855,   857,   860,   861,   862,   863,   864,   865,   866,   869, 0};\nstatic const WCHAR* const cp_table[] = {uc437, uc720, uc737, uc771, uc775, uc850, uc852, uc855, uc857, uc860, uc861, uc862, uc863, uc864, uc865, uc866, uc869, 0};\n\n\nWCHAR ff_uni2oem (\t/* Returns OEM code character, zero on error */\n\tDWORD\tuni,\t/* UTF-16 encoded character to be converted */\n\tWORD\tcp\t\t/* Code page for the conversion */\n)\n{\n\tconst WCHAR *p;\n\tWCHAR c = 0, uc;\n\tUINT i, n, li, hi;\n\n\n\tif (uni < 0x80) {\t/* ASCII? */\n\t\tc = (WCHAR)uni;\n\n\t} else {\t\t\t/* Non-ASCII */\n\t\tif (uni < 0x10000) { /* Is it in BMP? */\n\t\t\tuc = (WCHAR)uni;\n\t\t\tp = 0;\n\t\t\tif (cp < 900) {\t/* SBCS */\n\t\t\t\tfor (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ;\t\t/* Get conversion table */\n\t\t\t\tp = cp_table[i];\n\t\t\t\tif (p) {\t/* Is it valid code page ? */\n\t\t\t\t\tfor (c = 0; c < 0x80 && uc != p[c]; c++) ;\t/* Find OEM code in the table */\n\t\t\t\t\tc = (c + 0x80) & 0xFF;\n\t\t\t\t}\n\t\t\t} else {\t/* DBCS */\n\t\t\t\tswitch (cp) {\t/* Get conversion table */\n\t\t\t\tcase 932 : p = uni2oem932; hi = sizeof uni2oem932 / 4 - 1; break;\n\t\t\t\tcase 936 : p = uni2oem936; hi = sizeof uni2oem936 / 4 - 1; break;\n\t\t\t\tcase 949 : p = uni2oem949; hi = sizeof uni2oem949 / 4 - 1; break;\n\t\t\t\tcase 950 : p = uni2oem950; hi = sizeof uni2oem950 / 4 - 1; break;\n\t\t\t\t}\n\t\t\t\tif (p) {\t/* Is it valid code page? */\n\t\t\t\t\tli = 0;\n\t\t\t\t\tfor (n = 16; n; n--) {\t/* Find OEM code */\n\t\t\t\t\t\ti = li + (hi - li) / 2;\n\t\t\t\t\t\tif (uc == p[i * 2]) break;\n\t\t\t\t\t\tif (uc > p[i * 2]) {\n\t\t\t\t\t\t\tli = i;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\thi = i;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (n != 0) c = p[i * 2 + 1];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn c;\n}\n\n\nWCHAR ff_oem2uni (\t/* Returns Unicode character, zero on error */\n\tWCHAR\toem,\t/* OEM code to be converted (DBC if >=0x100) */\n\tWORD\tcp\t\t/* Code page for the conversion */\n)\n{\n\tconst WCHAR *p;\n\tWCHAR c = 0;\n\tUINT i, n, li, hi;\n\n\n\tif (oem < 0x80) {\t/* ASCII? */\n\t\tc = oem;\n\n\t} else {\t\t\t/* Extended char */\n\t\tp = 0;\n\t\tif (cp < 900) {\t/* SBCS */\n\t\t\tfor (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ;\t\t/* Get table */\n\t\t\tp = cp_table[i];\n\t\t\tif (p) {\t/* Is it a valid CP ? */\n\t\t\t\tif (oem < 0x100) c = p[oem - 0x80];\n\t\t\t}\n\t\t} else {\t/* DBCS */\n\t\t\tswitch (cp) {\n\t\t\tcase 932 : p = oem2uni932; hi = sizeof oem2uni932 / 4 - 1; break;\n\t\t\tcase 936 : p = oem2uni936; hi = sizeof oem2uni936 / 4 - 1; break;\n\t\t\tcase 949 : p = oem2uni949; hi = sizeof oem2uni949 / 4 - 1; break;\n\t\t\tcase 950 : p = oem2uni950; hi = sizeof oem2uni950 / 4 - 1; break;\n\t\t\t}\n\t\t\tif (p) {\n\t\t\t\tli = 0;\n\t\t\t\tfor (n = 16; n; n--) {\n\t\t\t\t\ti = li + (hi - li) / 2;\n\t\t\t\t\tif (oem == p[i * 2]) break;\n\t\t\t\t\tif (oem > p[i * 2]) {\n\t\t\t\t\t\tli = i;\n\t\t\t\t\t} else {\n\t\t\t\t\t\thi = i;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (n != 0) c = p[i * 2 + 1];\n\t\t\t}\n\t\t}\n\t}\n\n\treturn c;\n}\n#endif\n\n\n\n/*------------------------------------------------------------------------*/\n/* Unicode up-case conversion                                             */\n/*------------------------------------------------------------------------*/\n\nDWORD ff_wtoupper (\t/* Returns up-converted code point */\n\tDWORD uni\t\t/* Unicode code point to be up-converted */\n)\n{\n\tconst WORD *p;\n\tWORD uc, bc, nc, cmd;\n\tstatic const WORD cvt1[] = {\t/* Compressed up conversion table for U+0000 - U+0FFF */\n\t\t/* Basic Latin */\n\t\t0x0061,0x031A,\n\t\t/* Latin-1 Supplement */\n\t\t0x00E0,0x0317,\n\t\t0x00F8,0x0307,\n\t\t0x00FF,0x0001,0x0178,\n\t\t/* Latin Extended-A */\n\t\t0x0100,0x0130,\n\t\t0x0132,0x0106,\n\t\t0x0139,0x0110,\n\t\t0x014A,0x012E,\n\t\t0x0179,0x0106,\n\t\t/* Latin Extended-B */\n\t\t0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA,\n\t\t0x01CD,0x0110,\n\t\t0x01DD,0x0001,0x018E,\n\t\t0x01DE,0x0112,\n\t\t0x01F3,0x0003,0x01F1,0x01F4,0x01F4,\n\t\t0x01F8,0x0128,\n\t\t0x0222,0x0112,\n\t\t0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241,\n\t\t0x0246,0x010A,\n\t\t/* IPA Extensions */\n\t\t0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7,\n\t\t/* Greek, Coptic */\n\t\t0x037B,0x0003,0x03FD,0x03FE,0x03FF,\n\t\t0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A,\n\t\t0x03B1,0x0311,\n\t\t0x03C2,0x0002,0x03A3,0x03A3,\n\t\t0x03C4,0x0308,\n\t\t0x03CC,0x0003,0x038C,0x038E,0x038F,\n\t\t0x03D8,0x0118,\n\t\t0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA,\n\t\t/* Cyrillic */\n\t\t0x0430,0x0320,\n\t\t0x0450,0x0710,\n\t\t0x0460,0x0122,\n\t\t0x048A,0x0136,\n\t\t0x04C1,0x010E,\n\t\t0x04CF,0x0001,0x04C0,\n\t\t0x04D0,0x0144,\n\t\t/* Armenian */\n\t\t0x0561,0x0426,\n\n\t\t0x0000\t/* EOT */\n\t};\n\tstatic const WORD cvt2[] = {\t/* Compressed up conversion table for U+1000 - U+FFFF */\n\t\t/* Phonetic Extensions */\n\t\t0x1D7D,0x0001,0x2C63,\n\t\t/* Latin Extended Additional */\n\t\t0x1E00,0x0196,\n\t\t0x1EA0,0x015A,\n\t\t/* Greek Extended */\n\t\t0x1F00,0x0608,\n\t\t0x1F10,0x0606,\n\t\t0x1F20,0x0608,\n\t\t0x1F30,0x0608,\n\t\t0x1F40,0x0606,\n\t\t0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F,\n\t\t0x1F60,0x0608,\n\t\t0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB,\n\t\t0x1F80,0x0608,\n\t\t0x1F90,0x0608,\n\t\t0x1FA0,0x0608,\n\t\t0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC,\n\t\t0x1FCC,0x0001,0x1FC3,\n\t\t0x1FD0,0x0602,\n\t\t0x1FE0,0x0602,\n\t\t0x1FE5,0x0001,0x1FEC,\n\t\t0x1FF3,0x0001,0x1FFC,\n\t\t/* Letterlike Symbols */\n\t\t0x214E,0x0001,0x2132,\n\t\t/* Number forms */\n\t\t0x2170,0x0210,\n\t\t0x2184,0x0001,0x2183,\n\t\t/* Enclosed Alphanumerics */\n\t\t0x24D0,0x051A,\n\t\t0x2C30,0x042F,\n\t\t/* Latin Extended-C */\n\t\t0x2C60,0x0102,\n\t\t0x2C67,0x0106, 0x2C75,0x0102,\n\t\t/* Coptic */\n\t\t0x2C80,0x0164,\n\t\t/* Georgian Supplement */\n\t\t0x2D00,0x0826,\n\t\t/* Full-width */\n\t\t0xFF41,0x031A,\n\n\t\t0x0000\t/* EOT */\n\t};\n\n\n\tif (uni < 0x10000) {\t/* Is it in BMP? */\n\t\tuc = (WORD)uni;\n\t\tp = uc < 0x1000 ? cvt1 : cvt2;\n\t\tfor (;;) {\n\t\t\tbc = *p++;\t\t\t\t\t\t\t\t/* Get the block base */\n\t\t\tif (bc == 0 || uc < bc) break;\t\t\t/* Not matched? */\n\t\t\tnc = *p++; cmd = nc >> 8; nc &= 0xFF;\t/* Get processing command and block size */\n\t\t\tif (uc < bc + nc) {\t/* In the block? */\n\t\t\t\tswitch (cmd) {\n\t\t\t\tcase 0:\tuc = p[uc - bc]; break;\t\t/* Table conversion */\n\t\t\t\tcase 1:\tuc -= (uc - bc) & 1; break;\t/* Case pairs */\n\t\t\t\tcase 2: uc -= 16; break;\t\t\t/* Shift -16 */\n\t\t\t\tcase 3:\tuc -= 32; break;\t\t\t/* Shift -32 */\n\t\t\t\tcase 4:\tuc -= 48; break;\t\t\t/* Shift -48 */\n\t\t\t\tcase 5:\tuc -= 26; break;\t\t\t/* Shift -26 */\n\t\t\t\tcase 6:\tuc += 8; break;\t\t\t\t/* Shift +8 */\n\t\t\t\tcase 7: uc -= 80; break;\t\t\t/* Shift -80 */\n\t\t\t\tcase 8:\tuc -= 0x1C60; break;\t\t/* Shift -0x1C60 */\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (cmd == 0) p += nc;\t/* Skip table if needed */\n\t\t}\n\t\tuni = uc;\n\t}\n\n\treturn uni;\n}\n\n#endif /* #if FF_USE_LFN */\n"
  },
  {
    "path": "bdk/libs/lv_conf.h",
    "content": "/*\n * Copyright (c) 2018 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef LV_CONF_H\n#define LV_CONF_H\n\n#include <soc/timer.h>\n#include <memory_map.h>\n/*===================\n   Dynamic memory\n *===================*/\n\n/* Memory size which will be used by the library\n * to store the graphical objects and other data */\n#define LV_MEM_CUSTOM         0              /*1: use custom malloc/free, 0: use the built-in lv_mem_alloc/lv_mem_free*/\n#if LV_MEM_CUSTOM == 0\n#  define LV_MEM_SIZE         NYX_LV_MEM_SZ  /*Size memory used by `lv_mem_alloc` in bytes (>= 2kB)*/\n#  define LV_MEM_ATTR                        /*Complier prefix for big array declaration*/\n#  define LV_MEM_ADR          NYX_LV_MEM_ADR /*Set an address for memory pool instead of allocation it as an array. Can be in external SRAM too.*/\n#  define LV_MEM_AUTO_DEFRAG  1              /*Automatically defrag on free*/\n#else       /*LV_MEM_CUSTOM*/\n#  define LV_MEM_CUSTOM_INCLUDE <mem/heap.h> /*Header for the dynamic memory function*/\n#  define LV_MEM_CUSTOM_ALLOC   malloc       /*Wrapper to malloc*/\n#  define LV_MEM_CUSTOM_FREE    free         /*Wrapper to free*/\n#endif     /*LV_MEM_CUSTOM*/\n\n/* Garbage Collector settings\n * Used if lvgl is binded to higher language and the memory is managed by that language */\n#define LV_ENABLE_GC 0\n#if LV_ENABLE_GC != 0\n#  define LV_MEM_CUSTOM_REALLOC   your_realloc           /*Wrapper to realloc*/\n#  define LV_MEM_CUSTOM_GET_SIZE  your_mem_get_size      /*Wrapper to lv_mem_get_size*/\n#  define LV_GC_INCLUDE \"gc.h\"                           /*Include Garbage Collector related things*/\n#endif /* LV_ENABLE_GC */\n\n/*===================\n   Graphical settings\n *===================*/\n\n/* Horizontal and vertical resolution of the library.*/\n#define LV_HOR_RES          (1280)\n#define LV_VER_RES          (720)\n\n/* Dot Per Inch: used to initialize default sizes. E.g. a button with width = LV_DPI / 2 -> half inch wide\n * (Not so important, you can adjust it to modify default sizes and spaces)*/\n#define LV_DPI              100\n\n/* Enable anti-aliasing (lines, and radiuses will be smoothed) */\n#define LV_ANTIALIAS        1       /*1: Enable anti-aliasing*/\n\n/*Screen refresh period in milliseconds*/\n#define LV_REFR_PERIOD      33\n\n/*-----------------\n *  VDB settings\n *----------------*/\n\n/* VDB (Virtual Display Buffer) is an internal graphics buffer.\n * The GUI will be drawn into this buffer first and then\n * the buffer will be passed to your `disp_drv.disp_flush` function to\n * copy it to your frame buffer.\n * VDB is required for: buffered drawing, opacity, anti-aliasing and shadows\n * Learn more: https://docs.littlevgl.com/#Drawing*/\n\n/* Size of the VDB in pixels. Typical size: ~1/10 screen. Must be >= LV_HOR_RES\n * Setting it to 0 will disable VDB and `disp_drv.disp_fill` and `disp_drv.disp_map` functions\n * will be called to draw to the frame buffer directly*/\n#define LV_VDB_SIZE         (LV_VER_RES * LV_HOR_RES)\n\n /* Bit-per-pixel of VDB. Useful for monochrome or non-standard color format displays.\n  * Special formats are handled with `disp_drv.vdb_wr`)*/\n#define LV_VDB_PX_BPP       LV_COLOR_SIZE       /*LV_COLOR_SIZE comes from LV_COLOR_DEPTH below to set 8, 16 or 32 bit pixel size automatically */\n\n /* Place VDB to a specific address (e.g. in external RAM)\n  * 0: allocate automatically into RAM\n  * LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`*/\n#define LV_VDB_ADR          NYX_LV_VDB_ADR\n\n/* Use two Virtual Display buffers (VDB) to parallelize rendering and flushing\n * The flushing should use DMA to write the frame buffer in the background */\n#define LV_VDB_DOUBLE       0\n\n/* Place VDB2 to a specific address (e.g. in external RAM)\n * 0: allocate automatically into RAM\n * LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`*/\n#define LV_VDB2_ADR         0\n\n/* Using true double buffering in `disp_drv.disp_flush` you will always get the image of the whole screen.\n * Your only task is to set the rendered image (`color_p` parameter) as frame buffer address or send it to your display.\n * The best if you do in the blank period of you display to avoid tearing effect.\n * Requires:\n * - LV_VDB_SIZE = LV_HOR_RES * LV_VER_RES\n * - LV_VDB_DOUBLE = 1\n */\n#define LV_VDB_TRUE_DOUBLE_BUFFERED 0\n\n/*=================\n   Misc. setting\n *=================*/\n\n/*Input device settings*/\n#define LV_INDEV_READ_PERIOD            33                     /*Input device read period in milliseconds*/\n#define LV_INDEV_POINT_MARKER           0                      /*Mark the pressed points  (required: USE_LV_REAL_DRAW = 1)*/\n#define LV_INDEV_DRAG_LIMIT             10                     /*Drag threshold in pixels */\n#define LV_INDEV_DRAG_THROW             20                     /*Drag throw slow-down in [%]. Greater value means faster slow-down */\n#define LV_INDEV_LONG_PRESS_TIME        5000                   /*Long press time in milliseconds*/\n#define LV_INDEV_LONG_PRESS_REP_TIME    1000 //Fix lv_kb       /*Repeated trigger period in long press [ms] */\n\n/*Color settings*/\n#define LV_COLOR_DEPTH         32                /*Color depth: 1/8/16/32*/\n#define LV_COLOR_16_SWAP       0                 /*Swap the 2 bytes of RGB565 color. Useful if the display has a 8 bit interface (e.g. SPI)*/\n#define LV_COLOR_SCREEN_TRANSP 0                 /*1: Enable screen transparency. Useful for OSD or other overlapping GUIs. Requires ARGB8888 colors*/\n#define LV_COLOR_TRANSP        LV_COLOR_LIME     /*Images pixels with this color will not be drawn (with chroma keying)*/\n\n/*Text settings*/\n#define LV_TXT_UTF8             0                /*Enable UTF-8 coded Unicode character usage */\n#define LV_TXT_BREAK_CHARS     \" ,.;:-_\"         /*Can break texts on these chars*/\n#define LV_TXT_LINE_BREAK_LONG_LEN 12            /* If a character is at least this long, will break wherever \"prettiest\" */\n#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3     /* Minimum number of characters of a word to put on a line before a break */\n#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 1    /* Minimum number of characters of a word to put on a line after a break */\n\n/*Feature usage*/\n#define USE_LV_ANIMATION        1               /*1: Enable all animations*/\n#define USE_LV_SHADOW           1               /*1: Enable shadows*/\n#define USE_LV_GROUP            0               /*1: Enable object groups (for keyboards)*/\n#define USE_LV_GPU              0               /*1: Enable GPU interface*/\n#define USE_LV_REAL_DRAW        0               /*1: Enable function which draw directly to the frame buffer instead of VDB (required if LV_VDB_SIZE = 0)*/\n#define USE_LV_FILESYSTEM       0               /*1: Enable file system (might be required for images*/\n#define USE_LV_MULTI_LANG       0               /* Number of languages for labels to store (0: to disable this feature)*/\n\n/*Compiler settings*/\n#define LV_ATTRIBUTE_TICK_INC                   /* Define a custom attribute to `lv_tick_inc` function */\n#define LV_ATTRIBUTE_TASK_HANDLER               /* Define a custom attribute to `lv_task_handler` function */\n#define LV_COMPILER_VLA_SUPPORTED            1  /* 1: Variable length array is supported*/\n\n/*HAL settings*/\n#define LV_TICK_CUSTOM               1                      /*1: use a custom tick source (removing the need to manually update the tick with `lv_tick_inc`) */\n#if LV_TICK_CUSTOM == 1\n#define LV_TICK_CUSTOM_INCLUDE       <soc/timer.h>          /*Header for the sys time function*/\n#define LV_TICK_CUSTOM_SYS_TIME_EXPR ((u32)get_tmr_ms())         /*Expression evaluating to current systime in ms*/\n#endif     /*LV_TICK_CUSTOM*/\n\n\n/*Log settings*/\n#ifdef DEBUG_UART_LV_LOG\n#  define USE_LV_LOG        1   /*Enable/disable the log module*/\n#else\n#  define USE_LV_LOG        0   /*Enable/disable the log module*/\n#endif\n#if USE_LV_LOG\n/* How important log should be added:\n * LV_LOG_LEVEL_TRACE       A lot of logs to give detailed information\n * LV_LOG_LEVEL_INFO        Log important events\n * LV_LOG_LEVEL_WARN        Log if something unwanted happened but didn't caused problem\n * LV_LOG_LEVEL_ERROR       Only critical issue, when the system may fail\n */\n#  define LV_LOG_LEVEL    LV_LOG_LEVEL_WARN\n/* 1: Print the log with 'printf'; 0: user need to register a callback*/\n#  define LV_LOG_PRINTF   1\n#endif  /*USE_LV_LOG*/\n\n/*================\n *  THEME USAGE\n *================*/\n#define LV_THEME_LIVE_UPDATE    0       /*1: Allow theme switching at run time. Uses 8..10 kB of RAM*/\n\n#define USE_LV_THEME_HEKATE     1       /*Flat theme with bold colors and light shadows*/\n\n/*==================\n *    FONT USAGE\n *===================*/\n\n/* More info about fonts: https://docs.littlevgl.com/#Fonts\n * To enable a built-in font use 1,2,4 or 8 values\n * which will determine the bit-per-pixel. Higher value means smoother fonts */\n#define LV_FONT_QUALITY 8\n\n#define USE_UBUNTU_MONO            LV_FONT_QUALITY\n\n#define USE_INTERUI_20             LV_FONT_QUALITY\n#define USE_INTERUI_30             LV_FONT_QUALITY\n\n#define USE_HEKATE_SYMBOL_20       USE_INTERUI_20\n#define USE_HEKATE_SYMBOL_30       USE_INTERUI_30\n#define USE_HEKATE_SYMBOL_120      LV_FONT_QUALITY\n\n/* Optionally declare your custom fonts here.\n * You can use these fonts as default font too\n * and they will be available globally. E.g.\n * #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) \\\n *                                LV_FONT_DECLARE(my_font_2) \\\n */\n#define LV_FONT_CUSTOM_DECLARE\n\n#define LV_FONT_DEFAULT        &interui_30     /*Always set a default font from the built-in fonts*/\n\n/*===================\n *  LV_OBJ SETTINGS\n *==================*/\n#define LV_OBJ_FREE_NUM_TYPE    uint32_t    /*Type of free number attribute (comment out disable free number)*/\n#define LV_OBJ_FREE_PTR         1           /*Enable the free pointer attribute*/\n#define LV_OBJ_REALIGN          1  // 0 in OG gui         /*Enable `lv_obj_realaign()` based on `lv_obj_align()` parameters*/\n\n/*==================\n *  LV OBJ X USAGE\n *================*/\n/*\n * Documentation of the object types: https://docs.littlevgl.com/#Object-types\n */\n\n/*****************\n * Simple object\n *****************/\n\n/*Label (dependencies: -*/\n#define USE_LV_LABEL    1\n#if USE_LV_LABEL != 0\n#  define LV_LABEL_SCROLL_SPEED       25     /*Hor, or ver. scroll speed [px/sec] in 'LV_LABEL_LONG_SCROLL/ROLL' mode*/\n#endif\n\n/*Image (dependencies: lv_label*/\n#define USE_LV_IMG      1\n#if USE_LV_IMG != 0\n#  define LV_IMG_CF_INDEXED   0       /*Enable indexed (palette) images*/\n#  define LV_IMG_CF_ALPHA     0       /*Enable alpha indexed images*/\n#endif\n\n/*Line (dependencies: -*/\n#define USE_LV_LINE     1\n\n/*Arc (dependencies: -)*/\n#define USE_LV_ARC      0\n\n/*******************\n * Container objects\n *******************/\n\n/*Container (dependencies: -*/\n#define USE_LV_CONT     1\n\n/*Page (dependencies: lv_cont)*/\n#define USE_LV_PAGE     1\n\n/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/\n#define USE_LV_WIN      1\n\n/*Tab (dependencies: lv_page, lv_btnm)*/\n#define USE_LV_TABVIEW      1\n#  if USE_LV_TABVIEW != 0\n#  define LV_TABVIEW_ANIM_TIME    0     /*Time of slide animation [ms] (0: no animation)*/\n#endif\n\n/*Tileview (dependencies: lv_page) */\n#define USE_LV_TILEVIEW     0\n#if USE_LV_TILEVIEW\n#  define LV_TILEVIEW_ANIM_TIME   0     /*Time of slide animation [ms] (0: no animation)*/\n#endif\n\n/*************************\n * Data visualizer objects\n *************************/\n\n/*Bar (dependencies: -)*/\n#define USE_LV_BAR      1\n\n/*Line meter (dependencies: *;)*/\n#define USE_LV_LMETER   0\n\n/*Gauge (dependencies:lv_bar, lv_lmeter)*/\n#define USE_LV_GAUGE    0\n\n/*Chart (dependencies: -)*/\n#define USE_LV_CHART    0\n\n/*Table (dependencies: lv_label)*/\n#define USE_LV_TABLE    1\n#if USE_LV_TABLE\n#  define LV_TABLE_COL_MAX    12\n#endif\n\n/*LED (dependencies: -)*/\n#define USE_LV_LED      0\n\n/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/\n#define USE_LV_MBOX     1\n#if USE_LV_MBOX != 0\n#  define LV_MBOX_CLOSE_ANIM_TIME 200     /*ms*/\n#endif\n\n/*Text area (dependencies: lv_label, lv_page)*/\n#define USE_LV_TA       1\n#if USE_LV_TA != 0\n#  define LV_TA_CURSOR_BLINK_TIME 400     /*ms*/\n#  define LV_TA_PWD_SHOW_TIME     1500    /*ms*/\n#endif\n\n/*Spinbox (dependencies: lv_ta)*/\n#define USE_LV_SPINBOX  0\n\n/*Calendar (dependencies: -)*/\n#define USE_LV_CALENDAR 0\n\n/*Preload (dependencies: lv_arc)*/\n#define USE_LV_PRELOAD      0\n#if USE_LV_PRELOAD != 0\n#  define LV_PRELOAD_DEF_ARC_LENGTH   60      /*[deg]*/\n#  define LV_PRELOAD_DEF_SPIN_TIME    1000    /*[ms]*/\n#  define LV_PRELOAD_DEF_ANIM         LV_PRELOAD_TYPE_SPINNING_ARC\n#endif\n\n/*Canvas (dependencies: lv_img)*/\n#define USE_LV_CANVAS       0\n/*************************\n * User input objects\n *************************/\n\n/*Button (dependencies: lv_cont*/\n#define USE_LV_BTN      1\n#if USE_LV_BTN != 0\n#  define LV_BTN_INK_EFFECT   0       /*Enable button-state animations - draw a circle on click (dependencies: USE_LV_ANIMATION)*/\n#endif\n\n/*Image Button (dependencies: lv_btn*/\n#define USE_LV_IMGBTN   1\n#if USE_LV_IMGBTN\n#  define LV_IMGBTN_TILED 0           /*1: The imgbtn requires left, mid and right parts and the width can be set freely*/\n#endif\n\n/*Button matrix (dependencies: -)*/\n#define USE_LV_BTNM     1\n\n/*Keyboard (dependencies: lv_btnm)*/\n#define USE_LV_KB       0\n\n/*Check box (dependencies: lv_btn, lv_label)*/\n#define USE_LV_CB       0\n\n/*List (dependencies: lv_page, lv_btn, lv_label, (lv_img optionally for icons ))*/\n#define USE_LV_LIST     1\n#if USE_LV_LIST != 0\n#  define LV_LIST_FOCUS_TIME  100 /*Default animation time of focusing to a list element [ms] (0: no animation)  */\n#endif\n\n/*Drop down list (dependencies: lv_page, lv_label, lv_symbol_def.h)*/\n#define USE_LV_DDLIST    1\n#if USE_LV_DDLIST != 0\n#  define LV_DDLIST_ANIM_TIME     100     /*Open and close default animation time [ms] (0: no animation)*/\n#endif\n\n/*Roller (dependencies: lv_ddlist)*/\n#define USE_LV_ROLLER    1\n#if USE_LV_ROLLER != 0\n#  define LV_ROLLER_ANIM_TIME     200     /*Focus animation time [ms] (0: no animation)*/\n#endif\n\n/*Slider (dependencies: lv_bar)*/\n#define USE_LV_SLIDER    1\n\n/*Switch (dependencies: lv_slider)*/\n#define USE_LV_SW        0\n\n#endif /*LV_CONF_H*/\n\n"
  },
  {
    "path": "bdk/libs/lvgl/docs/CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [atom@github.com](mailto:atom@github.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "bdk/libs/lvgl/docs/CONTRIBUTING.md",
    "content": "# Contributing to Littlev Graphics Library\n\n**Welcome!  It's glad to see that you are interested in contributing to LittlevGL! There are several types of task where you can help to build a better library! Let's see how to get started!**\n\n\nThere are many different possibilities to join the community. If you have some time to work with us I'm sure you will find something that fits you! You can:\n- answer other's questions\n- report and/or fix bugs\n- suggest and/or implement new features\n- improve and/or translate the documentation\n- write a blog post about your experiences\n\nBut first, start with the most Frequently Asked Questions.\n\n## FAQ about contributing\n\n### What license does my code need to be under?\n\nAny code added to LittlevGL must be licensed under [MIT](https://choosealicense.com/licenses/mit/) or another license that is fully compatible. Contributions under other licenses are highly likely to be rejected.\n\nIf you borrow code from another project, please make sure to add their copyright notice to your contribution.\n\n### Where do I ask questions, give feedback, or report bugs?\n\nWe use the [forum](http://forum.littlevgl.com/) for questions, feature suggestions, and discussions.\n\nWe use [GitHub's issue tracker](https://github.com/littlevgl/lvgl/issues) to report bugs.\n\nFor both of these there are some rules:\n- Be kind and friendly.\n- Speak about one thing in one issue.\n- Give feedback and close the issue if your question is answered. \n- Explain exactly what you experience or expect. _\"The button is not working\"_ is not enough info to get help.\n- For most issues you should send an absolute minimal code example in order to reproduce the issue. Ideally this should be easily usable in the PC simulator.\n- Use [Markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) to format your post.\n- If you don't get any answer in a week write a comment like \"Can somebody help?\". Maybe your issue wasn't noticed.\n\n### How can I send fixes and improvements?\nMerging new code happens via Pull Requests. If you are still not familiar with the Pull Requests (PR for short) here is a quick guide about them:\n1. **Fork** the [lvgl repository](https://github.com/littlevgl/lvgl). To do this click the \"Fork\" button in the top right corner. It will \"copy\" the `lvgl` repository to your GitHub account (`https://github.com/your_name?tab=repositories`)\n2. **Clone**  the forked repository and add your updates\n3. **Create a PR** on the GitHub on the page of you `lvgl` repository(`https://github.com/your_name/lvgl`) by hitting the \"New pull request\" button \n4. **Set the base branch**. It means where you want to merge your update. Bugfixes for the last release go to `master`, new features to the actual `dev-x.y` branch. \n5. **Describe** what is in the update. An example code is welcome if applicable.\n\nSome advice:\n- If you are not sure about your fix or feature it's better to open an issue first, and discuss the details there.\n- Maybe your fix or update won't be perfect at first. Don't be afraid, just improve it and push the new commits. The PR will be updated accordingly. \n- If your update needs some extra work it's okay to say: _\"I'm busy now and I will improve it soon\"_ or _\"Sorry, I don't have time to improve it, I hope it helps in this form too\"_. So it's better to say don't have time to continue then saying nothing.\n- Please read and follow this [guide about the coding style](https://docs.littlevgl.com/#Coding-Style-Guide)\n\n\n### Where is the documentation?\n\nYou can read the documentation here: https://docs.littlevgl.com/  \nYou can edit the documentation here: https://github.com/littlevgl/doc  \n\n### Where is the blog?\n\nYou can read the blog here: https://blog.littlevgl.com/  \nYou can edit the blog here: https://github.com/littlevgl/blog  \n\n\n## So how and where can I contribute?\n\n### Answering other's questions\n\nIt's a great way to contribute to the library if you already use it. Just go the [issue tracker](https://github.com/littlevgl/lvgl/issues), read the titles and if you are already familiar with a topic, don't be shy, and write your suggestion.\n\n### Reporting and/or fixing bugs\nFor simple bugfixes (typos, missing error handling, fixing a warning) is fine to send a Pull request directly. However, for more complex bugs it's better to open an issue first. In the issue, you should describe how to reproduce the bug and even add the minimal code snippet.\n\n### Suggesting and/or implementing new features\nIf you have a good idea don't hesitate to share with us. It's even better if you have time to deal with its implementation. Don't be afraid if you still don't know LittlevGL well enough. We will help you to get started. \n\nDuring the implementation don't forget the [Code style guide](https://docs.littlevgl.com/#Coding-Style-Guide).\n\n### Improving and/or translating the documentation\n\nThe documentation of LittlevGL is written in Markdown and available [here](https://github.com/littlevgl/doc) for editing. If you find some parts of the documentation obscure or insufficient just search the related `.md` file, hit the edit icon and add your updates. This way a  new Pull request will be generated automatically.\n\nIf you can devote more time to improve the documentation you can translate it! \n1. Just copy the English `.md` files from the root folder to `locale/LANGUAGE_CODE` (language code is e.g. DE, FR, ES etc)\n2. Append the language code the end of files (e.g. Welcome_fr.md)\n3. Update the filenames in `_Sidebar.md`\n4. Translate the page(s) you want\n5. Create a Pull request\n\n### Writing a blog post about your experiences\n\nHave ported LittlevGL to a new platform? Have you created a fancy GUI? Do you know a great trick? \nYou can share your knowledge on LittelvGL's blog! It's super easy to add your own post:\n- Fork and clone the [blog repository](https://github.com/littlevgl/blog)\n- Add your post in Markdown to the `_posts` folder. \n- Store the images and other resources in a dedicated folder in `assets`\n- Create a Pull Request\n\nThe blog uses [Jekyll](https://jekyllrb.com/) to convert the `.md` files to a webpage. You can easily [run Jekyll offline](https://jekyllrb.com/docs/) to check your post before creating the Pull request\n\n## Summary\n\nI hope you have taken a liking to contribute to LittelvGL. A helpful and friendly community is waiting for you! :) \n\n"
  },
  {
    "path": "bdk/libs/lvgl/docs/astyle_c",
    "content": "--style=kr --convert-tabs --indent=spaces=4 --indent-switches   --pad-oper --unpad-paren  --align-pointer=middle --suffix=.bak --lineend=linux --min-conditional-indent=\n"
  },
  {
    "path": "bdk/libs/lvgl/docs/astyle_h",
    "content": "--convert-tabs --indent=spaces=4\n"
  },
  {
    "path": "bdk/libs/lvgl/licence.txt",
    "content": "MIT licence\nCopyright (c) 2016 Gábor Kiss-Vámosi\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_core/lv_core.mk",
    "content": "CSRCS += lv_group.c\nCSRCS += lv_indev.c\nCSRCS += lv_obj.c\nCSRCS += lv_refr.c\nCSRCS += lv_style.c\nCSRCS += lv_vdb.c\nCSRCS += lv_lang.c\n\nDEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_core\nVPATH += :$(LVGL_DIR)/lvgl/lv_core\n\nCFLAGS += \"-I$(LVGL_DIR)/lvgl/lv_core\"\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_core/lv_group.c",
    "content": "/**\n * @file lv_group.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_group.h\"\n#if USE_LV_GROUP != 0\n#include <stddef.h>\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic void style_mod_def(lv_style_t * style);\nstatic void style_mod_edit_def(lv_style_t * style);\nstatic void lv_group_refocus(lv_group_t *g);\nstatic void obj_to_foreground(lv_obj_t * obj);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a new object group\n * @return pointer to the new object group\n */\nlv_group_t * lv_group_create(void)\n{\n    lv_group_t * group = lv_mem_alloc(sizeof(lv_group_t));\n    lv_mem_assert(group);\n    if(group == NULL) return NULL;\n    lv_ll_init(&group->obj_ll, sizeof(lv_obj_t *));\n\n    group->style_mod = style_mod_def;\n    group->style_mod_edit = style_mod_edit_def;\n    group->obj_focus = NULL;\n    group->frozen = 0;\n    group->focus_cb = NULL;\n    group->click_focus = 1;\n    group->editing = 0;\n\n    return group;\n}\n\n/**\n * Delete a group object\n * @param group pointer to a group\n */\nvoid lv_group_del(lv_group_t * group)\n{\n    /*Defocus the the currently focused object*/\n    if(group->obj_focus != NULL) {\n        (*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_DEFOCUS, NULL);\n        lv_obj_invalidate(*group->obj_focus);\n    }\n\n    /*Remove the objects from the group*/\n    lv_obj_t ** obj;\n    LL_READ(group->obj_ll, obj) {\n        (*obj)->group_p = NULL;\n    }\n\n    lv_ll_clear(&(group->obj_ll));\n    lv_mem_free(group);\n}\n\n/**\n * Add an object to a group\n * @param group pointer to a group\n * @param obj pointer to an object to add\n */\nvoid lv_group_add_obj(lv_group_t * group, lv_obj_t * obj)\n{\n    if(group == NULL) return;\n\n    /*If the object is already in a group and focused then defocus it*/\n    if(obj->group_p) {\n        if(lv_obj_is_focused(obj)) {\n            lv_group_refocus(obj->group_p);\n\n            LV_LOG_INFO(\"group: assign object to an other group\");\n        }\n    }\n\n    obj->group_p = group;\n    lv_obj_t ** next = lv_ll_ins_tail(&group->obj_ll);\n    lv_mem_assert(next);\n    if(next == NULL) return;\n    *next = obj;\n\n    /* If the head and the tail is equal then there is only one object in the linked list.\n     * In this case automatically activate it*/\n    if(lv_ll_get_head(&group->obj_ll) == next) {\n        lv_group_refocus(group);\n    }\n}\n\n/**\n * Remove an object from its group\n * @param obj pointer to an object to remove\n */\nvoid lv_group_remove_obj(lv_obj_t * obj)\n{\n    lv_group_t * g = obj->group_p;\n    if(g == NULL) return;\n    if(g->obj_focus == NULL) return;        /*Just to be sure (Not possible if there is at least one object in the group)*/\n\n    /*Focus on the next object*/\n    if(*g->obj_focus == obj) {\n        /*If this is the only object in the group then focus to nothing.*/\n        if(lv_ll_get_head(&g->obj_ll) == g->obj_focus && lv_ll_get_tail(&g->obj_ll) == g->obj_focus) {\n            (*g->obj_focus)->signal_func(*g->obj_focus, LV_SIGNAL_DEFOCUS, NULL);\n        }\n        /*If there more objects in the group then focus to the next/prev object*/\n        else {\n            lv_group_refocus(g);\n        }\n    }\n\n    /* If the focuses object is still the same then it was the only object in the group but it will be deleted.\n     * Set the `obj_focus` to NULL to get back to the initial state of the group with zero objects*/\n    if(*g->obj_focus == obj) {\n        g->obj_focus = NULL;\n    }\n\n    /*Search the object and remove it from its group */\n    lv_obj_t ** i;\n    LL_READ(g->obj_ll, i) {\n        if(*i == obj) {\n            lv_ll_rem(&g->obj_ll, i);\n            lv_mem_free(i);\n            obj->group_p = NULL;\n            break;\n        }\n    }\n}\n\n/**\n * Focus on an object (defocus the current)\n * @param obj pointer to an object to focus on\n */\nvoid lv_group_focus_obj(lv_obj_t * obj)\n{\n    lv_group_t * g = obj->group_p;\n    if(g == NULL) return;\n\n    if(g->frozen != 0) return;\n\n    /*On defocus edit mode must be leaved*/\n    lv_group_set_editing(g, false);\n\n    lv_obj_t ** i;\n    LL_READ(g->obj_ll, i) {\n        if(*i == obj) {\n            if(g->obj_focus == i) return;       /*Don't focus the already focused object again*/\n            if(g->obj_focus != NULL) {\n                (*g->obj_focus)->signal_func(*g->obj_focus, LV_SIGNAL_DEFOCUS, NULL);\n                lv_obj_invalidate(*g->obj_focus);\n            }\n\n            g->obj_focus = i;\n\n            if(g->obj_focus != NULL) {\n                (*g->obj_focus)->signal_func(*g->obj_focus, LV_SIGNAL_FOCUS, NULL);\n                if(g->focus_cb) g->focus_cb(g);\n                lv_obj_invalidate(*g->obj_focus);\n\n                /*If the object or its parent has `top == true` bring it to the foregorund*/\n                obj_to_foreground(*g->obj_focus);\n            }\n            break;\n        }\n    }\n}\n\n/**\n * Focus the next object in a group (defocus the current)\n * @param group pointer to a group\n */\nvoid lv_group_focus_next(lv_group_t * group)\n{\n    if(group->frozen) return;\n\n    if(group->obj_focus) {\n        (*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_DEFOCUS, NULL);\n        lv_obj_invalidate(*group->obj_focus);\n    }\n\n    lv_obj_t ** obj_next;\n    if(group->obj_focus == NULL) obj_next = lv_ll_get_head(&group->obj_ll);\n    else obj_next = lv_ll_get_next(&group->obj_ll, group->obj_focus);\n\n    if(obj_next == NULL) {\n        if(group->wrap) obj_next = lv_ll_get_head(&group->obj_ll);\n        else obj_next = lv_ll_get_tail(&group->obj_ll);\n    }\n    group->obj_focus = obj_next;\n\n    if(group->obj_focus) {\n        (*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_FOCUS, NULL);\n        lv_obj_invalidate(*group->obj_focus);\n\n        if(group->focus_cb) group->focus_cb(group);\n\n        /*If the object or its parent has `top == true` bring it to the foregorund*/\n        obj_to_foreground(*group->obj_focus);\n    }\n}\n\n/**\n * Focus the previous object in a group (defocus the current)\n * @param group pointer to a group\n */\nvoid lv_group_focus_prev(lv_group_t * group)\n{\n    if(group->frozen) return;\n\n    if(group->obj_focus) {\n        (*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_DEFOCUS, NULL);\n        lv_obj_invalidate(*group->obj_focus);\n    }\n\n    lv_obj_t ** obj_next;\n    if(group->obj_focus == NULL) obj_next = lv_ll_get_tail(&group->obj_ll);\n    else obj_next = lv_ll_get_prev(&group->obj_ll, group->obj_focus);\n\n    if(obj_next == NULL) {\n        if(group->wrap) obj_next = lv_ll_get_tail(&group->obj_ll);\n        else  obj_next = lv_ll_get_head(&group->obj_ll);\n    }\n    group->obj_focus = obj_next;\n\n    if(group->obj_focus != NULL) {\n        (*group->obj_focus)->signal_func(*group->obj_focus, LV_SIGNAL_FOCUS, NULL);\n        lv_obj_invalidate(*group->obj_focus);\n\n        if(group->focus_cb) group->focus_cb(group);\n\n        /*If the object or its parent has `top == true` bring it to the foregorund*/\n        obj_to_foreground(*group->obj_focus);\n    }\n\n}\n\n/**\n * Do not let to change the focus from the current object\n * @param group pointer to a group\n * @param en true: freeze, false: release freezing (normal mode)\n */\nvoid lv_group_focus_freeze(lv_group_t * group, bool en)\n{\n    if(en == false) group->frozen = 0;\n    else group->frozen = 1;\n}\n\n/**\n * Send a control character to the focuses object of a group\n * @param group pointer to a group\n * @param c a character (use LV_GROUP_KEY_.. to navigate)\n * @return result of focused object in group.\n */\nlv_res_t lv_group_send_data(lv_group_t * group, uint32_t c)\n{\n    lv_obj_t * act = lv_group_get_focused(group);\n    if(act == NULL) return LV_RES_OK;\n\n    return act->signal_func(act, LV_SIGNAL_CONTROLL, &c);\n}\n\n/**\n * Set a function for a group which will modify the object's style if it is in focus\n * @param group pointer to a group\n * @param style_mod_func the style modifier function pointer\n */\nvoid lv_group_set_style_mod_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func)\n{\n    group->style_mod = style_mod_func;\n    if(group->obj_focus != NULL) lv_obj_invalidate(*group->obj_focus);\n}\n\n/**\n * Set a function for a group which will modify the object's style if it is in focus in edit mode\n * @param group pointer to a group\n * @param style_mod_func the style modifier function pointer\n */\nvoid lv_group_set_style_mod_edit_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func)\n{\n    group->style_mod_edit = style_mod_func;\n    if(group->obj_focus != NULL) lv_obj_invalidate(*group->obj_focus);\n}\n\n/**\n * Set a function for a group which will be called when a new object is focused\n * @param group pointer to a group\n * @param focus_cb the call back function or NULL if unused\n */\nvoid lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t focus_cb)\n{\n    group->focus_cb = focus_cb;\n}\n\n/**\n * Manually set the current mode (edit or navigate).\n * @param group pointer to group\n * @param edit: true: edit mode; false: navigate mode\n */\nvoid lv_group_set_editing(lv_group_t * group, bool edit)\n{\n    uint8_t en_val = edit ? 1 : 0;\n\n    if(en_val == group->editing) return;        /*Do not set the same mode again*/\n\n    group->editing = en_val;\n    lv_obj_t * focused = lv_group_get_focused(group);\n\n    if(focused) focused->signal_func(focused, LV_SIGNAL_FOCUS, NULL);       /*Focus again to properly leave edit mode*/\n\n    lv_obj_invalidate(focused);\n}\n\n/**\n * Set the `click_focus` attribute. If enabled then the object will be focused then it is clicked.\n * @param group pointer to group\n * @param en: true: enable `click_focus`\n */\nvoid lv_group_set_click_focus(lv_group_t * group, bool en)\n{\n    group->click_focus = en ? 1 : 0;\n}\n\nvoid lv_group_set_refocus_policy(lv_group_t * group, lv_group_refocus_policy_t policy) {\n    group->refocus_policy = policy & 0x01;\n}\n\nstatic void lv_group_refocus(lv_group_t *g) {\n    /*Refocus must temporarily allow wrapping to work correctly*/\n    uint8_t temp_wrap = g->wrap;\n    g->wrap = 1;\n\n    if(g->refocus_policy == LV_GROUP_REFOCUS_POLICY_NEXT)\n        lv_group_focus_next(g);\n    else if(g->refocus_policy == LV_GROUP_REFOCUS_POLICY_PREV)\n        lv_group_focus_prev(g);\n    /*Restore wrap property*/\n    g->wrap = temp_wrap;\n}\n\n/**\n * Set whether focus next/prev will allow wrapping from first->last or last->first.\n * @param group pointer to group\n * @param en: true: enable `click_focus`\n */\nvoid lv_group_set_wrap(lv_group_t * group, bool en)\n{\n    group->wrap = en ? 1 : 0;\n}\n\n/**\n * Modify a style with the set 'style_mod' function. The input style remains unchanged.\n * @param group pointer to group\n * @param style pointer to a style to modify\n * @return a copy of the input style but modified with the 'style_mod' function\n */\nlv_style_t * lv_group_mod_style(lv_group_t * group, const lv_style_t * style)\n{\n    lv_style_copy(&group->style_tmp, style);\n\n    if(group->editing) {\n        if(group->style_mod_edit) group->style_mod_edit(&group->style_tmp);\n    } else {\n        if(group->style_mod) group->style_mod(&group->style_tmp);\n    }\n    return &group->style_tmp;\n}\n\n/**\n * Get the focused object or NULL if there isn't one\n * @param group pointer to a group\n * @return pointer to the focused object\n */\nlv_obj_t * lv_group_get_focused(const lv_group_t * group)\n{\n    if(!group) return NULL;\n    if(group->obj_focus == NULL) return NULL;\n\n    return *group->obj_focus;\n}\n\n/**\n * Get a the style modifier function of a group\n * @param group pointer to a group\n * @return pointer to the style modifier function\n */\nlv_group_style_mod_func_t lv_group_get_style_mod_cb(const lv_group_t * group)\n{\n    if(!group) return false;\n    return group->style_mod ;\n}\n\n/**\n * Get a the style modifier function of a group in edit mode\n * @param group pointer to a group\n * @return pointer to the style modifier function\n */\nlv_group_style_mod_func_t lv_group_get_style_mod_edit_cb(const lv_group_t * group)\n{\n    if(!group) return false;\n    return group->style_mod_edit;\n}\n\n/**\n * Get the focus callback function of a group\n * @param group pointer to a group\n * @return the call back function or NULL if not set\n */\nlv_group_focus_cb_t lv_group_get_focus_cb(const lv_group_t * group)\n{\n    if(!group) return false;\n    return group->focus_cb;\n}\n\n/**\n * Get the current mode (edit or navigate).\n * @param group pointer to group\n * @return true: edit mode; false: navigate mode\n */\nbool lv_group_get_editing(const lv_group_t * group)\n{\n    if(!group) return false;\n    return group->editing ? true : false;\n}\n\n/**\n * Get the `click_focus` attribute.\n * @param group pointer to group\n * @return true: `click_focus` is enabled; false: disabled\n */\nbool lv_group_get_click_focus(const lv_group_t * group)\n{\n    if(!group) return false;\n    return group->click_focus ? true : false;\n}\n\n/**\n * Get whether focus next/prev will allow wrapping from first->last or last->first object.\n * @param group pointer to group\n * @param en: true: wrapping enabled; false: wrapping disabled\n */\nbool lv_group_get_wrap(lv_group_t * group)\n{\n    if(!group) return false;\n    return group->wrap ? true : false;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Default style modifier function\n * @param style pointer to a style to modify. (Typically group.style_tmp) It will be OVERWRITTEN.\n */\nstatic void style_mod_def(lv_style_t * style)\n{\n#if LV_COLOR_DEPTH != 1\n\n    /*Make the style to be a little bit orange*/\n    style->body.border.opa = LV_OPA_COVER;\n    style->body.border.color = LV_COLOR_ORANGE;\n\n    /*If not empty or has border then emphasis the border*/\n    if(style->body.empty == 0 || style->body.border.width != 0) style->body.border.width = LV_DPI / 20;\n\n    style->body.main_color = lv_color_mix(style->body.main_color, LV_COLOR_ORANGE, LV_OPA_70);\n    style->body.grad_color = lv_color_mix(style->body.grad_color, LV_COLOR_ORANGE, LV_OPA_70);\n    style->body.shadow.color = lv_color_mix(style->body.shadow.color, LV_COLOR_ORANGE, LV_OPA_60);\n\n    style->text.color = lv_color_mix(style->text.color, LV_COLOR_ORANGE, LV_OPA_70);\n#else\n    style->body.border.opa = LV_OPA_COVER;\n    style->body.border.color = LV_COLOR_BLACK;\n    style->body.border.width = 2;\n\n#endif\n\n}\n\n/**\n * Default style modifier function\n * @param style pointer to a style to modify. (Typically group.style_tmp) It will be OVERWRITTEN.\n */\nstatic void style_mod_edit_def(lv_style_t * style)\n{\n#if LV_COLOR_DEPTH != 1\n\n    /*Make the style to be a little bit orange*/\n    style->body.border.opa = LV_OPA_COVER;\n    style->body.border.color = LV_COLOR_GREEN;\n\n    /*If not empty or has border then emphasis the border*/\n    if(style->body.empty == 0 || style->body.border.width != 0) style->body.border.width = LV_DPI / 20;\n\n    style->body.main_color = lv_color_mix(style->body.main_color, LV_COLOR_GREEN, LV_OPA_70);\n    style->body.grad_color = lv_color_mix(style->body.grad_color, LV_COLOR_GREEN, LV_OPA_70);\n    style->body.shadow.color = lv_color_mix(style->body.shadow.color, LV_COLOR_GREEN, LV_OPA_60);\n\n    style->text.color = lv_color_mix(style->text.color, LV_COLOR_GREEN, LV_OPA_70);\n#else\n    style->body.border.opa = LV_OPA_COVER;\n    style->body.border.color = LV_COLOR_BLACK;\n    style->body.border.width = 3;\n\n#endif\n\n}\n\nstatic void obj_to_foreground(lv_obj_t * obj)\n{\n    /*Search for 'top' attribute*/\n    lv_obj_t * i = obj;\n    lv_obj_t * last_top = NULL;\n    while(i != NULL) {\n        if(i->top != 0) last_top = i;\n        i = lv_obj_get_parent(i);\n    }\n\n    if(last_top != NULL) {\n        /*Move the last_top object to the foreground*/\n        lv_obj_t * par = lv_obj_get_parent(last_top);\n        /*After list change it will be the new head*/\n        if (lv_ll_chg_list(&par->child_ll, &par->child_ll, last_top))\n            lv_obj_invalidate(last_top); /*Only invalidate if not top*/\n    }\n}\n\n#endif /*USE_LV_GROUP != 0*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_core/lv_group.h",
    "content": "/**\n * @file lv_group.h\n *\n */\n\n#ifndef LV_GROUP_H\n#define LV_GROUP_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#include \"lv_obj.h\"\n\n/*********************\n *      DEFINES\n *********************/\n/*Predefined keys to control the focused object via lv_group_send(group, c)*/\n/*For compatibility in signal function define the keys regardless to LV_GROUP*/\n#define LV_GROUP_KEY_UP             17      /*0x11*/\n#define LV_GROUP_KEY_DOWN           18      /*0x12*/\n#define LV_GROUP_KEY_RIGHT          19      /*0x13*/\n#define LV_GROUP_KEY_LEFT           20      /*0x14*/\n#define LV_GROUP_KEY_ESC            27      /*0x1B*/\n#define LV_GROUP_KEY_DEL            127     /*0x7F*/\n#define LV_GROUP_KEY_BACKSPACE      8       /*0x08*/\n#define LV_GROUP_KEY_ENTER          10      /*0x0A, '\\n'*/\n#define LV_GROUP_KEY_NEXT           9       /*0x09, '\\t'*/\n#define LV_GROUP_KEY_PREV           11      /*0x0B, '*/\n\n#if USE_LV_GROUP  != 0\n/**********************\n *      TYPEDEFS\n **********************/\nstruct _lv_group_t;\n\ntypedef void (*lv_group_style_mod_func_t)(lv_style_t *);\ntypedef void (*lv_group_focus_cb_t)(struct _lv_group_t *);\n\ntypedef struct _lv_group_t\n{\n    lv_ll_t obj_ll;                         /*Linked list to store the objects in the group */\n    lv_obj_t ** obj_focus;                  /*The object in focus*/\n    lv_group_style_mod_func_t style_mod;    /*A function which modifies the style of the focused object*/\n    lv_group_style_mod_func_t style_mod_edit;/*A function which modifies the style of the focused object*/\n    lv_group_focus_cb_t focus_cb;           /*A function to call when a new object is focused (optional)*/\n    lv_style_t style_tmp;                   /*Stores the modified style of the focused object */\n    uint8_t frozen          :1;             /*1: can't focus to new object*/\n    uint8_t editing         :1;             /*1: Edit mode, 0: Navigate mode*/\n    uint8_t click_focus     :1;             /*1: If an object in a group is clicked by an indev then it will be focused */\n    uint8_t refocus_policy  :1;             /*1: Focus prev if focused on deletion. 0: Focus prev if focused on deletion.*/\n    uint8_t wrap            :1;             /*1: Focus next/prev can wrap at end of list. 0: Focus next/prev stops at end of list.*/\n} lv_group_t;\n\ntypedef enum _lv_group_refocus_policy_t {\n    LV_GROUP_REFOCUS_POLICY_NEXT = 0,\n    LV_GROUP_REFOCUS_POLICY_PREV = 1\n} lv_group_refocus_policy_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a new object group\n * @return pointer to the new object group\n */\nlv_group_t * lv_group_create(void);\n\n/**\n * Delete a group object\n * @param group pointer to a group\n */\nvoid lv_group_del(lv_group_t * group);\n\n/**\n * Add an object to a group\n * @param group pointer to a group\n * @param obj pointer to an object to add\n */\nvoid lv_group_add_obj(lv_group_t * group, lv_obj_t * obj);\n\n/**\n * Remove an object from its group\n * @param obj pointer to an object to remove\n */\nvoid lv_group_remove_obj(lv_obj_t * obj);\n\n/**\n * Focus on an object (defocus the current)\n * @param obj pointer to an object to focus on\n */\nvoid lv_group_focus_obj(lv_obj_t * obj);\n\n/**\n * Focus the next object in a group (defocus the current)\n * @param group pointer to a group\n */\nvoid lv_group_focus_next(lv_group_t * group);\n\n/**\n * Focus the previous object in a group (defocus the current)\n * @param group pointer to a group\n */\nvoid lv_group_focus_prev(lv_group_t * group);\n\n/**\n * Do not let to change the focus from the current object\n * @param group pointer to a group\n * @param en true: freeze, false: release freezing (normal mode)\n */\nvoid lv_group_focus_freeze(lv_group_t * group, bool en);\n\n/**\n * Send a control character to the focuses object of a group\n * @param group pointer to a group\n * @param c a character (use LV_GROUP_KEY_.. to navigate)\n * @return result of focused object in group.\n */\nlv_res_t lv_group_send_data(lv_group_t * group, uint32_t c);\n\n/**\n * Set a function for a group which will modify the object's style if it is in focus\n * @param group pointer to a group\n * @param style_mod_func the style modifier function pointer\n */\nvoid lv_group_set_style_mod_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func);\n\n/**\n * Set a function for a group which will modify the object's style if it is in focus in edit mode\n * @param group pointer to a group\n * @param style_mod_func the style modifier function pointer\n */\nvoid lv_group_set_style_mod_edit_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func);\n\n/**\n * Set a function for a group which will be called when a new object is focused\n * @param group pointer to a group\n * @param focus_cb the call back function or NULL if unused\n */\nvoid lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t focus_cb);\n\n/**\n * Set whether the next or previous item in a group is focused if the currently focussed obj is deleted.\n * @param group pointer to a group\n * @param new refocus policy enum\n */\nvoid lv_group_set_refocus_policy(lv_group_t * group, lv_group_refocus_policy_t policy);\n\n/**\n * Manually set the current mode (edit or navigate).\n * @param group pointer to group\n * @param edit: true: edit mode; false: navigate mode\n */\nvoid lv_group_set_editing(lv_group_t * group, bool edit);\n\n/**\n * Set the `click_focus` attribute. If enabled then the object will be focused then it is clicked.\n * @param group pointer to group\n * @param en: true: enable `click_focus`\n */\nvoid lv_group_set_click_focus(lv_group_t * group, bool en);\n\n/**\n * Set whether focus next/prev will allow wrapping from first->last or last->first object.\n * @param group pointer to group\n * @param en: true: wrapping enabled; false: wrapping disabled\n */\nvoid lv_group_set_wrap(lv_group_t * group, bool en);\n\n/**\n * Modify a style with the set 'style_mod' function. The input style remains unchanged.\n * @param group pointer to group\n * @param style pointer to a style to modify\n * @return a copy of the input style but modified with the 'style_mod' function\n */\nlv_style_t * lv_group_mod_style(lv_group_t * group, const lv_style_t * style);\n\n/**\n * Get the focused object or NULL if there isn't one\n * @param group pointer to a group\n * @return pointer to the focused object\n */\nlv_obj_t * lv_group_get_focused(const lv_group_t * group);\n\n/**\n * Get a the style modifier function of a group\n * @param group pointer to a group\n * @return pointer to the style modifier function\n */\nlv_group_style_mod_func_t lv_group_get_style_mod_cb(const lv_group_t * group);\n\n/**\n * Get a the style modifier function of a group in edit mode\n * @param group pointer to a group\n * @return pointer to the style modifier function\n */\nlv_group_style_mod_func_t lv_group_get_style_mod_edit_cb(const lv_group_t * group);\n\n/**\n * Get the focus callback function of a group\n * @param group pointer to a group\n * @return the call back function or NULL if not set\n */\nlv_group_focus_cb_t lv_group_get_focus_cb(const lv_group_t * group);\n\n/**\n * Get the current mode (edit or navigate).\n * @param group pointer to group\n * @return true: edit mode; false: navigate mode\n */\nbool lv_group_get_editing(const lv_group_t * group);\n\n/**\n * Get the `click_focus` attribute.\n * @param group pointer to group\n * @return true: `click_focus` is enabled; false: disabled\n */\nbool lv_group_get_click_focus(const lv_group_t * group);\n\n/**\n * Get whether focus next/prev will allow wrapping from first->last or last->first object.\n * @param group pointer to group\n * @param en: true: wrapping enabled; false: wrapping disabled\n */\nbool lv_group_get_wrap(lv_group_t * group);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif /*USE_LV_GROUP != 0*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_GROUP_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_core/lv_indev.c",
    "content": "/**\n * @file lv_indev_proc.c\n *\n */\n\n/*********************\n *      INCLUDES\n ********************/\n#include \"lv_indev.h\"\n\n#include \"../lv_hal/lv_hal_tick.h\"\n#include \"../lv_core/lv_group.h\"\n#include \"../lv_core/lv_refr.h\"\n#include \"../lv_misc/lv_task.h\"\n#include \"../lv_misc/lv_math.h\"\n#include \"../lv_draw/lv_draw_rbasic.h\"\n#include \"lv_obj.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n#if LV_INDEV_DRAG_THROW <= 0\n#warning \"LV_INDEV_DRAG_THROW must be greater than 0\"\n#endif\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n\n#if LV_INDEV_READ_PERIOD != 0\nstatic void indev_proc_task(void * param);\nstatic void indev_pointer_proc(lv_indev_t * i, lv_indev_data_t * data);\nstatic void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data);\nstatic void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data);\nstatic void indev_button_proc(lv_indev_t * i, lv_indev_data_t * data);\nstatic void indev_proc_press(lv_indev_proc_t * proc);\nstatic void indev_proc_release(lv_indev_proc_t * proc);\nstatic void indev_proc_reset_query_handler(lv_indev_t * indev);\nstatic lv_obj_t * indev_search_obj(const lv_indev_proc_t * proc, lv_obj_t * obj);\nstatic void indev_drag(lv_indev_proc_t * state);\nstatic void indev_drag_throw(lv_indev_proc_t * state);\n#endif\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_indev_t * indev_act;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Initialize the display input device subsystem\n */\nvoid lv_indev_init(void)\n{\n#if LV_INDEV_READ_PERIOD != 0\n    lv_task_create(indev_proc_task, LV_INDEV_READ_PERIOD, LV_TASK_PRIO_MID, NULL);\n#endif\n\n    lv_indev_reset(NULL);   /*Reset all input devices*/\n}\n\n/**\n * Get the currently processed input device. Can be used in action functions too.\n * @return pointer to the currently processed input device or NULL if no input device processing right now\n */\nlv_indev_t * lv_indev_get_act(void)\n{\n    return indev_act;\n}\n\n/**\n * Get the type of an input device\n * @param indev pointer to an input device\n * @return the type of the input device from `lv_hal_indev_type_t` (`LV_INDEV_TYPE_...`)\n */\nlv_hal_indev_type_t lv_indev_get_type(const lv_indev_t * indev)\n{\n    if(indev == NULL) return LV_INDEV_TYPE_NONE;\n\n    return indev->driver.type;\n}\n/**\n * Reset one or all input devices\n * @param indev pointer to an input device to reset or NULL to reset all of them\n */\nvoid lv_indev_reset(lv_indev_t * indev)\n{\n    if(indev) indev->proc.reset_query = 1;\n    else {\n        lv_indev_t * i = lv_indev_next(NULL);\n        while(i) {\n            i->proc.reset_query = 1;\n            i = lv_indev_next(i);\n        }\n    }\n}\n\n/**\n * Reset the long press state of an input device\n * @param indev pointer to an input device\n */\nvoid lv_indev_reset_lpr(lv_indev_t * indev)\n{\n    indev->proc.long_pr_sent = 0;\n    indev->proc.longpr_rep_timestamp = lv_tick_get();\n    indev->proc.pr_timestamp = lv_tick_get();\n}\n\n/**\n * Enable input devices device by type\n * @param type Input device type\n * @param enable true: enable this type; false: disable this type\n */\nvoid lv_indev_enable(lv_hal_indev_type_t type, bool enable)\n{\n    lv_indev_t * i = lv_indev_next(NULL);\n\n    while(i) {\n        if(i->driver.type == type) i->proc.disabled = enable == false ? 1 : 0;\n        i = lv_indev_next(i);\n    }\n}\n\n/**\n * Set a cursor for a pointer input device (for LV_INPUT_TYPE_POINTER and LV_INPUT_TYPE_BUTTON)\n * @param indev pointer to an input device\n * @param cur_obj pointer to an object to be used as cursor\n */\nvoid lv_indev_set_cursor(lv_indev_t * indev, lv_obj_t * cur_obj)\n{\n    if(indev->driver.type != LV_INDEV_TYPE_POINTER) return;\n\n    indev->cursor = cur_obj;\n    if (indev->cursor)\n    {\n        lv_obj_set_parent(indev->cursor, lv_layer_sys());\n        lv_obj_set_pos(indev->cursor, indev->proc.act_point.x,  indev->proc.act_point.y);\n    }\n}\n\n#if USE_LV_GROUP\n/**\n * Set a destination group for a keypad input device (for LV_INDEV_TYPE_KEYPAD)\n * @param indev pointer to an input device\n * @param group point to a group\n */\nvoid lv_indev_set_group(lv_indev_t * indev, lv_group_t * group)\n{\n    if(indev->driver.type == LV_INDEV_TYPE_KEYPAD || indev->driver.type == LV_INDEV_TYPE_ENCODER) indev->group = group;\n}\n#endif\n\n/**\n * Set the an array of points for LV_INDEV_TYPE_BUTTON.\n * These points will be assigned to the buttons to press a specific point on the screen\n * @param indev pointer to an input device\n * @param group point to a group\n */\nvoid lv_indev_set_button_points(lv_indev_t * indev, const lv_point_t * points)\n{\n    if(indev->driver.type == LV_INDEV_TYPE_BUTTON) indev->btn_points = points;\n}\n\n/**\n * Set feedback callback for indev.\n * @param indev pointer to an input device\n * @param feedback feedback callback\n */\nvoid lv_indev_set_feedback(lv_indev_t *indev, lv_indev_feedback_t feedback)\n{\n\tindev->feedback = feedback;\n}\n\n/**\n * Get the last point of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON)\n * @param indev pointer to an input device\n * @param point pointer to a point to store the result\n */\nvoid lv_indev_get_point(const lv_indev_t * indev, lv_point_t * point)\n{\n    if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) {\n        point->x = -1;\n        point->y = -1;\n    } else {\n        point->x = indev->proc.act_point.x;\n        point->y = indev->proc.act_point.y;\n    }\n}\n\n/**\n * Get the last key of an input device (for LV_INDEV_TYPE_KEYPAD)\n * @param indev pointer to an input device\n * @return the last pressed key (0 on error)\n */\nuint32_t lv_indev_get_key(const lv_indev_t * indev)\n{\n    if(indev->driver.type != LV_INDEV_TYPE_KEYPAD) return 0;\n    else return indev->proc.last_key;\n}\n\n/**\n * Check if there is dragging with an input device or not (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON)\n * @param indev pointer to an input device\n * @return true: drag is in progress\n */\nbool lv_indev_is_dragging(const lv_indev_t * indev)\n{\n    if(indev == NULL) return false;\n    if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) return false;\n    return indev->proc.drag_in_prog == 0 ? false : true;\n}\n\n/**\n * Get the vector of dragging of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON)\n * @param indev pointer to an input device\n * @param point pointer to a point to store the vector\n */\nvoid lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point)\n{\n    if(indev == NULL) {\n        point->x = 0;\n        point->y = 0;\n        return;\n    }\n\n    if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) {\n        point->x = 0;\n        point->y = 0;\n    } else {\n        point->x = indev->proc.vect.x;\n        point->y = indev->proc.vect.y;\n    }\n}\n\n/**\n * Get elapsed time since last press\n * @param indev pointer to an input device (NULL to get the overall smallest inactivity)\n * @return Elapsed ticks (milliseconds) since last press\n */\nuint32_t lv_indev_get_inactive_time(const lv_indev_t * indev)\n{\n    uint32_t t;\n\n    if(indev) return t = lv_tick_elaps(indev->last_activity_time);\n\n    lv_indev_t * i;\n    t = UINT16_MAX;\n    i = lv_indev_next(NULL);\n    while(i) {\n        t = LV_MATH_MIN(t, lv_tick_elaps(i->last_activity_time));\n        i = lv_indev_next(i);\n    }\n\n    return t;\n}\n\n/**\n * Get feedback callback for indev.\n * @param indev pointer to an input device\n * @return feedback callback\n */\nlv_indev_feedback_t lv_indev_get_feedback(const lv_indev_t *indev)\n{\n\treturn indev->feedback;\n}\n\n/**\n * Do nothing until the next release\n * @param indev pointer to an input device\n */\nvoid lv_indev_wait_release(lv_indev_t * indev)\n{\n    indev->proc.wait_unil_release = 1;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n#if LV_INDEV_READ_PERIOD != 0\n/**\n * Called periodically to handle the input devices\n * @param param unused\n */\nstatic void indev_proc_task(void * param)\n{\n    (void)param;\n\n\n    LV_LOG_TRACE(\"indev task started\");\n\n    lv_indev_data_t data;\n    lv_indev_t * i;\n    i = lv_indev_next(NULL);\n\n    /*Read and process all indevs*/\n    while(i) {\n        indev_act = i;\n\n        /*Handle reset query before processing the point*/\n        indev_proc_reset_query_handler(i);\n\n        if(i->proc.disabled == 0) {\n            bool more_to_read;\n            do {\n                /*Read the data*/\n                more_to_read = lv_indev_read(i, &data);\n                indev_proc_reset_query_handler(i);          /*The active object might deleted even in the read function*/\n                i->proc.state = data.state;\n\n                if(i->proc.state == LV_INDEV_STATE_PR) {\n                    i->last_activity_time = lv_tick_get();\n                }\n\n                if(i->driver.type == LV_INDEV_TYPE_POINTER) {\n                    indev_pointer_proc(i, &data);\n                } else if(i->driver.type == LV_INDEV_TYPE_KEYPAD) {\n                    indev_keypad_proc(i, &data);\n                } else if(i->driver.type == LV_INDEV_TYPE_ENCODER) {\n                    indev_encoder_proc(i, &data);\n                } else if(i->driver.type == LV_INDEV_TYPE_BUTTON) {\n                    indev_button_proc(i, &data);\n                }\n                /*Handle reset query if it happened in during processing*/\n                indev_proc_reset_query_handler(i);\n            } while(more_to_read);\n        }\n        i = lv_indev_next(i);    /*Go to the next indev*/\n    }\n\n    indev_act = NULL;   /*End of indev processing, so no act indev*/\n\n    LV_LOG_TRACE(\"indev task finished\");\n}\n\n\n/**\n * Process a new point from LV_INDEV_TYPE_POINTER input device\n * @param i pointer to an input device\n * @param data pointer to the data read from the input device\n */\nstatic void indev_pointer_proc(lv_indev_t * i, lv_indev_data_t * data)\n{\n    /*Move the cursor if set and moved*/\n    if(i->cursor != NULL &&\n            (i->proc.last_point.x != data->point.x ||\n             i->proc.last_point.y != data->point.y)) {\n        /*Use cursor's center as pointer*/\n        uint32_t off_x = lv_obj_get_width(i->cursor) >> 1;\n        uint32_t off_y = lv_obj_get_height(i->cursor) >> 1;\n        lv_obj_set_pos(i->cursor, data->point.x - off_x, data->point.y - off_y);\n    }\n\n    i->proc.act_point.x = data->point.x;\n    i->proc.act_point.y = data->point.y;\n\n    if(i->proc.state == LV_INDEV_STATE_PR) {\n#if LV_INDEV_POINT_MARKER != 0\n        lv_area_t area;\n        area.x1 = i->proc.act_point.x - (LV_INDEV_POINT_MARKER >> 1);\n        area.y1 = i->proc.act_point.y - (LV_INDEV_POINT_MARKER >> 1);\n        area.x2 = i->proc.act_point.x + ((LV_INDEV_POINT_MARKER >> 1) | 0x1);\n        area.y2 = i->proc.act_point.y + ((LV_INDEV_POINT_MARKER >> 1) | 0x1);\n        lv_rfill(&area, NULL, LV_COLOR_MAKE(0xFF, 0, 0), LV_OPA_COVER);\n#endif\n        indev_proc_press(&i->proc);\n    } else {\n        indev_proc_release(&i->proc);\n    }\n\n    i->proc.last_point.x = i->proc.act_point.x;\n    i->proc.last_point.y = i->proc.act_point.y;\n}\n\n/**\n * Process a new point from LV_INDEV_TYPE_KEYPAD input device\n * @param i pointer to an input device\n * @param data pointer to the data read from the input device\n */\nstatic void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data)\n{\n#if USE_LV_GROUP\n    if(i->group == NULL) return;\n\n    /*Key press happened*/\n    if(data->state == LV_INDEV_STATE_PR &&\n            i->proc.last_state == LV_INDEV_STATE_REL) {\n        i->proc.pr_timestamp = lv_tick_get();\n        lv_obj_t * focused = lv_group_get_focused(i->group);\n        if(focused && data->key == LV_GROUP_KEY_ENTER) {\n            focused->signal_func(focused, LV_SIGNAL_PRESSED, indev_act);\n        }\n    }\n    /*Pressing*/\n    else if(data->state == LV_INDEV_STATE_PR && i->proc.last_state == LV_INDEV_STATE_PR) {\n        if(data->key == LV_GROUP_KEY_ENTER &&\n                i->proc.long_pr_sent == 0 &&\n                lv_tick_elaps(i->proc.pr_timestamp) > LV_INDEV_LONG_PRESS_TIME) {\n            /*On enter long press leave edit mode.*/\n            lv_obj_t * focused = lv_group_get_focused(i->group);\n            if(focused) {\n                focused->signal_func(focused, LV_SIGNAL_LONG_PRESS, indev_act);\n                i->proc.long_pr_sent = 1;\n            }\n        }\n    }\n    /*Release happened*/\n    else if(data->state == LV_INDEV_STATE_REL && i->proc.last_state == LV_INDEV_STATE_PR) {\n        /*The user might clear the key when it was released. Always release the pressed key*/\n        data->key = i->proc.last_key;\n\n        /* Edit mode is not used by KEYPAD devices.\n         * So leave edit mode if we are in it before focusing on the next/prev object*/\n        if(data->key == LV_GROUP_KEY_NEXT || data->key == LV_GROUP_KEY_PREV) {\n            lv_group_set_editing(i->group, false);\n        }\n\n        if(data->key == LV_GROUP_KEY_NEXT) {\n            lv_group_focus_next(i->group);\n        } else if(data->key == LV_GROUP_KEY_PREV) {\n            lv_group_focus_prev(i->group);\n        } else if(data->key == LV_GROUP_KEY_ENTER) {\n            if(!i->proc.long_pr_sent) {\n                lv_group_send_data(i->group, data->key);\n            }\n        } else {\n            lv_group_send_data(i->group, data->key);\n        }\n\n        if(i->proc.reset_query) return;     /*The object might be deleted in `focus_cb` or due to any other user event*/\n\n        i->proc.pr_timestamp = 0;\n        i->proc.long_pr_sent = 0;\n    }\n\n    i->proc.last_state = data->state;\n    i->proc.last_key = data->key;\n#else\n    (void)data; /*Unused*/\n    (void)i; /*Unused*/\n#endif\n}\n\n/**\n * Process a new point from LV_INDEV_TYPE_ENCODER input device\n * @param i pointer to an input device\n * @param data pointer to the data read from the input device\n */\nstatic void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data)\n{\n#if USE_LV_GROUP\n    if(i->group == NULL) return;\n\n    /*Process the steps first. They are valid only with released button*/\n    if(data->state == LV_INDEV_STATE_REL) {\n        /*In edit mode send LEFT/RIGHT keys*/\n        if(lv_group_get_editing(i->group)) {\n            int32_t s;\n            if(data->enc_diff < 0) {\n                for(s = 0; s < -data->enc_diff; s++) lv_group_send_data(i->group, LV_GROUP_KEY_LEFT);\n            } else if(data->enc_diff > 0) {\n                for(s = 0; s < data->enc_diff; s++) lv_group_send_data(i->group, LV_GROUP_KEY_RIGHT);\n            }\n        }\n        /*In navigate mode focus on the next/prev objects*/\n        else {\n            int32_t s;\n            if(data->enc_diff < 0) {\n                for(s = 0; s < -data->enc_diff; s++) lv_group_focus_prev(i->group);\n            } else if(data->enc_diff > 0) {\n                for(s = 0; s < data->enc_diff; s++) lv_group_focus_next(i->group);\n            }\n        }\n    }\n\n    /*Key press happened*/\n    if(data->state == LV_INDEV_STATE_PR &&\n            i->proc.last_state == LV_INDEV_STATE_REL) {\n        i->proc.pr_timestamp = lv_tick_get();\n    }\n    /*Pressing*/\n    else if(data->state == LV_INDEV_STATE_PR && i->proc.last_state == LV_INDEV_STATE_PR) {\n        if(i->proc.long_pr_sent == 0 &&\n                lv_tick_elaps(i->proc.pr_timestamp) > LV_INDEV_LONG_PRESS_TIME) {\n            /*On enter long press leave edit mode.*/\n            lv_obj_t * focused = lv_group_get_focused(i->group);\n\n            bool editable = false;\n            if(focused) focused->signal_func(focused, LV_SIGNAL_GET_EDITABLE, &editable);\n\n            if(editable) {\n                if(i->group->obj_ll.head != i->group->obj_ll.tail)\n                    lv_group_set_editing(i->group, lv_group_get_editing(i->group) ? false : true);  /*Toggle edit mode on long press*/\n                else if(focused)\n                    focused->signal_func(focused, LV_SIGNAL_LONG_PRESS, indev_act);\n            }\n            /*If not editable then just send a long press signal*/\n            else {\n                if(focused)\n                    focused->signal_func(focused, LV_SIGNAL_LONG_PRESS, indev_act);\n            }\n            i->proc.long_pr_sent = 1;\n        }\n    }\n    /*Release happened*/\n    else if(data->state == LV_INDEV_STATE_REL && i->proc.last_state == LV_INDEV_STATE_PR) {\n        lv_obj_t * focused = lv_group_get_focused(i->group);\n        bool editable = false;\n        if(focused) focused->signal_func(focused, LV_SIGNAL_GET_EDITABLE, &editable);\n\n        /*The button was released on a non-editable object. Just send enter*/\n        if(!editable) {\n            lv_group_send_data(i->group, LV_GROUP_KEY_ENTER);\n        }\n        /*An object is being edited and the button is releases. Just send enter */\n        else if(i->group->editing) {\n            if(!i->proc.long_pr_sent || i->group->obj_ll.head == i->group->obj_ll.tail)\n                lv_group_send_data(i->group, LV_GROUP_KEY_ENTER);  /*Ignore long pressed enter release because it comes from mode switch*/\n        }\n        /*If the focused object is editable and now in navigate mode then enter edit mode*/\n        else if(editable && !i->group->editing && !i->proc.long_pr_sent) {\n            lv_group_set_editing(i->group, lv_group_get_editing(i->group) ? false : true);  /*Toggle edit mode on long press*/\n        }\n\n        if(i->proc.reset_query) return;     /*The object might be deleted in `focus_cb` or due to any other user event*/\n\n        i->proc.pr_timestamp = 0;\n        i->proc.long_pr_sent = 0;\n    }\n\n    i->proc.last_state = data->state;\n    i->proc.last_key = data->key;\n#else\n    (void)data; /*Unused*/\n    (void)i; /*Unused*/\n#endif\n}\n\n/**\n * Process new points from a input device. indev->state.pressed has to be set\n * @param indev pointer to an input device state\n * @param x x coordinate of the next point\n * @param y y coordinate of the next point\n */\nstatic void indev_button_proc(lv_indev_t * i, lv_indev_data_t * data)\n{\n    i->proc.act_point.x = i->btn_points[data->btn].x;\n    i->proc.act_point.y = i->btn_points[data->btn].y;\n\n    /*Still the same point is pressed*/\n    if(i->proc.last_point.x == i->proc.act_point.x &&\n            i->proc.last_point.y == i->proc.act_point.y &&\n            data->state == LV_INDEV_STATE_PR) {\n#if LV_INDEV_POINT_MARKER != 0\n        lv_area_t area;\n        area.x1 = i->proc.act_point.x - (LV_INDEV_POINT_MARKER >> 1);\n        area.y1 = i->proc.act_point.y - (LV_INDEV_POINT_MARKER >> 1);\n        area.x2 = i->proc.act_point.x + ((LV_INDEV_POINT_MARKER >> 1) | 0x1);\n        area.y2 = i->proc.act_point.y + ((LV_INDEV_POINT_MARKER >> 1) | 0x1);\n        lv_rfill(&area, NULL, LV_COLOR_MAKE(0xFF, 0, 0), LV_OPA_COVER);\n#endif\n        indev_proc_press(&i->proc);\n    } else {\n        /*If a new point comes always make a release*/\n        indev_proc_release(&i->proc);\n    }\n\n    i->proc.last_point.x = i->proc.act_point.x;\n    i->proc.last_point.y = i->proc.act_point.y;\n}\n\n/**\n * Process the pressed state of LV_INDEV_TYPE_POINER input devices\n * @param indev pointer to an input device 'proc'\n */\nstatic void indev_proc_press(lv_indev_proc_t * proc)\n{\n    lv_obj_t * pr_obj = proc->act_obj;\n\n    if(proc->wait_unil_release != 0) return;\n\n    /*If there is no last object then search*/\n    if(proc->act_obj == NULL) {\n        pr_obj = indev_search_obj(proc, lv_layer_top());\n        if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_scr_act());\n    }\n    /*If there is last object but it is not dragged and not protected also search*/\n    else if(proc->drag_in_prog == 0 &&\n            lv_obj_is_protected(proc->act_obj, LV_PROTECT_PRESS_LOST) == false) {/*Now act_obj != NULL*/\n        pr_obj = indev_search_obj(proc, lv_layer_top());\n        if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_scr_act());\n    }\n    /*If a dragable or a protected object was the last then keep it*/\n    else {\n\n    }\n\n    /*If a new object was found reset some variables and send a pressed signal*/\n    if(pr_obj != proc->act_obj) {\n\n        proc->last_point.x = proc->act_point.x;\n        proc->last_point.y = proc->act_point.y;\n\n        /*If a new object found the previous was lost, so send a signal*/\n        if(proc->act_obj != NULL) {\n            proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_PRESS_LOST, indev_act);\n            if(proc->reset_query != 0) return;\n        }\n\n        proc->act_obj = pr_obj;           /*Save the pressed object*/\n        proc->last_obj = proc->act_obj;   /*Refresh the last_obj*/\n\n        if(proc->act_obj != NULL) {\n            /* Save the time when the obj pressed.\n             * It is necessary to count the long press time.*/\n            proc->pr_timestamp = lv_tick_get();\n            proc->long_pr_sent = 0;\n            proc->drag_range_out = 0;\n            proc->drag_in_prog = 0;\n            proc->drag_sum.x = 0;\n            proc->drag_sum.y = 0;\n            proc->vect.x = 0;\n            proc->vect.y = 0;\n\n            /*Search for 'top' attribute*/\n            lv_obj_t * i = proc->act_obj;\n            lv_obj_t * last_top = NULL;\n            while(i != NULL) {\n                if(i->top != 0) last_top = i;\n                i = lv_obj_get_parent(i);\n            }\n\n            if(last_top != NULL) {\n                /*Move the last_top object to the foreground*/\n                lv_obj_t * par = lv_obj_get_parent(last_top);\n                /*After list change it will be the new head*/\n                if (lv_ll_chg_list(&par->child_ll, &par->child_ll, last_top))\n                    lv_obj_invalidate(last_top); /*Only invalidate if not top*/\n            }\n\n            /*Send a signal about the press*/\n            proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_PRESSED, indev_act);\n            if(proc->reset_query != 0) return;\n        }\n    }\n\n    /*Calculate the vector*/\n    proc->vect.x = proc->act_point.x - proc->last_point.x;\n    proc->vect.y = proc->act_point.y - proc->last_point.y;\n\n    /*If there is active object and it can be dragged run the drag*/\n    if(proc->act_obj != NULL) {\n        proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_PRESSING, indev_act);\n        if(proc->reset_query != 0) return;\n\n        indev_drag(proc);\n        if(proc->reset_query != 0) return;\n\n        /*If there is no drag then check for long press time*/\n        if(proc->drag_in_prog == 0 && proc->long_pr_sent == 0) {\n            /*Send a signal about the long press if enough time elapsed*/\n            if(lv_tick_elaps(proc->pr_timestamp) > LV_INDEV_LONG_PRESS_TIME) {\n                pr_obj->signal_func(pr_obj, LV_SIGNAL_LONG_PRESS, indev_act);\n                if(proc->reset_query != 0) return;\n\n                /*Mark the signal sending to do not send it again*/\n                proc->long_pr_sent = 1;\n\n                /*Save the long press time stamp for the long press repeat handler*/\n                proc->longpr_rep_timestamp = lv_tick_get();\n            }\n        }\n        /*Send long press repeated signal*/\n        if(proc->drag_in_prog == 0 && proc->long_pr_sent == 1) {\n            /*Send a signal about the long press repeate if enough time elapsed*/\n            if(lv_tick_elaps(proc->longpr_rep_timestamp) > LV_INDEV_LONG_PRESS_REP_TIME) {\n                pr_obj->signal_func(pr_obj, LV_SIGNAL_LONG_PRESS_REP, indev_act);\n                if(proc->reset_query != 0) return;\n                proc->longpr_rep_timestamp = lv_tick_get();\n\n            }\n        }\n    }\n}\n\n/**\n * Process the released state of LV_INDEV_TYPE_POINER input devices\n * @param proc pointer to an input device 'proc'\n */\nstatic void indev_proc_release(lv_indev_proc_t * proc)\n{\n    if(proc->wait_unil_release != 0) {\n        proc->act_obj = NULL;\n        proc->last_obj = NULL;\n        proc->pr_timestamp = 0;\n        proc->longpr_rep_timestamp = 0;\n        proc->wait_unil_release = 0;\n    }\n\n    /*Forgot the act obj and send a released signal */\n    if(proc->act_obj != NULL) {\n        /* If the object was protected against press lost then it possible that\n         * the object is already not pressed but still it is the `act_obj`.\n         * In this case send the `LV_SIGNAL_RELEASED` if the indev is ON the `act_obj` */\n        if(lv_obj_is_protected(proc->act_obj, LV_PROTECT_PRESS_LOST)) {\n            /* Search the object on the current current coordinates.\n             * The start object is the object itself. If not ON it the the result will be NULL*/\n            lv_obj_t * obj_on = indev_search_obj(proc, proc->act_obj);\n            if(obj_on == proc->act_obj) proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_RELEASED, indev_act);\n            else proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_PRESS_LOST, indev_act);\n\n        }\n        /* The simple case: `act_obj` was not protected against press lost.\n         * If it is already not pressed then was handled in `indev_proc_press`*/\n        else {\n            proc->act_obj->signal_func(proc->act_obj, LV_SIGNAL_RELEASED, indev_act);\n        }\n\n        if(proc->reset_query != 0) return;\n\n        /*Handle click focus*/\n#if USE_LV_GROUP\n        /*Edit mode is not used by POINTER devices. So leave edit mode if we are in it*/\n        lv_group_t * act_g = lv_obj_get_group(proc->act_obj);\n        if(lv_group_get_editing(act_g)) {\n            lv_group_set_editing(act_g, false);\n        }\n\n        /*Check, if the parent is in a group focus on it.*/\n        if(lv_obj_is_protected(proc->act_obj, LV_PROTECT_CLICK_FOCUS) == false) {       /*Respect the click protection*/\n            lv_group_t * g = lv_obj_get_group(proc->act_obj);\n            lv_obj_t * parent = proc->act_obj;\n\n            while(g == NULL) {\n                parent = lv_obj_get_parent(parent);\n                if(parent == NULL) break;\n                if(lv_obj_is_protected(parent, LV_PROTECT_CLICK_FOCUS)) {   /*Ignore is the protected against click focus*/\n                    parent = NULL;\n                    break;\n                }\n                g = lv_obj_get_group(parent);\n            }\n\n            if(g != NULL && parent != NULL)\n                if(lv_group_get_click_focus(g)) {\n                    lv_group_focus_obj(parent);\n                }\n        }\n#endif\n\n        if(proc->reset_query != 0) return;\n        proc->act_obj = NULL;\n        proc->pr_timestamp = 0;\n        proc->longpr_rep_timestamp = 0;\n    }\n\n    /*The reset can be set in the signal function.\n     * In case of reset query ignore the remaining parts.*/\n    if(proc->last_obj != NULL && proc->reset_query == 0) {\n        indev_drag_throw(proc);\n        if(proc->reset_query != 0) return;\n    }\n}\n\n/**\n * Process a new point from LV_INDEV_TYPE_BUTTON input device\n * @param i pointer to an input device\n * @param data pointer to the data read from the input device\n * Reset input device if a reset query has been sent to it\n * @param indev pointer to an input device\n */\nstatic void indev_proc_reset_query_handler(lv_indev_t * indev)\n{\n    if(indev->proc.reset_query) {\n        indev->proc.act_obj = NULL;\n        indev->proc.last_obj = NULL;\n        indev->proc.drag_range_out = 0;\n        indev->proc.drag_in_prog = 0;\n        indev->proc.long_pr_sent = 0;\n        indev->proc.pr_timestamp = 0;\n        indev->proc.longpr_rep_timestamp = 0;\n        indev->proc.drag_sum.x = 0;\n        indev->proc.drag_sum.y = 0;\n        indev->proc.reset_query = 0;\n    }\n}\n/**\n * Search the most top, clickable object on the last point of an input device\n * @param proc pointer to  the `lv_indev_proc_t` part of the input device\n * @param obj pointer to a start object, typically the screen\n * @return pointer to the found object or NULL if there was no suitable object\n */\nstatic lv_obj_t * indev_search_obj(const lv_indev_proc_t * proc, lv_obj_t * obj)\n{\n    lv_obj_t * found_p = NULL;\n\n    /*If the point is on this object*/\n    /*Check its children too*/\n    if(lv_area_is_point_on(&obj->coords, &proc->act_point)) {\n        lv_obj_t * i;\n\n        LL_READ(obj->child_ll, i) {\n            found_p = indev_search_obj(proc, i);\n\n            /*If a child was found then break*/\n            if(found_p != NULL) {\n                break;\n            }\n        }\n\n        /*If then the children was not ok, and this obj is clickable\n         * and it or its parent is not hidden then save this object*/\n        if(found_p == NULL && lv_obj_get_click(obj) != false) {\n            lv_obj_t * hidden_i = obj;\n            while(hidden_i != NULL) {\n                if(lv_obj_get_hidden(hidden_i) == true) break;\n                hidden_i = lv_obj_get_parent(hidden_i);\n            }\n            /*No parent found with hidden == true*/\n            if(hidden_i == NULL) found_p = obj;\n        }\n\n    }\n\n    return found_p;\n}\n\n/**\n * Handle the dragging of indev_proc_p->act_obj\n * @param indev pointer to a input device state\n */\nstatic void indev_drag(lv_indev_proc_t * state)\n{\n    lv_obj_t * drag_obj = state->act_obj;\n\n    /*If drag parent is active check recursively the drag_parent attribute*/\n    while(lv_obj_get_drag_parent(drag_obj) != false &&\n            drag_obj != NULL) {\n        drag_obj = lv_obj_get_parent(drag_obj);\n    }\n\n    if(drag_obj == NULL) return;\n\n    if(lv_obj_get_drag(drag_obj) == false) return;\n\n    /*Count the movement by drag*/\n    state->drag_sum.x += state->vect.x;\n    state->drag_sum.y += state->vect.y;\n\n    /*Enough move?*/\n    if(state->drag_range_out == 0) {\n        /*If a move is greater then LV_DRAG_LIMIT then begin the drag*/\n        if(LV_MATH_ABS(state->drag_sum.x) >= LV_INDEV_DRAG_LIMIT ||\n                LV_MATH_ABS(state->drag_sum.y) >= LV_INDEV_DRAG_LIMIT) {\n            state->drag_range_out = 1;\n        }\n    }\n\n    /*If the drag limit is stepped over then handle the dragging*/\n    if(state->drag_range_out != 0) {\n        /*Set new position if the vector is not zero*/\n        if(state->vect.x != 0 ||\n                state->vect.y != 0) {\n            /*Get the coordinates of the object and modify them*/\n            lv_coord_t act_x = lv_obj_get_x(drag_obj);\n            lv_coord_t act_y = lv_obj_get_y(drag_obj);\n            uint16_t inv_buf_size = lv_refr_get_buf_size(); /*Get the number of currently invalidated areas*/\n\n            lv_coord_t prev_x = drag_obj->coords.x1;\n            lv_coord_t prev_y = drag_obj->coords.y1;\n            lv_coord_t prev_par_w = lv_obj_get_width(lv_obj_get_parent(drag_obj));\n            lv_coord_t prev_par_h = lv_obj_get_height(lv_obj_get_parent(drag_obj));\n\n            lv_obj_set_pos(drag_obj, act_x + state->vect.x, act_y + state->vect.y);\n\n            /*Set the drag in progress flag if the object is really moved*/\n\n            if(drag_obj->coords.x1 != prev_x || drag_obj->coords.y1 != prev_y) {\n                if(state->drag_range_out != 0) { /*Send the drag begin signal on first move*/\n                    drag_obj->signal_func(drag_obj,  LV_SIGNAL_DRAG_BEGIN, indev_act);\n                    if(state->reset_query != 0) return;\n                }\n                state->drag_in_prog = 1;\n            }\n            /*If the object didn't moved then clear the invalidated areas*/\n            else {\n                /*In a special case if the object is moved on a page and\n                 * the scrollable has fit == true and the object is dragged of the page then\n                 * while its coordinate is not changing only the parent's size is reduced */\n                lv_coord_t act_par_w = lv_obj_get_width(lv_obj_get_parent(drag_obj));\n                lv_coord_t act_par_h = lv_obj_get_height(lv_obj_get_parent(drag_obj));\n                if(act_par_w == prev_par_w && act_par_h == prev_par_h) {\n                    uint16_t new_inv_buf_size = lv_refr_get_buf_size();\n                    lv_refr_pop_from_buf(new_inv_buf_size - inv_buf_size);\n                }\n            }\n        }\n    }\n}\n\n/**\n * Handle throwing by drag if the drag is ended\n * @param indev pointer to an input device state\n */\nstatic void indev_drag_throw(lv_indev_proc_t * state)\n{\n    if(state->drag_in_prog == 0) return;\n\n    /*Set new position if the vector is not zero*/\n    lv_obj_t * drag_obj = state->last_obj;\n\n    /*If drag parent is active check recursively the drag_parent attribute*/\n    while(lv_obj_get_drag_parent(drag_obj) != false &&\n            drag_obj != NULL) {\n        drag_obj = lv_obj_get_parent(drag_obj);\n    }\n\n    if(drag_obj == NULL) return;\n\n    /*Return if the drag throw is not enabled*/\n    if(lv_obj_get_drag_throw(drag_obj) == false) {\n        state->drag_in_prog = 0;\n        drag_obj->signal_func(drag_obj, LV_SIGNAL_DRAG_END, indev_act);\n        return;\n    }\n\n    /*Reduce the vectors*/\n    state->vect.x = state->vect.x * (100 - LV_INDEV_DRAG_THROW) / 100;\n    state->vect.y = state->vect.y * (100 - LV_INDEV_DRAG_THROW) / 100;\n\n    if(state->vect.x != 0 ||\n            state->vect.y != 0) {\n        /*Get the coordinates and modify them*/\n        lv_area_t coords_ori;\n        lv_obj_get_coords(drag_obj, &coords_ori);\n        lv_coord_t act_x = lv_obj_get_x(drag_obj) + state->vect.x;\n        lv_coord_t act_y = lv_obj_get_y(drag_obj) + state->vect.y;\n        lv_obj_set_pos(drag_obj, act_x, act_y);\n\n        lv_area_t coord_new;\n        lv_obj_get_coords(drag_obj, &coord_new);\n\n        /*If non of the coordinates are changed then do not continue throwing*/\n        if((coords_ori.x1 == coord_new.x1 || state->vect.x == 0) &&\n                (coords_ori.y1 == coord_new.y1 || state->vect.y == 0)) {\n            state->drag_in_prog = 0;\n            state->vect.x = 0;\n            state->vect.y = 0;\n            drag_obj->signal_func(drag_obj, LV_SIGNAL_DRAG_END, indev_act);\n\n        }\n    }\n    /*If the vectors become 0 -> drag_in_prog = 0 and send a drag end signal*/\n    else {\n        state->drag_in_prog = 0;\n        drag_obj->signal_func(drag_obj, LV_SIGNAL_DRAG_END, indev_act);\n    }\n}\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_core/lv_indev.h",
    "content": "/**\n * @file lv_indev_proc.h\n *\n */\n\n#ifndef LV_INDEV_H\n#define LV_INDEV_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_obj.h\"\n#include \"../lv_hal/lv_hal_indev.h\"\n#include \"../lv_core/lv_group.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Initialize the display input device subsystem\n */\nvoid lv_indev_init(void);\n\n/**\n * Get the currently processed input device. Can be used in action functions too.\n * @return pointer to the currently processed input device or NULL if no input device processing right now\n */\nlv_indev_t * lv_indev_get_act(void);\n\n\n/**\n * Get the type of an input device\n * @param indev pointer to an input device\n * @return the type of the input device from `lv_hal_indev_type_t` (`LV_INDEV_TYPE_...`)\n */\nlv_hal_indev_type_t lv_indev_get_type(const lv_indev_t * indev);\n\n/**\n * Reset one or all input devices\n * @param indev pointer to an input device to reset or NULL to reset all of them\n */\nvoid lv_indev_reset(lv_indev_t * indev);\n\n/**\n * Reset the long press state of an input device\n * @param indev_proc pointer to an input device\n */\nvoid lv_indev_reset_lpr(lv_indev_t * indev);\n\n/**\n * Enable input devices device by type\n * @param type Input device type\n * @param enable true: enable this type; false: disable this type\n */\nvoid lv_indev_enable(lv_hal_indev_type_t type, bool enable);\n\n/**\n * Set a cursor for a pointer input device (for LV_INPUT_TYPE_POINTER and LV_INPUT_TYPE_BUTTON)\n * @param indev pointer to an input device\n * @param cur_obj pointer to an object to be used as cursor\n */\nvoid lv_indev_set_cursor(lv_indev_t *indev, lv_obj_t *cur_obj);\n\n#if USE_LV_GROUP\n/**\n * Set a destination group for a keypad input device (for LV_INDEV_TYPE_KEYPAD)\n * @param indev pointer to an input device\n * @param group point to a group\n */\nvoid lv_indev_set_group(lv_indev_t *indev, lv_group_t *group);\n#endif\n\n/**\n * Set the an array of points for LV_INDEV_TYPE_BUTTON.\n * These points will be assigned to the buttons to press a specific point on the screen\n * @param indev pointer to an input device\n * @param group point to a group\n */\nvoid lv_indev_set_button_points(lv_indev_t *indev, const lv_point_t *points);\n\n/**\n * Set feedback callback for indev.\n * @param indev pointer to an input device\n * @param feedback feedback callback\n */\nvoid lv_indev_set_feedback(lv_indev_t *indev, lv_indev_feedback_t feedback);\n\n/**\n * Get the last point of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON)\n * @param indev pointer to an input device\n * @param point pointer to a point to store the result\n */\nvoid lv_indev_get_point(const lv_indev_t * indev, lv_point_t * point);\n\n/**\n * Get the last key of an input device (for LV_INDEV_TYPE_KEYPAD)\n * @param indev pointer to an input device\n * @return the last pressed key (0 on error)\n */\nuint32_t lv_indev_get_key(const lv_indev_t * indev);\n\n/**\n * Check if there is dragging with an input device or not (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON)\n * @param indev pointer to an input device\n * @return true: drag is in progress\n */\nbool lv_indev_is_dragging(const lv_indev_t * indev);\n\n/**\n * Get the vector of dragging of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON)\n * @param indev pointer to an input device\n * @param point pointer to a point to store the vector\n */\nvoid lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point);\n/**\n * Get elapsed time since last press\n * @param indev pointer to an input device (NULL to get the overall smallest inactivity)\n * @return Elapsed ticks (milliseconds) since last press\n */\nuint32_t lv_indev_get_inactive_time(const lv_indev_t * indev);\n\n/**\n * Get feedback callback for indev.\n * @param indev pointer to an input device\n * @return feedback callback\n */\nlv_indev_feedback_t lv_indev_get_feedback(const lv_indev_t *indev);\n\n/**\n * Do nothing until the next release\n * @param indev pointer to an input device\n */\nvoid lv_indev_wait_release(lv_indev_t * indev);\n\n/**********************\n *      MACROS\n **********************/\n\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_INDEV_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_core/lv_lang.c",
    "content": "/**\n * @file lv_lang.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_lang.h\"\n#if USE_LV_MULTI_LANG\n\n#include \"lv_obj.h\"\n#include \"../lv_misc/lv_gc.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic void lang_set_core(lv_obj_t * obj);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic uint8_t lang_act = 0;\nstatic const void * (*get_txt)(uint16_t);\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Change the language\n * @param lang_id the id of the\n */\nvoid lv_lang_set(uint8_t lang_id)\n{\n    lang_act = lang_id;\n\n    lv_obj_t * i;\n    LL_READ(LV_GC_ROOT(_lv_scr_ll), i) {\n        i->signal_func(i, LV_SIGNAL_LANG_CHG, NULL);\n\n        lang_set_core(i);\n    }\n\n    lang_set_core(lv_scr_act());\n}\n\n/**\n * Set a function to get the texts of the set languages from a `txt_id`\n * @param fp a function pointer to get the texts\n */\nvoid lv_lang_set_text_func(const void * (*fp)(uint16_t))\n{\n    get_txt = fp;\n}\n\n/**\n * Use the function set by `lv_lang_set_text_func` to get the `txt_id` text in the set language\n * @param txt_id an ID of the text to get\n * @return the `txt_id` txt on the set language\n */\nconst void * lv_lang_get_text(uint16_t txt_id)\n{\n    if(get_txt == NULL) {\n        LV_LOG_WARN(\"lv_lang_get_text: text_func is not specified\");\n        return NULL;                    /*No text_get function specified */\n    }\n    if(txt_id == LV_LANG_TXT_ID_NONE) {\n        LV_LOG_WARN(\"lv_lang_get_text: attempts to get invalid text ID\");\n        return NULL;      /*Invalid txt_id*/\n    }\n\n    return get_txt(txt_id);\n}\n\n\n/**\n * Return with ID of the currently selected language\n * @return pointer to the active screen object (loaded by 'lv_scr_load()')\n */\nuint8_t lv_lang_act(void)\n{\n    return lang_act;\n}\n\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Change the language of the children. (Called recursively)\n * @param obj pointer to an object\n */\nstatic void lang_set_core(lv_obj_t * obj)\n{\n    lv_obj_t * i;\n    LL_READ(obj->child_ll, i) {\n        i->signal_func(i, LV_SIGNAL_LANG_CHG, NULL);\n\n        lang_set_core(i);\n    }\n}\n\n#endif /*USE_LV_MULTI_LANG*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_core/lv_lang.h",
    "content": "/**\n * @file lv_lang.h\n *\n */\n\n#ifndef LV_LANG_H\n#define LV_LANG_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_MULTI_LANG\n\n#include <stdint.h>\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_LANG_TXT_ID_NONE     0xFFFF /*Used to not assign any text IDs for a multi-language object.*/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Change the language\n * @param lang_id the id of the\n */\nvoid lv_lang_set(uint8_t lang_id);\n\n/**\n * Set a function to get the texts of the set languages from a `txt_id`\n * @param fp a function pointer to get the texts\n */\nvoid lv_lang_set_text_func(const void * (*fp)(uint16_t));\n\n/**\n * Use the function set by `lv_lang_set_text_func` to get the `txt_id` text in the set language\n * @param txt_id an ID of the text to get\n * @return the `txt_id` txt on the set language\n */\nconst void * lv_lang_get_text(uint16_t txt_id);\n\n/**\n * Return with ID of the currently selected language\n * @return pointer to the active screen object (loaded by 'lv_scr_load()')\n */\nuint8_t lv_lang_act(void);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif /*USE_LV_MULTI_LANG*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_LANG_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_core/lv_obj.c",
    "content": "/**\n * @file lv_base_obj.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_obj.h\"\n#include \"lv_indev.h\"\n#include \"lv_refr.h\"\n#include \"lv_group.h\"\n#include \"../lv_themes/lv_theme.h\"\n#include \"../lv_draw/lv_draw.h\"\n#include \"../lv_draw/lv_draw_rbasic.h\"\n#include \"../lv_misc/lv_anim.h\"\n#include \"../lv_misc/lv_task.h\"\n#include \"../lv_misc/lv_fs.h\"\n#include \"../lv_misc/lv_ufs.h\"\n#include <stdint.h>\n#include <string.h>\n#include \"../lv_misc/lv_gc.h\"\n\n#if defined(LV_GC_INCLUDE)\n#   include LV_GC_INCLUDE\n#endif /* LV_ENABLE_GC */\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_OBJ_DEF_WIDTH  (LV_DPI)\n#define LV_OBJ_DEF_HEIGHT  (2 * LV_DPI / 3)\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic void refresh_children_position(lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_diff);\nstatic void report_style_mod_core(void * style_p, lv_obj_t * obj);\nstatic void refresh_children_style(lv_obj_t * obj);\nstatic void delete_children(lv_obj_t * obj);\nstatic bool lv_obj_design(lv_obj_t * obj, const  lv_area_t * mask_p, lv_design_mode_t mode);\nstatic lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\nstatic bool _lv_initialized = false;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Init. the 'lv' library.\n */\nvoid lv_init(void)\n{\n    /* Do nothing if already initialized */\n    if (_lv_initialized)\n         return;\n\n    LV_GC_ROOT(_lv_def_scr) = NULL;\n    LV_GC_ROOT(_lv_act_scr) = NULL;\n    LV_GC_ROOT(_lv_top_layer) = NULL;\n    LV_GC_ROOT(_lv_sys_layer) = NULL;\n    LV_GC_ROOT(_lv_disp_list) = NULL;\n    LV_GC_ROOT(_lv_indev_list) = NULL;\n\n    LV_LOG_TRACE(\"lv_init started\");\n\n    /*Initialize the lv_misc modules*/\n    lv_mem_init();\n    lv_task_init();\n\n#if USE_LV_FILESYSTEM\n    lv_fs_init();\n    lv_ufs_init();\n#endif\n\n    lv_font_init();\n#if USE_LV_ANIMATION\n    lv_anim_init();\n#endif\n\n    /*Init. the sstyles*/\n    lv_style_init();\n\n    /*Initialize the screen refresh system*/\n    lv_refr_init();\n\n    /*Create the default screen*/\n    lv_ll_init(&LV_GC_ROOT(_lv_scr_ll), sizeof(lv_obj_t));\n    LV_GC_ROOT(_lv_def_scr) = lv_obj_create(NULL, NULL);\n\n    LV_GC_ROOT(_lv_act_scr) = LV_GC_ROOT(_lv_def_scr);\n\n    LV_GC_ROOT(_lv_top_layer) = lv_obj_create(NULL, NULL);\n    lv_obj_set_style(LV_GC_ROOT(_lv_top_layer), &lv_style_transp_fit);\n\n    LV_GC_ROOT(_lv_sys_layer) = lv_obj_create(NULL, NULL);\n    lv_obj_set_style(LV_GC_ROOT(_lv_sys_layer), &lv_style_transp_fit);\n\n    /*Refresh the screen*/\n    lv_obj_invalidate(LV_GC_ROOT(_lv_act_scr));\n\n#if LV_INDEV_READ_PERIOD != 0\n    /*Init the input device handling*/\n    lv_indev_init();\n#endif\n\n    _lv_initialized = true;\n    LV_LOG_INFO(\"lv_init ready\");\n}\n\n/*--------------------\n * Create and delete\n *-------------------*/\n\n/**\n * Create a basic object\n * @param parent pointer to a parent object.\n *                  If NULL then a screen will be created\n * @param copy pointer to a base object, if not NULL then the new object will be copied from it\n * @return pointer to the new object\n */\nlv_obj_t * lv_obj_create(lv_obj_t * parent, const  lv_obj_t * copy)\n{\n\n    lv_obj_t * new_obj = NULL;\n    /*Create a screen if the parent is NULL*/\n    if(parent == NULL) {\n        LV_LOG_TRACE(\"Screen create started\");\n\n        new_obj = lv_ll_ins_head(&LV_GC_ROOT(_lv_scr_ll));\n        lv_mem_assert(new_obj);\n        if(new_obj == NULL) return NULL;\n\n        new_obj->par = NULL; /*Screens has no a parent*/\n        lv_ll_init(&(new_obj->child_ll), sizeof(lv_obj_t));\n\n        /*Set coordinates to full screen size*/\n        new_obj->coords.x1 = 0;\n        new_obj->coords.y1 = 0;\n        new_obj->coords.x2 = LV_HOR_RES - 1;\n        new_obj->coords.y2 = LV_VER_RES - 1;\n        new_obj->ext_size = 0;\n\n        /*Init realign*/\n#if LV_OBJ_REALIGN\n        new_obj->realign.align = LV_ALIGN_CENTER;\n        new_obj->realign.xofs = 0;\n        new_obj->realign.yofs = 0;\n        new_obj->realign.base = NULL;\n        new_obj->realign.auto_realign = 0;\n#endif\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            new_obj->style_p = th->bg;\n        } else {\n            new_obj->style_p = &lv_style_scr;\n        }\n        /*Set virtual functions*/\n        lv_obj_set_signal_func(new_obj, lv_obj_signal);\n        lv_obj_set_design_func(new_obj, lv_obj_design);\n\n        /*Set free data*/\n#ifdef LV_OBJ_FREE_NUM_TYPE\n        new_obj->free_num = 0;\n#endif\n\n#if LV_OBJ_FREE_PTR != 0\n        new_obj->free_ptr = NULL;\n#endif\n\n#if USE_LV_GROUP\n        new_obj->group_p = NULL;\n#endif\n        /*Set attributes*/\n        new_obj->click = 0;\n        new_obj->drag = 0;\n        new_obj->drag_throw = 0;\n        new_obj->drag_parent = 0;\n        new_obj->hidden = 0;\n        new_obj->top = 0;\n        new_obj->opa_scale_en = 0;\n        new_obj->protect = LV_PROTECT_NONE;\n        new_obj->opa_scale = LV_OPA_COVER;\n\n        new_obj->ext_attr = NULL;\n\n        LV_LOG_INFO(\"Screen create ready\");\n    }\n    /*parent != NULL create normal obj. on a parent*/\n    else {\n        LV_LOG_TRACE(\"Object create started\");\n\n        new_obj = lv_ll_ins_head(&(parent)->child_ll);\n        lv_mem_assert(new_obj);\n        if(new_obj == NULL) return NULL;\n\n\n        new_obj->par = parent; /*Set the parent*/\n        lv_ll_init(&(new_obj->child_ll), sizeof(lv_obj_t));\n\n        /*Set coordinates left top corner of parent*/\n        new_obj->coords.x1 = parent->coords.x1;\n        new_obj->coords.y1 = parent->coords.y1;\n        new_obj->coords.x2 = parent->coords.x1 +\n                             LV_OBJ_DEF_WIDTH;\n        new_obj->coords.y2 = parent->coords.y1 +\n                             LV_OBJ_DEF_HEIGHT;\n        new_obj->ext_size = 0;\n\n        /*Init realign*/\n#if LV_OBJ_REALIGN\n        new_obj->realign.align = LV_ALIGN_CENTER;\n        new_obj->realign.xofs = 0;\n        new_obj->realign.yofs = 0;\n        new_obj->realign.base = NULL;\n        new_obj->realign.auto_realign = 0;\n#endif\n        /*Set appearance*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            new_obj->style_p = th->panel;\n        } else {\n            new_obj->style_p = &lv_style_plain_color;\n        }\n\n        /*Set virtual functions*/\n        lv_obj_set_signal_func(new_obj, lv_obj_signal);\n        lv_obj_set_design_func(new_obj, lv_obj_design);\n\n        /*Set free data*/\n#ifdef LV_OBJ_FREE_NUM_TYPE\n        new_obj->free_num = 0;\n#endif\n#if LV_OBJ_FREE_PTR != 0\n        new_obj->free_ptr = NULL;\n#endif\n#if USE_LV_GROUP\n        new_obj->group_p = NULL;\n#endif\n\n        /*Set attributes*/\n        new_obj->click = 1;\n        new_obj->drag = 0;\n        new_obj->drag_throw = 0;\n        new_obj->drag_parent = 0;\n        new_obj->hidden = 0;\n        new_obj->top = 0;\n        new_obj->protect = LV_PROTECT_NONE;\n        new_obj->opa_scale = LV_OPA_COVER;\n        new_obj->opa_scale_en = 0;\n\n        new_obj->ext_attr = NULL;\n    }\n\n    if(copy != NULL) {\n        lv_area_copy(&new_obj->coords, &copy->coords);\n        new_obj->ext_size = copy->ext_size;\n\n        /*Set free data*/\n#ifdef LV_OBJ_FREE_NUM_TYPE\n        new_obj->free_num = copy->free_num;\n#endif\n#if LV_OBJ_FREE_PTR != 0\n        new_obj->free_ptr = copy->free_ptr;\n#endif\n\n        /*Copy realign*/\n#if LV_OBJ_REALIGN\n        new_obj->realign.align = copy->realign.align;\n        new_obj->realign.xofs = copy->realign.xofs;\n        new_obj->realign.yofs = copy->realign.yofs;\n        new_obj->realign.base = copy->realign.base;\n        new_obj->realign.auto_realign = copy->realign.auto_realign;\n#endif\n\n        /*Set attributes*/\n        new_obj->click = copy->click;\n        new_obj->drag = copy->drag;\n        new_obj->drag_throw = copy->drag_throw;\n        new_obj->drag_parent = copy->drag_parent;\n        new_obj->hidden = copy->hidden;\n        new_obj->top = copy->top;\n\n        new_obj->opa_scale_en = copy->opa_scale_en;\n        new_obj->protect = copy->protect;\n        new_obj->opa_scale = copy->opa_scale;\n\n        new_obj->style_p = copy->style_p;\n\n#if USE_LV_GROUP\n        /*Add to the same group*/\n        if(copy->group_p != NULL) {\n            lv_group_add_obj(copy->group_p, new_obj);\n        }\n#endif\n\n        /*Set the same coordinates for non screen objects*/\n        if(lv_obj_get_parent(copy) != NULL && parent != NULL) {\n            lv_obj_set_pos(new_obj, lv_obj_get_x(copy), lv_obj_get_y(copy));\n        } else {\n            lv_obj_set_pos(new_obj, 0, 0);\n        }\n\n        LV_LOG_INFO(\"Object create ready\");\n    }\n\n\n    /*Send a signal to the parent to notify it about the new child*/\n    if(parent != NULL) {\n        parent->signal_func(parent, LV_SIGNAL_CHILD_CHG, new_obj);\n\n        /*Invalidate the area if not screen created*/\n        lv_obj_invalidate(new_obj);\n    }\n\n    return new_obj;\n}\n\n/**\n * Delete 'obj' and all of its children\n * @param obj pointer to an object to delete\n * @return LV_RES_INV because the object is deleted\n */\nlv_res_t lv_obj_del(lv_obj_t * obj)\n{\n    lv_obj_invalidate(obj);\n\n    /*Delete from the group*/\n#if USE_LV_GROUP\n    if(obj->group_p != NULL) lv_group_remove_obj(obj);\n#endif\n\n    /*Remove the animations from this object*/\n#if USE_LV_ANIMATION\n    lv_anim_del(obj, NULL);\n#endif\n\n    /*Recursively delete the children*/\n    lv_obj_t * i;\n    lv_obj_t * i_next;\n    i = lv_ll_get_head(&(obj->child_ll));\n    while(i != NULL) {\n        /*Get the next object before delete this*/\n        i_next = lv_ll_get_next(&(obj->child_ll), i);\n\n        /*Call the recursive del to the child too*/\n        delete_children(i);\n\n        /*Set i to the next node*/\n        i = i_next;\n    }\n\n    /*Remove the object from parent's children list*/\n    lv_obj_t * par = lv_obj_get_parent(obj);\n    if(par == NULL) { /*It is a screen*/\n        lv_ll_rem(&LV_GC_ROOT(_lv_scr_ll), obj);\n    } else {\n        lv_ll_rem(&(par->child_ll), obj);\n    }\n\n    /* Reset all input devices if\n     * the currently pressed object is deleted*/\n    lv_indev_t * indev = lv_indev_next(NULL);\n    while(indev) {\n        if(indev->proc.act_obj == obj || indev->proc.last_obj == obj) {\n            lv_indev_reset(indev);\n        }\n        indev = lv_indev_next(indev);\n    }\n\n    /* All children deleted.\n     * Now clean up the object specific data*/\n    obj->signal_func(obj, LV_SIGNAL_CLEANUP, NULL);\n\n    /*Delete the base objects*/\n    if(obj->ext_attr != NULL)  lv_mem_free(obj->ext_attr);\n    lv_mem_free(obj); /*Free the object itself*/\n\n    /*Send a signal to the parent to notify it about the child delete*/\n    if(par != NULL) {\n        par->signal_func(par, LV_SIGNAL_CHILD_CHG, NULL);\n    }\n\n    return LV_RES_INV;\n}\n\n/**\n * Delete all children of an object\n * @param obj pointer to an object\n */\nvoid lv_obj_clean(lv_obj_t * obj)\n{\n    lv_obj_t * child = lv_obj_get_child(obj, NULL);\n    lv_obj_t * child_next;\n    while(child) {\n        /* Read the next child before deleting the current\n         * because the next couldn't be read from a deleted (invalid) node*/\n        child_next = lv_obj_get_child(obj, child);\n        lv_obj_del(child);\n        child = child_next;\n    }\n}\n\n/**\n * Mark the object as invalid therefore its current position will be redrawn by 'lv_refr_task'\n * @param obj pointer to an object\n */\nvoid lv_obj_invalidate(const lv_obj_t * obj)\n{\n    if(lv_obj_get_hidden(obj)) return;\n\n    /*Invalidate the object only if it belongs to the 'LV_GC_ROOT(_lv_act_scr)'*/\n    lv_obj_t * obj_scr = lv_obj_get_screen(obj);\n    if(obj_scr == lv_scr_act() ||\n            obj_scr == lv_layer_top() ||\n            obj_scr == lv_layer_sys()) {\n        /*Truncate recursively to the parents*/\n        lv_area_t area_trunc;\n        lv_obj_t * par = lv_obj_get_parent(obj);\n        bool union_ok = true;\n        /*Start with the original coordinates*/\n        lv_coord_t ext_size = obj->ext_size;\n        lv_area_copy(&area_trunc, &obj->coords);\n        area_trunc.x1 -= ext_size;\n        area_trunc.y1 -= ext_size;\n        area_trunc.x2 += ext_size;\n        area_trunc.y2 += ext_size;\n\n        /*Check through all parents*/\n        while(par != NULL) {\n            union_ok = lv_area_intersect(&area_trunc, &area_trunc, &par->coords);\n            if(union_ok == false) break;        /*If no common parts with parent break;*/\n            if(lv_obj_get_hidden(par)) return;  /*If the parent is hidden then the child is hidden and won't be drawn*/\n\n            par = lv_obj_get_parent(par);\n        }\n\n        if(union_ok != false) lv_inv_area(&area_trunc);\n    }\n}\n\n\n/*=====================\n * Setter functions\n *====================*/\n\n/*--------------\n * Screen set\n *--------------*/\n\n/**\n * Load a new screen\n * @param scr pointer to a screen\n */\nvoid lv_scr_load(lv_obj_t * scr)\n{\n    LV_GC_ROOT(_lv_act_scr) = scr;\n\n    lv_obj_invalidate(LV_GC_ROOT(_lv_act_scr));\n}\n\n/*--------------------\n * Parent/children set\n *--------------------*/\n\n/**\n * Set a new parent for an object. Its relative position will be the same.\n * @param obj pointer to an object. Can't be a screen.\n * @param parent pointer to the new parent object. (Can't be NULL)\n */\nvoid lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent)\n{\n    if(obj->par == NULL) {\n        LV_LOG_WARN(\"Can't set the parent of a screen\");\n        return;\n    }\n\n    if(parent == NULL) {\n        LV_LOG_WARN(\"Can't set parent == NULL to an object\");\n        return;\n    }\n\n\n    lv_obj_invalidate(obj);\n\n    lv_point_t old_pos;\n    old_pos.x = lv_obj_get_x(obj);\n    old_pos.y = lv_obj_get_y(obj);\n\n    lv_obj_t * old_par = obj->par;\n\n    lv_ll_chg_list(&obj->par->child_ll, &parent->child_ll, obj);\n    obj->par = parent;\n    lv_obj_set_pos(obj, old_pos.x, old_pos.y);\n\n    /*Notify the original parent because one of its children is lost*/\n    old_par->signal_func(old_par, LV_SIGNAL_CHILD_CHG, NULL);\n\n    /*Notify the new parent about the child*/\n    parent->signal_func(parent, LV_SIGNAL_CHILD_CHG, obj);\n\n    lv_obj_invalidate(obj);\n}\n\n/*--------------------\n * Coordinate set\n * ------------------*/\n\n/**\n * Set relative the position of an object (relative to the parent)\n * @param obj pointer to an object\n * @param x new distance from the left side of the parent\n * @param y new distance from the top of the parent\n */\nvoid lv_obj_set_pos(lv_obj_t * obj, lv_coord_t x, lv_coord_t y)\n{\n    /*Convert x and y to absolute coordinates*/\n    lv_obj_t * par = obj->par;\n    x = x + par->coords.x1;\n    y = y + par->coords.y1;\n\n    /*Calculate and set the movement*/\n    lv_point_t diff;\n    diff.x =  x - obj->coords.x1;\n    diff.y =  y - obj->coords.y1;\n\n    /* Do nothing if the position is not changed */\n    /* It is very important else recursive positioning can\n     * occur without position change*/\n    if(diff.x == 0 && diff.y == 0) return;\n\n    /*Invalidate the original area*/\n    lv_obj_invalidate(obj);\n\n    /*Save the original coordinates*/\n    lv_area_t ori;\n    lv_obj_get_coords(obj, &ori);\n\n    obj->coords.x1 += diff.x;\n    obj->coords.y1 += diff.y;\n    obj->coords.x2 += diff.x;\n    obj->coords.y2 += diff.y;\n\n    refresh_children_position(obj, diff.x, diff.y);\n\n    /*Inform the object about its new coordinates*/\n    obj->signal_func(obj, LV_SIGNAL_CORD_CHG, &ori);\n\n    /*Send a signal to the parent too*/\n    par->signal_func(par, LV_SIGNAL_CHILD_CHG, obj);\n\n    /*Invalidate the new area*/\n    lv_obj_invalidate(obj);\n}\n\n\n/**\n * Set the x coordinate of a object\n * @param obj pointer to an object\n * @param x new distance from the left side from the parent\n */\nvoid lv_obj_set_x(lv_obj_t * obj, lv_coord_t x)\n{\n    lv_obj_set_pos(obj, x, lv_obj_get_y(obj));\n}\n\n\n/**\n * Set the y coordinate of a object\n * @param obj pointer to an object\n * @param y new distance from the top of the parent\n */\nvoid lv_obj_set_y(lv_obj_t * obj, lv_coord_t y)\n{\n    lv_obj_set_pos(obj, lv_obj_get_x(obj), y);\n}\n\n/**\n * Set the size of an object\n * @param obj pointer to an object\n * @param w new width\n * @param h new height\n */\nvoid lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h)\n{\n\n    /* Do nothing if the size is not changed */\n    /* It is very important else recursive resizing can\n     * occur without size change*/\n    if(lv_obj_get_width(obj) == w && lv_obj_get_height(obj) == h) {\n        return;\n    }\n\n    /*Invalidate the original area*/\n    lv_obj_invalidate(obj);\n\n    /*Save the original coordinates*/\n    lv_area_t ori;\n    lv_obj_get_coords(obj, &ori);\n\n    //Set the length and height\n    obj->coords.x2 = obj->coords.x1 + w - 1;\n    obj->coords.y2 = obj->coords.y1 + h - 1;\n\n\n    /*Send a signal to the object with its new coordinates*/\n    obj->signal_func(obj, LV_SIGNAL_CORD_CHG, &ori);\n\n    /*Send a signal to the parent too*/\n    lv_obj_t * par = lv_obj_get_parent(obj);\n    if(par != NULL) par->signal_func(par, LV_SIGNAL_CHILD_CHG, obj);\n\n    /*Invalidate the new area*/\n    lv_obj_invalidate(obj);\n\n    /*Automatically realign the object if required*/\n#if LV_OBJ_REALIGN\n    if(obj->realign.auto_realign) lv_obj_realign(obj);\n#endif\n}\n\n/**\n * Set the width of an object\n * @param obj pointer to an object\n * @param w new width\n */\nvoid lv_obj_set_width(lv_obj_t * obj, lv_coord_t w)\n{\n    lv_obj_set_size(obj, w, lv_obj_get_height(obj));\n}\n\n/**\n * Set the height of an object\n * @param obj pointer to an object\n * @param h new height\n */\nvoid lv_obj_set_height(lv_obj_t * obj, lv_coord_t h)\n{\n    lv_obj_set_size(obj, lv_obj_get_width(obj), h);\n}\n\n/**\n * Align an object to an other object.\n * @param obj pointer to an object to align\n * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it.\n * @param align type of alignment (see 'lv_align_t' enum)\n * @param x_mod x coordinate shift after alignment\n * @param y_mod y coordinate shift after alignment\n */\nvoid lv_obj_align(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod)\n{\n    lv_coord_t new_x = lv_obj_get_x(obj);\n    lv_coord_t new_y = lv_obj_get_y(obj);\n\n    if(base == NULL) {\n        base = lv_obj_get_parent(obj);\n    }\n\n    switch(align) {\n        case LV_ALIGN_CENTER:\n            new_x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2;\n            new_y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2;\n            break;\n\n        case LV_ALIGN_IN_TOP_LEFT:\n            new_x = 0;\n            new_y = 0;\n            break;\n        case LV_ALIGN_IN_TOP_MID:\n            new_x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2;\n            new_y = 0;\n            break;\n\n        case LV_ALIGN_IN_TOP_RIGHT:\n            new_x = lv_obj_get_width(base) - lv_obj_get_width(obj);\n            new_y = 0;\n            break;\n\n        case LV_ALIGN_IN_BOTTOM_LEFT:\n            new_x = 0;\n            new_y = lv_obj_get_height(base) - lv_obj_get_height(obj);\n            break;\n        case LV_ALIGN_IN_BOTTOM_MID:\n            new_x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2;\n            new_y = lv_obj_get_height(base) - lv_obj_get_height(obj);\n            break;\n\n        case LV_ALIGN_IN_BOTTOM_RIGHT:\n            new_x = lv_obj_get_width(base) - lv_obj_get_width(obj);\n            new_y = lv_obj_get_height(base) - lv_obj_get_height(obj);\n            break;\n\n        case LV_ALIGN_IN_LEFT_MID:\n            new_x = 0;\n            new_y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2;\n            break;\n\n        case LV_ALIGN_IN_RIGHT_MID:\n            new_x = lv_obj_get_width(base) - lv_obj_get_width(obj);\n            new_y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2;\n            break;\n\n        case LV_ALIGN_OUT_TOP_LEFT:\n            new_x = 0;\n            new_y = -lv_obj_get_height(obj);\n            break;\n\n        case LV_ALIGN_OUT_TOP_MID:\n            new_x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2;\n            new_y = - lv_obj_get_height(obj);\n            break;\n\n        case LV_ALIGN_OUT_TOP_RIGHT:\n            new_x = lv_obj_get_width(base) - lv_obj_get_width(obj);\n            new_y = - lv_obj_get_height(obj);\n            break;\n\n        case LV_ALIGN_OUT_BOTTOM_LEFT:\n            new_x = 0;\n            new_y = lv_obj_get_height(base);\n            break;\n\n        case LV_ALIGN_OUT_BOTTOM_MID:\n            new_x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2;\n            new_y = lv_obj_get_height(base);\n            break;\n\n        case LV_ALIGN_OUT_BOTTOM_RIGHT:\n            new_x = lv_obj_get_width(base) - lv_obj_get_width(obj);\n            new_y = lv_obj_get_height(base);\n            break;\n\n        case LV_ALIGN_OUT_LEFT_TOP:\n            new_x = - lv_obj_get_width(obj);\n            new_y = 0;\n            break;\n\n        case LV_ALIGN_OUT_LEFT_MID:\n            new_x = - lv_obj_get_width(obj);\n            new_y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2;\n            break;\n\n        case LV_ALIGN_OUT_LEFT_BOTTOM:\n            new_x = - lv_obj_get_width(obj);\n            new_y = lv_obj_get_height(base) - lv_obj_get_height(obj);\n            break;\n\n        case LV_ALIGN_OUT_RIGHT_TOP:\n            new_x = lv_obj_get_width(base);\n            new_y = 0;\n            break;\n\n        case LV_ALIGN_OUT_RIGHT_MID:\n            new_x = lv_obj_get_width(base);\n            new_y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2;\n            break;\n\n        case LV_ALIGN_OUT_RIGHT_BOTTOM:\n            new_x = lv_obj_get_width(base);\n            new_y = lv_obj_get_height(base) - lv_obj_get_height(obj);\n            break;\n    }\n\n    /*Bring together the coordination system of base and obj*/\n    lv_obj_t * par = lv_obj_get_parent(obj);\n    lv_coord_t base_abs_x = base->coords.x1;\n    lv_coord_t base_abs_y = base->coords.y1;\n    lv_coord_t par_abs_x = par->coords.x1;\n    lv_coord_t par_abs_y = par->coords.y1;\n    new_x += x_mod + base_abs_x;\n    new_y += y_mod + base_abs_y;\n    new_x -= par_abs_x;\n    new_y -= par_abs_y;\n\n    lv_obj_set_pos(obj, new_x, new_y);\n\n#if LV_OBJ_REALIGN\n    /*Save the last align parameters to use them in `lv_obj_realign`*/\n    obj->realign.align = align;\n    obj->realign.xofs = x_mod;\n    obj->realign.yofs = y_mod;\n    obj->realign.base = base;\n    obj->realign.origo_align = 0;\n#endif\n}\n\n/**\n * Align an object to an other object.\n * @param obj pointer to an object to align\n * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it.\n * @param align type of alignment (see 'lv_align_t' enum)\n * @param x_mod x coordinate shift after alignment\n * @param y_mod y coordinate shift after alignment\n */\nvoid lv_obj_align_origo(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod)\n{\n    lv_coord_t new_x = lv_obj_get_x(obj);\n    lv_coord_t new_y = lv_obj_get_y(obj);\n\n    lv_coord_t obj_w_half =  lv_obj_get_width(obj) / 2;\n    lv_coord_t obj_h_half = lv_obj_get_height(obj) / 2;\n\n    if(base == NULL) {\n        base = lv_obj_get_parent(obj);\n    }\n\n    switch(align) {\n        case LV_ALIGN_CENTER:\n            new_x = lv_obj_get_width(base) / 2 - obj_w_half;\n            new_y = lv_obj_get_height(base) / 2 - obj_h_half;\n            break;\n\n        case LV_ALIGN_IN_TOP_LEFT:\n            new_x = -obj_w_half;\n            new_y = -obj_h_half;\n            break;\n        case LV_ALIGN_IN_TOP_MID:\n            new_x = lv_obj_get_width(base) / 2 - obj_w_half;\n            new_y = -obj_h_half;\n            break;\n\n        case LV_ALIGN_IN_TOP_RIGHT:\n            new_x = lv_obj_get_width(base) - obj_w_half;\n            new_y = -obj_h_half;\n            break;\n\n        case LV_ALIGN_IN_BOTTOM_LEFT:\n            new_x = -obj_w_half;\n            new_y = lv_obj_get_height(base) - obj_h_half;\n            break;\n        case LV_ALIGN_IN_BOTTOM_MID:\n            new_x = lv_obj_get_width(base) / 2 - obj_w_half;\n            new_y = lv_obj_get_height(base) - obj_h_half;\n            break;\n\n        case LV_ALIGN_IN_BOTTOM_RIGHT:\n            new_x = lv_obj_get_width(base) - obj_w_half;\n            new_y = lv_obj_get_height(base) - obj_h_half;\n            break;\n\n        case LV_ALIGN_IN_LEFT_MID:\n            new_x = -obj_w_half;\n            new_y = lv_obj_get_height(base) / 2 - obj_h_half;\n            break;\n\n        case LV_ALIGN_IN_RIGHT_MID:\n            new_x = lv_obj_get_width(base) - obj_w_half;\n            new_y = lv_obj_get_height(base) / 2 - obj_h_half;\n            break;\n\n        case LV_ALIGN_OUT_TOP_LEFT:\n            new_x = -obj_w_half;\n            new_y = -obj_h_half;\n            break;\n\n        case LV_ALIGN_OUT_TOP_MID:\n            new_x = lv_obj_get_width(base) / 2 - obj_w_half;\n            new_y = -obj_h_half;\n            break;\n\n        case LV_ALIGN_OUT_TOP_RIGHT:\n            new_x = lv_obj_get_width(base) - obj_w_half;\n            new_y = - obj_h_half;\n            break;\n\n        case LV_ALIGN_OUT_BOTTOM_LEFT:\n            new_x = -obj_w_half;\n            new_y = lv_obj_get_height(base) - obj_h_half;\n            break;\n\n        case LV_ALIGN_OUT_BOTTOM_MID:\n            new_x = lv_obj_get_width(base) / 2 - obj_w_half;\n            new_y = lv_obj_get_height(base) - obj_h_half;\n            break;\n\n        case LV_ALIGN_OUT_BOTTOM_RIGHT:\n            new_x = lv_obj_get_width(base) - obj_w_half;\n            new_y = lv_obj_get_height(base) - obj_h_half;\n            break;\n\n        case LV_ALIGN_OUT_LEFT_TOP:\n            new_x = - obj_w_half ;\n            new_y = - obj_h_half;\n            break;\n\n        case LV_ALIGN_OUT_LEFT_MID:\n            new_x = - obj_w_half;\n            new_y = lv_obj_get_height(base) / 2 - obj_h_half;\n            break;\n\n        case LV_ALIGN_OUT_LEFT_BOTTOM:\n            new_x = - obj_w_half;\n            new_y = lv_obj_get_height(base) - obj_h_half;\n            break;\n\n        case LV_ALIGN_OUT_RIGHT_TOP:\n            new_x = lv_obj_get_width(base) - obj_w_half;\n            new_y = -obj_h_half;\n            break;\n\n        case LV_ALIGN_OUT_RIGHT_MID:\n            new_x = lv_obj_get_width(base) - obj_w_half;\n            new_y = lv_obj_get_height(base) / 2 - obj_h_half;\n            break;\n\n        case LV_ALIGN_OUT_RIGHT_BOTTOM:\n            new_x = lv_obj_get_width(base) - obj_w_half;\n            new_y = lv_obj_get_height(base) - obj_h_half;\n            break;\n    }\n\n    /*Bring together the coordination system of base and obj*/\n    lv_obj_t * par = lv_obj_get_parent(obj);\n    lv_coord_t base_abs_x = base->coords.x1;\n    lv_coord_t base_abs_y = base->coords.y1;\n    lv_coord_t par_abs_x = par->coords.x1;\n    lv_coord_t par_abs_y = par->coords.y1;\n    new_x += x_mod + base_abs_x;\n    new_y += y_mod + base_abs_y;\n    new_x -= par_abs_x;\n    new_y -= par_abs_y;\n\n    lv_obj_set_pos(obj, new_x, new_y);\n\n#if LV_OBJ_REALIGN\n    /*Save the last align parameters to use them in `lv_obj_realign`*/\n    obj->realign.align = align;\n    obj->realign.xofs = x_mod;\n    obj->realign.yofs = y_mod;\n    obj->realign.base = base;\n    obj->realign.origo_align = 1;\n#endif\n}\n\n/**\n * Realign the object based on the last `lv_obj_align` parameters.\n * @param obj pointer to an object\n */\nvoid lv_obj_realign(lv_obj_t * obj)\n{\n#if LV_OBJ_REALIGN\n    if(obj->realign.origo_align) lv_obj_align_origo(obj, obj->realign.base, obj->realign.align, obj->realign.xofs, obj->realign.yofs);\n    else lv_obj_align(obj, obj->realign.base, obj->realign.align, obj->realign.xofs, obj->realign.yofs);\n#else\n    (void) obj;\n    LV_LOG_WARN(\"lv_obj_realaign: no effect because LV_OBJ_REALIGN = 0\");\n#endif\n}\n\n/**\n * Enable the automatic realign of the object when its size has changed based on the last `lv_obj_align` parameters.\n * @param obj pointer to an object\n * @param en true: enable auto realign; false: disable auto realign\n */\nvoid lv_obj_set_auto_realign(lv_obj_t * obj, bool en)\n{\n#if LV_OBJ_REALIGN\n    obj->realign.auto_realign = en ? 1 : 0;\n#else\n    (void) obj;\n    (void) en;\n    LV_LOG_WARN(\"lv_obj_set_auto_realign: no effect because LV_OBJ_REALIGN = 0\");\n#endif\n}\n\n/*---------------------\n * Appearance set\n *--------------------*/\n\n/**\n * Set a new style for an object\n * @param obj pointer to an object\n * @param style_p pointer to the new style\n */\nvoid lv_obj_set_style(lv_obj_t * obj, lv_style_t * style)\n{\n    obj->style_p = style;\n\n    /*Send a signal about style change to every children with NULL style*/\n    refresh_children_style(obj);\n\n    /*Notify the object about the style change too*/\n    lv_obj_refresh_style(obj);\n}\n\n/**\n * Notify an object about its style is modified\n * @param obj pointer to an object\n */\nvoid lv_obj_refresh_style(lv_obj_t * obj)\n{\n    lv_obj_invalidate(obj);\n    obj->signal_func(obj, LV_SIGNAL_STYLE_CHG, NULL);\n    lv_obj_invalidate(obj);\n\n}\n\n/**\n * Notify all object if a style is modified\n * @param style pointer to a style. Only the objects with this style will be notified\n *               (NULL to notify all objects)\n */\nvoid lv_obj_report_style_mod(lv_style_t * style)\n{\n    lv_obj_t * i;\n    LL_READ(LV_GC_ROOT(_lv_scr_ll), i) {\n        if(i->style_p == style || style == NULL) {\n            lv_obj_refresh_style(i);\n        }\n\n        report_style_mod_core(style, i);\n    }\n}\n\n/*-----------------\n * Attribute set\n *----------------*/\n\n/**\n * Hide an object. It won't be visible and clickable.\n * @param obj pointer to an object\n * @param en true: hide the object\n */\nvoid lv_obj_set_hidden(lv_obj_t * obj, bool en)\n{\n    if(!obj->hidden) lv_obj_invalidate(obj);    /*Invalidate when not hidden (hidden objects are ignored) */\n\n    obj->hidden = en == false ? 0 : 1;\n\n    if(!obj->hidden) lv_obj_invalidate(obj);    /*Invalidate when not hidden (hidden objects are ignored) */\n\n    lv_obj_t * par = lv_obj_get_parent(obj);\n    par->signal_func(par, LV_SIGNAL_CHILD_CHG, obj);\n\n}\n\n/**\n * Enable or disable the clicking of an object\n * @param obj pointer to an object\n * @param en true: make the object clickable\n */\nvoid lv_obj_set_click(lv_obj_t * obj, bool en)\n{\n    obj->click = (en == true ? 1 : 0);\n}\n\n/**\n * Enable to bring this object to the foreground if it\n * or any of its children is clicked\n * @param obj pointer to an object\n * @param en true: enable the auto top feature\n */\nvoid lv_obj_set_top(lv_obj_t * obj, bool en)\n{\n    obj->top = (en == true ? 1 : 0);\n}\n\n/**\n * Enable the dragging of an object\n * @param obj pointer to an object\n * @param en true: make the object dragable\n */\nvoid lv_obj_set_drag(lv_obj_t * obj, bool en)\n{\n    if(en == true) lv_obj_set_click(obj, true);     /*Drag is useless without enabled clicking*/\n    obj->drag = (en == true ? 1 : 0);\n}\n\n/**\n * Enable the throwing of an object after is is dragged\n * @param obj pointer to an object\n * @param en true: enable the drag throw\n */\nvoid lv_obj_set_drag_throw(lv_obj_t * obj, bool en)\n{\n    obj->drag_throw = (en == true ? 1 : 0);\n}\n\n/**\n * Enable to use parent for drag related operations.\n * If trying to drag the object the parent will be moved instead\n * @param obj pointer to an object\n * @param en true: enable the 'drag parent' for the object\n */\nvoid lv_obj_set_drag_parent(lv_obj_t * obj, bool en)\n{\n    obj->drag_parent = (en == true ? 1 : 0);\n}\n\n/**\n * Set the opa scale enable parameter (required to set opa_scale with `lv_obj_set_opa_scale()`)\n * @param obj pointer to an object\n * @param en true: opa scaling is enabled for this object and all children; false: no opa scaling\n */\nvoid lv_obj_set_opa_scale_enable(lv_obj_t * obj, bool en)\n{\n    obj->opa_scale_en =  en ? 1 : 0;\n}\n\n/**\n * Set the opa scale of an object\n * @param obj pointer to an object\n * @param opa_scale a factor to scale down opacity [0..255]\n */\nvoid lv_obj_set_opa_scale(lv_obj_t * obj, lv_opa_t opa_scale)\n{\n    obj->opa_scale = opa_scale;\n    lv_obj_invalidate(obj);\n}\n\n/**\n * Set a bit or bits in the protect filed\n * @param obj pointer to an object\n * @param prot 'OR'-ed values from `lv_protect_t`\n */\nvoid lv_obj_set_protect(lv_obj_t * obj, uint8_t prot)\n{\n    obj->protect |= prot;\n}\n\n/**\n * Clear a bit or bits in the protect filed\n * @param obj pointer to an object\n * @param prot 'OR'-ed values from `lv_protect_t`\n */\nvoid lv_obj_clear_protect(lv_obj_t * obj, uint8_t prot)\n{\n    prot = (~prot) & 0xFF;\n    obj->protect &= prot;\n}\n\n/**\n * Set the signal function of an object.\n * Always call the previous signal function in the new.\n * @param obj pointer to an object\n * @param fp the new signal function\n */\nvoid lv_obj_set_signal_func(lv_obj_t * obj, lv_signal_func_t fp)\n{\n    obj->signal_func = fp;\n}\n\n/**\n * Set a new design function for an object\n * @param obj pointer to an object\n * @param fp the new design function\n */\nvoid lv_obj_set_design_func(lv_obj_t * obj, lv_design_func_t fp)\n{\n    obj->design_func = fp;\n}\n\n/*----------------\n * Other set\n *--------------*/\n\n/**\n * Allocate a new ext. data for an object\n * @param obj pointer to an object\n * @param ext_size the size of the new ext. data\n * @return Normal pointer to the allocated ext\n */\nvoid * lv_obj_allocate_ext_attr(lv_obj_t * obj, uint16_t ext_size)\n{\n    obj->ext_attr = lv_mem_realloc(obj->ext_attr, ext_size);\n\n    return (void *)obj->ext_attr;\n}\n\n/**\n * Send a 'LV_SIGNAL_REFR_EXT_SIZE' signal to the object\n * @param obj pointer to an object\n */\nvoid lv_obj_refresh_ext_size(lv_obj_t * obj)\n{\n    obj->ext_size = 0;\n    obj->signal_func(obj, LV_SIGNAL_REFR_EXT_SIZE, NULL);\n\n    lv_obj_invalidate(obj);\n}\n\n#ifdef LV_OBJ_FREE_NUM_TYPE\n/**\n * Set an application specific number for an object.\n * It can help to identify objects in the application.\n * @param obj pointer to an object\n * @param free_num the new free number\n */\nvoid lv_obj_set_free_num(lv_obj_t * obj, LV_OBJ_FREE_NUM_TYPE free_num)\n{\n    obj->free_num = free_num;\n}\n#endif\n\n#if LV_OBJ_FREE_PTR != 0\n/**\n * Set an application specific  pointer for an object.\n * It can help to identify objects in the application.\n * @param obj pointer to an object\n * @param free_p the new free pinter\n */\nvoid lv_obj_set_free_ptr(lv_obj_t * obj, void * free_p)\n{\n    obj->free_ptr = free_p;\n}\n#endif\n\n#if USE_LV_ANIMATION\n/**\n * Animate an object\n * @param obj pointer to an object to animate\n * @param type type of animation from 'lv_anim_builtin_t'. 'OR' it with ANIM_IN or ANIM_OUT\n * @param time time of animation in milliseconds\n * @param delay delay before the animation in milliseconds\n * @param cb a function to call when the animation is ready\n */\nvoid lv_obj_animate(lv_obj_t * obj, lv_anim_builtin_t type, uint16_t time, uint16_t delay, void (*cb)(lv_obj_t *))\n{\n    lv_obj_t * par = lv_obj_get_parent(obj);\n\n    /*Get the direction*/\n    bool out = (type & LV_ANIM_DIR_MASK) == LV_ANIM_IN ? false : true;\n    type = type & (~LV_ANIM_DIR_MASK);\n\n    lv_anim_t a;\n    a.var = obj;\n    a.time = time;\n    a.act_time = (int32_t) - delay;\n    a.end_cb = (void(*)(void *))cb;\n    a.path = lv_anim_path_linear;\n    a.playback_pause = 0;\n    a.repeat_pause = 0;\n    a.playback = 0;\n    a.repeat = 0;\n\n    /*Init to ANIM_IN*/\n    switch(type) {\n        case LV_ANIM_FLOAT_LEFT:\n            a.fp = (void(*)(void *, int32_t))lv_obj_set_x;\n            a.start = -lv_obj_get_width(obj);\n            a.end = lv_obj_get_x(obj);\n            break;\n        case LV_ANIM_FLOAT_RIGHT:\n            a.fp = (void(*)(void *, int32_t))lv_obj_set_x;\n            a.start = lv_obj_get_width(par);\n            a.end = lv_obj_get_x(obj);\n            break;\n        case LV_ANIM_FLOAT_TOP:\n            a.fp = (void(*)(void *, int32_t))lv_obj_set_y;\n            a.start = -lv_obj_get_height(obj);\n            a.end = lv_obj_get_y(obj);\n            break;\n        case LV_ANIM_FLOAT_BOTTOM:\n            a.fp = (void(*)(void *, int32_t))lv_obj_set_y;\n            a.start = lv_obj_get_height(par);\n            a.end = lv_obj_get_y(obj);\n            break;\n        case LV_ANIM_GROW_H:\n            a.fp = (void(*)(void *, int32_t))lv_obj_set_width;\n            a.start = 0;\n            a.end = lv_obj_get_width(obj);\n            break;\n        case LV_ANIM_GROW_V:\n            a.fp = (void(*)(void *, int32_t))lv_obj_set_height;\n            a.start = 0;\n            a.end = lv_obj_get_height(obj);\n            break;\n        case LV_ANIM_NONE:\n            a.fp = NULL;\n            a.start = 0;\n            a.end = 0;\n            break;\n        default:\n            break;\n    }\n\n    /*Swap start and end in case of ANIM OUT*/\n    if(out != false) {\n        int32_t tmp = a.start;\n        a.start = a.end;\n        a.end = tmp;\n    }\n\n    lv_anim_create(&a);\n}\n\n#endif\n\n/*=======================\n * Getter functions\n *======================*/\n\n/*------------------\n * Screen get\n *-----------------*/\n\n/**\n * Return with a pointer to the active screen\n * @return pointer to the active screen object (loaded by 'lv_scr_load()')\n */\nlv_obj_t * lv_scr_act(void)\n{\n    return LV_GC_ROOT(_lv_act_scr);\n}\n\n/**\n * Return with the top layer. (Same on every screen and it is above the normal screen layer)\n * @return pointer to the top layer object  (transparent screen sized lv_obj)\n */\nlv_obj_t * lv_layer_top(void)\n{\n    return LV_GC_ROOT(_lv_top_layer);\n}\n\n/**\n * Return with the system layer. (Same on every screen and it is above the all other layers)\n * It is used for example by the cursor\n * @return pointer to the system layer object (transparent screen sized lv_obj)\n */\nlv_obj_t * lv_layer_sys(void)\n{\n    return LV_GC_ROOT(_lv_sys_layer);\n}\n\n/**\n * Return with the screen of an object\n * @param obj pointer to an object\n * @return pointer to a screen\n */\nlv_obj_t * lv_obj_get_screen(const lv_obj_t * obj)\n{\n    const lv_obj_t * par = obj;\n    const lv_obj_t * act_p;\n\n    do {\n        act_p = par;\n        par = lv_obj_get_parent(act_p);\n    } while(par != NULL);\n\n    return (lv_obj_t *)act_p;\n}\n\n/*---------------------\n * Parent/children get\n *--------------------*/\n\n/**\n * Returns with the parent of an object\n * @param obj pointer to an object\n * @return pointer to the parent of  'obj'\n */\nlv_obj_t * lv_obj_get_parent(const lv_obj_t * obj)\n{\n    return obj->par;\n}\n\n/**\n * Iterate through the children of an object (start from the \"youngest\")\n * @param obj pointer to an object\n * @param child NULL at first call to get the next children\n *                  and the previous return value later\n * @return the child after 'act_child' or NULL if no more child\n */\nlv_obj_t * lv_obj_get_child(const lv_obj_t * obj, const lv_obj_t * child)\n{\n    lv_obj_t * result = NULL;\n\n    if(child == NULL) {\n        result = lv_ll_get_head(&obj->child_ll);\n    } else {\n        result = lv_ll_get_next(&obj->child_ll, child);\n    }\n\n    return result;\n}\n\n/**\n * Iterate through the children of an object (start from the \"oldest\")\n * @param obj pointer to an object\n * @param child NULL at first call to get the next children\n *                  and the previous return value later\n * @return the child after 'act_child' or NULL if no more child\n */\nlv_obj_t * lv_obj_get_child_back(const lv_obj_t * obj, const lv_obj_t * child)\n{\n    lv_obj_t * result = NULL;\n\n    if(child == NULL) {\n        result = lv_ll_get_tail(&obj->child_ll);\n    } else {\n        result = lv_ll_get_prev(&obj->child_ll, child);\n    }\n\n    return result;\n}\n\n/**\n * Count the children of an object (only children directly on 'obj')\n * @param obj pointer to an object\n * @return children number of 'obj'\n */\nuint16_t lv_obj_count_children(const lv_obj_t * obj)\n{\n    lv_obj_t * i;\n    uint16_t cnt = 0;\n\n    LL_READ(obj->child_ll, i) cnt++;\n\n    return cnt;\n}\n\n/*---------------------\n * Coordinate get\n *--------------------*/\n\n/**\n * Copy the coordinates of an object to an area\n * @param obj pointer to an object\n * @param cords_p pointer to an area to store the coordinates\n */\nvoid lv_obj_get_coords(const lv_obj_t * obj, lv_area_t * cords_p)\n{\n    lv_area_copy(cords_p, &obj->coords);\n}\n\n\n/**\n * Get the x coordinate of object\n * @param obj pointer to an object\n * @return distance of 'obj' from the left side of its parent\n */\nlv_coord_t lv_obj_get_x(const lv_obj_t * obj)\n{\n    lv_coord_t rel_x;\n    lv_obj_t * parent = lv_obj_get_parent(obj);\n    rel_x = obj->coords.x1 - parent->coords.x1;\n\n    return rel_x;\n}\n\n/**\n * Get the y coordinate of object\n * @param obj pointer to an object\n * @return distance of 'obj' from the top of its parent\n */\nlv_coord_t lv_obj_get_y(const lv_obj_t * obj)\n{\n    lv_coord_t rel_y;\n    lv_obj_t * parent = lv_obj_get_parent(obj);\n    rel_y = obj->coords.y1 - parent->coords.y1;\n\n    return rel_y;\n}\n\n/**\n * Get the width of an object\n * @param obj pointer to an object\n * @return the width\n */\nlv_coord_t lv_obj_get_width(const lv_obj_t * obj)\n{\n    return lv_area_get_width(&obj->coords);\n}\n\n/**\n * Get the height of an object\n * @param obj pointer to an object\n * @return the height\n */\nlv_coord_t lv_obj_get_height(const lv_obj_t * obj)\n{\n    return lv_area_get_height(&obj->coords);\n}\n\n/**\n * Get the extended size attribute of an object\n * @param obj pointer to an object\n * @return the extended size attribute\n */\nlv_coord_t lv_obj_get_ext_size(const lv_obj_t * obj)\n{\n    return obj->ext_size;\n}\n\n/**\n * Get the automatic realign property of the object.\n * @param obj pointer to an object\n * @return  true: auto realign is enabled; false: auto realign is disabled\n */\nbool lv_obj_get_auto_realign(lv_obj_t * obj)\n{\n#if LV_OBJ_REALIGN\n    return obj->realign.auto_realign ? true : false;\n#else\n    (void) obj;\n    return false;\n#endif\n}\n\n/*-----------------\n * Appearance get\n *---------------*/\n\n/**\n * Get the style pointer of an object (if NULL get style of the parent)\n * @param obj pointer to an object\n * @return pointer to a style\n */\nlv_style_t * lv_obj_get_style(const lv_obj_t * obj)\n{\n    lv_style_t * style_act = obj->style_p;\n    if(style_act == NULL) {\n        lv_obj_t * par = obj->par;\n\n        while(par) {\n            if(par->style_p) {\n                if(par->style_p->glass == 0) {\n#if USE_LV_GROUP == 0\n                    style_act = par->style_p;\n#else\n                    /*Is a parent is focused then use then focused style*/\n                    lv_group_t * g = lv_obj_get_group(par);\n                    if(lv_group_get_focused(g) == par) {\n                        style_act = lv_group_mod_style(g, par->style_p);\n                    } else {\n                        style_act = par->style_p;\n                    }\n#endif\n                    break;\n                }\n            }\n            par = par->par;\n        }\n    }\n#if USE_LV_GROUP\n    if(obj->group_p) {\n        if(lv_group_get_focused(obj->group_p) == obj) {\n            style_act = lv_group_mod_style(obj->group_p, style_act);\n        }\n    }\n#endif\n\n    if(style_act == NULL) style_act = &lv_style_plain;\n\n    return style_act;\n}\n\n/*-----------------\n * Attribute get\n *----------------*/\n\n/**\n * Get the hidden attribute of an object\n * @param obj pointer to an object\n * @return true: the object is hidden\n */\nbool lv_obj_get_hidden(const lv_obj_t * obj)\n{\n    return obj->hidden == 0 ? false : true;\n}\n\n/**\n * Get the click enable attribute of an object\n * @param obj pointer to an object\n * @return true: the object is clickable\n */\nbool lv_obj_get_click(const lv_obj_t * obj)\n{\n    return obj->click == 0 ? false : true;\n}\n\n/**\n * Get the top enable attribute of an object\n * @param obj pointer to an object\n * @return true: the auto top feture is enabled\n */\nbool lv_obj_get_top(const lv_obj_t * obj)\n{\n    return obj->top == 0 ? false : true;\n}\n\n/**\n * Get the drag enable attribute of an object\n * @param obj pointer to an object\n * @return true: the object is dragable\n */\nbool lv_obj_get_drag(const lv_obj_t * obj)\n{\n    return obj->drag == 0 ? false : true;\n}\n\n/**\n * Get the drag throw enable attribute of an object\n * @param obj pointer to an object\n * @return true: drag throw is enabled\n */\nbool lv_obj_get_drag_throw(const lv_obj_t * obj)\n{\n    return obj->drag_throw == 0 ? false : true;\n}\n\n/**\n * Get the drag parent attribute of an object\n * @param obj pointer to an object\n * @return true: drag parent is enabled\n */\nbool lv_obj_get_drag_parent(const lv_obj_t * obj)\n{\n    return obj->drag_parent == 0 ? false : true;\n}\n\n/**\n * Get the opa scale enable parameter\n * @param obj pointer to an object\n * @return true: opa scaling is enabled for this object and all children; false: no opa scaling\n */\nlv_opa_t lv_obj_get_opa_scale_enable(const lv_obj_t * obj)\n{\n    return obj->opa_scale_en == 0 ? false : true;\n}\n\n/**\n * Get the opa scale parameter of an object\n * @param obj pointer to an object\n * @return opa scale [0..255]\n */\nlv_opa_t lv_obj_get_opa_scale(const lv_obj_t * obj)\n{\n    const lv_obj_t * parent = obj;\n\n    while(parent) {\n        if(parent->opa_scale_en) return parent->opa_scale;\n        parent = lv_obj_get_parent(parent);\n    }\n\n    return LV_OPA_COVER;\n}\n\n/**\n * Get the protect field of an object\n * @param obj pointer to an object\n * @return protect field ('OR'ed values of `lv_protect_t`)\n */\nuint8_t lv_obj_get_protect(const lv_obj_t * obj)\n{\n    return obj->protect ;\n}\n\n/**\n * Check at least one bit of a given protect bitfield is set\n * @param obj pointer to an object\n * @param prot protect bits to test ('OR'ed values of `lv_protect_t`)\n * @return false: none of the given bits are set, true: at least one bit is set\n */\nbool lv_obj_is_protected(const lv_obj_t * obj, uint8_t prot)\n{\n    return (obj->protect & prot) == 0 ? false : true ;\n}\n\n/**\n * Get the signal function of an object\n * @param obj pointer to an object\n * @return the signal function\n */\nlv_signal_func_t lv_obj_get_signal_func(const lv_obj_t * obj)\n{\n    return obj->signal_func;\n}\n\n/**\n * Get the design function of an object\n * @param obj pointer to an object\n * @return the design function\n */\nlv_design_func_t lv_obj_get_design_func(const lv_obj_t * obj)\n{\n    return obj->design_func;\n}\n\n/*------------------\n * Other get\n *-----------------*/\n\n/**\n * Get the ext pointer\n * @param obj pointer to an object\n * @return the ext pointer but not the dynamic version\n *         Use it as ext->data1, and NOT da(ext)->data1\n */\nvoid * lv_obj_get_ext_attr(const lv_obj_t * obj)\n{\n    return obj->ext_attr;\n}\n\n/**\n * Get object's and its ancestors type. Put their name in `type_buf` starting with the current type.\n * E.g. buf.type[0]=\"lv_btn\", buf.type[1]=\"lv_cont\", buf.type[2]=\"lv_obj\"\n * @param obj pointer to an object which type should be get\n * @param buf pointer to an `lv_obj_type_t` buffer to store the types\n */\nvoid lv_obj_get_type(lv_obj_t * obj, lv_obj_type_t * buf)\n{\n    lv_obj_type_t tmp;\n\n    memset(buf, 0, sizeof(lv_obj_type_t));\n    memset(&tmp, 0, sizeof(lv_obj_type_t));\n\n    obj->signal_func(obj, LV_SIGNAL_GET_TYPE, &tmp);\n\n    uint8_t cnt;\n    for(cnt = 0; cnt < LV_MAX_ANCESTOR_NUM; cnt++) {\n        if(tmp.type[cnt] == NULL) break;\n    }\n\n\n    /*Swap the order. The real type comes first*/\n    uint8_t i;\n    for(i = 0; i < cnt; i++) {\n        buf->type[i] = tmp.type[cnt - 1 - i];\n    }\n}\n\n#ifdef LV_OBJ_FREE_NUM_TYPE\n/**\n * Get the free number\n * @param obj pointer to an object\n * @return the free number\n */\nLV_OBJ_FREE_NUM_TYPE lv_obj_get_free_num(const lv_obj_t * obj)\n{\n    return obj->free_num;\n}\n#endif\n\n#if LV_OBJ_FREE_PTR != 0\n/**\n * Get the free pointer\n * @param obj pointer to an object\n * @return the free pointer\n */\nvoid * lv_obj_get_free_ptr(const lv_obj_t * obj)\n{\n    return obj->free_ptr;\n}\n#endif\n\n\n#if USE_LV_GROUP\n/**\n * Get the group of the object\n * @param obj pointer to an object\n * @return the pointer to group of the object\n */\nvoid * lv_obj_get_group(const lv_obj_t * obj)\n{\n    return obj->group_p;\n}\n\n/**\n * Tell whether the ohe object is the focused object of a group or not.\n * @param obj pointer to an object\n * @return true: the object is focused, false: the object is not focused or not in a group\n */\nbool lv_obj_is_focused(const lv_obj_t * obj)\n{\n    if(obj->group_p) {\n        if(lv_group_get_focused(obj->group_p) == obj) return true;\n    }\n\n    return false;\n}\n#endif\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Handle the drawing related tasks of the base objects.\n * @param obj pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_obj_design(lv_obj_t * obj, const  lv_area_t * mask_p, lv_design_mode_t mode)\n{\n    if(mode == LV_DESIGN_COVER_CHK) {\n\n        /* Because of the radius it is not sure the area is covered\n         * Check the areas where there is no radius*/\n        lv_style_t * style = lv_obj_get_style(obj);\n        if(style->body.empty != 0) return false;\n\n        uint16_t r = style->body.radius;\n\n        if(r == LV_RADIUS_CIRCLE) return false;\n\n        lv_area_t area_tmp;\n\n        /*Check horizontally without radius*/\n        lv_obj_get_coords(obj, &area_tmp);\n        area_tmp.x1 += r;\n        area_tmp.x2 -= r;\n        if(lv_area_is_in(mask_p, &area_tmp) == false) return false;\n\n        /*Check vertically without radius*/\n        lv_obj_get_coords(obj, &area_tmp);\n        area_tmp.y1 += r;\n        area_tmp.y2 -= r;\n        if(lv_area_is_in(mask_p, &area_tmp) == false) return false;\n\n    } else if(mode == LV_DESIGN_DRAW_MAIN) {\n        lv_style_t * style = lv_obj_get_style(obj);\n        lv_draw_rect(&obj->coords, mask_p, style, lv_obj_get_opa_scale(obj));\n    }\n\n    return true;\n}\n\n/**\n * Signal function of the basic object\n * @param obj pointer to an object\n * @param sign signal type\n * @param param parameter for the signal (depends on signal type)\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param)\n{\n    (void)param;\n\n    lv_res_t res = LV_RES_OK;\n\n    lv_style_t * style = lv_obj_get_style(obj);\n\n    lv_indev_t *indev_act = lv_indev_get_act();\n\n    if(sign > _LV_SIGNAL_FEEDBACK_SECTION_START && sign < _LV_SIGNAL_FEEDBACK_SECTION_END) {\n\t\tif(indev_act != NULL && indev_act->feedback != NULL)\n\t\t\tindev_act->feedback(indev_act, sign);\n    }\n\n    if(sign == LV_SIGNAL_CHILD_CHG) {\n        /*Return 'invalid' if the child change signal is not enabled*/\n        if(lv_obj_is_protected(obj, LV_PROTECT_CHILD_CHG) != false) res = LV_RES_INV;\n    } else if(sign == LV_SIGNAL_REFR_EXT_SIZE) {\n        if(style->body.shadow.width > obj->ext_size) obj->ext_size = style->body.shadow.width;\n    } else if(sign ==  LV_SIGNAL_STYLE_CHG) {\n        lv_obj_refresh_ext_size(obj);\n    } else if(sign ==  LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        buf->type[0] = \"lv_obj\";\n    }\n\n    return res;\n}\n\n/**\n * Reposition the children of an object. (Called recursively)\n * @param obj pointer to an object which children will be repositioned\n * @param x_diff x coordinate shift\n * @param y_diff y coordinate shift\n */\nstatic void refresh_children_position(lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_diff)\n{\n    lv_obj_t * i;\n    LL_READ(obj->child_ll, i) {\n        i->coords.x1 += x_diff;\n        i->coords.y1 += y_diff;\n        i->coords.x2 += x_diff;\n        i->coords.y2 += y_diff;\n\n        refresh_children_position(i, x_diff, y_diff);\n    }\n}\n\n/**\n * Refresh the style of all children of an object. (Called recursively)\n * @param style_p refresh objects only with this style.\n * @param obj pointer to an object\n */\nstatic void report_style_mod_core(void * style_p, lv_obj_t * obj)\n{\n    lv_obj_t * i;\n    LL_READ(obj->child_ll, i) {\n        if(i->style_p == style_p || style_p == NULL) {\n            refresh_children_style(i);\n            lv_obj_refresh_style(i);\n        }\n\n        report_style_mod_core(style_p, i);\n    }\n}\n\n/**\n * Recursively refresh the style of the children. Go deeper until a not NULL style is found\n * because the NULL styles are inherited from the parent\n * @param obj pointer to an object\n */\nstatic void refresh_children_style(lv_obj_t * obj)\n{\n    lv_obj_t * child = lv_obj_get_child(obj, NULL);\n    while(child != NULL) {\n        if(child->style_p == NULL) {\n            refresh_children_style(child);     /*Check children too*/\n            lv_obj_refresh_style(child);       /*Notify the child about the style change*/\n        } else if(child->style_p->glass) {\n            /*Children with 'glass' parent might be effected if their style == NULL*/\n            refresh_children_style(child);\n        }\n        child = lv_obj_get_child(obj, child);\n    }\n}\n\n/**\n * Called by 'lv_obj_del' to delete the children objects\n * @param obj pointer to an object (all of its children will be deleted)\n */\nstatic void delete_children(lv_obj_t * obj)\n{\n    lv_obj_t * i;\n    lv_obj_t * i_next;\n    i = lv_ll_get_head(&(obj->child_ll));\n\n    /*Remove from the group; remove before transversing children so that\n     * the object still has access to all children during the\n     * LV_SIGNAL_DEFOCUS call*/\n#if USE_LV_GROUP\n    if(obj->group_p != NULL) lv_group_remove_obj(obj);\n#endif\n\n    while(i != NULL) {\n        /*Get the next object before delete this*/\n        i_next = lv_ll_get_next(&(obj->child_ll), i);\n\n        /*Call the recursive del to the child too*/\n        delete_children(i);\n\n        /*Set i to the next node*/\n        i = i_next;\n    }\n\n    /*Remove the animations from this object*/\n#if USE_LV_ANIMATION\n    lv_anim_del(obj, NULL);\n#endif\n\n\n    /* Reset the input devices if\n     * the currently pressed object is deleted*/\n    lv_indev_t * indev = lv_indev_next(NULL);\n    while(indev) {\n        if(indev->proc.act_obj == obj || indev->proc.last_obj == obj) {\n            lv_indev_reset(indev);\n        }\n        indev = lv_indev_next(indev);\n    }\n\n    /*Remove the object from parent's children list*/\n    lv_obj_t * par = lv_obj_get_parent(obj);\n    lv_ll_rem(&(par->child_ll), obj);\n\n    /* Clean up the object specific data*/\n    obj->signal_func(obj, LV_SIGNAL_CLEANUP, NULL);\n\n    /*Delete the base objects*/\n    if(obj->ext_attr != NULL)  lv_mem_free(obj->ext_attr);\n    lv_mem_free(obj); /*Free the object itself*/\n\n}\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_core/lv_obj.h",
    "content": "/**\n * @file lv_obj.h\n *\n */\n\n#ifndef LV_OBJ_H\n#define LV_OBJ_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#include <stddef.h>\n#include \"lv_style.h\"\n#include \"../lv_misc/lv_area.h\"\n#include \"../lv_misc/lv_mem.h\"\n#include \"../lv_misc/lv_ll.h\"\n#include \"../lv_misc/lv_color.h\"\n#include \"../lv_misc/lv_log.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/*Error check of lv_conf.h*/\n#if LV_HOR_RES == 0 || LV_VER_RES == 0\n#error \"LittlevGL: LV_HOR_RES and LV_VER_RES must be greater than 0\"\n#endif\n\n#if LV_ANTIALIAS > 1\n#error \"LittlevGL: LV_ANTIALIAS can be only 0 or 1\"\n#endif\n\n#if LV_VDB_SIZE == 0 && LV_ANTIALIAS != 0\n#error \"LittlevGL: If LV_VDB_SIZE == 0 the anti-aliasing must be disabled\"\n#endif\n\n#if LV_VDB_SIZE > 0 && LV_VDB_SIZE < LV_HOR_RES\n#error \"LittlevGL: Small Virtual Display Buffer (lv_conf.h: LV_VDB_SIZE >= LV_HOR_RES)\"\n#endif\n\n#if LV_VDB_SIZE == 0 && USE_LV_REAL_DRAW == 0\n#error \"LittlevGL: If LV_VDB_SIZE = 0 Real drawing function are required (lv_conf.h: USE_LV_REAL_DRAW 1)\"\n#endif\n\n\n#define LV_ANIM_IN              0x00    /*Animation to show an object. 'OR' it with lv_anim_builtin_t*/\n#define LV_ANIM_OUT             0x80    /*Animation to hide an object. 'OR' it with lv_anim_builtin_t*/\n#define LV_ANIM_DIR_MASK        0x80    /*ANIM_IN/ANIM_OUT mask*/\n\n#define LV_MAX_ANCESTOR_NUM     8\n\n/**********************\n *      TYPEDEFS\n **********************/\n\nstruct _lv_obj_t;\n\nenum\n{\n    LV_DESIGN_DRAW_MAIN,\n    LV_DESIGN_DRAW_POST,\n    LV_DESIGN_COVER_CHK,\n};\ntypedef uint8_t lv_design_mode_t;\n\ntypedef bool (* lv_design_func_t) (struct _lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mode_t mode);\n\nenum\n{\n    LV_RES_INV = 0,      /*Typically indicates that the object is deleted (become invalid) in the action function or an operation was failed*/\n    LV_RES_OK,           /*The object is valid (no deleted) after the action*/\n};\ntypedef uint8_t lv_res_t;\n\nenum\n{\n    /*General signals*/\n    LV_SIGNAL_CLEANUP,\n    LV_SIGNAL_CHILD_CHG,\n    LV_SIGNAL_CORD_CHG,\n    LV_SIGNAL_STYLE_CHG,\n    LV_SIGNAL_REFR_EXT_SIZE,\n    LV_SIGNAL_LANG_CHG,\n    LV_SIGNAL_GET_TYPE,\n\n\t_LV_SIGNAL_FEEDBACK_SECTION_START,\n    /*Input device related*/\n    LV_SIGNAL_PRESSED,\n    LV_SIGNAL_PRESSING,\n    LV_SIGNAL_PRESS_LOST,\n    LV_SIGNAL_RELEASED,\n    LV_SIGNAL_LONG_PRESS,\n    LV_SIGNAL_LONG_PRESS_REP,\n    LV_SIGNAL_DRAG_BEGIN,\n    LV_SIGNAL_DRAG_END,\n\n    /*Group related*/\n    LV_SIGNAL_FOCUS,\n    LV_SIGNAL_DEFOCUS,\n    LV_SIGNAL_CONTROLL,\n    _LV_SIGNAL_FEEDBACK_SECTION_END,\n    LV_SIGNAL_GET_EDITABLE,\n};\ntypedef uint8_t lv_signal_t;\n\ntypedef lv_res_t (* lv_signal_func_t) (struct _lv_obj_t * obj, lv_signal_t sign, void * param);\n\nenum\n{\n    LV_ALIGN_CENTER = 0,\n    LV_ALIGN_IN_TOP_LEFT,\n    LV_ALIGN_IN_TOP_MID,\n    LV_ALIGN_IN_TOP_RIGHT,\n    LV_ALIGN_IN_BOTTOM_LEFT,\n    LV_ALIGN_IN_BOTTOM_MID,\n    LV_ALIGN_IN_BOTTOM_RIGHT,\n    LV_ALIGN_IN_LEFT_MID,\n    LV_ALIGN_IN_RIGHT_MID,\n    LV_ALIGN_OUT_TOP_LEFT,\n    LV_ALIGN_OUT_TOP_MID,\n    LV_ALIGN_OUT_TOP_RIGHT,\n    LV_ALIGN_OUT_BOTTOM_LEFT,\n    LV_ALIGN_OUT_BOTTOM_MID,\n    LV_ALIGN_OUT_BOTTOM_RIGHT,\n    LV_ALIGN_OUT_LEFT_TOP,\n    LV_ALIGN_OUT_LEFT_MID,\n    LV_ALIGN_OUT_LEFT_BOTTOM,\n    LV_ALIGN_OUT_RIGHT_TOP,\n    LV_ALIGN_OUT_RIGHT_MID,\n    LV_ALIGN_OUT_RIGHT_BOTTOM,\n};\ntypedef uint8_t lv_align_t;\n\n#if LV_OBJ_REALIGN\ntypedef struct {\n    const struct _lv_obj_t * base;\n    lv_coord_t xofs;\n    lv_coord_t yofs;\n    lv_align_t align;\n    uint8_t auto_realign :1;\n    uint8_t origo_align  :1;        /*1: the oigo (center of the object) was aligned with `lv_obj_align_origo`*/\n}lv_reailgn_t;\n#endif\n\n\ntypedef struct _lv_obj_t\n{\n    struct _lv_obj_t * par;    /*Pointer to the parent object*/\n    lv_ll_t child_ll;          /*Linked list to store the children objects*/\n\n    lv_area_t coords;               /*Coordinates of the object (x1, y1, x2, y2)*/\n\n    lv_signal_func_t signal_func;     /*Object type specific signal function*/\n    lv_design_func_t design_func;     /*Object type specific design function*/\n\n    void * ext_attr;                 /*Object type specific extended data*/\n    lv_style_t * style_p;       /*Pointer to the object's style*/\n\n#if LV_OBJ_FREE_PTR != 0\n    void * free_ptr;              /*Application specific pointer (set it freely)*/\n#endif\n\n#if USE_LV_GROUP != 0\n    void * group_p;                 /*Pointer to the group of the object*/\n#endif\n    /*Attributes and states*/\n    uint8_t click         :1;    /*1: Can be pressed by an input device*/\n    uint8_t drag          :1;    /*1: Enable the dragging*/\n    uint8_t drag_throw    :1;    /*1: Enable throwing with drag*/\n    uint8_t drag_parent   :1;    /*1: Parent will be dragged instead*/\n    uint8_t hidden        :1;    /*1: Object is hidden*/\n    uint8_t top           :1;    /*1: If the object or its children is clicked it goes to the foreground*/\n    uint8_t opa_scale_en  :1;    /*1: opa_scale is set*/\n    uint8_t protect;            /*Automatically happening actions can be prevented. 'OR'ed values from `lv_protect_t`*/\n    lv_opa_t opa_scale;         /*Scale down the opacity by this factor. Effects all children as well*/\n\n    lv_coord_t ext_size;        /*EXTtend the size of the object in every direction. E.g. for shadow drawing*/\n#if LV_OBJ_REALIGN\n    lv_reailgn_t realign;\n#endif\n\n#ifdef LV_OBJ_FREE_NUM_TYPE\n    LV_OBJ_FREE_NUM_TYPE free_num;          /*Application specific identifier (set it freely)*/\n#endif\n} lv_obj_t;\n\ntypedef lv_res_t (*lv_action_t) (struct _lv_obj_t * obj);\n\n/*Protect some attributes (max. 8 bit)*/\nenum\n{\n    LV_PROTECT_NONE      = 0x00,\n    LV_PROTECT_CHILD_CHG = 0x01, /*Disable the child change signal. Used by the library*/\n    LV_PROTECT_PARENT    = 0x02, /*Prevent automatic parent change (e.g. in lv_page)*/\n    LV_PROTECT_POS       = 0x04, /*Prevent automatic positioning (e.g. in lv_cont layout)*/\n    LV_PROTECT_FOLLOW    = 0x08, /*Prevent the object be followed in automatic ordering (e.g. in lv_cont PRETTY layout)*/\n    LV_PROTECT_PRESS_LOST= 0x10, /*If the `indev` was pressing this object but swiped out while pressing do not search other object.*/\n    LV_PROTECT_CLICK_FOCUS= 0x20,/*Prevent focusing the object by clicking on it*/\n};\ntypedef uint8_t lv_protect_t;\n\n\n/*Used by `lv_obj_get_type()`. The object's and its ancestor types are stored here*/\ntypedef struct {\n    const char * type[LV_MAX_ANCESTOR_NUM];   /*[0]: the actual type, [1]: ancestor, [2] #1's ancestor ... [x]: \"lv_obj\" */\n} lv_obj_type_t;\n\nenum\n{\n    LV_ANIM_NONE = 0,\n    LV_ANIM_FLOAT_TOP,      /*Float from/to the top*/\n    LV_ANIM_FLOAT_LEFT,     /*Float from/to the left*/\n    LV_ANIM_FLOAT_BOTTOM,   /*Float from/to the bottom*/\n    LV_ANIM_FLOAT_RIGHT,    /*Float from/to the right*/\n    LV_ANIM_GROW_H,         /*Grow/shrink  horizontally*/\n    LV_ANIM_GROW_V,         /*Grow/shrink  vertically*/\n};\ntypedef uint8_t lv_anim_builtin_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Init. the 'lv' library.\n */\nvoid lv_init(void);\n\n/*--------------------\n * Create and delete\n *-------------------*/\n\n/**\n * Create a basic object\n * @param parent pointer to a parent object.\n *                  If NULL then a screen will be created\n * @param copy pointer to a base object, if not NULL then the new object will be copied from it\n * @return pointer to the new object\n */\nlv_obj_t * lv_obj_create(lv_obj_t * parent,const  lv_obj_t * copy);\n\n/**\n * Delete 'obj' and all of its children\n * @param obj pointer to an object to delete\n * @return LV_RES_INV because the object is deleted\n */\nlv_res_t lv_obj_del(lv_obj_t * obj);\n\n/**\n * Delete all children of an object\n * @param obj pointer to an object\n */\nvoid lv_obj_clean(lv_obj_t *obj);\n\n/**\n * Mark the object as invalid therefore its current position will be redrawn by 'lv_refr_task'\n * @param obj pointer to an object\n */\nvoid lv_obj_invalidate(const lv_obj_t * obj);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/*--------------\n * Screen set\n *--------------*/\n\n/**\n * Load a new screen\n * @param scr pointer to a screen\n */\nvoid lv_scr_load(lv_obj_t * scr);\n\n/*--------------------\n * Parent/children set\n *--------------------*/\n\n/**\n * Set a new parent for an object. Its relative position will be the same.\n * @param obj pointer to an object. Can't be a screen.\n * @param parent pointer to the new parent object. (Can't be NULL)\n */\nvoid lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent);\n\n/*--------------------\n * Coordinate set\n * ------------------*/\n\n/**\n * Set relative the position of an object (relative to the parent)\n * @param obj pointer to an object\n * @param x new distance from the left side of the parent\n * @param y new distance from the top of the parent\n */\nvoid lv_obj_set_pos(lv_obj_t * obj, lv_coord_t x, lv_coord_t y);\n\n/**\n * Set the x coordinate of a object\n * @param obj pointer to an object\n * @param x new distance from the left side from the parent\n */\nvoid lv_obj_set_x(lv_obj_t * obj, lv_coord_t x);\n\n/**\n * Set the y coordinate of a object\n * @param obj pointer to an object\n * @param y new distance from the top of the parent\n */\nvoid lv_obj_set_y(lv_obj_t * obj, lv_coord_t y);\n\n/**\n * Set the size of an object\n * @param obj pointer to an object\n * @param w new width\n * @param h new height\n */\nvoid lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h);\n\n/**\n * Set the width of an object\n * @param obj pointer to an object\n * @param w new width\n */\nvoid lv_obj_set_width(lv_obj_t * obj, lv_coord_t w);\n\n/**\n * Set the height of an object\n * @param obj pointer to an object\n * @param h new height\n */\nvoid lv_obj_set_height(lv_obj_t * obj, lv_coord_t h);\n\n/**\n * Align an object to an other object.\n * @param obj pointer to an object to align\n * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it.\n * @param align type of alignment (see 'lv_align_t' enum)\n * @param x_mod x coordinate shift after alignment\n * @param y_mod y coordinate shift after alignment\n */\nvoid lv_obj_align(lv_obj_t * obj,const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod);\n\n/**\n * Align an object to an other object.\n * @param obj pointer to an object to align\n * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it.\n * @param align type of alignment (see 'lv_align_t' enum)\n * @param x_mod x coordinate shift after alignment\n * @param y_mod y coordinate shift after alignment\n */\nvoid lv_obj_align_origo(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod);\n\n/**\n * Realign the object based on the last `lv_obj_align` parameters.\n * @param obj pointer to an object\n */\nvoid lv_obj_realign(lv_obj_t * obj);\n\n/**\n * Enable the automatic realign of the object when its size has changed based on the last `lv_obj_align` parameters.\n * @param obj pointer to an object\n * @param en true: enable auto realign; false: disable auto realign\n */\nvoid lv_obj_set_auto_realign(lv_obj_t * obj, bool en);\n\n/*---------------------\n * Appearance set\n *--------------------*/\n\n/**\n * Set a new style for an object\n * @param obj pointer to an object\n * @param style_p pointer to the new style\n */\nvoid lv_obj_set_style(lv_obj_t * obj, lv_style_t * style);\n\n/**\n * Notify an object about its style is modified\n * @param obj pointer to an object\n */\nvoid lv_obj_refresh_style(lv_obj_t * obj);\n\n/**\n * Notify all object if a style is modified\n * @param style pointer to a style. Only the objects with this style will be notified\n *               (NULL to notify all objects)\n */\nvoid lv_obj_report_style_mod(lv_style_t * style);\n\n/*-----------------\n * Attribute set\n *----------------*/\n\n/**\n * Hide an object. It won't be visible and clickable.\n * @param obj pointer to an object\n * @param en true: hide the object\n */\nvoid lv_obj_set_hidden(lv_obj_t * obj, bool en);\n\n/**\n * Enable or disable the clicking of an object\n * @param obj pointer to an object\n * @param en true: make the object clickable\n */\nvoid lv_obj_set_click(lv_obj_t * obj, bool en);\n\n/**\n * Enable to bring this object to the foreground if it\n * or any of its children is clicked\n * @param obj pointer to an object\n * @param en true: enable the auto top feature\n */\nvoid lv_obj_set_top(lv_obj_t * obj, bool en);\n\n/**\n * Enable the dragging of an object\n * @param obj pointer to an object\n * @param en true: make the object dragable\n */\nvoid lv_obj_set_drag(lv_obj_t * obj, bool en);\n\n/**\n * Enable the throwing of an object after is is dragged\n * @param obj pointer to an object\n * @param en true: enable the drag throw\n */\nvoid lv_obj_set_drag_throw(lv_obj_t * obj, bool en);\n\n/**\n * Enable to use parent for drag related operations.\n * If trying to drag the object the parent will be moved instead\n * @param obj pointer to an object\n * @param en true: enable the 'drag parent' for the object\n */\nvoid lv_obj_set_drag_parent(lv_obj_t * obj, bool en);\n\n/**\n * Set editable parameter Used by groups and keyboard/encoder control.\n * Editable object has something inside to choose (the elements of a list)\n * @param obj pointer to an object\n * @param en true: enable editing\n */\n//void lv_obj_set_editable(lv_obj_t * obj, bool en);\n\n/**\n * Set the opa scale enable parameter (required to set opa_scale with `lv_obj_set_opa_scale()`)\n * @param obj pointer to an object\n * @param en true: opa scaling is enabled for this object and all children; false: no opa scaling\n */\nvoid lv_obj_set_opa_scale_enable(lv_obj_t * obj, bool en);\n\n/**\n * Set the opa scale of an object\n * @param obj pointer to an object\n * @param opa_scale a factor to scale down opacity [0..255]\n */\nvoid lv_obj_set_opa_scale(lv_obj_t * obj, lv_opa_t opa_scale);\n\n/**\n * Set a bit or bits in the protect filed\n * @param obj pointer to an object\n * @param prot 'OR'-ed values from `lv_protect_t`\n */\nvoid lv_obj_set_protect(lv_obj_t * obj, uint8_t prot);\n\n/**\n * Clear a bit or bits in the protect filed\n * @param obj pointer to an object\n * @param prot 'OR'-ed values from `lv_protect_t`\n */\nvoid lv_obj_clear_protect(lv_obj_t * obj, uint8_t prot);\n\n/**\n * Set the signal function of an object.\n * Always call the previous signal function in the new.\n * @param obj pointer to an object\n * @param fp the new signal function\n */\nvoid lv_obj_set_signal_func(lv_obj_t * obj, lv_signal_func_t fp);\n\n/**\n * Set a new design function for an object\n * @param obj pointer to an object\n * @param fp the new design function\n */\nvoid lv_obj_set_design_func(lv_obj_t * obj, lv_design_func_t fp);\n\n/*----------------\n * Other set\n *--------------*/\n\n/**\n * Allocate a new ext. data for an object\n * @param obj pointer to an object\n * @param ext_size the size of the new ext. data\n * @return pointer to the allocated ext\n */\nvoid * lv_obj_allocate_ext_attr(lv_obj_t * obj, uint16_t ext_size);\n\n/**\n * Send a 'LV_SIGNAL_REFR_EXT_SIZE' signal to the object\n * @param obj pointer to an object\n */\nvoid lv_obj_refresh_ext_size(lv_obj_t * obj);\n\n#ifdef LV_OBJ_FREE_NUM_TYPE\n/**\n * Set an application specific number for an object.\n * It can help to identify objects in the application.\n * @param obj pointer to an object\n * @param free_num the new free number\n */\nvoid lv_obj_set_free_num(lv_obj_t * obj, LV_OBJ_FREE_NUM_TYPE free_num);\n#endif\n\n#if LV_OBJ_FREE_PTR != 0\n/**\n * Set an application specific  pointer for an object.\n * It can help to identify objects in the application.\n * @param obj pointer to an object\n * @param free_p the new free pinter\n */\nvoid lv_obj_set_free_ptr(lv_obj_t * obj, void * free_p);\n#endif\n\n#if USE_LV_ANIMATION\n/**\n * Animate an object\n * @param obj pointer to an object to animate\n * @param type type of animation from 'lv_anim_builtin_t'. 'OR' it with ANIM_IN or ANIM_OUT\n * @param time time of animation in milliseconds\n * @param delay delay before the animation in milliseconds\n * @param cb a function to call when the animation is ready\n */\nvoid lv_obj_animate(lv_obj_t * obj, lv_anim_builtin_t type, uint16_t time, uint16_t delay, void (*cb) (lv_obj_t *));\n#endif\n\n/*=======================\n * Getter functions\n *======================*/\n\n/*------------------\n * Screen get\n *-----------------*/\n\n/**\n * Return with a pointer to the active screen\n * @return pointer to the active screen object (loaded by 'lv_scr_load()')\n */\nlv_obj_t * lv_scr_act(void);\n\n/**\n * Return with the top layer. (Same on every screen and it is above the normal screen layer)\n * @return pointer to the top layer object  (transparent screen sized lv_obj)\n */\nlv_obj_t * lv_layer_top(void);\n\n/**\n * Return with the system layer. (Same on every screen and it is above the all other layers)\n * It is used for example by the cursor\n * @return pointer to the system layer object (transparent screen sized lv_obj)\n */\nlv_obj_t * lv_layer_sys(void);\n\n/**\n * Return with the screen of an object\n * @param obj pointer to an object\n * @return pointer to a screen\n */\nlv_obj_t * lv_obj_get_screen(const lv_obj_t * obj);\n\n/*---------------------\n * Parent/children get\n *--------------------*/\n\n/**\n * Returns with the parent of an object\n * @param obj pointer to an object\n * @return pointer to the parent of  'obj'\n */\nlv_obj_t * lv_obj_get_parent(const lv_obj_t * obj);\n\n/**\n * Iterate through the children of an object (start from the \"youngest, lastly created\")\n * @param obj pointer to an object\n * @param child NULL at first call to get the next children\n *                  and the previous return value later\n * @return the child after 'act_child' or NULL if no more child\n */\nlv_obj_t * lv_obj_get_child(const lv_obj_t * obj, const lv_obj_t * child);\n\n/**\n * Iterate through the children of an object (start from the \"oldest\", firstly created)\n * @param obj pointer to an object\n * @param child NULL at first call to get the next children\n *                  and the previous return value later\n * @return the child after 'act_child' or NULL if no more child\n */\nlv_obj_t * lv_obj_get_child_back(const lv_obj_t * obj, const lv_obj_t * child);\n\n/**\n * Count the children of an object (only children directly on 'obj')\n * @param obj pointer to an object\n * @return children number of 'obj'\n */\nuint16_t lv_obj_count_children(const lv_obj_t * obj);\n\n/*---------------------\n * Coordinate get\n *--------------------*/\n\n/**\n * Copy the coordinates of an object to an area\n * @param obj pointer to an object\n * @param cords_p pointer to an area to store the coordinates\n */\nvoid lv_obj_get_coords(const lv_obj_t * obj, lv_area_t * cords_p);\n\n/**\n * Get the x coordinate of object\n * @param obj pointer to an object\n * @return distance of 'obj' from the left side of its parent\n */\nlv_coord_t lv_obj_get_x(const lv_obj_t * obj);\n\n/**\n * Get the y coordinate of object\n * @param obj pointer to an object\n * @return distance of 'obj' from the top of its parent\n */\nlv_coord_t lv_obj_get_y(const lv_obj_t * obj);\n\n/**\n * Get the width of an object\n * @param obj pointer to an object\n * @return the width\n */\nlv_coord_t lv_obj_get_width(const lv_obj_t * obj);\n\n/**\n * Get the height of an object\n * @param obj pointer to an object\n * @return the height\n */\nlv_coord_t lv_obj_get_height(const lv_obj_t * obj);\n\n/**\n * Get the extended size attribute of an object\n * @param obj pointer to an object\n * @return the extended size attribute\n */\nlv_coord_t lv_obj_get_ext_size(const lv_obj_t * obj);\n\n/**\n * Get the automatic realign property of the object.\n * @param obj pointer to an object\n * @return  true: auto realign is enabled; false: auto realign is disabled\n */\nbool lv_obj_get_auto_realign(lv_obj_t * obj);\n\n/*-----------------\n * Appearance get\n *---------------*/\n\n/**\n * Get the style pointer of an object (if NULL get style of the parent)\n * @param obj pointer to an object\n * @return pointer to a style\n */\nlv_style_t * lv_obj_get_style(const lv_obj_t * obj);\n\n/*-----------------\n * Attribute get\n *----------------*/\n\n/**\n * Get the hidden attribute of an object\n * @param obj pointer to an object\n * @return true: the object is hidden\n */\nbool lv_obj_get_hidden(const lv_obj_t * obj);\n\n/**\n * Get the click enable attribute of an object\n * @param obj pointer to an object\n * @return true: the object is clickable\n */\nbool lv_obj_get_click(const lv_obj_t * obj);\n\n/**\n * Get the top enable attribute of an object\n * @param obj pointer to an object\n * @return true: the auto top feature is enabled\n */\nbool lv_obj_get_top(const lv_obj_t * obj);\n\n/**\n * Get the drag enable attribute of an object\n * @param obj pointer to an object\n * @return true: the object is dragable\n */\nbool lv_obj_get_drag(const lv_obj_t * obj);\n\n/**\n * Get the drag throw enable attribute of an object\n * @param obj pointer to an object\n * @return true: drag throw is enabled\n */\nbool lv_obj_get_drag_throw(const lv_obj_t * obj);\n\n/**\n * Get the drag parent attribute of an object\n * @param obj pointer to an object\n * @return true: drag parent is enabled\n */\nbool lv_obj_get_drag_parent(const lv_obj_t * obj);\n\n\n/**\n * Get the opa scale enable parameter\n * @param obj pointer to an object\n * @return true: opa scaling is enabled for this object and all children; false: no opa scaling\n */\nlv_opa_t lv_obj_get_opa_scale_enable(const lv_obj_t * obj);\n\n/**\n * Get the opa scale parameter of an object\n * @param obj pointer to an object\n * @return opa scale [0..255]\n */\nlv_opa_t lv_obj_get_opa_scale(const lv_obj_t * obj);\n\n/**\n * Get the protect field of an object\n * @param obj pointer to an object\n * @return protect field ('OR'ed values of `lv_protect_t`)\n */\nuint8_t lv_obj_get_protect(const lv_obj_t * obj);\n\n/**\n * Check at least one bit of a given protect bitfield is set\n * @param obj pointer to an object\n * @param prot protect bits to test ('OR'ed values of `lv_protect_t`)\n * @return false: none of the given bits are set, true: at least one bit is set\n */\nbool lv_obj_is_protected(const lv_obj_t * obj, uint8_t prot);\n\n/**\n * Get the signal function of an object\n * @param obj pointer to an object\n * @return the signal function\n */\nlv_signal_func_t lv_obj_get_signal_func(const lv_obj_t * obj);\n\n/**\n * Get the design function of an object\n * @param obj pointer to an object\n * @return the design function\n */\nlv_design_func_t lv_obj_get_design_func(const lv_obj_t * obj);\n\n/*------------------\n * Other get\n *-----------------*/\n\n/**\n * Get the ext pointer\n * @param obj pointer to an object\n * @return the ext pointer but not the dynamic version\n *         Use it as ext->data1, and NOT da(ext)->data1\n */\nvoid * lv_obj_get_ext_attr(const lv_obj_t * obj);\n\n/**\n * Get object's and its ancestors type. Put their name in `type_buf` starting with the current type.\n * E.g. buf.type[0]=\"lv_btn\", buf.type[1]=\"lv_cont\", buf.type[2]=\"lv_obj\"\n * @param obj pointer to an object which type should be get\n * @param buf pointer to an `lv_obj_type_t` buffer to store the types\n */\nvoid lv_obj_get_type(lv_obj_t * obj, lv_obj_type_t * buf);\n\n#ifdef LV_OBJ_FREE_NUM_TYPE\n/**\n * Get the free number\n * @param obj pointer to an object\n * @return the free number\n */\nLV_OBJ_FREE_NUM_TYPE lv_obj_get_free_num(const lv_obj_t * obj);\n#endif\n\n#if LV_OBJ_FREE_PTR != 0\n/**\n * Get the free pointer\n * @param obj pointer to an object\n * @return the free pointer\n */\nvoid * lv_obj_get_free_ptr(const lv_obj_t * obj);\n#endif\n\n#if USE_LV_GROUP\n/**\n * Get the group of the object\n * @param obj pointer to an object\n * @return the pointer to group of the object\n */\nvoid * lv_obj_get_group(const lv_obj_t * obj);\n\n\n/**\n * Tell whether the object is the focused object of a group or not.\n * @param obj pointer to an object\n * @return true: the object is focused, false: the object is not focused or not in a group\n */\nbool lv_obj_is_focused(const lv_obj_t * obj);\n\n#endif\n\n\n/**********************\n *      MACROS\n **********************/\n\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_OBJ_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_core/lv_refr.c",
    "content": "/**\n * @file lv_refr.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include <stddef.h>\n#include \"lv_refr.h\"\n#include \"lv_vdb.h\"\n#include \"../lv_hal/lv_hal_tick.h\"\n#include \"../lv_hal/lv_hal_disp.h\"\n#include \"../lv_misc/lv_task.h\"\n#include \"../lv_misc/lv_mem.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#ifndef LV_INV_FIFO_SIZE\n#define LV_INV_FIFO_SIZE    32    /*The average count of objects on a screen */\n#endif\n\n/**********************\n *      TYPEDEFS\n **********************/\ntypedef struct {\n    lv_area_t area;\n    uint8_t joined;\n} lv_join_t;\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic void lv_refr_task(void * param);\nstatic void lv_refr_join_area(void);\nstatic void lv_refr_areas(void);\n#if LV_VDB_SIZE == 0\nstatic void lv_refr_area_no_vdb(const lv_area_t * area_p);\n#else\nstatic void lv_refr_area_with_vdb(const lv_area_t * area_p);\nstatic void lv_refr_area_part_vdb(const lv_area_t * area_p);\n#endif\nstatic lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj);\nstatic void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p);\nstatic void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_join_t inv_buf[LV_INV_FIFO_SIZE];\nstatic uint16_t inv_buf_p;\nstatic void (*monitor_cb)(uint32_t, uint32_t); /*Monitor the rendering time*/\nstatic void (*round_cb)(lv_area_t *);          /*If set then called to modify invalidated areas for special display controllers*/\nstatic uint32_t px_num;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Initialize the screen refresh subsystem\n */\nvoid lv_refr_init(void)\n{\n    inv_buf_p = 0;\n    memset(inv_buf, 0, sizeof(inv_buf));\n\n    lv_task_t * task;\n    task = lv_task_create(lv_refr_task, LV_REFR_PERIOD, LV_TASK_PRIO_MID, NULL);\n    lv_task_ready(task);        /*Be sure the screen will be refreshed immediately on start up*/\n}\n\n/**\n * Redraw the invalidated areas now.\n * Normally the redrawing is periodically executed in `lv_task_handler` but a long blocking process can\n * prevent the call of `lv_task_handler`. In this case if the the GUI is updated in the process (e.g. progress bar)\n * this function can be called when the screen should be updated.\n */\nvoid lv_refr_now(void)\n{\n    lv_refr_task(NULL);\n}\n\n\n/**\n * Invalidate an area\n * @param area_p pointer to area which should be invalidated\n */\nvoid lv_inv_area(const lv_area_t * area_p)\n{\n    /*Clear the invalidate buffer if the parameter is NULL*/\n    if(area_p == NULL) {\n        inv_buf_p = 0;\n        return;\n    }\n\n    lv_area_t scr_area;\n    scr_area.x1 = 0;\n    scr_area.y1 = 0;\n    scr_area.x2 = LV_HOR_RES - 1;\n    scr_area.y2 = LV_VER_RES - 1;\n\n    lv_area_t com_area;\n    bool suc;\n\n    suc = lv_area_intersect(&com_area, area_p, &scr_area);\n\n    /*The area is truncated to the screen*/\n    if(suc != false) {\n        if(round_cb) round_cb(&com_area);\n\n        /*Save only if this area is not in one of the saved areas*/\n        uint16_t i;\n        for(i = 0; i < inv_buf_p; i++) {\n            if(lv_area_is_in(&com_area, &inv_buf[i].area) != false) return;\n        }\n\n        /*Save the area*/\n        if(inv_buf_p < LV_INV_FIFO_SIZE) {\n            lv_area_copy(&inv_buf[inv_buf_p].area, &com_area);\n        } else {/*If no place for the area add the screen*/\n            inv_buf_p = 0;\n            lv_area_copy(&inv_buf[inv_buf_p].area, &scr_area);\n        }\n        inv_buf_p ++;\n    }\n}\n\n/**\n * Set a function to call after every refresh to announce the refresh time and the number of refreshed pixels\n * @param cb pointer to a callback function (void my_refr_cb(uint32_t time_ms, uint32_t px_num))\n *           time_ms: refresh time in [ms]\n *           px_num: not the drawn pixels but the number of affected pixels of the screen\n *                   (more pixels are drawn because of overlapping objects)\n */\nvoid lv_refr_set_monitor_cb(void (*cb)(uint32_t, uint32_t))\n{\n    monitor_cb = cb;\n}\n\n/**\n * Called when an area is invalidated to modify the coordinates of the area.\n * Special display controllers may require special coordinate rounding\n * @param cb pointer to the a function which will modify the area\n */\nvoid lv_refr_set_round_cb(void(*cb)(lv_area_t *))\n{\n    round_cb = cb;\n}\n\n/**\n * Get the number of areas in the buffer\n * @return number of invalid areas\n */\nuint16_t lv_refr_get_buf_size(void)\n{\n    return inv_buf_p;\n}\n\n/**\n * Pop (delete) the last 'num' invalidated areas from the buffer\n * @param num number of areas to delete\n */\nvoid lv_refr_pop_from_buf(uint16_t num)\n{\n    if(inv_buf_p < num) inv_buf_p = 0;\n    else inv_buf_p -= num;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Called periodically to handle the refreshing\n * @param param unused\n */\nstatic void lv_refr_task(void * param)\n{\n    (void)param;\n\n    LV_LOG_TRACE(\"display refresh task started\");\n\n    uint32_t start = lv_tick_get();\n\n    if(lv_disp_get_active() == NULL) {\n        LV_LOG_TRACE(\"No display is registered\");\n        return;\n    }\n\n    lv_refr_join_area();\n\n    lv_refr_areas();\n\n    /*If refresh happened ...*/\n    if(inv_buf_p != 0) {\n\n        /*In true double buffered mode copy the refreshed areas to the new VDB to keep it up to date*/\n#if LV_VDB_TRUE_DOUBLE_BUFFERED\n        lv_vdb_t * vdb_p = lv_vdb_get();\n        vdb_p->area.x1 = 0;\n        vdb_p->area.x2 = LV_HOR_RES-1;\n        vdb_p->area.y1 = 0;\n        vdb_p->area.y2 = LV_VER_RES - 1;\n\n        /*Flush the content of the VDB*/\n        lv_vdb_flush();\n\n        /* With true double buffering the flushing should be only the address change of the current frame buffer\n         * Wait until the address change is ready and copy the active content to the other frame buffer (new active VDB)\n         * The changes will be written to the new VDB.*/\n        lv_vdb_t * vdb_act = lv_vdb_get_active();\n        lv_vdb_t * vdb_ina = lv_vdb_get_inactive();\n\n        uint8_t * buf_act = (uint8_t *) vdb_act->buf;\n        uint8_t * buf_ina = (uint8_t *) vdb_ina->buf;\n\n        uint16_t a;\n        for(a = 0; a < inv_buf_p; a++) {\n            if(inv_buf[a].joined == 0) {\n                lv_coord_t y;\n                uint32_t start_offs = ((LV_HOR_RES * inv_buf[a].area.y1 + inv_buf[a].area.x1) * LV_VDB_PX_BPP) >> 3;\n                uint32_t line_length = (lv_area_get_width(&inv_buf[a].area) * LV_VDB_PX_BPP) >> 3;\n\n                for(y = inv_buf[a].area.y1; y <= inv_buf[a].area.y2; y++) {\n                    memcpy(buf_act + start_offs, buf_ina + start_offs, line_length);\n                    start_offs += (LV_HOR_RES * LV_VDB_PX_BPP) >> 3;\n                }\n            }\n        }\n\n#endif\n\n        /*Clean up*/\n        memset(inv_buf, 0, sizeof(inv_buf));\n        inv_buf_p = 0;\n\n        /*Call monitor cb if present*/\n        if(monitor_cb != NULL) {\n            monitor_cb(lv_tick_elaps(start), px_num);\n        }\n    }\n\n    LV_LOG_TRACE(\"display refresh task finished\");\n}\n\n\n/**\n * Join the areas which has got common parts\n */\nstatic void lv_refr_join_area(void)\n{\n    uint32_t join_from;\n    uint32_t join_in;\n    lv_area_t joined_area;\n    for(join_in = 0; join_in < inv_buf_p; join_in++) {\n        if(inv_buf[join_in].joined != 0) continue;\n\n        /*Check all areas to join them in 'join_in'*/\n        for(join_from = 0; join_from < inv_buf_p; join_from++) {\n            /*Handle only unjoined areas and ignore itself*/\n            if(inv_buf[join_from].joined != 0 || join_in == join_from) {\n                continue;\n            }\n\n            /*Check if the areas are on each other*/\n            if(lv_area_is_on(&inv_buf[join_in].area,\n                             &inv_buf[join_from].area) == false) {\n                continue;\n            }\n\n            lv_area_join(&joined_area, &inv_buf[join_in].area,\n                         &inv_buf[join_from].area);\n\n            /*Join two area only if the joined area size is smaller*/\n            if(lv_area_get_size(&joined_area) <\n                    (lv_area_get_size(&inv_buf[join_in].area) + lv_area_get_size(&inv_buf[join_from].area))) {\n                lv_area_copy(&inv_buf[join_in].area, &joined_area);\n\n                /*Mark 'join_form' is joined into 'join_in'*/\n                inv_buf[join_from].joined = 1;\n            }\n        }\n    }\n}\n\n/**\n * Refresh the joined areas\n */\nstatic void lv_refr_areas(void)\n{\n    px_num = 0;\n    uint32_t i;\n\n    for(i = 0; i < inv_buf_p; i++) {\n        /*Refresh the unjoined areas*/\n        if(inv_buf[i].joined == 0) {\n            /*If there is no VDB do simple drawing*/\n#if LV_VDB_SIZE == 0\n            lv_refr_area_no_vdb(&inv_buf[i].area);\n#else\n            /*If VDB is used...*/\n            lv_refr_area_with_vdb(&inv_buf[i].area);\n#endif\n            if(monitor_cb != NULL) px_num += lv_area_get_size(&inv_buf[i].area);\n        }\n    }\n\n}\n\n#if LV_VDB_SIZE == 0\n/**\n * Refresh an area if there is no Virtual Display Buffer\n * @param area_p pointer to an area to refresh\n */\nstatic void lv_refr_area_no_vdb(const lv_area_t * area_p)\n{\n    lv_obj_t * top_p;\n\n    /*Get top object which is not covered by others*/\n    top_p = lv_refr_get_top_obj(area_p, lv_scr_act());\n\n    /*Do the refreshing*/\n    lv_refr_obj_and_children(top_p, area_p);\n\n    /*Also refresh top and sys layer unconditionally*/\n    lv_refr_obj_and_children(lv_layer_top(), area_p);\n    lv_refr_obj_and_children(lv_layer_sys(), area_p);\n}\n\n#else\n\n/**\n * Refresh an area if there is Virtual Display Buffer\n * @param area_p  pointer to an area to refresh\n */\nstatic void lv_refr_area_with_vdb(const lv_area_t * area_p)\n{\n\n#if LV_VDB_TRUE_DOUBLE_BUFFERED == 0\n    /*Calculate the max row num*/\n    lv_coord_t w = lv_area_get_width(area_p);\n    lv_coord_t h = lv_area_get_height(area_p);\n    lv_coord_t y2 = area_p->y2 >= LV_VER_RES ? y2 = LV_VER_RES - 1 : area_p->y2;\n\n    int32_t max_row = (uint32_t) LV_VDB_SIZE / w;\n\n    if(max_row > h) max_row = h;\n\n\n    /*Round down the lines of VDB if rounding is added*/\n    if(round_cb) {\n        lv_area_t tmp;\n        tmp.x1 = 0;\n        tmp.x2 = 0;\n        tmp.y1 = 0;\n\n        lv_coord_t y_tmp = max_row - 1;\n        do {\n            tmp.y2 = y_tmp;\n            round_cb(&tmp);\n\n            /*If this height fits into `max_row` then fine*/\n            if(lv_area_get_height(&tmp) <= max_row) break;\n\n            /*Decrement the height of the area until it fits into `max_row` after rounding*/\n            y_tmp --;\n        } while(y_tmp != 0);\n\n        if(y_tmp == 0) {\n            LV_LOG_WARN(\"Can't set VDB height using the round function. (Wrong round_cb or to small VDB)\");\n            return;\n        } else {\n            max_row = tmp.y2 + 1;\n        }\n    }\n\n    /*Always use the full row*/\n    lv_coord_t row;\n    lv_coord_t row_last = 0;\n    for(row = area_p->y1; row  + max_row - 1 <= y2; row += max_row)  {\n        lv_vdb_t * vdb_p = lv_vdb_get();\n        if(!vdb_p) {\n            LV_LOG_WARN(\"Invalid VDB pointer\");\n            return;\n        }\n\n        /*Calc. the next y coordinates of VDB*/\n        vdb_p->area.x1 = area_p->x1;\n        vdb_p->area.x2 = area_p->x2;\n        vdb_p->area.y1 = row;\n        vdb_p->area.y2 = row + max_row - 1;\n        if(vdb_p->area.y2 > y2) vdb_p->area.y2 = y2;\n        row_last = vdb_p->area.y2;\n        lv_refr_area_part_vdb(area_p);\n    }\n\n    /*If the last y coordinates are not handled yet ...*/\n    if(y2 != row_last) {\n        lv_vdb_t * vdb_p = lv_vdb_get();\n        if(!vdb_p) {\n            LV_LOG_WARN(\"Invalid VDB pointer\");\n            return;\n        }\n\n        /*Calc. the next y coordinates of VDB*/\n        vdb_p->area.x1 = area_p->x1;\n        vdb_p->area.x2 = area_p->x2;\n        vdb_p->area.y1 = row;\n        vdb_p->area.y2 = y2;\n\n        /*Refresh this part too*/\n        lv_refr_area_part_vdb(area_p);\n    }\n#else\n    lv_vdb_t * vdb_p = lv_vdb_get();\n    vdb_p->area.x1 = 0;\n    vdb_p->area.x2 = LV_HOR_RES-1;\n    vdb_p->area.y1 = 0;\n    vdb_p->area.y2 = LV_VER_RES - 1;\n    lv_refr_area_part_vdb(area_p);\n#endif\n}\n\n/**\n * Refresh a part of an area which is on the actual Virtual Display Buffer\n * @param area_p pointer to an area to refresh\n */\nstatic void lv_refr_area_part_vdb(const lv_area_t * area_p)\n{\n    lv_vdb_t * vdb_p = lv_vdb_get();\n    if(!vdb_p) {\n        LV_LOG_WARN(\"Invalid VDB pointer\");\n        return;\n    }\n    lv_obj_t * top_p;\n\n    /*Get the new mask from the original area and the act. VDB\n     It will be a part of 'area_p'*/\n    lv_area_t start_mask;\n    lv_area_intersect(&start_mask, area_p, &vdb_p->area);\n\n    /*Get the most top object which is not covered by others*/\n    top_p = lv_refr_get_top_obj(&start_mask, lv_scr_act());\n\n    /*Do the refreshing from the top object*/\n    lv_refr_obj_and_children(top_p, &start_mask);\n\n    /*Also refresh top and sys layer unconditionally*/\n    lv_refr_obj_and_children(lv_layer_top(), &start_mask);\n    lv_refr_obj_and_children(lv_layer_sys(), &start_mask);\n\n    /* In true double buffered mode flush only once when all areas were rendered.\n     * In normal mode flush after every area */\n#if LV_VDB_TRUE_DOUBLE_BUFFERED == 0\n    /*Flush the content of the VDB*/\n    lv_vdb_flush();\n#endif\n}\n\n#endif /*LV_VDB_SIZE == 0*/\n\n/**\n * Search the most top object which fully covers an area\n * @param area_p pointer to an area\n * @param obj the first object to start the searching (typically a screen)\n * @return\n */\nstatic lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj)\n{\n    lv_obj_t * i;\n    lv_obj_t * found_p = NULL;\n\n    /*If this object is fully cover the draw area check the children too */\n    if(lv_area_is_in(area_p, &obj->coords) && obj->hidden == 0) {\n        LL_READ(obj->child_ll, i)        {\n            found_p = lv_refr_get_top_obj(area_p, i);\n\n            /*If a children is ok then break*/\n            if(found_p != NULL) {\n                break;\n            }\n        }\n\n        /*If no better children check this object*/\n        if(found_p == NULL) {\n            lv_style_t * style = lv_obj_get_style(obj);\n            if(style->body.opa == LV_OPA_COVER &&\n                    obj->design_func(obj, area_p, LV_DESIGN_COVER_CHK) != false &&\n                    lv_obj_get_opa_scale(obj) == LV_OPA_COVER) {\n                found_p = obj;\n            }\n        }\n    }\n\n    return found_p;\n}\n\n/**\n * Make the refreshing from an object. Draw all its children and the youngers too.\n * @param top_p pointer to an objects. Start the drawing from it.\n * @param mask_p pointer to an area, the objects will be drawn only here\n */\nstatic void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p)\n{\n    /* Normally always will be a top_obj (at least the screen)\n     * but in special cases (e.g. if the screen has alpha) it won't.\n     * In this case use the screen directly */\n    if(top_p == NULL) top_p = lv_scr_act();\n\n    /*Refresh the top object and its children*/\n    lv_refr_obj(top_p, mask_p);\n\n    /*Draw the 'younger' sibling objects because they can be on top_obj */\n    lv_obj_t * par;\n    lv_obj_t * i;\n    lv_obj_t * border_p = top_p;\n\n    par = lv_obj_get_parent(top_p);\n\n    /*Do until not reach the screen*/\n    while(par != NULL) {\n        /*object before border_p has to be redrawn*/\n        i = lv_ll_get_prev(&(par->child_ll), border_p);\n\n        while(i != NULL) {\n            /*Refresh the objects*/\n            lv_refr_obj(i, mask_p);\n            i = lv_ll_get_prev(&(par->child_ll), i);\n        }\n\n        /*The new border will be there last parents,\n         *so the 'younger' brothers of parent will be refreshed*/\n        border_p = par;\n        /*Go a level deeper*/\n        par = lv_obj_get_parent(par);\n    }\n\n    /*Call the post draw design function of the parents of the to object*/\n    par = lv_obj_get_parent(top_p);\n    while(par != NULL) {\n        par->design_func(par, mask_p, LV_DESIGN_DRAW_POST);\n        par = lv_obj_get_parent(par);\n    }\n}\n\n/**\n * Refresh an object an all of its children. (Called recursively)\n * @param obj pointer to an object to refresh\n * @param mask_ori_p pointer to an area, the objects will be drawn only here\n */\nstatic void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p)\n{\n    /*Do not refresh hidden objects*/\n    if(obj->hidden != 0) return;\n\n    bool union_ok;  /* Store the return value of area_union */\n    /* Truncate the original mask to the coordinates of the parent\n     * because the parent and its children are visible only here */\n    lv_area_t obj_mask;\n    lv_area_t obj_ext_mask;\n    lv_area_t obj_area;\n    lv_coord_t ext_size = obj->ext_size;\n    lv_obj_get_coords(obj, &obj_area);\n    obj_area.x1 -= ext_size;\n    obj_area.y1 -= ext_size;\n    obj_area.x2 += ext_size;\n    obj_area.y2 += ext_size;\n    union_ok = lv_area_intersect(&obj_ext_mask, mask_ori_p, &obj_area);\n\n    /*Draw the parent and its children only if they ore on 'mask_parent'*/\n    if(union_ok != false) {\n\n        /* Redraw the object */\n        obj->design_func(obj, &obj_ext_mask, LV_DESIGN_DRAW_MAIN);\n        //usleep(5 * 1000);  /*DEBUG: Wait after every object draw to see the order of drawing*/\n\n\n        /*Create a new 'obj_mask' without 'ext_size' because the children can't be visible there*/\n        lv_obj_get_coords(obj, &obj_area);\n        union_ok = lv_area_intersect(&obj_mask, mask_ori_p, &obj_area);\n        if(union_ok != false) {\n            lv_area_t mask_child; /*Mask from obj and its child*/\n            lv_obj_t * child_p;\n            lv_area_t child_area;\n            LL_READ_BACK(obj->child_ll, child_p) {\n                lv_obj_get_coords(child_p, &child_area);\n                ext_size = child_p->ext_size;\n                child_area.x1 -= ext_size;\n                child_area.y1 -= ext_size;\n                child_area.x2 += ext_size;\n                child_area.y2 += ext_size;\n                /* Get the union (common parts) of original mask (from obj)\n                 * and its child */\n                union_ok = lv_area_intersect(&mask_child, &obj_mask, &child_area);\n\n                /*If the parent and the child has common area then refresh the child */\n                if(union_ok) {\n                    /*Refresh the next children*/\n                    lv_refr_obj(child_p, &mask_child);\n                }\n            }\n        }\n\n        /* If all the children are redrawn make 'post draw' design */\n        obj->design_func(obj, &obj_ext_mask, LV_DESIGN_DRAW_POST);\n\n    }\n}\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_core/lv_refr.h",
    "content": "/**\n * @file lv_refr.h\n *\n */\n\n#ifndef LV_REFR_H\n#define LV_REFR_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_obj.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Initialize the screen refresh subsystem\n */\nvoid lv_refr_init(void);\n\n/**\n * Redraw the invalidated areas now.\n * Normally the redrawing is periodically executed in `lv_task_handler` but a long blocking process can\n * prevent the call of `lv_task_handler`. In this case if the the GUI is updated in the process (e.g. progress bar)\n * this function can be called when the screen should be updated.\n */\nvoid lv_refr_now(void);\n\n/**\n * Invalidate an area\n * @param area_p pointer to area which should be invalidated\n */\nvoid lv_inv_area(const lv_area_t * area_p);\n\n/**\n * Set a function to call after every refresh to announce the refresh time and the number of refreshed pixels\n * @param cb pointer to a callback function (void my_refr_cb(uint32_t time_ms, uint32_t px_num))\n */\nvoid lv_refr_set_monitor_cb(void (*cb)(uint32_t, uint32_t));\n\n/**\n * Called when an area is invalidated to modify the coordinates of the area.\n * Special display controllers may require special coordinate rounding\n * @param cb pointer to the a function which will modify the area\n */\nvoid lv_refr_set_round_cb(void(*cb)(lv_area_t*));\n\n/**\n * Get the number of areas in the buffer\n * @return number of invalid areas\n */\nuint16_t lv_refr_get_buf_size(void);\n\n/**\n * Pop (delete) the last 'num' invalidated areas from the buffer\n * @param num number of areas to delete\n */\nvoid lv_refr_pop_from_buf(uint16_t num);\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_REFR_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_core/lv_style.c",
    "content": "/*\n * Copyright (c) 2018 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_obj.h\"\n#include \"../lv_misc/lv_mem.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define STYLE_MIX_MAX       256\n#define STYLE_MIX_SHIFT     8      /*log2(STYLE_MIX_MAX)*/\n\n#define VAL_PROP(v1, v2, r)   v1 + (((v2-v1) * r) >> STYLE_MIX_SHIFT)\n#define STYLE_ATTR_MIX(attr, r)   if(start->attr != end->attr) {res->attr = VAL_PROP(start->attr, end->attr, r);} else {res->attr = start->attr;}\n\n\n/**********************\n *      TYPEDEFS\n **********************/\n#if USE_LV_ANIMATION\ntypedef struct {\n    lv_style_t style_start;   /*Save not only pointers because can be same as 'style_anim' then it will be modified too*/\n    lv_style_t style_end;\n    lv_style_t * style_anim;\n    void (*end_cb)(void *);\n} lv_style_anim_dsc_t;\n#endif\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n#if USE_LV_ANIMATION\nstatic void style_animator(lv_style_anim_dsc_t * dsc, int32_t val);\nstatic void style_animation_common_end_cb(void * ptr);\n#endif\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nlv_style_t lv_style_scr;\nlv_style_t lv_style_transp;\nlv_style_t lv_style_transp_fit;\nlv_style_t lv_style_transp_tight;\nlv_style_t lv_style_plain;\nlv_style_t lv_style_plain_color;\nlv_style_t lv_style_pretty;\nlv_style_t lv_style_pretty_color;\nlv_style_t lv_style_btn_rel;\nlv_style_t lv_style_btn_pr;\nlv_style_t lv_style_btn_tgl_rel;\nlv_style_t lv_style_btn_tgl_pr;\nlv_style_t lv_style_btn_ina;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n *  Init the basic styles\n */\nvoid lv_style_init(void)\n{\n    /* Not White/Black/Gray colors are created by HSV model with\n     * HUE = 210*/\n\n    /*Screen style*/\n    lv_style_scr.glass = 0;\n    lv_style_scr.body.opa = LV_OPA_COVER;\n    lv_style_scr.body.main_color = LV_COLOR_BLACK;\n    lv_style_scr.body.grad_color = LV_COLOR_BLACK;\n    lv_style_scr.body.radius = 0;\n    lv_style_scr.body.padding.ver = LV_DPI / 12;\n    lv_style_scr.body.padding.hor = LV_DPI / 12;\n    lv_style_scr.body.padding.inner = LV_DPI / 12;\n\n    lv_style_scr.body.border.color = LV_COLOR_WHITE;\n    lv_style_scr.body.border.opa = LV_OPA_COVER;\n    lv_style_scr.body.border.width = 0;\n    lv_style_scr.body.border.part = LV_BORDER_FULL;\n\n    lv_style_scr.body.shadow.color = LV_COLOR_GRAY;\n    lv_style_scr.body.shadow.type = LV_SHADOW_FULL;\n    lv_style_scr.body.shadow.width = 0;\n\n    lv_style_scr.text.opa = LV_OPA_COVER;\n    lv_style_scr.text.color = LV_COLOR_HEX(0xFBFBFB);\n    lv_style_scr.text.font = LV_FONT_DEFAULT;\n    lv_style_scr.text.letter_space = 3; // Important\n    lv_style_scr.text.line_space = 2;\n\n    lv_style_scr.image.opa = LV_OPA_COVER;\n    lv_style_scr.image.color = LV_COLOR_MAKE(0x20, 0x20, 0x20);\n    lv_style_scr.image.intense = LV_OPA_TRANSP;\n\n    lv_style_scr.line.opa = LV_OPA_COVER;\n    lv_style_scr.line.color = LV_COLOR_MAKE(0x20, 0x20, 0x20);\n    lv_style_scr.line.width = 2;\n    lv_style_scr.line.rounded = 0;\n\n    /*Plain style (by default near the same as the screen style)*/\n    memcpy(&lv_style_plain, &lv_style_scr, sizeof(lv_style_t));\n\n    /*Plain color style*/\n    memcpy(&lv_style_plain_color, &lv_style_plain, sizeof(lv_style_t));\n    lv_style_plain_color.text.color = LV_COLOR_MAKE(0xf0, 0xf0, 0xf0);\n    lv_style_plain_color.image.color = LV_COLOR_MAKE(0xf0, 0xf0, 0xf0);\n    lv_style_plain_color.line.color = LV_COLOR_MAKE(0xf0, 0xf0, 0xf0);\n    lv_style_plain_color.body.main_color = LV_COLOR_MAKE(0x55, 0x96, 0xd8);\n    lv_style_plain_color.body.grad_color = lv_style_plain_color.body.main_color;\n\n    /*Pretty style */\n    memcpy(&lv_style_pretty, &lv_style_plain, sizeof(lv_style_t));\n    lv_style_pretty.text.color = LV_COLOR_MAKE(0x20, 0x20, 0x20);\n    lv_style_pretty.image.color = LV_COLOR_MAKE(0x20, 0x20, 0x20);\n    lv_style_pretty.line.color = LV_COLOR_MAKE(0x20, 0x20, 0x20);\n    lv_style_pretty.body.main_color = LV_COLOR_WHITE;\n    lv_style_pretty.body.grad_color = LV_COLOR_SILVER;\n    lv_style_pretty.body.radius = LV_DPI / 15;\n    lv_style_pretty.body.border.color = LV_COLOR_MAKE(0x40, 0x40, 0x40);\n    lv_style_pretty.body.border.width = LV_DPI / 50 >= 1 ? LV_DPI / 50  : 1;\n    lv_style_pretty.body.border.opa = LV_OPA_30;\n\n    /*Pretty color style*/\n    memcpy(&lv_style_pretty_color, &lv_style_pretty, sizeof(lv_style_t));\n    lv_style_pretty_color.text.color = LV_COLOR_MAKE(0xe0, 0xe0, 0xe0);\n    lv_style_pretty_color.image.color = LV_COLOR_MAKE(0xe0, 0xe0, 0xe0);\n    lv_style_pretty_color.line.color = LV_COLOR_MAKE(0xc0, 0xc0, 0xc0);\n    lv_style_pretty_color.body.main_color = LV_COLOR_MAKE(0x6b, 0x9a, 0xc7);\n    lv_style_pretty_color.body.grad_color = LV_COLOR_MAKE(0x2b, 0x59, 0x8b);\n    lv_style_pretty_color.body.border.color = LV_COLOR_MAKE(0x15, 0x2c, 0x42);\n\n    /*Transparent style*/\n    memcpy(&lv_style_transp, &lv_style_plain, sizeof(lv_style_t));\n    lv_style_transp.body.empty = 1;\n    lv_style_transp.glass = 1;\n    lv_style_transp.body.border.width = 0;\n\n    /*Transparent fitting size*/\n    memcpy(&lv_style_transp_fit, &lv_style_transp, sizeof(lv_style_t));\n    lv_style_transp_fit.body.padding.hor = 0;\n    lv_style_transp_fit.body.padding.ver = 0;\n\n    /*Transparent tight style*/\n    memcpy(&lv_style_transp_tight, &lv_style_transp_fit, sizeof(lv_style_t));\n    lv_style_transp_tight.body.padding.inner = 0;\n\n    /*Button released style*/\n    memcpy(&lv_style_btn_rel, &lv_style_plain, sizeof(lv_style_t));\n    lv_style_btn_rel.body.main_color = LV_COLOR_MAKE(0x76, 0xa2, 0xd0);\n    lv_style_btn_rel.body.grad_color = LV_COLOR_MAKE(0x19, 0x3a, 0x5d);\n    lv_style_btn_rel.body.radius = LV_DPI / 15;\n    lv_style_btn_rel.body.padding.hor = LV_DPI / 4;\n    lv_style_btn_rel.body.padding.ver = LV_DPI / 6;\n    lv_style_btn_rel.body.padding.inner = LV_DPI / 10;\n    lv_style_btn_rel.body.border.color = LV_COLOR_MAKE(0x0b, 0x19, 0x28);\n    lv_style_btn_rel.body.border.width = LV_DPI / 50 >= 1 ? LV_DPI / 50  : 1;\n    lv_style_btn_rel.body.border.opa = LV_OPA_70;\n    lv_style_btn_rel.body.shadow.color = LV_COLOR_GRAY;\n    lv_style_btn_rel.body.shadow.width = 0;\n    lv_style_btn_rel.text.color = LV_COLOR_MAKE(0xff, 0xff, 0xff);\n    lv_style_btn_rel.image.color = LV_COLOR_MAKE(0xff, 0xff, 0xff);\n\n    /*Button pressed style*/\n    memcpy(&lv_style_btn_pr, &lv_style_btn_rel, sizeof(lv_style_t));\n    lv_style_btn_pr.body.main_color = LV_COLOR_MAKE(0x33, 0x62, 0x94);\n    lv_style_btn_pr.body.grad_color = LV_COLOR_MAKE(0x10, 0x26, 0x3c);\n    lv_style_btn_pr.text.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6);\n    lv_style_btn_pr.image.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6);\n    lv_style_btn_pr.line.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6);\n\n    /*Button toggle released style*/\n    memcpy(&lv_style_btn_tgl_rel, &lv_style_btn_rel, sizeof(lv_style_t));\n    lv_style_btn_tgl_rel.body.main_color = LV_COLOR_MAKE(0x0a, 0x11, 0x22);\n    lv_style_btn_tgl_rel.body.grad_color = LV_COLOR_MAKE(0x37, 0x62, 0x90);\n    lv_style_btn_tgl_rel.body.border.color = LV_COLOR_MAKE(0x01, 0x07, 0x0d);\n    lv_style_btn_tgl_rel.text.color = LV_COLOR_MAKE(0xc8, 0xdd, 0xf4);\n    lv_style_btn_tgl_rel.image.color = LV_COLOR_MAKE(0xc8, 0xdd, 0xf4);\n    lv_style_btn_tgl_rel.line.color = LV_COLOR_MAKE(0xc8, 0xdd, 0xf4);\n\n    /*Button toggle pressed style*/\n    memcpy(&lv_style_btn_tgl_pr, &lv_style_btn_tgl_rel, sizeof(lv_style_t));\n    lv_style_btn_tgl_pr.body.main_color = LV_COLOR_MAKE(0x02, 0x14, 0x27);\n    lv_style_btn_tgl_pr.body.grad_color = LV_COLOR_MAKE(0x2b, 0x4c, 0x70);\n    lv_style_btn_tgl_pr.text.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6);\n    lv_style_btn_tgl_pr.image.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6);\n    lv_style_btn_tgl_pr.line.color = LV_COLOR_MAKE(0xa4, 0xb5, 0xc6);\n\n    /*Button inactive style*/\n    memcpy(&lv_style_btn_ina, &lv_style_btn_rel, sizeof(lv_style_t));\n    lv_style_btn_ina.body.main_color = LV_COLOR_MAKE(0xd8, 0xd8, 0xd8);\n    lv_style_btn_ina.body.grad_color = LV_COLOR_MAKE(0xd8, 0xd8, 0xd8);\n    lv_style_btn_ina.body.border.color = LV_COLOR_MAKE(0x90, 0x90, 0x90);\n    lv_style_btn_ina.text.color = LV_COLOR_MAKE(0x70, 0x70, 0x70);\n    lv_style_btn_ina.image.color = LV_COLOR_MAKE(0x70, 0x70, 0x70);\n    lv_style_btn_ina.line.color = LV_COLOR_MAKE(0x70, 0x70, 0x70);\n}\n\n\n/**\n * Copy a style to an other\n * @param dest pointer to the destination style\n * @param src pointer to the source style\n */\nvoid lv_style_copy(lv_style_t * dest, const lv_style_t * src)\n{\n    memcpy(dest, src, sizeof(lv_style_t));\n}\n\n\n/**\n * Mix two styles according to a given ratio\n * @param start start style\n * @param end end style\n * @param res store the result style here\n * @param ratio the ratio of mix [0..256]; 0: `start` style; 256: `end` style\n */\nvoid lv_style_mix(const lv_style_t * start, const lv_style_t * end, lv_style_t * res, uint16_t ratio)\n{\n    STYLE_ATTR_MIX(body.opa, ratio);\n    STYLE_ATTR_MIX(body.radius, ratio);\n    STYLE_ATTR_MIX(body.border.width, ratio);\n    STYLE_ATTR_MIX(body.border.opa, ratio);\n    STYLE_ATTR_MIX(body.shadow.width, ratio);\n    STYLE_ATTR_MIX(body.padding.hor, ratio);\n    STYLE_ATTR_MIX(body.padding.ver, ratio);\n    STYLE_ATTR_MIX(body.padding.inner, ratio);\n    STYLE_ATTR_MIX(text.line_space, ratio);\n    STYLE_ATTR_MIX(text.letter_space, ratio);\n    STYLE_ATTR_MIX(text.opa, ratio);\n    STYLE_ATTR_MIX(line.width, ratio);\n    STYLE_ATTR_MIX(line.opa, ratio);\n    STYLE_ATTR_MIX(image.intense, ratio);\n    STYLE_ATTR_MIX(image.opa, ratio);\n\n    lv_opa_t opa = ratio == STYLE_MIX_MAX ? LV_OPA_COVER : ratio;\n\n    res->body.main_color = lv_color_mix(end->body.main_color, start->body.main_color, opa);\n    res->body.grad_color = lv_color_mix(end->body.grad_color, start->body.grad_color, opa);\n    res->body.border.color = lv_color_mix(end->body.border.color, start->body.border.color, opa);\n    res->body.shadow.color = lv_color_mix(end->body.shadow.color, start->body.shadow.color, opa);\n    res->text.color = lv_color_mix(end->text.color, start->text.color, opa);\n    res->image.color = lv_color_mix(end->image.color, start->image.color, opa);\n    res->line.color = lv_color_mix(end->line.color, start->line.color, opa);\n\n    if(ratio < (STYLE_MIX_MAX >> 1)) {\n        res->body.empty = start->body.empty;\n        res->body.border.part = start->body.border.part;\n        res->glass = start->glass;\n        res->text.font = start->text.font;\n        res->body.shadow.type = start->body.shadow.type;\n        res->line.rounded = start->line.rounded;\n    } else {\n        res->body.empty = end->body.empty;\n        res->body.border.part = end->body.border.part;\n        res->glass = end->glass;\n        res->text.font = end->text.font;\n        res->body.shadow.type = end->body.shadow.type;\n        res->line.rounded = end->line.rounded;\n    }\n}\n\n#if USE_LV_ANIMATION\n\n/**\n * Create an animation from a pre-configured 'lv_style_anim_t' variable\n * @param anim pointer to a pre-configured 'lv_style_anim_t' variable (will be copied)\n * @return pointer to a descriptor. Really this variable will be animated. (Can be used in `lv_anim_del(dsc, NULL)`)\n */\nvoid * lv_style_anim_create(lv_style_anim_t * anim)\n{\n    lv_style_anim_dsc_t * dsc;\n    dsc = lv_mem_alloc(sizeof(lv_style_anim_dsc_t));\n    lv_mem_assert(dsc);\n    if(dsc == NULL) return NULL;\n\n    dsc->style_anim = anim->style_anim;\n    memcpy(&dsc->style_start, anim->style_start, sizeof(lv_style_t));\n    memcpy(&dsc->style_end, anim->style_end, sizeof(lv_style_t));\n    memcpy(dsc->style_anim, anim->style_start, sizeof(lv_style_t));\n    dsc->end_cb = anim->end_cb;\n\n\n    lv_anim_t a;\n    a.var = (void *)dsc;\n    a.start = 0;\n    a.end = STYLE_MIX_MAX;\n    a.fp = (lv_anim_fp_t)style_animator;\n    a.path = lv_anim_path_linear;\n    a.end_cb = style_animation_common_end_cb;\n    a.act_time = anim->act_time;\n    a.time = anim->time;\n    a.playback = anim->playback;\n    a.playback_pause = anim->playback_pause;\n    a.repeat = anim->repeat;\n    a.repeat_pause = anim->repeat_pause;\n\n    lv_anim_create(&a);\n\n    return dsc;\n}\n\n#endif\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n#if USE_LV_ANIMATION\n/**\n * Used by the style animations to set the values of a style according to start and end style.\n * @param dsc the 'animated variable' set by lv_style_anim_create()\n * @param val the current state of the animation between 0 and LV_STYLE_ANIM_RES\n */\nstatic void style_animator(lv_style_anim_dsc_t * dsc, int32_t val)\n{\n    const lv_style_t * start = &dsc->style_start;\n    const lv_style_t * end = &dsc->style_end;\n    lv_style_t * act = dsc->style_anim;\n\n    lv_style_mix(start, end, act, val);\n\n    lv_obj_report_style_mod(dsc->style_anim);\n}\n\n/**\n * Called when a style animation is ready\n * It called the user defined call back and free the allocated memories\n * @param ptr the 'animated variable' set by lv_style_anim_create()\n */\nstatic void style_animation_common_end_cb(void * ptr)\n{\n    lv_style_anim_dsc_t * dsc = ptr;    /*To avoid casting*/\n\n    if(dsc->end_cb) dsc->end_cb(dsc);\n\n    lv_mem_free(dsc);\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_core/lv_style.h",
    "content": "/**\n * @file lv_style.h\n *\n */\n\n#ifndef LV_STYLE_H\n#define LV_STYLE_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"../lv_misc/lv_color.h\"\n#include \"../lv_misc/lv_area.h\"\n#include \"../lv_misc/lv_font.h\"\n#include \"../lv_misc/lv_anim.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_RADIUS_CIRCLE  (LV_COORD_MAX)    /*A very big radius to always draw as circle*/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/*Border types (Use 'OR'ed values)*/\nenum\n{\n    LV_BORDER_NONE =     0x00,\n    LV_BORDER_BOTTOM =   0x01,\n    LV_BORDER_TOP =      0x02,\n    LV_BORDER_LEFT =     0x04,\n    LV_BORDER_RIGHT =    0x08,\n    LV_BORDER_FULL =     0x0F,\n    LV_BORDER_INTERNAL = 0x10,    /*FOR matrix-like objects (e.g. Button matrix)*/\n};\ntypedef uint8_t lv_border_part_t;\n\n/*Shadow types*/\nenum\n{\n    LV_SHADOW_BOTTOM = 0,\n    LV_SHADOW_FULL,\n};\ntypedef uint8_t lv_shadow_type_t;\n\ntypedef struct\n{\n    uint8_t glass :1;           /*1: Do not inherit this style*/\n\n    struct {\n        lv_color_t main_color;\n        lv_color_t grad_color;      /*`grad_color` will be removed in v6.0, use `aux_color` instead*/\n        lv_coord_t radius;\n        lv_opa_t opa;\n\n        struct {\n            lv_color_t color;\n            lv_coord_t width;\n            lv_border_part_t part;\n            lv_opa_t opa;\n        } border;\n\n        struct {\n            lv_color_t color;\n            lv_coord_t width;\n            lv_shadow_type_t type;\n        } shadow;\n\n        struct {\n            lv_coord_t ver;\n            lv_coord_t hor;\n            lv_coord_t inner;\n        } padding;\n\n        uint8_t empty :1;   /*Transparent background (border still drawn)*/\n    } body;\n\n\n    struct {\n        lv_color_t color;\n        const lv_font_t * font;\n        lv_coord_t letter_space;\n        lv_coord_t line_space;\n        lv_opa_t opa;\n    } text;\n\n    struct {\n        lv_color_t color;\n        lv_opa_t intense;\n        lv_opa_t opa;\n    } image;\n\n    struct {\n        lv_color_t color;\n        lv_coord_t width;\n        lv_opa_t opa;\n        uint8_t rounded :1;     /*1: rounded line endings*/\n    } line;\n} lv_style_t;\n\n#if USE_LV_ANIMATION\ntypedef struct {\n    const lv_style_t * style_start; /*Pointer to the starting style*/\n    const lv_style_t * style_end;   /*Pointer to the destination style*/\n    lv_style_t * style_anim;        /*Pointer to a style to animate*/\n    lv_anim_cb_t end_cb;            /*Call it when the animation is ready (NULL if unused)*/\n    int16_t time;                   /*Animation time in ms*/\n    int16_t act_time;               /*Current time in animation. Set to negative to make delay.*/\n    uint16_t playback_pause;        /*Wait before play back*/\n    uint16_t repeat_pause;          /*Wait before repeat*/\n    uint8_t playback :1;            /*When the animation is ready play it back*/\n    uint8_t repeat :1;              /*Repeat the animation infinitely*/\n} lv_style_anim_t;\n\n/* Example initialization\nlv_style_anim_t a;\na.style_anim = &style_to_anim;\na.style_start = &style_1;\na.style_end = &style_2;\na.act_time = 0;\na.time = 1000;\na.playback = 0;\na.playback_pause = 0;\na.repeat = 0;\na.repeat_pause = 0;\na.end_cb = NULL;\nlv_style_anim_create(&a);\n */\n#endif\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n *  Init the basic styles\n */\nvoid lv_style_init (void);\n\n/**\n * Copy a style to an other\n * @param dest pointer to the destination style\n * @param src pointer to the source style\n */\nvoid lv_style_copy(lv_style_t * dest, const lv_style_t * src);\n\n\n/**\n * Mix two styles according to a given ratio\n * @param start start style\n * @param end end style\n * @param res store the result style here\n * @param ratio the ratio of mix [0..256]; 0: `start` style; 256: `end` style\n */\nvoid lv_style_mix(const lv_style_t * start, const lv_style_t * end, lv_style_t * res, uint16_t ratio);\n\n#if USE_LV_ANIMATION\n\n/**\n * Create an animation from a pre-configured 'lv_style_anim_t' variable\n * @param anim pointer to a pre-configured 'lv_style_anim_t' variable (will be copied)\n * @return pointer to a descriptor. Really this variable will be animated. (Can be used in `lv_anim_del(dsc, NULL)`)\n */\nvoid * lv_style_anim_create(lv_style_anim_t * anim);\n#endif\n\n/*************************\n *    GLOBAL VARIABLES\n *************************/\nextern lv_style_t lv_style_scr;\nextern lv_style_t lv_style_transp;\nextern lv_style_t lv_style_transp_fit;\nextern lv_style_t lv_style_transp_tight;\nextern lv_style_t lv_style_plain;\nextern lv_style_t lv_style_plain_color;\nextern lv_style_t lv_style_pretty;\nextern lv_style_t lv_style_pretty_color;\nextern lv_style_t lv_style_btn_rel;\nextern lv_style_t lv_style_btn_pr;\nextern lv_style_t lv_style_btn_tgl_rel;\nextern lv_style_t lv_style_btn_tgl_pr;\nextern lv_style_t lv_style_btn_ina;\n\n/**********************\n *      MACROS\n **********************/\n\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_STYLE_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_core/lv_vdb.c",
    "content": "/**\n * @file lv_vdb.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_vdb.h\"\n#if LV_VDB_SIZE != 0\n\n#include \"../lv_hal/lv_hal_disp.h\"\n#include \"../lv_misc/lv_log.h\"\n#include <stddef.h>\n\n/*********************\n *      DEFINES\n *********************/\n#ifndef LV_ATTRIBUTE_FLUSH_READY\n#define LV_ATTRIBUTE_FLUSH_READY\n#endif\n\n#ifndef LV_ATTRIBUTE_MEM_ALIGN\n#define LV_ATTRIBUTE_MEM_ALIGN\n#endif\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\n/*Simple VDB*/\n#if LV_VDB_DOUBLE == 0\n#  if LV_VDB_ADR == 0\n/*If the buffer address is not specified  simply allocate it*/\nstatic LV_ATTRIBUTE_MEM_ALIGN uint8_t vdb_buf[LV_VDB_SIZE_IN_BYTES];\nstatic lv_vdb_t vdb = {.buf = (lv_color_t *)vdb_buf};\n#  else     /*LV_VDB_ADR != 0*/\n/*If the buffer address is specified use that address*/\nstatic lv_vdb_t vdb = {.buf = (lv_color_t *)LV_VDB_ADR};\n#  endif\n\n/*LV_VDB_DOUBLE != 0*/\n#else\n/*Double VDB*/\nstatic uint8_t vdb_active = 0;\n#  if LV_VDB_ADR == 0\n/*If the buffer address is not specified  simply allocate it*/\nstatic LV_ATTRIBUTE_MEM_ALIGN uint8_t vdb_buf1[LV_VDB_SIZE_IN_BYTES];\nstatic LV_ATTRIBUTE_MEM_ALIGN uint8_t vdb_buf2[LV_VDB_SIZE_IN_BYTES];\nstatic lv_vdb_t vdb[2] = {{.buf = (lv_color_t *) vdb_buf1}, {.buf = (lv_color_t *) vdb_buf2}};\n#  else /*LV_VDB_ADR != 0*/\n/*If the buffer address is specified use that address*/\nstatic lv_vdb_t vdb[2] = {{.buf = (lv_color_t *)LV_VDB_ADR}, {.buf = (lv_color_t *)LV_VDB2_ADR}};\n#  endif\n#endif\n\nstatic volatile bool vdb_flushing = false;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Get the 'vdb' variable or allocate one in LV_VDB_DOUBLE mode\n * @return pointer to a 'vdb' variable\n */\nlv_vdb_t * lv_vdb_get(void)\n{\n#if LV_VDB_DOUBLE == 0\n    /* Wait until VDB is flushing.\n     * (Until this user calls of 'lv_flush_ready()' in the display drivers's flush function*/\n    while(vdb_flushing);\n\n    return &vdb;\n#else\n    /*If already there is an active do nothing*/\n    return &vdb[vdb_active];\n#endif\n}\n\n/**\n * Flush the content of the VDB\n */\nvoid lv_vdb_flush(void)\n{\n    lv_vdb_t * vdb_act = lv_vdb_get();\n    if(!vdb_act) {\n        LV_LOG_WARN(\"Invalid VDB pointer\");\n        return;\n    }\n\n    /*Don't start a new flush while the previous is not finished*/\n#if LV_VDB_DOUBLE\n    while(vdb_flushing);\n#endif  /*LV_VDB_DOUBLE*/\n\n    vdb_flushing = true;\n\n    /*Flush the rendered content to the display*/\n    lv_disp_flush(vdb_act->area.x1, vdb_act->area.y1, vdb_act->area.x2, vdb_act->area.y2, vdb_act->buf);\n\n\n#if LV_VDB_DOUBLE\n    /*Make the other VDB active. The content of the current will be kept until the next flush*/\n    vdb_active++;\n    vdb_active &= 0x1;\n\n    /*If the screen is transparent initialize it when the new VDB is selected*/\n#  if LV_COLOR_SCREEN_TRANSP\n        memset(vdb[vdb_active].buf, 0x00, LV_VDB_SIZE_IN_BYTES);\n#  endif  /*LV_COLOR_SCREEN_TRANSP*/\n\n#endif  /*#if LV_VDB_DOUBLE*/\n\n}\n\n/**\n * Set the address of VDB buffer(s) manually. To use this set `LV_VDB_ADR` (and `LV_VDB2_ADR`) to `LV_VDB_ADR_INV` in `lv_conf.h`.\n * It should be called before `lv_init()`. The size of the buffer should be: `LV_VDB_SIZE_IN_BYTES`\n * @param buf1 address of the VDB.\n * @param buf2 address of the second buffer. `NULL` if `LV_VDB_DOUBLE  0`\n */\nvoid lv_vdb_set_adr(void * buf1, void * buf2)\n{\n#if LV_VDB_DOUBLE == 0\n    (void) buf2;   /*unused*/\n    vdb.buf = buf1;\n#else\n    vdb[0].buf = buf1;\n    vdb[1].buf = buf2;\n#endif\n}\n\n/**\n * Call in the display driver's  'disp_flush' function when the flushing is finished\n */\nLV_ATTRIBUTE_FLUSH_READY void lv_flush_ready(void)\n{\n    vdb_flushing = false;\n\n    /*If the screen is transparent initialize it when the flushing is ready*/\n#if LV_VDB_DOUBLE == 0 && LV_COLOR_SCREEN_TRANSP\n    memset(vdb_buf, 0x00, LV_VDB_SIZE_IN_BYTES);\n#endif\n}\n\n/**\n * Get currently active VDB, where the drawing happens. Used with `LV_VDB_DOUBLE  1`\n * @return pointer to the active VDB. If `LV_VDB_DOUBLE  0` give the single VDB\n */\nlv_vdb_t * lv_vdb_get_active(void)\n{\n#if LV_VDB_DOUBLE == 0\n    return &vdb;\n#else\n    return &vdb[vdb_active];\n#endif\n}\n\n/**\n * Get currently inactive VDB, which is being displayed or being flushed. Used with `LV_VDB_DOUBLE  1`\n * @return pointer to the inactive VDB. If `LV_VDB_DOUBLE  0` give the single VDB\n */\nlv_vdb_t * lv_vdb_get_inactive(void)\n{\n#if LV_VDB_DOUBLE == 0\n    return &vdb;\n#else\n    return &vdb[(vdb_active + 1) & 0x1];\n#endif\n}\n\n/**\n * Whether the flushing is in progress or not\n * @return true: flushing is in progress; false: flushing ready\n */\nbool lv_vdb_is_flushing(void)\n{\n    return vdb_flushing;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n#else\n\n/**\n * Just for compatibility\n */\nvoid lv_flush_ready(void)\n{\n    /*Do nothing. It is used only for VDB*/\n}\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_core/lv_vdb.h",
    "content": "/**\n * @file lv_vdb.h\n *\n */\n\n#ifndef LV_VDB_H\n#define LV_VDB_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if LV_VDB_SIZE != 0\n\n#include \"../lv_misc/lv_color.h\"\n#include \"../lv_misc/lv_area.h\"\n\n/*********************\n *      DEFINES\n *********************/\n/*Can be used in `lv_conf.h` the set an invalid address for the VDB. It should be replaced later by a valid address using `lv_vdb_set_adr()`*/\n#define LV_VDB_ADR_INV  8       /*8 is still too small to be valid but it's aligned on 64 bit machines as well*/\n\n#ifndef LV_VDB_PX_BPP\n#define LV_VDB_PX_BPP LV_COLOR_SIZE     /* Default is LV_COLOR_SIZE */\n#endif\n\n\n#if LV_VDB_TRUE_DOUBLE_BUFFERED && (LV_VDB_SIZE != LV_HOR_RES * LV_VER_RES || LV_VDB_DOUBLE == 0)\n#error \"With LV_VDB_TRUE_DOUBLE_BUFFERED: (LV_VDB_SIZE = LV_HOR_RES * LV_VER_RES and LV_VDB_DOUBLE = 1 is required\"\n#endif\n\n\n/* The size of VDB in bytes.\n * (LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3): just divide by 8 to convert bits to bytes\n * (((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0): add an extra byte to round up.\n *    E.g. if LV_VDB_SIZE = 10 and LV_VDB_PX_BPP = 1 -> 10 bits -> 2 bytes*/\n#define LV_VDB_SIZE_IN_BYTES ((LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3) + (((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0)\n\n/**********************\n *      TYPEDEFS\n **********************/\n\ntypedef struct\n{\n    lv_area_t area;\n    lv_color_t *buf;\n} lv_vdb_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Get the 'vdb' variable or allocate one in LV_VDB_DOUBLE mode\n * @return pointer to a 'vdb' variable\n */\nlv_vdb_t * lv_vdb_get(void);\n\n/**\n * Flush the content of the vdb\n */\nvoid lv_vdb_flush(void);\n\n/**\n * Set the address of VDB buffer(s) manually. To use this set `LV_VDB_ADR` (and `LV_VDB2_ADR`) to `LV_VDB_ADR_INV` in `lv_conf.h`.\n * It should be called before `lv_init()`. The size of the buffer should be: `LV_VDB_SIZE_IN_BYTES`\n * @param buf1 address of the VDB.\n * @param buf2 address of the second buffer. `NULL` if `LV_VDB_DOUBLE  0`\n */\nvoid lv_vdb_set_adr(void * buf1, void * buf2);\n\n/**\n * Call in the display driver's  'disp_flush' function when the flushing is finished\n */\nvoid lv_flush_ready(void);\n\n/**\n * Get currently active VDB, where the drawing happens. Used with `LV_VDB_DOUBLE  1`\n * @return pointer to the active VDB. If `LV_VDB_DOUBLE  0` give the single VDB\n */\nlv_vdb_t * lv_vdb_get_active(void);\n\n/**\n * Get currently inactive VDB, which is being displayed or being flushed. Used with `LV_VDB_DOUBLE  1`\n * @return pointer to the inactive VDB. If `LV_VDB_DOUBLE  0` give the single VDB\n */\nlv_vdb_t * lv_vdb_get_inactive(void);\n\n/**\n * Whether the flushing is in progress or not\n * @return true: flushing is in progress; false: flushing ready\n */\nbool lv_vdb_is_flushing(void);\n\n/**********************\n *      MACROS\n **********************/\n\n#else /*LV_VDB_SIZE != 0*/\n\n/*Just for compatibility*/\nvoid lv_flush_ready(void);\n#endif\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_VDB_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_draw/lv_draw.c",
    "content": "/**\n * @file lv_draw.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n\n#include <stdio.h>\n#include \"lv_draw.h\"\n#include \"lv_draw_rbasic.h\"\n#include \"lv_draw_vbasic.h\"\n#include \"../lv_misc/lv_fs.h\"\n#include \"../lv_misc/lv_math.h\"\n#include \"../lv_misc/lv_ufs.h\"\n#include \"../lv_objx/lv_img.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\n#if LV_VDB_SIZE != 0\nvoid (*const px_fp)(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) = lv_vpx;\nvoid (*const fill_fp)(const lv_area_t * coords, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) =  lv_vfill;\nvoid (*const letter_fp)(const lv_point_t * pos_p, const lv_area_t * mask, const lv_font_t * font_p, uint32_t letter, lv_color_t color, lv_opa_t opa) = lv_vletter;\nvoid (*const map_fp)(const lv_area_t * cords_p, const lv_area_t * mask_p,\n                     const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte,\n                     lv_color_t recolor, lv_opa_t recolor_opa) = lv_vmap;\n#else\nvoid (*const px_fp)(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) = lv_rpx;\nvoid (*const fill_fp)(const lv_area_t * coords, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) =  lv_rfill;\nvoid (*const letter_fp)(const lv_point_t * pos_p, const lv_area_t * mask, const lv_font_t * font_p, uint32_t letter, lv_color_t color, lv_opa_t opa) = lv_rletter;\nvoid (*const map_fp)(const lv_area_t * cords_p, const lv_area_t * mask_p,\n                     const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte,\n                     lv_color_t recolor, lv_opa_t recolor_opa) = lv_rmap;\n#endif\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n#if LV_ANTIALIAS != 0\n\n/**\n * Get the opacity of a pixel based it's position in a line segment\n * @param seg segment length\n * @param px_id position of  of a pixel which opacity should be get [0..seg-1]\n * @param base_opa the base opacity\n * @return the opacity of the given pixel\n */\nlv_opa_t lv_draw_aa_get_opa(lv_coord_t seg, lv_coord_t px_id, lv_opa_t base_opa)\n{\n    /* How to calculate the opacity of pixels on the edges which makes the anti-aliasing?\n     * For example we have a line like this (y = -0.5 * x):\n     *\n     *  | _ _\n     *    * * |\n     *\n     * Anti-aliased pixels come to the '*' characters\n     * Calculate what percentage of the pixels should be covered if real line (not rasterized) would be drawn:\n     * 1. A real line should start on (0;0) and end on (2;1)\n     * 2. So the line intersection coordinates on the first pixel: (0;0) (1;0.5) -> 25% covered pixel in average\n     * 3. For the second pixel: (1;0.5) (2;1) -> 75% covered pixel in average\n     * 4. The equation: (px_id * 2 + 1) / (segment_width * 2)\n     *                   segment_width: the line segment which is being anti-aliased (was 2 in the example)\n     *                   px_id: pixel ID from 0 to  (segment_width - 1)\n     *                   result: [0..1] coverage of the pixel\n     */\n\n    /*Accelerate the common segment sizes to avoid division*/\n    static const  lv_opa_t seg1[1] = {128};\n    static const  lv_opa_t seg2[2] = {64, 192};\n    static const  lv_opa_t seg3[3] = {42, 128, 212};\n    static const  lv_opa_t seg4[4] = {32, 96, 159, 223};\n    static const  lv_opa_t seg5[5] = {26,  76, 128, 178, 230};\n    static const  lv_opa_t seg6[6] = {21,  64, 106, 148, 191, 234};\n    static const  lv_opa_t seg7[7] = {18,  55, 91, 128, 164, 200, 237};\n    static const  lv_opa_t seg8[8] = {16,  48, 80, 112, 143, 175, 207, 239};\n\n    static const lv_opa_t * seg_map[] = {seg1, seg2, seg3, seg4,\n                                         seg5, seg6, seg7, seg8\n                                        };\n\n    if(seg == 0) return LV_OPA_TRANSP;\n    else if(seg < 8) return (uint32_t)((uint32_t)seg_map[seg - 1][px_id] * base_opa) >> 8;\n    else {\n        return ((px_id * 2 + 1) * base_opa) / (2 * seg);\n    }\n\n}\n\n/**\n * Add a vertical  anti-aliasing segment (pixels with decreasing opacity)\n * @param x start point x coordinate\n * @param y start point y coordinate\n * @param length length of segment (negative value to start from 0 opacity)\n * @param mask draw only in this area\n * @param color color of pixels\n * @param opa maximum opacity\n */\nvoid lv_draw_aa_ver_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa)\n{\n    bool aa_inv = false;\n    if(length < 0) {\n        aa_inv = true;\n        length = -length;\n    }\n\n    lv_coord_t i;\n    for(i = 0; i < length; i++) {\n        lv_opa_t px_opa = lv_draw_aa_get_opa(length, i, opa);\n        if(aa_inv) px_opa = opa - px_opa;\n        px_fp(x, y + i, mask, color, px_opa);\n    }\n}\n\n/**\n * Add a horizontal anti-aliasing segment (pixels with decreasing opacity)\n * @param x start point x coordinate\n * @param y start point y coordinate\n * @param length length of segment (negative value to start from 0 opacity)\n * @param mask draw only in this area\n * @param color color of pixels\n * @param opa maximum opacity\n */\nvoid lv_draw_aa_hor_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa)\n{\n    bool aa_inv = false;\n    if(length < 0) {\n        aa_inv = true;\n        length = -length;\n    }\n\n    lv_coord_t i;\n    for(i = 0; i < length; i++) {\n        lv_opa_t px_opa = lv_draw_aa_get_opa(length, i, opa);\n        if(aa_inv) px_opa = opa - px_opa;\n        px_fp(x + i, y, mask, color, px_opa);\n    }\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_draw/lv_draw.h",
    "content": "/**\n * @file lv_draw.h\n *\n */\n\n#ifndef LV_DRAW_H\n#define LV_DRAW_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#include \"../lv_core/lv_style.h\"\n#include \"../lv_misc/lv_txt.h\"\n\n/*********************\n *      DEFINES\n *********************/\n/*If image pixels contains alpha we need to know how much byte is a pixel*/\n#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8\n# define LV_IMG_PX_SIZE_ALPHA_BYTE   2\n#elif LV_COLOR_DEPTH == 16\n# define LV_IMG_PX_SIZE_ALPHA_BYTE   3\n#elif LV_COLOR_DEPTH == 32\n# define LV_IMG_PX_SIZE_ALPHA_BYTE   4\n#endif\n\n/**********************\n *      TYPEDEFS\n **********************/\n\nenum {\n    LV_IMG_SRC_VARIABLE,\n    LV_IMG_SRC_FILE,\n    LV_IMG_SRC_SYMBOL,\n    LV_IMG_SRC_UNKNOWN,\n};\ntypedef uint8_t lv_img_src_t;\n\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n#if LV_ANTIALIAS != 0\n\n/**\n * Get the opacity of a pixel based it's position in a line segment\n * @param seg segment length\n * @param px_id position of  of a pixel which opacity should be get [0..seg-1]\n * @param base_opa the base opacity\n * @return the opacity of the given pixel\n */\nlv_opa_t lv_draw_aa_get_opa(lv_coord_t seg, lv_coord_t px_id, lv_opa_t base_opa);\n\n/**\n * Add a vertical  anti-aliasing segment (pixels with decreasing opacity)\n * @param x start point x coordinate\n * @param y start point y coordinate\n * @param length length of segment (negative value to start from 0 opacity)\n * @param mask draw only in this area\n * @param color color of pixels\n * @param opa maximum opacity\n */\nvoid lv_draw_aa_ver_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa);\n\n/**\n * Add a horizontal anti-aliasing segment (pixels with decreasing opacity)\n * @param x start point x coordinate\n * @param y start point y coordinate\n * @param length length of segment (negative value to start from 0 opacity)\n * @param mask draw only in this area\n * @param color color of pixels\n * @param opa maximum opacity\n */\nvoid lv_draw_aa_hor_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa);\n#endif\n\n/**********************\n *  GLOBAL VARIABLES\n **********************/\nextern void (*const px_fp)(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_color_t color, lv_opa_t opa);\nextern void (*const fill_fp)(const lv_area_t * coords, const lv_area_t * mask, lv_color_t color, lv_opa_t opa);\nextern void (*const letter_fp)(const lv_point_t * pos_p, const lv_area_t * mask, const lv_font_t * font_p, uint32_t letter, lv_color_t color, lv_opa_t opa);\nextern void (*const map_fp)(const lv_area_t * cords_p, const lv_area_t * mask_p,\n                            const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte,\n                            lv_color_t recolor, lv_opa_t recolor_opa);\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   POST INCLUDES\n *********************/\n#include \"lv_draw_rect.h\"\n#include \"lv_draw_label.h\"\n#include \"lv_draw_img.h\"\n#include \"lv_draw_line.h\"\n#include \"lv_draw_triangle.h\"\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_DRAW_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_draw/lv_draw.mk",
    "content": "CSRCS += lv_draw_vbasic.c\nCSRCS += lv_draw_rbasic.c\nCSRCS += lv_draw.c\nCSRCS += lv_draw_rect.c\nCSRCS += lv_draw_label.c\nCSRCS += lv_draw_line.c\nCSRCS += lv_draw_img.c\nCSRCS += lv_draw_arc.c\nCSRCS += lv_draw_triangle.c\n\nDEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_draw\nVPATH += :$(LVGL_DIR)/lvgl/lv_draw\n\nCFLAGS += \"-I$(LVGL_DIR)/lvgl/lv_draw\"\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_draw/lv_draw_arc.c",
    "content": "/**\n * @file lv_draw_arc.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_draw_arc.h\"\n#include \"../lv_misc/lv_math.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic uint16_t fast_atan2(int x, int y);\nstatic void ver_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa);\nstatic void hor_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa);\nstatic bool deg_test_norm(uint16_t deg, uint16_t start, uint16_t end);\nstatic bool deg_test_inv(uint16_t deg, uint16_t start, uint16_t end);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Draw an arc. (Can draw pie too with great thickness.)\n * @param center_x the x coordinate of the center of the arc\n * @param center_y the y coordinate of the center of the arc\n * @param radius the radius of the arc\n * @param mask the arc will be drawn only in this mask\n * @param start_angle the start angle of the arc (0 deg on the bottom, 90 deg on the right)\n * @param end_angle the end angle of the arc\n * @param style style of the arc (`body.thickness`, `body.main_color`, `body.opa` is used)\n * @param opa_scale scale down all opacities by the factor\n */\nvoid lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, const lv_area_t * mask,\n                 uint16_t start_angle, uint16_t end_angle, const lv_style_t * style, lv_opa_t opa_scale)\n{\n    lv_coord_t thickness = style->line.width;\n    if(thickness > radius) thickness = radius;\n\n    lv_coord_t r_out = radius;\n    lv_coord_t r_in = r_out - thickness;\n    int16_t deg_base;\n    int16_t deg;\n    lv_coord_t x_start[4];\n    lv_coord_t x_end[4];\n\n    lv_color_t color = style->line.color;\n    lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8;\n\n\n    bool (*deg_test)(uint16_t, uint16_t, uint16_t);\n    if(start_angle <= end_angle) deg_test = deg_test_norm;\n    else deg_test = deg_test_inv;\n\n    if(deg_test(270, start_angle, end_angle))  hor_line(center_x - r_out + 1, center_y, mask, thickness - 1, color, opa);   // Left Middle\n    if(deg_test(90, start_angle, end_angle))   hor_line(center_x + r_in, center_y,  mask, thickness - 1, color, opa);       // Right Middle\n    if(deg_test(180, start_angle, end_angle))  ver_line(center_x, center_y - r_out + 1,  mask, thickness - 1, color, opa);  // Top Middle\n    if(deg_test(0, start_angle, end_angle))    ver_line(center_x, center_y + r_in,  mask, thickness - 1, color, opa);       // Bottom middle\n\n    uint32_t r_out_sqr = r_out * r_out;\n    uint32_t r_in_sqr = r_in * r_in;\n    int16_t xi;\n    int16_t yi;\n    for(yi = -r_out; yi < 0; yi++) {\n        x_start[0] = LV_COORD_MIN;\n        x_start[1] = LV_COORD_MIN;\n        x_start[2] = LV_COORD_MIN;\n        x_start[3] = LV_COORD_MIN;\n        x_end[0] = LV_COORD_MIN;\n        x_end[1] = LV_COORD_MIN;\n        x_end[2] = LV_COORD_MIN;\n        x_end[3] = LV_COORD_MIN;\n        for(xi = -r_out; xi < 0; xi++) {\n\n            uint32_t r_act_sqr = xi * xi + yi * yi;\n            if(r_act_sqr > r_out_sqr) continue;\n\n            deg_base =  fast_atan2(xi, yi) - 180;\n\n            deg = 180 + deg_base;\n            if(deg_test(deg, start_angle, end_angle)) {\n                if(x_start[0] == LV_COORD_MIN) x_start[0] = xi;\n            } else if(x_start[0] != LV_COORD_MIN && x_end[0] == LV_COORD_MIN) {\n                x_end[0] = xi - 1;\n            }\n\n            deg = 360 - deg_base;\n            if(deg_test(deg, start_angle, end_angle)) {\n                if(x_start[1] == LV_COORD_MIN) x_start[1] = xi;\n            } else if(x_start[1] != LV_COORD_MIN && x_end[1] == LV_COORD_MIN) {\n                x_end[1] = xi - 1;\n            }\n\n            deg = 180 - deg_base;\n            if(deg_test(deg, start_angle, end_angle)) {\n                if(x_start[2] == LV_COORD_MIN) x_start[2] = xi;\n            } else if(x_start[2] != LV_COORD_MIN && x_end[2] == LV_COORD_MIN) {\n                x_end[2] = xi - 1;\n            }\n\n            deg = deg_base;\n            if(deg_test(deg, start_angle, end_angle)) {\n                if(x_start[3] == LV_COORD_MIN) x_start[3] = xi;\n            } else if(x_start[3] != LV_COORD_MIN && x_end[3] == LV_COORD_MIN) {\n                x_end[3] = xi - 1;\n            }\n\n            if(r_act_sqr < r_in_sqr) break; /*No need to continue the iteration in x once we found the inner edge of the arc*/\n        }\n\n\n        if(x_start[0] != LV_COORD_MIN) {\n            if(x_end[0] == LV_COORD_MIN) x_end[0] = xi - 1;\n            hor_line(center_x + x_start[0], center_y + yi, mask, x_end[0] - x_start[0], color, opa);\n        }\n\n        if(x_start[1] != LV_COORD_MIN) {\n            if(x_end[1] == LV_COORD_MIN) x_end[1] = xi - 1;\n            hor_line(center_x + x_start[1], center_y - yi, mask, x_end[1] - x_start[1], color, opa);\n        }\n\n        if(x_start[2] != LV_COORD_MIN) {\n            if(x_end[2] == LV_COORD_MIN) x_end[2] = xi - 1;\n            hor_line(center_x - x_end[2], center_y + yi, mask, LV_MATH_ABS(x_end[2] - x_start[2]), color, opa);\n        }\n\n        if(x_start[3] != LV_COORD_MIN) {\n            if(x_end[3] == LV_COORD_MIN) x_end[3] = xi - 1;\n            hor_line(center_x - x_end[3], center_y - yi, mask, LV_MATH_ABS(x_end[3] - x_start[3]), color, opa);\n        }\n\n\n#if LV_ANTIALIAS\n        /*TODO*/\n\n#endif\n\n    }\n}\n\nstatic uint16_t fast_atan2(int x, int y)\n{\n    // Fast XY vector to integer degree algorithm - Jan 2011 www.RomanBlack.com\n    // Converts any XY values including 0 to a degree value that should be\n    // within +/- 1 degree of the accurate value without needing\n    // large slow trig functions like ArcTan() or ArcCos().\n    // NOTE! at least one of the X or Y values must be non-zero!\n    // This is the full version, for all 4 quadrants and will generate\n    // the angle in integer degrees from 0-360.\n    // Any values of X and Y are usable including negative values provided\n    // they are between -1456 and 1456 so the 16bit multiply does not overflow.\n\n    unsigned char negflag;\n    unsigned char tempdegree;\n    unsigned char comp;\n    unsigned int degree;     // this will hold the result\n    //signed int x;            // these hold the XY vector at the start\n    //signed int y;            // (and they will be destroyed)\n    unsigned int ux;\n    unsigned int uy;\n\n    // Save the sign flags then remove signs and get XY as unsigned ints\n    negflag = 0;\n    if(x < 0) {\n        negflag += 0x01;    // x flag bit\n        x = (0 - x);        // is now +\n    }\n    ux = x;                // copy to unsigned var before multiply\n    if(y < 0) {\n        negflag += 0x02;    // y flag bit\n        y = (0 - y);        // is now +\n    }\n    uy = y;                // copy to unsigned var before multiply\n\n    // 1. Calc the scaled \"degrees\"\n    if(ux > uy) {\n        degree = (uy * 45) / ux;   // degree result will be 0-45 range\n        negflag += 0x10;    // octant flag bit\n    } else {\n        degree = (ux * 45) / uy;   // degree result will be 0-45 range\n    }\n\n    // 2. Compensate for the 4 degree error curve\n    comp = 0;\n    tempdegree = degree;    // use an unsigned char for speed!\n    if(tempdegree > 22) {    // if top half of range\n        if(tempdegree <= 44) comp++;\n        if(tempdegree <= 41) comp++;\n        if(tempdegree <= 37) comp++;\n        if(tempdegree <= 32) comp++;  // max is 4 degrees compensated\n    } else { // else is lower half of range\n        if(tempdegree >= 2) comp++;\n        if(tempdegree >= 6) comp++;\n        if(tempdegree >= 10) comp++;\n        if(tempdegree >= 15) comp++;  // max is 4 degrees compensated\n    }\n    degree += comp;   // degree is now accurate to +/- 1 degree!\n\n    // Invert degree if it was X>Y octant, makes 0-45 into 90-45\n    if(negflag & 0x10) degree = (90 - degree);\n\n    // 3. Degree is now 0-90 range for this quadrant,\n    // need to invert it for whichever quadrant it was in\n    if(negflag & 0x02) { // if -Y\n        if(negflag & 0x01)   // if -Y -X\n            degree = (180 + degree);\n        else        // else is -Y +X\n            degree = (180 - degree);\n    } else { // else is +Y\n        if(negflag & 0x01)   // if +Y -X\n            degree = (360 - degree);\n    }\n    return degree;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\nstatic void ver_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa)\n{\n    lv_area_t area;\n    lv_area_set(&area, x, y, x, y + len);\n\n    fill_fp(&area, mask, color, opa);\n}\n\nstatic void hor_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa)\n{\n    lv_area_t area;\n    lv_area_set(&area, x, y, x + len, y);\n\n    fill_fp(&area, mask, color, opa);\n}\n\nstatic bool deg_test_norm(uint16_t deg, uint16_t start, uint16_t end)\n{\n    if(deg >= start && deg <= end) return true;\n    else return false;\n}\n\nstatic bool deg_test_inv(uint16_t deg, uint16_t start, uint16_t end)\n{\n    if(deg >= start || deg <= end) {\n        return true;\n    } else return false;\n}\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_draw/lv_draw_arc.h",
    "content": "/**\n * @file lv_draw_arc.h\n *\n */\n\n#ifndef LV_DRAW_ARC_H\n#define LV_DRAW_ARC_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_draw.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Draw an arc. (Can draw pie too with great thickness.)\n * @param center_x the x coordinate of the center of the arc\n * @param center_y the y coordinate of the center of the arc\n * @param radius the radius of the arc\n * @param mask the arc will be drawn only in this mask\n * @param start_angle the start angle of the arc (0 deg on the bottom, 90 deg on the right)\n * @param end_angle the end angle of the arc\n * @param style style of the arc (`body.thickness`, `body.main_color`, `body.opa` is used)\n * @param opa_scale scale down all opacities by the factor\n */\nvoid lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, const lv_area_t * mask,\n                 uint16_t start_angle, uint16_t end_angle, const lv_style_t * style, lv_opa_t opa_scale);\n\n/**********************\n *      MACROS\n **********************/\n\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_DRAW_ARC*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_draw/lv_draw_img.c",
    "content": "/**\n * @file lv_draw_img.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_draw_img.h\"\n#include \"../lv_misc/lv_fs.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mask,\n                                 const void * src, const lv_style_t * style, lv_opa_t opa_scale);\n\nstatic const uint8_t * lv_img_decoder_open(const void * src, const lv_style_t * style);\nstatic lv_res_t lv_img_decoder_read_line(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf);\nstatic void lv_img_decoder_close(void);\nstatic lv_res_t lv_img_built_in_decoder_line_alpha(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf);\nstatic lv_res_t lv_img_built_in_decoder_line_indexed(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic bool decoder_custom;\nstatic const void * decoder_src;\nstatic lv_img_src_t decoder_src_type;\nstatic lv_img_header_t decoder_header;\nstatic const lv_style_t * decoder_style;\n#if USE_LV_FILESYSTEM\nstatic lv_fs_file_t decoder_file;\n#endif\n#if LV_IMG_CF_INDEXED\nstatic lv_color_t decoder_index_map[256];\n#endif\n\nstatic lv_img_decoder_info_f_t lv_img_decoder_info_custom;\nstatic lv_img_decoder_open_f_t lv_img_decoder_open_custom;\nstatic lv_img_decoder_read_line_f_t lv_img_decoder_read_line_custom;\nstatic lv_img_decoder_close_f_t lv_img_decoder_close_custom;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Draw an image\n * @param coords the coordinates of the image\n * @param mask the image will be drawn only in this area\n * @param src pointer to a lv_color_t array which contains the pixels of the image\n * @param style style of the image\n * @param opa_scale scale down all opacities by the factor\n */\nvoid lv_draw_img(const lv_area_t * coords, const lv_area_t * mask,\n                 const void * src, const lv_style_t * style, lv_opa_t opa_scale)\n{\n    if(src == NULL) {\n        LV_LOG_WARN(\"Image draw: src is NULL\");\n        lv_draw_rect(coords, mask, &lv_style_plain, LV_OPA_COVER);\n        lv_draw_label(coords, mask, &lv_style_plain, LV_OPA_COVER, \"No\\ndata\", LV_TXT_FLAG_NONE, NULL);\n        return;\n    }\n\n    lv_res_t res;\n    res = lv_img_draw_core(coords, mask, src, style, opa_scale);\n\n    if(res ==  LV_RES_INV) {\n        LV_LOG_WARN(\"Image draw error\");\n        lv_draw_rect(coords, mask, &lv_style_plain, LV_OPA_COVER);\n        lv_draw_label(coords, mask, &lv_style_plain, LV_OPA_COVER, \"No\\ndata\", LV_TXT_FLAG_NONE, NULL);\n        return;\n    }\n}\n\n\n/**\n *\n * @param src\n * @param header\n * @param style\n * @return\n */\nlv_res_t lv_img_dsc_get_info(const char * src, lv_img_header_t * header)\n{\n    header->always_zero = 0;\n    /*Try to get info with the custom functions first*/\n    if(lv_img_decoder_info_custom) {\n        lv_res_t custom_res;\n        custom_res = lv_img_decoder_info_custom(src, header);\n        if(custom_res == LV_RES_OK) return LV_RES_OK;       /*Custom info has supported this source*/\n    }\n\n    lv_img_src_t src_type = lv_img_src_get_type(src);\n    if(src_type == LV_IMG_SRC_VARIABLE) {\n        header->w = ((lv_img_dsc_t *)src)->header.w;\n        header->h = ((lv_img_dsc_t *)src)->header.h;\n        header->cf = ((lv_img_dsc_t *)src)->header.cf;\n    }\n#if USE_LV_FILESYSTEM\n    else if(src_type == LV_IMG_SRC_FILE) {\n        lv_fs_file_t file;\n        lv_fs_res_t res;\n        uint32_t rn;\n        res = lv_fs_open(&file, src, LV_FS_MODE_RD);\n        if(res == LV_FS_RES_OK) {\n            res = lv_fs_read(&file, header, sizeof(lv_img_header_t), &rn);\n        }\n\n        /*Create a dummy header on fs error*/\n        if(res != LV_FS_RES_OK || rn != sizeof(lv_img_header_t)) {\n            header->w = LV_DPI;\n            header->h = LV_DPI;\n            header->cf = LV_IMG_CF_UNKOWN;\n        }\n\n        lv_fs_close(&file);\n    }\n#endif\n    else if(src_type == LV_IMG_SRC_SYMBOL) {\n        /*The size depend on the font but it is unknown here. It should be handled outside of the function*/\n        header->w = 1;\n        header->h = 1;\n        /* Symbols always have transparent parts. Important because of cover check in the design function.\n         * The actual value doesn't matter because lv_draw_label will draw it*/\n        header->cf  = LV_IMG_CF_ALPHA_1BIT;\n    } else {\n        LV_LOG_WARN(\"Image get info found unknown src type\");\n        return false;\n    }\n    return true;\n\n}\n\nuint8_t lv_img_color_format_get_px_size(lv_img_cf_t cf)\n{\n    uint8_t px_size = 0;\n\n    switch(cf) {\n        case LV_IMG_CF_UNKOWN:\n        case LV_IMG_CF_RAW:\n            px_size = 0;\n            break;\n        case LV_IMG_CF_TRUE_COLOR:\n        case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED:\n            px_size = LV_COLOR_SIZE;\n            break;\n        case LV_IMG_CF_TRUE_COLOR_ALPHA:\n            px_size = LV_IMG_PX_SIZE_ALPHA_BYTE << 3;\n            break;\n        case LV_IMG_CF_INDEXED_1BIT:\n        case LV_IMG_CF_ALPHA_1BIT:\n            px_size = 1;\n            break;\n        case LV_IMG_CF_INDEXED_2BIT:\n        case LV_IMG_CF_ALPHA_2BIT:\n            px_size = 2;\n            break;\n        case LV_IMG_CF_INDEXED_4BIT:\n        case LV_IMG_CF_ALPHA_4BIT:\n            px_size = 4;\n            break;\n        case LV_IMG_CF_INDEXED_8BIT:\n        case LV_IMG_CF_ALPHA_8BIT:\n            px_size = 8;\n            break;\n        default:\n            px_size = 0;\n            break;\n    }\n\n    return px_size;\n}\n\nbool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf)\n{\n    bool is_chroma_keyed = false;\n\n    switch(cf) {\n        case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED:\n        case LV_IMG_CF_RAW_CHROMA_KEYED:\n        case LV_IMG_CF_INDEXED_1BIT:\n        case LV_IMG_CF_INDEXED_2BIT:\n        case LV_IMG_CF_INDEXED_4BIT:\n        case LV_IMG_CF_INDEXED_8BIT:\n            is_chroma_keyed = true;\n            break;\n        default:\n            is_chroma_keyed = false;\n            break;\n    }\n\n    return is_chroma_keyed;\n}\n\n\nbool lv_img_color_format_has_alpha(lv_img_cf_t cf)\n{\n    bool has_alpha = false;\n\n    switch(cf) {\n        case LV_IMG_CF_TRUE_COLOR_ALPHA:\n        case LV_IMG_CF_RAW_ALPHA:\n        case LV_IMG_CF_ALPHA_1BIT:\n        case LV_IMG_CF_ALPHA_2BIT:\n        case LV_IMG_CF_ALPHA_4BIT:\n        case LV_IMG_CF_ALPHA_8BIT:\n            has_alpha = true;\n            break;\n        default:\n            has_alpha = false;\n            break;\n    }\n\n    return has_alpha;\n}\n\n/**\n * Get the type of an image source\n * @param src pointer to an image source:\n *  - pointer to an 'lv_img_t' variable (image stored internally and compiled into the code)\n *  - a path to a file (e.g. \"S:/folder/image.bin\")\n *  - or a symbol (e.g. SYMBOL_CLOSE)\n * @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKOWN\n */\nlv_img_src_t lv_img_src_get_type(const void * src)\n{\n    lv_img_src_t img_src_type = LV_IMG_SRC_UNKNOWN;\n\n    if(src == NULL) return img_src_type;\n    const uint8_t * u8_p = src;\n\n    /*The first byte shows the type of the image source*/\n    if(u8_p[0] >= 0x20 && u8_p[0] <= 0x7F) {\n        img_src_type = LV_IMG_SRC_FILE;     /*If it's an ASCII character then it's file name*/\n    } else if(u8_p[0] >= 0x80) {\n        img_src_type = LV_IMG_SRC_SYMBOL;   /*Symbols begins after 0x7F*/\n    } else {\n        img_src_type = LV_IMG_SRC_VARIABLE; /*`lv_img_dsc_t` is design to the first byte < 0x20*/\n    }\n\n    if (LV_IMG_SRC_UNKNOWN == img_src_type) {\n        LV_LOG_WARN(\"lv_img_src_get_type: unknown image type\");\n    }\n\n    return img_src_type;\n}\n\n/**\n * Set custom decoder functions. See the typdefs of the function typed above for more info about them\n * @param info_fp info get function\n * @param open_fp open function\n * @param read_fp read line function\n * @param close_fp clode function\n */\nvoid lv_img_decoder_set_custom(lv_img_decoder_info_f_t  info_fp, lv_img_decoder_open_f_t  open_fp,\n                               lv_img_decoder_read_line_f_t read_fp, lv_img_decoder_close_f_t close_fp)\n{\n    lv_img_decoder_info_custom = info_fp;\n    lv_img_decoder_open_custom = open_fp;\n    lv_img_decoder_read_line_custom = read_fp;\n    lv_img_decoder_close_custom = close_fp;\n}\n\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n\nstatic lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mask,\n                                 const void * src, const lv_style_t * style, lv_opa_t opa_scale)\n{\n\n    lv_area_t mask_com;    /*Common area of mask and coords*/\n    bool union_ok;\n    union_ok = lv_area_intersect(&mask_com, mask, coords);\n    if(union_ok == false) {\n        return LV_RES_OK;         /*Out of mask. There is nothing to draw so the image is drawn successfully.*/\n    }\n\n    lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->image.opa : (uint16_t)((uint16_t) style->image.opa * opa_scale) >> 8;\n\n    lv_img_header_t header;\n    lv_res_t header_res;\n    header_res = lv_img_dsc_get_info(src, &header);\n    if(header_res != LV_RES_OK) {\n        LV_LOG_WARN(\"Image draw can't get image info\");\n        lv_img_decoder_close();\n        return LV_RES_INV;\n    }\n\n    bool chroma_keyed = lv_img_color_format_is_chroma_keyed(header.cf);\n    bool alpha_byte = lv_img_color_format_has_alpha(header.cf);\n\n    const uint8_t * img_data = lv_img_decoder_open(src, style);\n    if(img_data == LV_IMG_DECODER_OPEN_FAIL) {\n        LV_LOG_WARN(\"Image draw cannot open the image resource\");\n        lv_img_decoder_close();\n        return LV_RES_INV;\n    }\n\n    /* The decoder open could open the image and gave the entire uncompressed image.\n     * Just draw it!*/\n    if(img_data) {\n        map_fp(coords, mask, img_data, opa, chroma_keyed, alpha_byte, style->image.color, style->image.intense);\n    }\n    /* The whole uncompressed image is not available. Try to read it line-by-line*/\n    else {\n        lv_coord_t width = lv_area_get_width(&mask_com);\n\n#if LV_COMPILER_VLA_SUPPORTED\n        uint8_t buf[(lv_area_get_width(&mask_com) * ((LV_COLOR_DEPTH >> 3) + 1))];\n#else\n        uint8_t buf[LV_HOR_RES * ((LV_COLOR_DEPTH >> 3) + 1)];  /*+1 because of the possible alpha byte*/\n#endif\n        lv_area_t line;\n        lv_area_copy(&line, &mask_com);\n        lv_area_set_height(&line, 1);\n        lv_coord_t x = mask_com.x1 - coords->x1;\n        lv_coord_t y = mask_com.y1 - coords->y1;\n        lv_coord_t row;\n        lv_res_t read_res;\n        for(row = mask_com.y1; row <= mask_com.y2; row++) {\n            read_res = lv_img_decoder_read_line(x, y, width, buf);\n            if(read_res != LV_RES_OK) {\n                lv_img_decoder_close();\n                LV_LOG_WARN(\"Image draw can't read the line\");\n                return LV_RES_INV;\n            }\n            map_fp(&line, mask, buf, opa, chroma_keyed, alpha_byte, style->image.color, style->image.intense);\n            line.y1++;\n            line.y2++;\n            y++;\n        }\n    }\n\n    lv_img_decoder_close();\n\n    return LV_RES_OK;\n}\n\n\nstatic const uint8_t * lv_img_decoder_open(const void * src, const lv_style_t * style)\n{\n    decoder_custom = false;\n\n    /*Try to open with the custom functions first*/\n    if(lv_img_decoder_open_custom) {\n        const uint8_t * custom_res;\n        custom_res = lv_img_decoder_open_custom(src, style);\n        if(custom_res != LV_IMG_DECODER_OPEN_FAIL) {\n            decoder_custom = true;  /*Mark that custom decoder function should be used for this img source.*/\n            return custom_res;      /*Custom open supported this source*/\n        }\n    }\n\n    decoder_src = src;\n    decoder_style = style;\n    decoder_src_type = lv_img_src_get_type(src);\n\n    lv_res_t header_res;\n    header_res = lv_img_dsc_get_info(src, &decoder_header);\n    if(header_res == LV_RES_INV) {\n        decoder_src = NULL;\n        decoder_src_type = LV_IMG_SRC_UNKNOWN;\n        LV_LOG_WARN(\"Built-in image decoder can't get the header info\");\n        return LV_IMG_DECODER_OPEN_FAIL;\n    }\n\n    /*Open the file if it's a file*/\n    if(decoder_src_type == LV_IMG_SRC_FILE) {\n#if USE_LV_FILESYSTEM\n        lv_fs_res_t res = lv_fs_open(&decoder_file, src, LV_FS_MODE_RD);\n        if(res != LV_FS_RES_OK) {\n            LV_LOG_WARN(\"Built-in image decoder can't open the file\");\n            return LV_IMG_DECODER_OPEN_FAIL;\n        }\n#else\n        LV_LOG_WARN(\"Image built-in decoder can read file because USE_LV_FILESYSTEM = 0\");\n        return LV_IMG_DECODER_OPEN_FAIL;\n#endif\n    }\n\n\n    /*Process the different color formats*/\n    lv_img_cf_t cf = decoder_header.cf;\n    if(cf == LV_IMG_CF_TRUE_COLOR ||\n            cf == LV_IMG_CF_TRUE_COLOR_ALPHA ||\n            cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {\n        if(decoder_src_type == LV_IMG_SRC_VARIABLE) {\n            /*In case of uncompressed formats if the image stored in the ROM/RAM simply give it's pointer*/\n            return ((lv_img_dsc_t *)decoder_src)->data;\n        } else {\n            /*If it's file it need to be read line by line later*/\n            return NULL;\n        }\n    } else if(cf == LV_IMG_CF_INDEXED_1BIT ||\n              cf == LV_IMG_CF_INDEXED_2BIT ||\n              cf == LV_IMG_CF_INDEXED_4BIT ||\n              cf == LV_IMG_CF_INDEXED_8BIT) {\n\n#if LV_IMG_CF_INDEXED\n#if USE_LV_FILESYSTEM\n        lv_color32_t palette_file[256];\n#endif\n\n        lv_color32_t * palette_p = NULL;\n        uint8_t px_size = lv_img_color_format_get_px_size(cf);\n        uint32_t palette_size = 1 << px_size;\n\n        if(decoder_src_type == LV_IMG_SRC_FILE) {\n            /*Read the palette from file*/\n#if USE_LV_FILESYSTEM\n            lv_fs_seek(&decoder_file, 4);   /*Skip the header*/\n            lv_fs_read(&decoder_file, palette_file, palette_size * sizeof(lv_color32_t), NULL);\n            palette_p = palette_file;\n#else\n            LV_LOG_WARN(\"Image built-in decoder can read the palette because USE_LV_FILESYSTEM = 0\");\n            return LV_IMG_DECODER_OPEN_FAIL;\n#endif\n        } else {\n            /*The palette begins in the beginning of the image data. Just point to it.*/\n            palette_p = (lv_color32_t *)((lv_img_dsc_t *)decoder_src)->data;\n        }\n\n        uint32_t i;\n        for(i = 0; i < palette_size; i++) {\n            decoder_index_map[i] = LV_COLOR_MAKE(palette_p[i].red, palette_p[i].green, palette_p[i].blue);\n        }\n        return NULL;\n#else\n        LV_LOG_WARN(\"Indexed (palette) images are not enabled in lv_conf.h. See LV_IMG_CF_INDEXED\");\n        return LV_IMG_DECODER_OPEN_FAIL;\n#endif\n    } else if(cf == LV_IMG_CF_ALPHA_1BIT ||\n              cf == LV_IMG_CF_ALPHA_2BIT ||\n              cf == LV_IMG_CF_ALPHA_4BIT ||\n              cf == LV_IMG_CF_ALPHA_8BIT) {\n#if LV_IMG_CF_ALPHA\n        return NULL;   /*Nothing to process*/\n#else\n        LV_LOG_WARN(\"Alpha indexed images are not enabled in lv_conf.h. See LV_IMG_CF_ALPHA\");\n        return LV_IMG_DECODER_OPEN_FAIL;\n#endif\n    } else {\n        LV_LOG_WARN(\"Image decoder open: unknown color format\")\n        return LV_IMG_DECODER_OPEN_FAIL;\n    }\n}\n\n\nstatic lv_res_t lv_img_decoder_read_line(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf)\n{\n    /*Try to read the line with the custom functions*/\n    if(decoder_custom) {\n        if(lv_img_decoder_read_line_custom) {\n            lv_res_t custom_res;\n            custom_res = lv_img_decoder_read_line_custom(x, y, len, buf);\n            return custom_res;\n        } else {\n            LV_LOG_WARN(\"Image open with custom decoder but read not supported\")\n        }\n        return LV_RES_INV;  /*It\"s an error if not returned earlier*/\n    }\n\n    if(decoder_src_type == LV_IMG_SRC_FILE) {\n#if USE_LV_FILESYSTEM\n        uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf);\n\n        lv_fs_res_t res;\n\n        if(decoder_header.cf == LV_IMG_CF_TRUE_COLOR ||\n                decoder_header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA ||\n                decoder_header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {\n            uint32_t pos = ((y * decoder_header.w + x) * px_size) >> 3;\n            pos += 4;    /*Skip the header*/\n            res = lv_fs_seek(&decoder_file, pos);\n            if(res != LV_FS_RES_OK) {\n                LV_LOG_WARN(\"Built-in image decoder seek failed\");\n                return false;\n            }\n            uint32_t btr = len * (px_size >> 3);\n            uint32_t br = 0;\n            lv_fs_read(&decoder_file, buf, btr, &br);\n            if(res != LV_FS_RES_OK || btr != br) {\n                LV_LOG_WARN(\"Built-in image decoder read failed\");\n                return false;\n            }\n        } else if(decoder_header.cf == LV_IMG_CF_ALPHA_1BIT ||\n                  decoder_header.cf == LV_IMG_CF_ALPHA_2BIT ||\n                  decoder_header.cf == LV_IMG_CF_ALPHA_4BIT ||\n                  decoder_header.cf == LV_IMG_CF_ALPHA_8BIT) {\n\n            lv_img_built_in_decoder_line_alpha(x, y, len, buf);\n        } else if(decoder_header.cf == LV_IMG_CF_INDEXED_1BIT ||\n                  decoder_header.cf == LV_IMG_CF_INDEXED_2BIT ||\n                  decoder_header.cf == LV_IMG_CF_INDEXED_4BIT ||\n                  decoder_header.cf == LV_IMG_CF_INDEXED_8BIT) {\n            lv_img_built_in_decoder_line_indexed(x, y, len, buf);\n        } else {\n            LV_LOG_WARN(\"Built-in image decoder read not supports the color format\");\n            return false;\n        }\n#else\n        LV_LOG_WARN(\"Image built-in decoder can't read file because USE_LV_FILESYSTEM = 0\");\n        return false;\n#endif\n    } else if(decoder_src_type == LV_IMG_SRC_VARIABLE) {\n        const lv_img_dsc_t * img_dsc = decoder_src;\n\n        if(img_dsc->header.cf == LV_IMG_CF_ALPHA_1BIT ||\n                img_dsc->header.cf == LV_IMG_CF_ALPHA_2BIT ||\n                img_dsc->header.cf == LV_IMG_CF_ALPHA_4BIT ||\n                img_dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {\n            lv_img_built_in_decoder_line_alpha(x, y, len, buf);\n        } else if(img_dsc->header.cf == LV_IMG_CF_INDEXED_1BIT ||\n                  img_dsc->header.cf == LV_IMG_CF_INDEXED_2BIT ||\n                  img_dsc->header.cf == LV_IMG_CF_INDEXED_4BIT ||\n                  img_dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) {\n            lv_img_built_in_decoder_line_indexed(x, y, len, buf);\n        } else {\n            LV_LOG_WARN(\"Built-in image decoder not supports the color format\");\n            return false;\n        }\n    }\n\n    return true;\n}\n\nstatic void lv_img_decoder_close(void)\n{\n    /*Try to close with the custom functions*/\n    if(decoder_custom) {\n        if(lv_img_decoder_close_custom) lv_img_decoder_close_custom();\n        return;\n    }\n\n    /*It was opened with built-in decoder*/\n    if(decoder_src) {\n#if USE_LV_FILESYSTEM\n        if(decoder_src_type == LV_IMG_SRC_FILE) {\n            lv_fs_close(&decoder_file);\n        }\n#endif\n        decoder_src_type = LV_IMG_SRC_UNKNOWN;\n        decoder_src = NULL;\n    }\n}\n\nstatic lv_res_t lv_img_built_in_decoder_line_alpha(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf)\n{\n\n#if LV_IMG_CF_ALPHA\n    const lv_opa_t alpha1_opa_table[2] =  {0, 255};                   /*Opacity mapping with bpp = 1 (Just for compatibility)*/\n    const lv_opa_t alpha2_opa_table[4] =  {0, 85, 170, 255};          /*Opacity mapping with bpp = 2*/\n    const lv_opa_t alpha4_opa_table[16] = {0,   17,  34,  51,         /*Opacity mapping with bpp = 4*/\n                                           68,  85,  102, 119,\n                                           136, 153, 170, 187,\n                                           204, 221, 238, 255\n                                          };\n\n    /*Simply fill the buffer with the color. Later only the alpha value will be modified.*/\n    lv_color_t bg_color = decoder_style->image.color;\n    lv_coord_t i;\n    for(i = 0; i < len; i++) {\n#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1\n        buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full;\n#elif LV_COLOR_DEPTH == 16\n        /*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/\n        buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full & 0xFF;\n        buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (bg_color.full >> 8) & 0xFF;\n#elif LV_COLOR_DEPTH == 32\n        *((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = bg_color.full;\n#else\n#error \"Invalid LV_COLOR_DEPTH. Check it in lv_conf.h\"\n#endif\n    }\n\n    const lv_opa_t * opa_table = NULL;\n    uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf);\n    uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/\n\n    lv_coord_t w = 0;\n    uint32_t ofs = 0;\n    int8_t pos = 0;\n    switch(decoder_header.cf) {\n        case LV_IMG_CF_ALPHA_1BIT:\n            w = (decoder_header.w >> 3);        /*E.g. w = 20 -> w = 2 + 1*/\n            if(decoder_header.w & 0x7) w++;\n            ofs += w * y + (x >> 3);      /*First pixel*/\n            pos = 7 - (x & 0x7);\n            opa_table = alpha1_opa_table;\n            break;\n        case LV_IMG_CF_ALPHA_2BIT:\n            w = (decoder_header.w >> 2);       /*E.g. w = 13 -> w = 3 + 1 (bytes)*/\n            if(decoder_header.w & 0x3) w++;\n            ofs += w * y + (x >> 2);      /*First pixel*/\n            pos = 6 - ((x & 0x3) * 2);\n            opa_table = alpha2_opa_table;\n            break;\n        case LV_IMG_CF_ALPHA_4BIT:\n            w = (decoder_header.w >> 1);       /*E.g. w = 13 -> w = 6 + 1 (bytes)*/\n            if(decoder_header.w & 0x1) w++;\n            ofs += w * y + (x >> 1);      /*First pixel*/\n            pos = 4 - ((x & 0x1) * 4);\n            opa_table = alpha4_opa_table;\n            break;\n        case LV_IMG_CF_ALPHA_8BIT:\n            w = decoder_header.w;              /*E.g. x = 7 -> w = 7 (bytes)*/\n            ofs += w * y + x;      /*First pixel*/\n            pos = 0;\n            break;\n    }\n\n#if USE_LV_FILESYSTEM\n# if LV_COMPILER_VLA_SUPPORTED\n    uint8_t fs_buf[w];\n# else\n    uint8_t fs_buf[LV_HOR_RES];\n# endif\n#endif\n    const uint8_t * data_tmp = NULL;\n    if(decoder_src_type == LV_IMG_SRC_VARIABLE) {\n        const lv_img_dsc_t * img_dsc = decoder_src;\n        data_tmp = img_dsc->data + ofs;\n    } else {\n#if USE_LV_FILESYSTEM\n        lv_fs_seek(&decoder_file, ofs + 4);     /*+4 to skip the header*/\n        lv_fs_read(&decoder_file, fs_buf, w, NULL);\n        data_tmp = fs_buf;\n#else\n        LV_LOG_WARN(\"Image built-in alpha line reader can't read file because USE_LV_FILESYSTEM = 0\");\n        data_tmp = NULL;        /*To avoid warnings*/\n        return LV_RES_INV;\n#endif\n    }\n\n\n    uint8_t byte_act = 0;\n    uint8_t val_act;\n    for(i = 0; i < len; i ++) {\n        val_act = (data_tmp[byte_act] & (mask << pos)) >> pos;\n\n        buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] =\n            decoder_header.cf == LV_IMG_CF_ALPHA_8BIT ? val_act : opa_table[val_act];\n\n        pos -= px_size;\n        if(pos < 0) {\n            pos = 8 - px_size;\n            data_tmp++;\n        }\n    }\n\n    return LV_RES_OK;\n\n#else\n    LV_LOG_WARN(\"Image built-in alpha line reader failed because LV_IMG_CF_ALPHA is 0 in lv_conf.h\");\n    return LV_RES_INV;\n#endif\n}\n\nstatic lv_res_t lv_img_built_in_decoder_line_indexed(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf)\n{\n\n#if LV_IMG_CF_INDEXED\n    uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf);\n    uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/\n\n    lv_coord_t w = 0;\n    int8_t pos = 0;\n    uint32_t ofs = 0;\n    switch(decoder_header.cf) {\n        case LV_IMG_CF_INDEXED_1BIT:\n            w = (decoder_header.w >> 3);       /*E.g. w = 20 -> w = 2 + 1*/\n            if(decoder_header.w & 0x7) w++;\n            ofs += w * y + (x >> 3);      /*First pixel*/\n            ofs += 8;                    /*Skip the palette*/\n            pos = 7 - (x & 0x7);\n            break;\n        case LV_IMG_CF_INDEXED_2BIT:\n            w = (decoder_header.w >> 2);       /*E.g. w = 13 -> w = 3 + 1 (bytes)*/\n            if(decoder_header.w & 0x3) w++;\n            ofs += w * y + (x >> 2);      /*First pixel*/\n            ofs += 16;                    /*Skip the palette*/\n            pos = 6 - ((x & 0x3) * 2);\n            break;\n        case LV_IMG_CF_INDEXED_4BIT:\n            w = (decoder_header.w >> 1);       /*E.g. w = 13 -> w = 6 + 1 (bytes)*/\n            if(decoder_header.w & 0x1) w++;\n            ofs += w * y + (x >> 1);      /*First pixel*/\n            ofs += 64;                    /*Skip the palette*/\n            pos = 4 - ((x & 0x1) * 4);\n            break;\n        case LV_IMG_CF_INDEXED_8BIT:\n            w = decoder_header.w;              /*E.g. x = 7 -> w = 7 (bytes)*/\n            ofs += w * y + x;              /*First pixel*/\n            ofs += 1024;                    /*Skip the palette*/\n            pos = 0;\n            break;\n    }\n\n#if USE_LV_FILESYSTEM\n# if LV_COMPILER_VLA_SUPPORTED\n    uint8_t fs_buf[w];\n# else\n    uint8_t fs_buf[LV_HOR_RES];\n# endif\n#endif\n    const uint8_t * data_tmp = NULL;\n    if(decoder_src_type == LV_IMG_SRC_VARIABLE) {\n        const lv_img_dsc_t * img_dsc = decoder_src;\n        data_tmp = img_dsc->data + ofs;\n    } else {\n#if USE_LV_FILESYSTEM\n        lv_fs_seek(&decoder_file, ofs + 4);     /*+4 to skip the header*/\n        lv_fs_read(&decoder_file, fs_buf, w, NULL);\n        data_tmp = fs_buf;\n#else\n        LV_LOG_WARN(\"Image built-in indexed line reader can't read file because USE_LV_FILESYSTEM = 0\");\n        data_tmp = NULL;        /*To avoid warnings*/\n        return LV_RES_INV;\n#endif\n    }\n\n    uint8_t byte_act = 0;\n    uint8_t val_act;\n    lv_coord_t i;\n    lv_color_t * cbuf = (lv_color_t *) buf;\n    for(i = 0; i < len; i ++) {\n        val_act = (data_tmp[byte_act] & (mask << pos)) >> pos;\n        cbuf[i] = decoder_index_map[val_act];\n\n        pos -= px_size;\n        if(pos < 0) {\n            pos = 8 - px_size;\n            data_tmp++;\n        }\n    }\n\n    return LV_RES_OK;\n#else\n    LV_LOG_WARN(\"Image built-in indexed line reader failed because LV_IMG_CF_INDEXED is 0 in lv_conf.h\");\n    return LV_RES_INV;\n#endif\n}\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_draw/lv_draw_img.h",
    "content": "/**\n * @file lv_draw_img.h\n *\n */\n\n#ifndef LV_DRAW_IMG_H\n#define LV_DRAW_IMG_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_draw.h\"\n#include \"../lv_core/lv_obj.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_IMG_DECODER_OPEN_FAIL    ((void*)(-1))\n\n/**********************\n *      TYPEDEFS\n **********************/\nstruct _lv_img_t;\n\ntypedef struct {\n\n    /* The first 8 bit is very important to distinguish the different source types.\n     * For more info see `lv_img_get_src_type()` in lv_img.c */\n    uint32_t cf           :5;    /* Color format: See `lv_img_color_format_t`*/\n    uint32_t always_zero  :3;    /*It the upper bits of the first byte. Always zero to look like a non-printable character*/\n\n    uint32_t reserved     :2;   /*Reserved to be used later*/\n\n    uint32_t w:11;              /*Width of the image map*/\n    uint32_t h:11;              /*Height of the image map*/\n} lv_img_header_t;\n\n/*Image color format*/\nenum {\n    LV_IMG_CF_UNKOWN = 0,\n\n    LV_IMG_CF_RAW,                  /*Contains the file as it is. Needs custom decoder function*/\n    LV_IMG_CF_RAW_ALPHA,            /*Contains the file as it is. The image has alpha. Needs custom decoder function*/\n    LV_IMG_CF_RAW_CHROMA_KEYED,     /*Contains the file as it is. The image is chroma keyed. Needs custom decoder function*/\n\n    LV_IMG_CF_TRUE_COLOR,           /*Color format and depth should match with LV_COLOR settings*/\n    LV_IMG_CF_TRUE_COLOR_ALPHA,     /*Same as `LV_IMG_CF_TRUE_COLOR` but every pixel has an alpha byte*/\n    LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED,  /*Same as `LV_IMG_CF_TRUE_COLOR` but LV_COLOR_TRANSP pixels will be transparent*/\n\n    LV_IMG_CF_INDEXED_1BIT,         /*Can have 2 different colors in a palette (always chroma keyed)*/\n    LV_IMG_CF_INDEXED_2BIT,         /*Can have 4 different colors in a palette (always chroma keyed)*/\n    LV_IMG_CF_INDEXED_4BIT,         /*Can have 16 different colors in a palette (always chroma keyed)*/\n    LV_IMG_CF_INDEXED_8BIT,         /*Can have 256 different colors in a palette (always chroma keyed)*/\n\n    LV_IMG_CF_ALPHA_1BIT,           /*Can have one color and it can be drawn or not*/\n    LV_IMG_CF_ALPHA_2BIT,           /*Can have one color but 4 different alpha value*/\n    LV_IMG_CF_ALPHA_4BIT,           /*Can have one color but 16 different alpha value*/\n    LV_IMG_CF_ALPHA_8BIT,           /*Can have one color but 256 different alpha value*/\n};\ntypedef uint8_t lv_img_cf_t;\n\n/* Image header it is compatible with\n * the result image converter utility*/\ntypedef struct\n{\n    lv_img_header_t header;\n    uint32_t data_size;\n    const uint8_t * data;\n} lv_img_dsc_t;\n\n/* Decoder function definitions */\n\n\n/**\n * Get info from an image and store in the `header`\n * @param src the image source. Can be a pointer to a C array or a file name (Use `lv_img_src_get_type` to determine the type)\n * @param header store the info here\n * @return LV_RES_OK: info written correctly; LV_RES_INV: failed\n */\ntypedef lv_res_t (*lv_img_decoder_info_f_t)(const void * src, lv_img_header_t * header);\n\n/**\n * Open an image for decoding. Prepare it as it is required to read it later\n * @param src the image source. Can be a pointer to a C array or a file name (Use `lv_img_src_get_type` to determine the type)\n * @param style the style of image (maybe it will be required to determine a color or something)\n * @return there are 3 possible return values:\n *    1) buffer with the decoded image\n *    2) if can decode the whole image NULL. decoder_read_line will be called to read the image line-by-line\n *    3) LV_IMG_DECODER_OPEN_FAIL if the image format is unknown to the decoder or an error occurred\n */\ntypedef const uint8_t * (*lv_img_decoder_open_f_t)(const void * src, const lv_style_t * style);\n\n/**\n * Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`.\n * Required only if the \"open\" function can't return with the whole decoded pixel array.\n * @param x start x coordinate\n * @param y startt y coordinate\n * @param len number of pixels to decode\n * @param buf a buffer to store the decoded pixels\n * @return LV_RES_OK: ok; LV_RES_INV: failed\n */\ntypedef lv_res_t (*lv_img_decoder_read_line_f_t)(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf);\n\n/**\n * Close the pending decoding. Free resources etc.\n */\ntypedef void (*lv_img_decoder_close_f_t)(void);\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Draw an image\n * @param coords the coordinates of the image\n * @param mask the image will be drawn only in this area\n * @param src pointer to a lv_color_t array which contains the pixels of the image\n * @param style style of the image\n * @param opa_scale scale down all opacities by the factor\n */\nvoid lv_draw_img(const lv_area_t * coords, const lv_area_t * mask,\n                 const void * src, const lv_style_t * style, lv_opa_t opa_scale);\n\n\n/**\n * Get the type of an image source\n * @param src pointer to an image source:\n *  - pointer to an 'lv_img_t' variable (image stored internally and compiled into the code)\n *  - a path to a file (e.g. \"S:/folder/image.bin\")\n *  - or a symbol (e.g. SYMBOL_CLOSE)\n * @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKOWN\n */\nlv_img_src_t lv_img_src_get_type(const void * src);\n\n/**\n * Set custom decoder functions. See the typdefs of the function typed above for more info about them\n * @param info_fp info get function\n * @param open_fp open function\n * @param read_fp read line function\n * @param close_fp clode function\n */\nvoid lv_img_decoder_set_custom(lv_img_decoder_info_f_t  info_fp, lv_img_decoder_open_f_t  open_fp,\n                               lv_img_decoder_read_line_f_t read_fp, lv_img_decoder_close_f_t close_fp);\n\nlv_res_t lv_img_dsc_get_info(const char * src, lv_img_header_t * header);\n\nuint8_t lv_img_color_format_get_px_size(lv_img_cf_t cf);\n\nbool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf);\n\nbool lv_img_color_format_has_alpha(lv_img_cf_t cf);\n\n\n/**********************\n *      MACROS\n **********************/\n\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_TEMPL_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_draw/lv_draw_label.c",
    "content": "/**\n * @file lv_draw_label.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_draw_label.h\"\n#include \"lv_draw_rbasic.h\"\n#include \"../lv_misc/lv_math.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define LABEL_RECOLOR_PAR_LENGTH    6\n\n/**********************\n *      TYPEDEFS\n **********************/\nenum {\n    CMD_STATE_WAIT,\n    CMD_STATE_PAR,\n    CMD_STATE_IN,\n};\ntypedef uint8_t cmd_state_t;\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic uint8_t hex_char_to_num(char hex);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Write a text\n * @param coords coordinates of the label\n * @param mask the label will be drawn only in this area\n * @param style pointer to a style\n * @param opa_scale scale down all opacities by the factor\n * @param txt 0 terminated text to write\n * @param flag settings for the text from 'txt_flag_t' enum\n * @param offset text offset in x and y direction (NULL if unused)\n *\n */\nvoid lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale,\n                   const char * txt, lv_txt_flag_t flag, lv_point_t * offset)\n{\n    const lv_font_t * font = style->text.font;\n    lv_coord_t w;\n    if((flag & LV_TXT_FLAG_EXPAND) == 0) {\n        /*Normally use the label's width as width*/\n        w = lv_area_get_width(coords);\n    } else {\n        /*If EXAPND is enabled then not limit the text's width to the object's width*/\n        lv_point_t p;\n        lv_txt_get_size(&p, txt, style->text.font, style->text.letter_space, style->text.line_space, LV_COORD_MAX, flag);\n        w = p.x;\n    }\n\n    lv_coord_t line_height = lv_font_get_height(font) + style->text.line_space;\n\n\n    /*Init variables for the first line*/\n    lv_coord_t line_width = 0;\n    lv_point_t pos;\n    pos.x = coords->x1;\n    pos.y = coords->y1;\n\n    lv_coord_t x_ofs = 0;\n    lv_coord_t y_ofs = 0;\n    if(offset != NULL) {\n        x_ofs = offset->x;\n        y_ofs = offset->y;\n        pos.y += y_ofs;\n    }\n\n    uint32_t line_start = 0;\n    uint32_t line_end = lv_txt_get_next_line(txt, font, style->text.letter_space, w, flag);\n\n    /*Go the first visible line*/\n    while(pos.y + line_height < mask->y1) {\n        /*Go to next line*/\n        line_start = line_end;\n        line_end += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, w, flag);\n        pos.y += line_height;\n\n        if(txt[line_start] == '\\0') return;\n    }\n\n    /*Align to middle*/\n    if(flag & LV_TXT_FLAG_CENTER) {\n        line_width = lv_txt_get_width(&txt[line_start], line_end - line_start,\n                                      font, style->text.letter_space, flag);\n\n        pos.x += (lv_area_get_width(coords) - line_width) / 2;\n\n    }\n    /*Align to the right*/\n    else if(flag & LV_TXT_FLAG_RIGHT) {\n        line_width = lv_txt_get_width(&txt[line_start], line_end - line_start,\n                                      font, style->text.letter_space, flag);\n        pos.x += lv_area_get_width(coords) - line_width;\n    }\n\n\n    lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->text.opa : (uint16_t)((uint16_t) style->text.opa * opa_scale) >> 8;\n\n    cmd_state_t cmd_state = CMD_STATE_WAIT;\n    uint32_t i;\n    uint16_t par_start = 0;\n    lv_color_t recolor;\n    lv_coord_t letter_w;\n\n    /*Real draw need a background color for higher bpp letter*/\n#if LV_VDB_SIZE == 0\n    lv_rletter_set_background(style->body.main_color);\n#endif\n\n\n    /*Write out all lines*/\n    while(txt[line_start] != '\\0') {\n        if(offset != NULL) {\n            pos.x += x_ofs;\n        }\n        /*Write all letter of a line*/\n        cmd_state = CMD_STATE_WAIT;\n        i = line_start;\n        uint32_t letter;\n        while(i < line_end) {\n            letter = lv_txt_encoded_next(txt, &i);\n\n            /*Handle the re-color command*/\n            if((flag & LV_TXT_FLAG_RECOLOR) != 0) {\n                if(letter == (uint32_t)LV_TXT_COLOR_CMD[0]) {\n                    if(cmd_state == CMD_STATE_WAIT) { /*Start char*/\n                        par_start = i;\n                        cmd_state = CMD_STATE_PAR;\n                        continue;\n                    } else if(cmd_state == CMD_STATE_PAR) { /*Other start char in parameter escaped cmd. char */\n                        cmd_state = CMD_STATE_WAIT;\n                    } else if(cmd_state == CMD_STATE_IN) { /*Command end */\n                        cmd_state = CMD_STATE_WAIT;\n                        continue;\n                    }\n                }\n\n                /*Skip the color parameter and wait the space after it*/\n                if(cmd_state == CMD_STATE_PAR) {\n                    if(letter == ' ') {\n                        /*Get the parameter*/\n                        if(i - par_start == LABEL_RECOLOR_PAR_LENGTH + 1) {\n                            char buf[LABEL_RECOLOR_PAR_LENGTH + 1];\n                            memcpy(buf, &txt[par_start], LABEL_RECOLOR_PAR_LENGTH);\n                            buf[LABEL_RECOLOR_PAR_LENGTH] = '\\0';\n                            int r, g, b;\n                            r = (hex_char_to_num(buf[0]) << 4) + hex_char_to_num(buf[1]);\n                            g = (hex_char_to_num(buf[2]) << 4) + hex_char_to_num(buf[3]);\n                            b = (hex_char_to_num(buf[4]) << 4) + hex_char_to_num(buf[5]);\n                            recolor = LV_COLOR_MAKE(r, g, b);\n                        } else {\n                            recolor.full = style->text.color.full;\n                        }\n                        cmd_state = CMD_STATE_IN; /*After the parameter the text is in the command*/\n                    }\n                    continue;\n                }\n            }\n\n            lv_color_t color = style->text.color;\n\n            if(cmd_state == CMD_STATE_IN) color = recolor;\n\n            letter_fp(&pos, mask, font, letter, color, opa);\n            letter_w = lv_font_get_width(font, letter);\n\n            if(letter_w > 0){\n                pos.x += letter_w + style->text.letter_space;\n            }\n        }\n        /*Go to next line*/\n        line_start = line_end;\n        line_end += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, w, flag);\n\n        pos.x = coords->x1;\n        /*Align to middle*/\n        if(flag & LV_TXT_FLAG_CENTER) {\n            line_width = lv_txt_get_width(&txt[line_start], line_end - line_start,\n                                          font, style->text.letter_space, flag);\n\n            pos.x += (lv_area_get_width(coords) - line_width) / 2;\n\n        }\n        /*Align to the right*/\n        else if(flag & LV_TXT_FLAG_RIGHT) {\n            line_width = lv_txt_get_width(&txt[line_start], line_end - line_start,\n                                          font, style->text.letter_space, flag);\n            pos.x += lv_area_get_width(coords) - line_width;\n        }\n\n        /*Go the next line position*/\n        pos.y += line_height;\n\n        if(pos.y > mask->y2) return;\n    }\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Convert a hexadecimal characters to a number (0..15)\n * @param hex Pointer to a hexadecimal character (0..9, A..F)\n * @return the numerical value of `hex` or 0 on error\n */\nstatic uint8_t hex_char_to_num(char hex)\n{\n    uint8_t result = 0;\n\n    if(hex >= '0' && hex <= '9') {\n        result = hex - '0';\n    }\n    else {\n        if(hex >= 'a') hex -= 'a' - 'A';    /*Convert to upper case*/\n\n        switch(hex) {\n            case 'A':\n                result = 10;\n                break;\n            case 'B':\n                result = 11;\n                break;\n            case 'C':\n                result = 12;\n                break;\n            case 'D':\n                result = 13;\n                break;\n            case 'E':\n                result = 14;\n                break;\n            case 'F':\n                result = 15;\n                break;\n            default:\n                result = 0;\n                break;\n        }\n    }\n\n    return result;\n}\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_draw/lv_draw_label.h",
    "content": "/**\n * @file lv_draw_label.h\n *\n */\n\n#ifndef LV_DRAW_LABEL_H\n#define LV_DRAW_LABEL_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_draw.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Write a text\n * @param coords coordinates of the label\n * @param mask the label will be drawn only in this area\n * @param style pointer to a style\n * @param opa_scale scale down all opacities by the factor\n * @param txt 0 terminated text to write\n * @param flag settings for the text from 'txt_flag_t' enum\n * @param offset text offset in x and y direction (NULL if unused)\n *\n */\nvoid lv_draw_label(const lv_area_t * coords,const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale,\n                   const char * txt, lv_txt_flag_t flag, lv_point_t * offset);\n\n/**********************\n *      MACROS\n **********************/\n\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_DRAW_LABEL_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_draw/lv_draw_line.c",
    "content": "/**\n * @file lv_draw_line.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include <stdio.h>\n#include \"lv_draw.h\"\n#include \"../lv_misc/lv_math.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#if LV_COMPILER_VLA_SUPPORTED == 0\n#define LINE_MAX_WIDTH        64\n#endif\n\n/**********************\n *      TYPEDEFS\n **********************/\n\ntypedef struct {\n    lv_point_t p1;\n    lv_point_t p2;\n    lv_point_t p_act;\n    lv_coord_t dx;\n    lv_coord_t sx;      /*-1: x1 < x2; 1: x2 >= x1*/\n    lv_coord_t dy;\n    lv_coord_t sy;      /*-1: y1 < y2; 1: y2 >= y1*/\n    lv_coord_t err;\n    lv_coord_t e2;\n    bool hor;   /*Rather horizontal or vertical*/\n} line_draw_t;\n\ntypedef struct {\n    lv_coord_t width;\n    lv_coord_t width_1;\n    lv_coord_t width_half;\n} line_width_t;\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic void line_draw_hor(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);\nstatic void line_draw_ver(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);\nstatic void line_draw_skew(line_draw_t * main_line, bool dir_ori, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);\nstatic void line_init(line_draw_t * line, const lv_point_t * p1, const lv_point_t * p2);\nstatic bool line_next(line_draw_t * line);\nstatic bool line_next_y(line_draw_t * line);\nstatic bool line_next_x(line_draw_t * line);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Draw a line\n * @param point1 first point of the line\n * @param point2 second point of the line\n * @param mask the line will be drawn only on this area\n * @param style pointer to a line's style\n * @param opa_scale scale down all opacities by the factor\n */\nvoid lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * mask,\n        const lv_style_t * style, lv_opa_t opa_scale)\n{\n\n    if(style->line.width == 0) return;\n    if(point1->x == point2->x && point1->y == point2->y) return;\n\n    line_draw_t main_line;\n    lv_point_t p1;\n    lv_point_t p2;\n\n    /*If the line if rather vertical then be sure y1 < y2 else x1 < x2*/\n\n    if(LV_MATH_ABS(point1->x - point2->x) > LV_MATH_ABS(point1->y - point2->y)) {\n\n        /*Steps less in y then x -> rather horizontal*/\n        if(point1->x < point2->x) {\n            p1.x = point1->x;\n            p1.y = point1->y;\n            p2.x = point2->x;\n            p2.y = point2->y;\n        } else {\n            p1.x = point2->x;\n            p1.y = point2->y;\n            p2.x = point1->x;\n            p2.y = point1->y;\n        }\n    } else {\n        /*Steps less in x then y -> rather vertical*/\n        if(point1->y < point2->y) {\n            p1.x = point1->x;\n            p1.y = point1->y;\n            p2.x = point2->x;\n            p2.y = point2->y;\n        } else {\n            p1.x = point2->x;\n            p1.y = point2->y;\n            p2.x = point1->x;\n            p2.y = point1->y;\n        }\n    }\n\n    line_init(&main_line, &p1, &p2);\n\n\n    /*Special case draw a horizontal line*/\n    if(main_line.p1.y == main_line.p2.y) {\n        line_draw_hor(&main_line, mask, style, opa_scale);\n    }\n    /*Special case draw a vertical line*/\n    else if(main_line.p1.x == main_line.p2.x) {\n        line_draw_ver(&main_line, mask, style, opa_scale);\n    }\n    /*Arbitrary skew line*/\n    else {\n        bool dir_ori = false;\n#if LV_ANTIALIAS\n        lv_point_t p_tmp;\n\n        if(main_line.hor) {\n            if(main_line.p1.y < main_line.p2.y) {\n                dir_ori = true;\n                p_tmp.x = main_line.p2.x;\n                p_tmp.y = main_line.p2.y - 1;\n                line_init(&main_line, &p1, &p_tmp);\n                main_line.sy = LV_MATH_ABS(main_line.sy);   /*The sign can change if the line becomes horizontal*/\n            }\n            else if(main_line.p1.y > main_line.p2.y) {\n                dir_ori = false;\n                p_tmp.x = main_line.p2.x;\n                p_tmp.y = main_line.p2.y + 1;\n                line_init(&main_line, &p1, &p_tmp);\n                main_line.sy = -LV_MATH_ABS(main_line.sy);  /*The sign can change if the line becomes horizontal*/\n            }\n        }\n        else {\n            if(main_line.p1.x < main_line.p2.x) {\n                dir_ori = true;\n                p_tmp.x = main_line.p2.x - 1;\n                p_tmp.y = main_line.p2.y;\n                line_init(&main_line, &p1, &p_tmp);\n                main_line.sx = LV_MATH_ABS(main_line.sx);   /*The sign can change if the line becomes vertical*/\n            }\n            else if(main_line.p1.x > main_line.p2.x) {\n                dir_ori = false;\n                p_tmp.x = main_line.p2.x + 1;\n                p_tmp.y = main_line.p2.y;\n                line_init(&main_line, &p1, &p_tmp);\n                main_line.sx = -LV_MATH_ABS(main_line.sx);  /*The sign can change if the line becomes vertical*/\n            }\n        }\n#endif\n        line_draw_skew(&main_line, dir_ori, mask, style, opa_scale);\n    }\n}\n\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n\nstatic void line_draw_hor(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)\n{\n    lv_coord_t width = style->line.width - 1;\n    lv_coord_t width_half = width >> 1;\n    lv_coord_t width_1 = width & 0x1;\n    lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t) style->line.opa * opa_scale) >> 8;\n\n    lv_area_t act_area;\n    act_area.x1 = main_line->p1.x;\n    act_area.x2 = main_line->p2.x;\n    act_area.y1 = main_line->p1.y - width_half - width_1;\n    act_area.y2 = main_line->p2.y + width_half ;\n\n    lv_area_t draw_area;\n    draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2);\n    draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2);\n    draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2);\n    draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2);\n    fill_fp(&draw_area, mask, style->line.color, opa);\n}\n\nstatic void line_draw_ver(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)\n{\n    lv_coord_t width = style->line.width - 1;\n    lv_coord_t width_half = width >> 1;\n    lv_coord_t width_1 = width & 0x1;\n    lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t) style->line.opa * opa_scale) >> 8;\n\n\n    lv_area_t act_area;\n    act_area.x1 = main_line->p1.x - width_half;\n    act_area.x2 = main_line->p2.x + width_half + width_1;\n    act_area.y1 = main_line->p1.y;\n    act_area.y2 = main_line->p2.y;\n\n    lv_area_t draw_area;\n    draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2);\n    draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2);\n    draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2);\n    draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2);\n    fill_fp(&draw_area, mask, style->line.color, opa);\n}\n\nstatic void line_draw_skew(line_draw_t * main_line, bool dir_ori, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)\n{\n\n    lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t) style->line.opa * opa_scale) >> 8;\n\n    lv_point_t vect_main, vect_norm;\n    vect_main.x = main_line->p2.x - main_line->p1.x;\n    vect_main.y = main_line->p2.y - main_line->p1.y;\n\n    if(main_line->hor) {\n        if(main_line->p1.y < main_line->p2.y + dir_ori) {\n            vect_norm.x = - vect_main.y;\n            vect_norm.y = vect_main.x;\n        } else {\n            vect_norm.x = vect_main.y;\n            vect_norm.y = -vect_main.x;\n        }\n    } else {\n        if(main_line->p1.x < main_line->p2.x + dir_ori) {\n            vect_norm.x = vect_main.y;\n            vect_norm.y = - vect_main.x;\n        } else {\n            vect_norm.x = - vect_main.y;\n            vect_norm.y = vect_main.x;\n        }\n    }\n\n    /* In case of a short but tick line the perpendicular ending is longer then the real line.\n     * it would break the calculations so make the normal vector larger*/\n    vect_norm.x = vect_norm.x << 4;\n    vect_norm.y = vect_norm.y << 4;\n\n    lv_coord_t width;\n    width = style->line.width;\n\n    /* The pattern stores the points of the line ending. It has the good direction and length.\n     * The worth case is the 45° line where pattern can have 1.41 x `width` points*/\n#if LV_COMPILER_VLA_SUPPORTED\n    lv_point_t pattern[width * 2];\n#else\n    lv_point_t pattern[LINE_MAX_WIDTH];\n#endif\n    lv_coord_t i = 0;\n\n    /*Create a perpendicular pattern (a small line)*/\n    if(width != 0) {\n        line_draw_t pattern_line;\n        lv_point_t p0 = {0, 0};\n        line_init(&pattern_line, &p0, &vect_norm);\n\n        uint32_t width_sqr = width * width;\n        /* Run for a lot of times. Meanwhile the real width will be determined as well */\n        for(i = 0; i < (lv_coord_t)sizeof(pattern); i ++) {\n            pattern[i].x = pattern_line.p_act.x;\n            pattern[i].y = pattern_line.p_act.y;\n\n            /*Finish the pattern line if it's length equal to the desired width (Use Pythagoras theorem)*/\n            uint32_t  sqr = pattern_line.p_act.x * pattern_line.p_act.x + pattern_line.p_act.y * pattern_line.p_act.y;\n            if(sqr >= width_sqr) {\n                width = i;\n#if LV_ANTIALIAS\n                width--;\n#endif\n                break;\n            }\n\n            line_next(&pattern_line);\n        }\n    }\n\n#if LV_ANTIALIAS\n    lv_coord_t width_safe = width;\n    if(width == 0) width_safe = 1;\n\n    lv_coord_t aa_last_corner;\n    aa_last_corner = 0;\n#endif\n\n    lv_coord_t x_center_ofs = 0;\n    lv_coord_t y_center_ofs = 0;\n\n    if(width != 0) {\n        x_center_ofs = pattern[width - 1].x / 2;\n        y_center_ofs = pattern[width - 1].y / 2;\n    }\n    else {\n        if(main_line->hor && main_line->p1.y >= main_line->p2.y + dir_ori) pattern[0].y --;\n        if(!main_line->hor && main_line->p1.x >= main_line->p2.x + dir_ori) pattern[0].x --;\n    }\n\n    /* Make the coordinates relative to the center */\n    for(i = 0; i < width; i++) {\n        pattern[i].x -= x_center_ofs;\n        pattern[i].y -= y_center_ofs;\n#if LV_ANTIALIAS\n        if(i != 0) {\n            if(main_line->hor) {\n                if(pattern[i - 1].x != pattern[i].x) {\n                    lv_coord_t seg_w = pattern[i].y - pattern[aa_last_corner].y;\n                    if(main_line->sy < 0) {\n                        lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, main_line->p1.y + pattern[aa_last_corner].y + seg_w + 1,\n                                seg_w, mask, style->line.color, opa);\n\n                        lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, main_line->p2.y + pattern[aa_last_corner].y + seg_w + 1,\n                                -seg_w, mask, style->line.color, opa);\n                    } else {\n                        lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, main_line->p1.y + pattern[aa_last_corner].y,\n                                seg_w, mask, style->line.color, opa);\n\n                        lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, main_line->p2.y + pattern[aa_last_corner].y,\n                                -seg_w, mask, style->line.color, opa);\n                    }\n                    aa_last_corner = i;\n                }\n            } else {\n                if(pattern[i - 1].y != pattern[i].y) {\n                    lv_coord_t seg_w = pattern[i].x - pattern[aa_last_corner].x;\n                    if(main_line->sx < 0) {\n                        lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x + seg_w + 1, main_line->p1.y + pattern[aa_last_corner].y - 1,\n                                seg_w, mask, style->line.color, opa);\n\n                        lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x + seg_w + 1, main_line->p2.y + pattern[aa_last_corner].y + 1,\n                                -seg_w, mask, style->line.color, opa);\n                    } else {\n                        lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x, main_line->p1.y + pattern[aa_last_corner].y - 1,\n                                seg_w, mask, style->line.color, opa);\n\n                        lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x, main_line->p2.y + pattern[aa_last_corner].y + 1,\n                                -seg_w, mask, style->line.color, opa);\n                    }\n                    aa_last_corner = i;\n                }\n            }\n\n        }\n#endif\n    }\n\n\n\n#if LV_ANTIALIAS\n    /*Add the last part of anti-aliasing for the perpendicular ending*/\n    if(width != 0) {    /*Due to rounding error with very thin lines it looks ugly*/\n        if(main_line->hor) {\n            lv_coord_t seg_w = pattern[width_safe - 1].y - pattern[aa_last_corner].y;\n            if(main_line->sy < 0) {\n                lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, main_line->p1.y + pattern[aa_last_corner].y + seg_w,\n                        seg_w + main_line->sy, mask, style->line.color, opa);\n\n                lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, main_line->p2.y + pattern[aa_last_corner].y + seg_w,\n                        -(seg_w + main_line->sy), mask, style->line.color, opa);\n\n            } else {\n                lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, main_line->p1.y + pattern[aa_last_corner].y,\n                        seg_w + main_line->sy, mask, style->line.color, opa);\n\n                lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, main_line->p2.y + pattern[aa_last_corner].y,\n                        -(seg_w + main_line->sy), mask, style->line.color, opa);\n            }\n        } else {\n            lv_coord_t seg_w = pattern[width_safe - 1].x - pattern[aa_last_corner].x;\n            if(main_line->sx < 0) {\n                lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x + seg_w, main_line->p1.y + pattern[aa_last_corner].y - 1,\n                        seg_w + main_line->sx, mask, style->line.color, opa);\n\n                lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x + seg_w, main_line->p2.y + pattern[aa_last_corner].y + 1,\n                        -(seg_w + main_line->sx), mask, style->line.color, opa);\n\n            } else {\n                lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x, main_line->p1.y + pattern[aa_last_corner].y - 1,\n                        seg_w + main_line->sx, mask, style->line.color, opa);\n\n                lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x, main_line->p2.y + pattern[aa_last_corner].y + 1,\n                        -(seg_w + main_line->sx), mask, style->line.color, opa);\n            }\n\n        }\n    }\n#endif\n\n#if LV_ANTIALIAS\n\n    /*Shift the anti aliasing on the edges (-1, 1 or 0 (zero only in case width == 0))*/\n    lv_coord_t aa_shift1;\n    lv_coord_t aa_shift2;\n\n    if(main_line->hor == false) {\n        if(main_line->sx < 0) {\n            aa_shift1 = -1;\n            aa_shift2 = width == 0 ? 0 : aa_shift1;\n        } else {\n            aa_shift2 = 1;\n            aa_shift1 = width == 0 ? 0 : aa_shift2;\n        }\n    } else {\n        if(main_line->sy < 0) {\n            aa_shift1 = -1;\n            aa_shift2 = width == 0 ? 0 : aa_shift1;\n        } else {\n            aa_shift2 = 1;\n            aa_shift1 = width == 0 ? 0 : aa_shift2;\n        }\n    }\n\n#endif\n\n    volatile lv_point_t prev_p;\n    prev_p.x = main_line->p1.x;\n    prev_p.y = main_line->p1.y;\n    lv_area_t draw_area;\n    bool first_run = true;\n\n    if(main_line->hor) {\n        while(line_next_y(main_line)) {\n            for(i = 0; i < width; i++) {\n                draw_area.x1 = prev_p.x + pattern[i].x;\n                draw_area.y1 = prev_p.y + pattern[i].y;\n                draw_area.x2 = draw_area.x1 + main_line->p_act.x - prev_p.x - 1;\n                draw_area.y2 = draw_area.y1;\n                fill_fp(&draw_area, mask, style->line.color, opa);\n\n                /* Fill the gaps\n                 * When stepping in y one pixel remains empty on every corner (don't do this on the first segment ) */\n                if(i != 0 && pattern[i].x != pattern[i - 1].x && !first_run) {\n                    px_fp(draw_area.x1, draw_area.y1 - main_line->sy, mask, style->line.color, opa);\n                }\n            }\n\n#if LV_ANTIALIAS\n            lv_draw_aa_hor_seg(prev_p.x + pattern[0].x, prev_p.y + pattern[0].y - aa_shift1,\n                    -(main_line->p_act.x - prev_p.x), mask, style->line.color, opa);\n            lv_draw_aa_hor_seg(prev_p.x + pattern[width_safe - 1].x, prev_p.y + pattern[width_safe - 1].y + aa_shift2,\n                    main_line->p_act.x - prev_p.x, mask, style->line.color, opa);\n#endif\n\n            first_run = false;\n\n            prev_p.x = main_line->p_act.x;\n            prev_p.y = main_line->p_act.y;\n        }\n\n        for(i = 0; i < width; i++) {\n            draw_area.x1 = prev_p.x + pattern[i].x;\n            draw_area.y1 = prev_p.y + pattern[i].y;\n            draw_area.x2 = draw_area.x1 + main_line->p_act.x - prev_p.x;\n            draw_area.y2 = draw_area.y1;\n            fill_fp(&draw_area, mask, style->line.color, opa);\n\n            /* Fill the gaps\n             * When stepping in y one pixel remains empty on every corner */\n            if(i != 0 && pattern[i].x != pattern[i - 1].x && !first_run) {\n                px_fp(draw_area.x1, draw_area.y1 - main_line->sy, mask, style->line.color, opa);\n            }\n        }\n\n#if LV_ANTIALIAS\n        lv_draw_aa_hor_seg(prev_p.x + pattern[0].x, prev_p.y + pattern[0].y - aa_shift1,\n                -(main_line->p_act.x - prev_p.x + 1), mask, style->line.color, opa);\n        lv_draw_aa_hor_seg(prev_p.x + pattern[width_safe - 1].x, prev_p.y + pattern[width_safe - 1].y + aa_shift2,\n                main_line->p_act.x - prev_p.x + 1, mask, style->line.color, opa);\n#endif\n    }\n    /*Rather a vertical line*/\n    else {\n\n        while(line_next_x(main_line)) {\n            for(i = 0; i < width; i++) {\n                draw_area.x1 = prev_p.x + pattern[i].x;\n                draw_area.y1 = prev_p.y + pattern[i].y;\n                draw_area.x2 = draw_area.x1;\n                draw_area.y2 = draw_area.y1 + main_line->p_act.y - prev_p.y - 1;\n\n                fill_fp(&draw_area, mask, style->line.color, opa);\n\n                /* Fill the gaps\n                 * When stepping in x one pixel remains empty on every corner (don't do this on the first segment ) */\n                if(i != 0 && pattern[i].y != pattern[i - 1].y && !first_run) {\n                    px_fp(draw_area.x1 - main_line->sx, draw_area.y1, mask, style->line.color, opa);\n                }\n\n            }\n\n#if LV_ANTIALIAS\n            lv_draw_aa_ver_seg(prev_p.x + pattern[0].x - aa_shift1, prev_p.y + pattern[0].y,\n                    -(main_line->p_act.y - prev_p.y), mask, style->line.color, opa);\n            lv_draw_aa_ver_seg(prev_p.x + pattern[width_safe - 1].x + aa_shift2, prev_p.y + pattern[width_safe - 1].y,\n                    main_line->p_act.y - prev_p.y, mask, style->line.color, opa);\n#endif\n\n            first_run = false;\n\n            prev_p.x = main_line->p_act.x;\n            prev_p.y = main_line->p_act.y;\n        }\n\n        /*Draw the last part*/\n        for(i = 0; i < width; i++) {\n            draw_area.x1 = prev_p.x + pattern[i].x;\n            draw_area.y1 = prev_p.y + pattern[i].y;\n            draw_area.x2 = draw_area.x1;\n            draw_area.y2 = draw_area.y1 + main_line->p_act.y - prev_p.y;\n\n            fill_fp(&draw_area, mask, style->line.color, opa);\n\n            /* Fill the gaps\n             * When stepping in x one pixel remains empty on every corner */\n            if(i != 0 && pattern[i].y != pattern[i - 1].y && !first_run) {\n                px_fp(draw_area.x1 - main_line->sx, draw_area.y1, mask, style->line.color, opa);\n            }\n        }\n\n#if LV_ANTIALIAS\n        lv_draw_aa_ver_seg(prev_p.x + pattern[0].x - aa_shift1, prev_p.y + pattern[0].y,\n                -(main_line->p_act.y - prev_p.y + 1), mask, style->line.color, opa);\n        lv_draw_aa_ver_seg(prev_p.x + pattern[width_safe - 1].x + aa_shift2, prev_p.y + pattern[width_safe - 1].y,\n                main_line->p_act.y - prev_p.y + 1, mask, style->line.color, opa);\n#endif\n    }\n}\n\n\nstatic void line_init(line_draw_t * line, const lv_point_t * p1, const lv_point_t * p2)\n{\n    line->p1.x = p1->x;\n    line->p1.y = p1->y;\n    line->p2.x = p2->x;\n    line->p2.y = p2->y;\n\n    line->dx = LV_MATH_ABS(line->p2.x - line->p1.x);\n    line->sx = line->p1.x < line->p2.x ? 1 : -1;\n    line->dy = LV_MATH_ABS(line->p2.y - line->p1.y);\n    line->sy = line->p1.y < line->p2.y ? 1 : -1;\n    line->err = (line->dx > line->dy ? line->dx : -line->dy) / 2;\n    line->e2 = 0;\n    line->hor = line->dx > line->dy ? true : false; /*Rather horizontal or vertical*/\n\n    line->p_act.x = line->p1.x;\n    line->p_act.y = line->p1.y;\n}\n\nstatic bool line_next(line_draw_t * line)\n{\n    if(line->p_act.x == line->p2.x && line->p_act.y == line->p2.y) return false;\n    line->e2 = line->err;\n    if(line->e2 > -line->dx) {\n        line->err -= line->dy;\n        line->p_act.x += line->sx;\n    }\n    if(line->e2 < line->dy) {\n        line->err += line->dx;\n        line->p_act.y += line->sy;\n    }\n    return true;\n}\n\n/**\n * Iterate until step one in y direction.\n * @param line\n * @return\n */\nstatic bool line_next_y(line_draw_t * line)\n{\n    lv_coord_t last_y = line->p_act.y;\n\n    do {\n        if(!line_next(line)) return false;\n    } while(last_y == line->p_act.y);\n\n    return true;\n\n}\n\n/**\n * Iterate until step one in x direction.\n * @param line\n * @return\n */\nstatic bool line_next_x(line_draw_t * line)\n{\n    lv_coord_t last_x = line->p_act.x;\n\n    do {\n        if(!line_next(line)) return false;\n    } while(last_x == line->p_act.x);\n\n    return true;\n\n}\n\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_draw/lv_draw_line.h",
    "content": "/**\n * @file lv_draw_line.h\n *\n */\n\n#ifndef LV_DRAW_LINE_H\n#define LV_DRAW_LINE_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Draw a line\n * @param point1 first point of the line\n * @param point2 second point of the line\n * @param mask the line will be drawn only on this area\n * @param style pointer to a line's style\n * @param opa_scale scale down all opacities by the factor\n */\nvoid lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * mask,\n                  const lv_style_t * style, lv_opa_t opa_scale);\n\n/**********************\n *      MACROS\n **********************/\n\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_DRAW_LINE_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_draw/lv_draw_rbasic.c",
    "content": "/**\n * @file lv_draw_rbasic.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_draw_rbasic.h\"\n#if USE_LV_REAL_DRAW != 0\n\n#include \"../lv_hal/lv_hal_disp.h\"\n#include \"../lv_misc/lv_font.h\"\n#include \"lv_draw.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_color_t letter_bg_color;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Put a pixel to the display\n * @param x x coordinate of the pixel\n * @param y y coordinate of the pixel\n * @param mask_p the pixel will be drawn on this area\n * @param color color of the pixel\n * @param opa opacity (ignored, only for compatibility with lv_vpx)\n */\nvoid lv_rpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa)\n{\n    (void)opa;      /*Opa is used only for compatibility with lv_vpx*/\n\n    lv_area_t area;\n    area.x1 = x;\n    area.y1 = y;\n    area.x2 = x;\n    area.y2 = y;\n\n    lv_rfill(&area, mask_p, color, LV_OPA_COVER);\n}\n\n/**\n * Fill an area on the display\n * @param cords_p coordinates of the area to fill\n * @param mask_p fill only o this mask\n * @param color fill color\n * @param opa opacity (ignored, only for compatibility with lv_vfill)\n */\nvoid lv_rfill(const lv_area_t * cords_p, const lv_area_t * mask_p,\n              lv_color_t color, lv_opa_t opa)\n{\n\n    (void)opa;      /*Opa is used only for compatibility with lv_vfill*/\n\n    lv_area_t masked_area;\n    bool union_ok = true;\n\n    if(mask_p != NULL) {\n        union_ok = lv_area_intersect(&masked_area, cords_p, mask_p);\n    } else {\n        lv_area_t scr_area;\n        lv_area_set(&scr_area, 0, 0, LV_HOR_RES - 1, LV_VER_RES - 1);\n        union_ok = lv_area_intersect(&masked_area, cords_p, &scr_area);\n    }\n\n    if(union_ok != false) {\n        lv_disp_fill(masked_area.x1, masked_area.y1, masked_area.x2, masked_area.y2, color);\n    }\n}\n\n/**\n * Draw a letter to the display\n * @param pos_p left-top coordinate of the latter\n * @param mask_p the letter will be drawn only on this area\n * @param font_p pointer to font\n * @param letter a letter to draw\n * @param color color of letter\n * @param opa opacity of letter (ignored, only for compatibility with lv_vletter)\n */\nvoid lv_rletter(const lv_point_t * pos_p, const lv_area_t * mask_p,\n                const lv_font_t * font_p, uint32_t letter,\n                lv_color_t color, lv_opa_t opa)\n{\n    (void)opa;      /*Opa is used only for compatibility with lv_vletter*/\n\n    static uint8_t bpp1_opa_table[2] =  {0, 255};                   /*Opacity mapping with bpp = 1 (Just for compatibility)*/\n    static uint8_t bpp2_opa_table[4] =  {0, 85, 170, 255};          /*Opacity mapping with bpp = 2*/\n    static uint8_t bpp4_opa_table[16] = {0,   17,  34,  51,         /*Opacity mapping with bpp = 4*/\n                                         68,  85,  102, 119,\n                                         136, 153, 170, 187,\n                                         204, 221, 238, 255\n                                        };\n\n    if(font_p == NULL) return;\n\n    uint8_t letter_w = lv_font_get_width(font_p, letter);\n    uint8_t letter_h = lv_font_get_height(font_p);\n    uint8_t bpp = lv_font_get_bpp(font_p, letter);  /*Bit per pixel (1,2, 4 or 8)*/\n    uint8_t * bpp_opa_table;\n    uint8_t mask_init;\n    uint8_t mask;\n\n    switch(bpp) {\n        case 1:\n            bpp_opa_table = bpp1_opa_table;\n            mask_init = 0x80;\n            break;\n        case 2:\n            bpp_opa_table = bpp2_opa_table;\n            mask_init = 0xC0;\n            break;\n        case 4:\n            bpp_opa_table = bpp4_opa_table;\n            mask_init = 0xF0;\n            break;\n        case 8:\n            bpp_opa_table = NULL;\n            mask_init = 0xFF;\n            break;             /*No opa table, pixel value will be used directly*/\n        default:\n            return;        /*Invalid bpp. Can't render the letter*/\n    }\n\n    const uint8_t * map_p = lv_font_get_bitmap(font_p, letter);\n\n    if(map_p == NULL) return;\n\n    /*If the letter is completely out of mask don't draw it */\n    if(pos_p->x + letter_w < mask_p->x1 || pos_p->x > mask_p->x2 ||\n            pos_p->y + letter_h < mask_p->y1 || pos_p->y > mask_p->y2) return;\n\n    lv_coord_t col, row;\n    uint8_t col_bit;\n    uint8_t col_byte_cnt;\n    uint8_t width_byte_scr = letter_w >> 3;      /*Width in bytes (on the screen finally) (e.g. w = 11 -> 2 bytes wide)*/\n    if(letter_w & 0x7) width_byte_scr++;\n    uint8_t width_byte_bpp = (letter_w * bpp) >> 3;    /*Letter width in byte. Real width in the font*/\n    if((letter_w * bpp) & 0x7) width_byte_bpp++;\n\n    /* Calculate the col/row start/end on the map*/\n    lv_coord_t col_start = pos_p->x >= mask_p->x1 ? 0 : mask_p->x1 - pos_p->x;\n    lv_coord_t col_end = pos_p->x + letter_w <= mask_p->x2 ? letter_w : mask_p->x2 - pos_p->x + 1;\n    lv_coord_t row_start = pos_p->y >= mask_p->y1 ? 0 : mask_p->y1 - pos_p->y;\n    lv_coord_t row_end  = pos_p->y + letter_h <= mask_p->y2 ? letter_h : mask_p->y2 - pos_p->y + 1;\n\n    /*Move on the map too*/\n    map_p += (row_start * width_byte_bpp) + ((col_start * bpp) >> 3);\n\n    uint8_t letter_px;\n    for(row = row_start; row < row_end; row ++) {\n        col_byte_cnt = 0;\n        col_bit = (col_start * bpp) % 8;\n        mask = mask_init >> col_bit;\n        for(col = col_start; col < col_end; col ++) {\n            letter_px = (*map_p & mask) >> (8 - col_bit - bpp);\n            if(letter_px != 0) {\n                lv_rpx(pos_p->x + col, pos_p->y + row, mask_p, lv_color_mix(color, letter_bg_color, bpp == 8 ? letter_px : bpp_opa_table[letter_px]), LV_OPA_COVER);\n            }\n\n            if(col_bit < 8 - bpp) {\n                col_bit += bpp;\n                mask = mask >> bpp;\n            } else {\n                col_bit = 0;\n                col_byte_cnt ++;\n                mask = mask_init;\n                map_p ++;\n            }\n        }\n\n        map_p += (width_byte_bpp) - col_byte_cnt;\n    }\n}\n\n/**\n * When the letter is ant-aliased it needs to know the background color\n * @param bg_color the background color of the currently drawn letter\n */\nvoid lv_rletter_set_background(lv_color_t color)\n{\n    letter_bg_color = color;\n}\n\n/**\n * Draw a color map to the display (image)\n * @param cords_p coordinates the color map\n * @param mask_p the map will drawn only on this area\n * @param map_p pointer to a lv_color_t array\n * @param opa opacity of the map (ignored, only for compatibility with 'lv_vmap')\n * @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels\n * @param alpha_byte true: extra alpha byte is inserted for every pixel (not supported, only l'v_vmap' can draw it)\n * @param recolor mix the pixels with this color\n * @param recolor_opa the intense of recoloring\n */\nvoid lv_rmap(const lv_area_t * cords_p, const lv_area_t * mask_p,\n             const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte,\n             lv_color_t recolor, lv_opa_t recolor_opa)\n{\n    if(alpha_byte) return;      /*Pixel level opacity i not supported in real map drawing*/\n\n    (void)opa;              /*opa is used only for compatibility with lv_vmap*/\n    lv_area_t masked_a;\n    bool union_ok;\n\n    union_ok = lv_area_intersect(&masked_a, cords_p, mask_p);\n\n    /*If there are common part of the mask and map then draw the map*/\n    if(union_ok == false) return;\n\n    /*Go to the first pixel*/\n    lv_coord_t map_width = lv_area_get_width(cords_p);\n    map_p += (masked_a.y1 - cords_p->y1) * map_width * sizeof(lv_color_t);\n    map_p += (masked_a.x1 - cords_p->x1) * sizeof(lv_color_t);\n\n    lv_coord_t row;\n    if(recolor_opa == LV_OPA_TRANSP && chroma_key == false) {\n        lv_coord_t mask_w = lv_area_get_width(&masked_a) - 1;\n        for(row = masked_a.y1; row <= masked_a.y2; row++) {\n            lv_disp_map(masked_a.x1, row, masked_a.x1 + mask_w, row, (lv_color_t *)map_p);\n            map_p += map_width * sizeof(lv_color_t);               /*Next row on the map*/\n        }\n    } else {\n        lv_color_t chroma_key_color = LV_COLOR_TRANSP;\n        lv_coord_t col;\n        for(row = masked_a.y1; row <= masked_a.y2; row++) {\n            for(col = masked_a.x1; col <= masked_a.x2; col++) {\n                lv_color_t * px_color = (lv_color_t *) &map_p[(uint32_t)(col - masked_a.x1) * sizeof(lv_color_t)];\n\n                if(chroma_key && chroma_key_color.full == px_color->full) continue;\n\n                if(recolor_opa != LV_OPA_TRANSP) {\n                    lv_color_t recolored_px = lv_color_mix(recolor, *px_color, recolor_opa);\n\n                    lv_rpx(col, row, mask_p, recolored_px, LV_OPA_COVER);\n                } else {\n                    lv_rpx(col, row, mask_p, *px_color, LV_OPA_COVER);\n                }\n\n            }\n            map_p += map_width * sizeof(lv_color_t);               /*Next row on the map*/\n        }\n    }\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n#endif  /*USE_LV_REAL_DRAW*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_draw/lv_draw_rbasic.h",
    "content": "/**\n * @file lv_draw_rbasic..h\n *\n */\n\n#ifndef LV_DRAW_RBASIC_H\n#define LV_DRAW_RBASIC_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_REAL_DRAW != 0\n\n#include \"../lv_misc/lv_color.h\"\n#include \"../lv_misc/lv_area.h\"\n#include \"../lv_misc/lv_font.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\nvoid lv_rpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa);\n\n/**\n * Fill an area on the display\n * @param cords_p coordinates of the area to fill\n * @param mask_p fill only o this mask\n * @param color fill color\n * @param opa opacity (ignored, only for compatibility with lv_vfill)\n */\nvoid lv_rfill(const lv_area_t * cords_p, const lv_area_t * mask_p,\n              lv_color_t color, lv_opa_t opa);\n\n/**\n * Draw a letter to the display\n * @param pos_p left-top coordinate of the latter\n * @param mask_p the letter will be drawn only on this area\n * @param font_p pointer to font\n * @param letter a letter to draw\n * @param color color of letter\n * @param opa opacity of letter (ignored, only for compatibility with lv_vletter)\n */\nvoid lv_rletter(const lv_point_t * pos_p, const lv_area_t * mask_p,\n                const lv_font_t * font_p, uint32_t letter,\n                lv_color_t color, lv_opa_t opa);\n\n/**\n * When the letter is ant-aliased it needs to know the background color\n * @param bg_color the background color of the currently drawn letter\n */\nvoid lv_rletter_set_background(lv_color_t color);\n\n\n/**\n * Draw a color map to the display (image)\n * @param cords_p coordinates the color map\n * @param mask_p the map will drawn only on this area\n * @param map_p pointer to a lv_color_t array\n * @param opa opacity of the map (ignored, only for compatibility with 'lv_vmap')\n * @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels\n * @param alpha_byte true: extra alpha byte is inserted for every pixel (not supported, only l'v_vmap' can draw it)\n * @param recolor mix the pixels with this color\n * @param recolor_opa the intense of recoloring\n */\nvoid lv_rmap(const lv_area_t * cords_p, const lv_area_t * mask_p,\n             const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte,\n             lv_color_t recolor, lv_opa_t recolor_opa);\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_REAL_DRAW*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_DRAW_RBASIC_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_draw/lv_draw_rect.c",
    "content": "/**\n * @file lv_draw_rect.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_draw_rect.h\"\n#include \"../lv_misc/lv_circ.h\"\n#include \"../lv_misc/lv_math.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define CIRCLE_AA_NON_LINEAR_OPA_THRESHOLD  5   /*Circle segment greater then this value will be anti-aliased by a non-linear (cos) opacity mapping*/\n\n#define SHADOW_OPA_EXTRA_PRECISION      8       /*Calculate with 2^x bigger shadow opacity values to avoid rounding errors*/\n#define SHADOW_BOTTOM_AA_EXTRA_RADIUS   3       /*Add extra radius with LV_SHADOW_BOTTOM to cover anti-aliased corners*/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic void lv_draw_rect_main_mid(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);\nstatic void lv_draw_rect_main_corner(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);\nstatic void lv_draw_rect_border_straight(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);\nstatic void lv_draw_rect_border_corner(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);\n\n#if USE_LV_SHADOW && LV_VDB_SIZE\nstatic void lv_draw_shadow(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);\nstatic void lv_draw_shadow_full(const lv_area_t * coords, const lv_area_t * mask, const  lv_style_t * style, lv_opa_t opa_scale);\nstatic void lv_draw_shadow_bottom(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);\nstatic void lv_draw_shadow_full_straight(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, const lv_opa_t * map);\n#endif\n\nstatic uint16_t lv_draw_cont_radius_corr(uint16_t r, lv_coord_t w, lv_coord_t h);\n\n#if LV_ANTIALIAS\nstatic lv_opa_t antialias_get_opa_circ(lv_coord_t seg, lv_coord_t px_id, lv_opa_t opa);\n#endif\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Draw a rectangle\n * @param coords the coordinates of the rectangle\n * @param mask the rectangle will be drawn only in this mask\n * @param style pointer to a style\n * @param opa_scale scale down all opacities by the factor\n */\nvoid lv_draw_rect(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)\n{\n    if(lv_area_get_height(coords) < 1 || lv_area_get_width(coords) < 1) return;\n\n#if USE_LV_SHADOW && LV_VDB_SIZE\n    if(style->body.shadow.width != 0) {\n        lv_draw_shadow(coords, mask, style, opa_scale);\n    }\n#endif\n    if(style->body.empty == 0 && style->body.opa >= LV_OPA_MIN) {\n        lv_draw_rect_main_mid(coords, mask, style, opa_scale);\n\n        if(style->body.radius != 0) {\n            lv_draw_rect_main_corner(coords, mask, style, opa_scale);\n        }\n    }\n\n    if(style->body.border.width != 0 && style->body.border.part != LV_BORDER_NONE && style->body.border.opa >= LV_OPA_MIN) {\n        lv_draw_rect_border_straight(coords, mask, style, opa_scale);\n\n        if(style->body.radius != 0) {\n            lv_draw_rect_border_corner(coords, mask, style, opa_scale);\n        }\n    }\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Draw the middle part (rectangular) of a rectangle\n * @param coords the coordinates of the original rectangle\n * @param mask the rectangle will be drawn only  on this area\n * @param rects_p pointer to a rectangle style\n * @param opa_scale scale down all opacities by the factor\n */\nstatic void lv_draw_rect_main_mid(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)\n{\n    uint16_t radius = style->body.radius;\n\n    lv_color_t mcolor = style->body.main_color;\n    lv_color_t gcolor = style->body.grad_color;\n    uint8_t mix;\n    lv_coord_t height = lv_area_get_height(coords);\n    lv_coord_t width = lv_area_get_width(coords);\n    lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8;\n\n    radius = lv_draw_cont_radius_corr(radius, width, height);\n\n    /*If the radius is too big then there is no body*/\n    if(radius > height / 2)  return;\n\n    lv_area_t work_area;\n    work_area.x1 = coords->x1;\n    work_area.x2 = coords->x2;\n\n    if(mcolor.full == gcolor.full) {\n        work_area.y1 = coords->y1 + radius;\n        work_area.y2 = coords->y2 - radius;\n\n        if(style->body.radius != 0) {\n#if LV_ANTIALIAS\n            work_area.y1 += 2;\n            work_area.y2 -= 2;\n#else\n            work_area.y1 += 1;\n            work_area.y2 -= 1;\n#endif\n        }\n\n        fill_fp(&work_area, mask, mcolor, opa);\n    } else {\n        lv_coord_t row;\n        lv_coord_t row_start = coords->y1 + radius;\n        lv_coord_t row_end = coords->y2 - radius;\n        lv_color_t act_color;\n\n        if(style->body.radius != 0) {\n#if LV_ANTIALIAS\n            row_start += 2;\n            row_end -= 2;\n#else\n            row_start += 1;\n            row_end -= 1;\n#endif\n        }\n        if(row_start < 0) row_start = 0;\n\n        for(row = row_start; row <= row_end; row ++) {\n            work_area.y1 = row;\n            work_area.y2 = row;\n            mix = (uint32_t)((uint32_t)(coords->y2 - work_area.y1) * 255) / height;\n            act_color = lv_color_mix(mcolor, gcolor, mix);\n\n            fill_fp(&work_area, mask, act_color, opa);\n        }\n    }\n}\n/**\n * Draw the top and bottom parts (corners) of a rectangle\n * @param coords the coordinates of the original rectangle\n * @param mask the rectangle will be drawn only  on this area\n * @param rects_p pointer to a rectangle style\n * @param opa_scale scale down all opacities by the factor\n */\nstatic void lv_draw_rect_main_corner(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)\n{\n    uint16_t radius = style->body.radius;\n\n    lv_color_t mcolor = style->body.main_color;\n    lv_color_t gcolor = style->body.grad_color;\n    lv_color_t act_color;\n    lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8;\n    uint8_t mix;\n    lv_coord_t height = lv_area_get_height(coords);\n    lv_coord_t width = lv_area_get_width(coords);\n\n    radius = lv_draw_cont_radius_corr(radius, width, height);\n\n    lv_point_t lt_origo;   /*Left  Top    origo*/\n    lv_point_t lb_origo;   /*Left  Bottom origo*/\n    lv_point_t rt_origo;   /*Right Top    origo*/\n    lv_point_t rb_origo;   /*Left  Bottom origo*/\n\n    lt_origo.x = coords->x1 + radius + LV_ANTIALIAS;\n    lt_origo.y = coords->y1 + radius + LV_ANTIALIAS;\n\n    lb_origo.x = coords->x1 + radius + LV_ANTIALIAS;\n    lb_origo.y = coords->y2 - radius - LV_ANTIALIAS;\n\n    rt_origo.x = coords->x2 - radius - LV_ANTIALIAS;\n    rt_origo.y = coords->y1 + radius + LV_ANTIALIAS;\n\n    rb_origo.x = coords->x2 - radius - LV_ANTIALIAS;\n    rb_origo.y = coords->y2 - radius - LV_ANTIALIAS;\n\n    lv_area_t edge_top_area;\n    lv_area_t mid_top_area;\n    lv_area_t mid_bot_area;\n    lv_area_t edge_bot_area;\n\n    lv_point_t cir;\n    lv_coord_t cir_tmp;\n    lv_circ_init(&cir, &cir_tmp, radius);\n\n    /*Init the areas*/\n    lv_area_set(&mid_bot_area,  lb_origo.x + LV_CIRC_OCT4_X(cir),\n                lb_origo.y + LV_CIRC_OCT4_Y(cir),\n                rb_origo.x + LV_CIRC_OCT1_X(cir),\n                rb_origo.y + LV_CIRC_OCT1_Y(cir));\n\n    lv_area_set(&edge_bot_area, lb_origo.x + LV_CIRC_OCT3_X(cir),\n                lb_origo.y + LV_CIRC_OCT3_Y(cir),\n                rb_origo.x + LV_CIRC_OCT2_X(cir),\n                rb_origo.y + LV_CIRC_OCT2_Y(cir));\n\n    lv_area_set(&mid_top_area,  lt_origo.x + LV_CIRC_OCT5_X(cir),\n                lt_origo.y + LV_CIRC_OCT5_Y(cir),\n                rt_origo.x + LV_CIRC_OCT8_X(cir),\n                rt_origo.y + LV_CIRC_OCT8_Y(cir));\n\n    lv_area_set(&edge_top_area, lt_origo.x + LV_CIRC_OCT6_X(cir),\n                lt_origo.y + LV_CIRC_OCT6_Y(cir),\n                rt_origo.x + LV_CIRC_OCT7_X(cir),\n                rt_origo.y + LV_CIRC_OCT7_Y(cir));\n#if LV_ANTIALIAS\n    /*Store some internal states for anti-aliasing*/\n    lv_coord_t out_y_seg_start = 0;\n    lv_coord_t out_y_seg_end = 0;\n    lv_coord_t out_x_last = radius;\n\n    lv_color_t aa_color_hor_top;\n    lv_color_t aa_color_hor_bottom;\n    lv_color_t aa_color_ver;\n#endif\n\n    while(lv_circ_cont(&cir)) {\n#if LV_ANTIALIAS != 0\n        /*New step in y on the outter circle*/\n        if(out_x_last != cir.x) {\n            out_y_seg_end = cir.y;\n            lv_coord_t seg_size = out_y_seg_end - out_y_seg_start;\n            lv_point_t aa_p;\n\n            aa_p.x = out_x_last;\n            aa_p.y = out_y_seg_start;\n\n            mix = (uint32_t)((uint32_t)(radius - out_x_last) * 255) / height;\n            aa_color_hor_top = lv_color_mix(gcolor, mcolor, mix);\n            aa_color_hor_bottom = lv_color_mix(mcolor, gcolor, mix);\n\n            lv_coord_t i;\n            for(i = 0; i  < seg_size; i++) {\n                lv_opa_t aa_opa;\n                if(seg_size > CIRCLE_AA_NON_LINEAR_OPA_THRESHOLD) {    /*Use non-linear opa mapping on the first segment*/\n                    aa_opa = antialias_get_opa_circ(seg_size, i, opa);\n                } else {\n                    aa_opa = opa - lv_draw_aa_get_opa(seg_size, i, opa);\n                }\n\n                px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) + 1, mask, aa_color_hor_bottom, aa_opa);\n                px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) + 1, mask, aa_color_hor_bottom, aa_opa);\n                px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) - 1, mask, aa_color_hor_top, aa_opa);\n                px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) - 1, mask, aa_color_hor_top, aa_opa);\n\n                mix = (uint32_t)((uint32_t)(radius - out_y_seg_start + i) * 255) / height;\n                aa_color_ver = lv_color_mix(mcolor, gcolor, mix);\n                px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) + 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, aa_color_ver, aa_opa);\n                px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) - 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, aa_color_ver, aa_opa);\n\n                aa_color_ver = lv_color_mix(gcolor, mcolor, mix);\n                px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) - 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, aa_color_ver, aa_opa);\n                px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) + 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, aa_color_ver, aa_opa);\n            }\n\n            out_x_last = cir.x;\n            out_y_seg_start = out_y_seg_end;\n        }\n#endif\n        uint8_t edge_top_refr = 0;\n        uint8_t mid_top_refr = 0;\n        uint8_t mid_bot_refr = 0;\n        uint8_t edge_bot_refr = 0;\n\n        /* If a new row coming draw the previous\n         * The y coordinate can remain the same so wait for a new*/\n        if(mid_bot_area.y1 != LV_CIRC_OCT4_Y(cir) + lb_origo.y) mid_bot_refr = 1;\n\n        if(edge_bot_area.y1 != LV_CIRC_OCT2_Y(cir) + lb_origo.y) edge_bot_refr = 1;\n\n        if(mid_top_area.y1 != LV_CIRC_OCT8_Y(cir) + lt_origo.y) mid_top_refr = 1;\n\n        if(edge_top_area.y1 != LV_CIRC_OCT7_Y(cir) + lt_origo.y) edge_top_refr = 1;\n\n        /*Draw the areas which are not disabled*/\n        if(edge_top_refr != 0) {\n            if(mcolor.full == gcolor.full) act_color = mcolor;\n            else {\n                mix = (uint32_t)((uint32_t)(coords->y2 - edge_top_area.y1)  * 255) / height;\n                act_color = lv_color_mix(mcolor, gcolor, mix);\n            }\n            fill_fp(&edge_top_area, mask, act_color, opa);\n        }\n\n        if(mid_top_refr != 0) {\n            if(mcolor.full == gcolor.full) act_color = mcolor;\n            else {\n                mix = (uint32_t)((uint32_t)(coords->y2 - mid_top_area.y1) * 255) / height;\n                act_color = lv_color_mix(mcolor, gcolor, mix);\n            }\n            fill_fp(&mid_top_area, mask, act_color, opa);\n        }\n\n        if(mid_bot_refr != 0) {\n            if(mcolor.full == gcolor.full) act_color = mcolor;\n            else {\n                mix = (uint32_t)((uint32_t)(coords->y2 - mid_bot_area.y1) * 255) / height;\n                act_color = lv_color_mix(mcolor, gcolor, mix);\n            }\n            fill_fp(&mid_bot_area, mask, act_color, opa);\n        }\n\n        if(edge_bot_refr != 0) {\n\n            if(mcolor.full == gcolor.full) act_color = mcolor;\n            else {\n                mix = (uint32_t)((uint32_t)(coords->y2 - edge_bot_area.y1) * 255) / height;\n                act_color = lv_color_mix(mcolor, gcolor, mix);\n            }\n            fill_fp(&edge_bot_area, mask, act_color, opa);\n        }\n\n        /*Save the current coordinates*/\n        lv_area_set(&mid_bot_area,  lb_origo.x + LV_CIRC_OCT4_X(cir),\n                    lb_origo.y + LV_CIRC_OCT4_Y(cir),\n                    rb_origo.x + LV_CIRC_OCT1_X(cir),\n                    rb_origo.y + LV_CIRC_OCT1_Y(cir));\n\n        lv_area_set(&edge_bot_area, lb_origo.x + LV_CIRC_OCT3_X(cir),\n                    lb_origo.y + LV_CIRC_OCT3_Y(cir),\n                    rb_origo.x + LV_CIRC_OCT2_X(cir),\n                    rb_origo.y + LV_CIRC_OCT2_Y(cir));\n\n        lv_area_set(&mid_top_area,  lt_origo.x + LV_CIRC_OCT5_X(cir),\n                    lt_origo.y + LV_CIRC_OCT5_Y(cir),\n                    rt_origo.x + LV_CIRC_OCT8_X(cir),\n                    rt_origo.y + LV_CIRC_OCT8_Y(cir));\n\n        lv_area_set(&edge_top_area, lt_origo.x + LV_CIRC_OCT6_X(cir),\n                    lt_origo.y + LV_CIRC_OCT6_Y(cir),\n                    rt_origo.x + LV_CIRC_OCT7_X(cir),\n                    rt_origo.y + LV_CIRC_OCT7_Y(cir));\n\n        lv_circ_next(&cir, &cir_tmp);\n    }\n\n    if(mcolor.full == gcolor.full) act_color = mcolor;\n    else {\n        mix = (uint32_t)((uint32_t)(coords->y2 - edge_top_area.y1)  * 255) / height;\n        act_color = lv_color_mix(mcolor, gcolor, mix);\n    }\n    fill_fp(&edge_top_area, mask, act_color, opa);\n\n    if(edge_top_area.y1 != mid_top_area.y1) {\n\n        if(mcolor.full == gcolor.full) act_color = mcolor;\n        else {\n            mix = (uint32_t)((uint32_t)(coords->y2 - mid_top_area.y1) * 255) / height;\n            act_color = lv_color_mix(mcolor, gcolor, mix);\n        }\n        fill_fp(&mid_top_area, mask, act_color, opa);\n    }\n\n    if(mcolor.full == gcolor.full) act_color = mcolor;\n    else {\n        mix = (uint32_t)((uint32_t)(coords->y2 - mid_bot_area.y1) * 255) / height;\n        act_color = lv_color_mix(mcolor, gcolor, mix);\n    }\n    fill_fp(&mid_bot_area, mask, act_color, opa);\n\n    if(edge_bot_area.y1 != mid_bot_area.y1) {\n\n        if(mcolor.full == gcolor.full) act_color = mcolor;\n        else {\n            mix = (uint32_t)((uint32_t)(coords->y2 - edge_bot_area.y1) * 255) / height;\n            act_color = lv_color_mix(mcolor, gcolor, mix);\n        }\n        fill_fp(&edge_bot_area, mask, act_color, opa);\n    }\n\n\n#if LV_ANTIALIAS\n    /*The first and the last line is not drawn*/\n    edge_top_area.x1 = coords->x1 + radius + 2;\n    edge_top_area.x2 = coords->x2 - radius - 2;\n    edge_top_area.y1 = coords->y1;\n    edge_top_area.y2 = coords->y1;\n    fill_fp(&edge_top_area, mask, style->body.main_color, opa);\n\n    edge_top_area.y1 = coords->y2;\n    edge_top_area.y2 = coords->y2;\n    fill_fp(&edge_top_area, mask, style->body.grad_color, opa);\n\n    /*Last parts of the anti-alias*/\n    out_y_seg_end = cir.y;\n    lv_coord_t seg_size = out_y_seg_end - out_y_seg_start;\n    lv_point_t aa_p;\n\n    aa_p.x = out_x_last;\n    aa_p.y = out_y_seg_start;\n\n    mix = (uint32_t)((uint32_t)(radius - out_x_last) * 255) / height;\n    aa_color_hor_bottom = lv_color_mix(gcolor, mcolor, mix);\n    aa_color_hor_top = lv_color_mix(mcolor, gcolor, mix);\n\n    lv_coord_t i;\n    for(i = 0; i  < seg_size; i++) {\n        lv_opa_t aa_opa = opa - lv_draw_aa_get_opa(seg_size, i, opa);\n        px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) + 1, mask, aa_color_hor_top, aa_opa);\n        px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) + 1, mask, aa_color_hor_top, aa_opa);\n        px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) - 1, mask, aa_color_hor_bottom, aa_opa);\n        px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) - 1, mask, aa_color_hor_bottom, aa_opa);\n\n        mix = (uint32_t)((uint32_t)(radius - out_y_seg_start + i) * 255) / height;\n        aa_color_ver = lv_color_mix(mcolor, gcolor, mix);\n        px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) + 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, aa_color_ver, aa_opa);\n        px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) - 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, aa_color_ver, aa_opa);\n\n        aa_color_ver = lv_color_mix(gcolor, mcolor, mix);\n        px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) - 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, aa_color_ver, aa_opa);\n        px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) + 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, aa_color_ver, aa_opa);\n    }\n\n    /*In some cases the last pixel is not drawn*/\n    if(LV_MATH_ABS(aa_p.x - aa_p.y) == seg_size) {\n        aa_p.x = out_x_last;\n        aa_p.y = out_x_last;\n\n        mix = (uint32_t)((uint32_t)(out_x_last) * 255) / height;\n        aa_color_hor_top = lv_color_mix(gcolor, mcolor, mix);\n        aa_color_hor_bottom = lv_color_mix(mcolor, gcolor, mix);\n\n        lv_opa_t aa_opa = opa >> 1;\n        px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p), rb_origo.y + LV_CIRC_OCT2_Y(aa_p), mask, aa_color_hor_bottom, aa_opa);\n        px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p), lb_origo.y + LV_CIRC_OCT4_Y(aa_p), mask, aa_color_hor_bottom, aa_opa);\n        px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p), lt_origo.y + LV_CIRC_OCT6_Y(aa_p), mask, aa_color_hor_top, aa_opa);\n        px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p), rt_origo.y + LV_CIRC_OCT8_Y(aa_p), mask, aa_color_hor_top, aa_opa);\n    }\n\n#endif\n\n\n}\n\n/**\n * Draw the straight parts of a rectangle border\n * @param coords the coordinates of the original rectangle\n * @param mask_ the rectangle will be drawn only  on this area\n * @param rstyle pointer to a rectangle style\n * @param opa_scale scale down all opacities by the factor\n */\nstatic void lv_draw_rect_border_straight(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)\n{\n    uint16_t radius = style->body.radius;\n\n    lv_coord_t width = lv_area_get_width(coords);\n    lv_coord_t height = lv_area_get_height(coords);\n    uint16_t bwidth = style->body.border.width;\n    lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.border.opa : (uint16_t)((uint16_t) style->body.border.opa * opa_scale) >> 8;\n    lv_border_part_t part = style->body.border.part;\n    lv_color_t color = style->body.border.color;\n    lv_area_t work_area;\n    lv_coord_t length_corr = 0;\n    lv_coord_t corner_size = 0;\n\n    /*the 0 px border width drawn as 1 px, so decrement the b_width*/\n    bwidth--;\n\n    radius = lv_draw_cont_radius_corr(radius, width, height);\n\n    if(radius < bwidth) {\n        length_corr = bwidth - radius - LV_ANTIALIAS;\n        corner_size = bwidth;\n    } else {\n        corner_size = radius + LV_ANTIALIAS;\n    }\n\n    /*If radius == 0 is a special case*/\n    if(style->body.radius == 0) {\n        /*Left top corner*/\n        if(part & LV_BORDER_TOP) {\n            work_area.x1 = coords->x1;\n            work_area.x2 = coords->x2;\n            work_area.y1 = coords->y1;\n            work_area.y2 = coords->y1 + bwidth;\n            fill_fp(&work_area, mask, color, opa);\n        }\n\n        /*Right top corner*/\n        if(part & LV_BORDER_RIGHT) {\n            work_area.x1 = coords->x2 - bwidth;\n            work_area.x2 = coords->x2;\n            work_area.y1 = coords->y1 + (part & LV_BORDER_TOP ? bwidth + 1 : 0);\n            work_area.y2 = coords->y2 - (part & LV_BORDER_BOTTOM ? bwidth + 1 : 0);\n            fill_fp(&work_area, mask, color, opa);\n        }\n\n        /*Left bottom corner*/\n        if(part & LV_BORDER_LEFT) {\n            work_area.x1 = coords->x1;\n            work_area.x2 = coords->x1 + bwidth;\n            work_area.y1 = coords->y1 + (part & LV_BORDER_TOP ? bwidth + 1 : 0);\n            work_area.y2 = coords->y2 - (part & LV_BORDER_BOTTOM ? bwidth + 1 : 0);\n            fill_fp(&work_area, mask, color, opa);\n        }\n\n        /*Right bottom corner*/\n        if(part & LV_BORDER_BOTTOM) {\n            work_area.x1 = coords->x1;\n            work_area.x2 = coords->x2;\n            work_area.y1 = coords->y2 - bwidth;\n            work_area.y2 = coords->y2;\n            fill_fp(&work_area, mask, color, opa);\n        }\n        return;\n    }\n\n    /* Modify the corner_size if corner is drawn */\n    corner_size ++;\n\n    /*Depending one which part's are drawn modify the area lengths */\n    if(part & LV_BORDER_TOP) work_area.y1 = coords->y1 + corner_size;\n    else  work_area.y1 = coords->y1 + radius;\n\n    if(part & LV_BORDER_BOTTOM) work_area.y2 = coords->y2 - corner_size;\n    else work_area.y2 = coords->y2 - radius;\n\n    /*Left border*/\n    if(part & LV_BORDER_LEFT) {\n        work_area.x1 = coords->x1;\n        work_area.x2 = work_area.x1 + bwidth;\n        fill_fp(&work_area, mask, color, opa);\n    }\n\n    /*Right border*/\n    if(part & LV_BORDER_RIGHT) {\n        work_area.x2 = coords->x2;\n        work_area.x1 = work_area.x2 - bwidth;\n        fill_fp(&work_area, mask, color, opa);\n    }\n\n    work_area.x1 = coords->x1 + corner_size - length_corr;\n    work_area.x2 = coords->x2 - corner_size + length_corr;\n\n    /*Upper border*/\n    if(part & LV_BORDER_TOP) {\n        work_area.y1 = coords->y1;\n        work_area.y2 = coords->y1 + bwidth;\n        fill_fp(&work_area, mask, color, opa);\n    }\n\n    /*Lower border*/\n    if(part & LV_BORDER_BOTTOM) {\n        work_area.y2 = coords->y2;\n        work_area.y1 = work_area.y2 - bwidth;\n        fill_fp(&work_area, mask, color, opa);\n    }\n\n    /*Draw the a remaining rectangles if the radius is smaller then bwidth */\n    if(length_corr != 0) {\n        /*Left top correction*/\n        if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {\n            work_area.x1 = coords->x1;\n            work_area.x2 = coords->x1 + radius + LV_ANTIALIAS;\n            work_area.y1 = coords->y1 + radius + 1 + LV_ANTIALIAS;\n            work_area.y2 = coords->y1 + bwidth;\n            fill_fp(&work_area, mask, color, opa);\n        }\n\n        /*Right top correction*/\n        if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {\n            work_area.x1 = coords->x2 - radius - LV_ANTIALIAS;\n            work_area.x2 = coords->x2;\n            work_area.y1 = coords->y1 + radius + 1 + LV_ANTIALIAS;\n            work_area.y2 = coords->y1 + bwidth;\n            fill_fp(&work_area, mask, color, opa);\n        }\n\n        /*Left bottom correction*/\n        if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {\n            work_area.x1 = coords->x1;\n            work_area.x2 = coords->x1 + radius + LV_ANTIALIAS;\n            work_area.y1 = coords->y2 - bwidth;\n            work_area.y2 = coords->y2 - radius - 1 - LV_ANTIALIAS;\n            fill_fp(&work_area, mask, color, opa);\n        }\n\n        /*Right bottom correction*/\n        if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {\n            work_area.x1 = coords->x2 - radius - LV_ANTIALIAS;\n            work_area.x2 = coords->x2;\n            work_area.y1 = coords->y2 - bwidth;\n            work_area.y2 = coords->y2 - radius - 1 - LV_ANTIALIAS;\n            fill_fp(&work_area, mask, color, opa);\n        }\n    }\n\n    /*If radius == 0 one px on the corners are not drawn by main drawer*/\n    if(style->body.radius == 0) {\n        /*Left top corner*/\n        if(part & (LV_BORDER_TOP | LV_BORDER_LEFT)) {\n            work_area.x1 = coords->x1;\n            work_area.x2 = coords->x1 + LV_ANTIALIAS;\n            work_area.y1 = coords->y1;\n            work_area.y2 = coords->y1 + LV_ANTIALIAS;\n            fill_fp(&work_area, mask, color, opa);\n        }\n\n        /*Right top corner*/\n        if(part & (LV_BORDER_TOP | LV_BORDER_RIGHT)) {\n            work_area.x1 = coords->x2 - LV_ANTIALIAS;\n            work_area.x2 = coords->x2;\n            work_area.y1 = coords->y1;\n            work_area.y2 = coords->y1 + LV_ANTIALIAS;\n            fill_fp(&work_area, mask, color, opa);\n        }\n\n        /*Left bottom corner*/\n        if(part & (LV_BORDER_BOTTOM | LV_BORDER_LEFT)) {\n            work_area.x1 = coords->x1;\n            work_area.x2 = coords->x1 + LV_ANTIALIAS;\n            work_area.y1 = coords->y2 - LV_ANTIALIAS;\n            work_area.y2 = coords->y2;\n            fill_fp(&work_area, mask, color, opa);\n        }\n\n        /*Right bottom corner*/\n        if(part & (LV_BORDER_BOTTOM | LV_BORDER_RIGHT)) {\n            work_area.x1 = coords->x2 - LV_ANTIALIAS;\n            work_area.x2 = coords->x2;\n            work_area.y1 = coords->y2 - LV_ANTIALIAS;\n            work_area.y2 = coords->y2;\n            fill_fp(&work_area, mask, color, opa);\n        }\n    }\n}\n\n\n/**\n * Draw the corners of a rectangle border\n * @param coords the coordinates of the original rectangle\n * @param mask the rectangle will be drawn only  on this area\n * @param style pointer to a style\n * @param opa_scale scale down all opacities by the factor\n */\nstatic void lv_draw_rect_border_corner(const lv_area_t * coords, const lv_area_t * mask, const  lv_style_t * style, lv_opa_t opa_scale)\n{\n    uint16_t radius = style->body.radius ;\n    uint16_t bwidth = style->body.border.width;\n    lv_color_t color = style->body.border.color;\n    lv_border_part_t part = style->body.border.part;\n    lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.border.opa : (uint16_t)((uint16_t) style->body.border.opa * opa_scale) >> 8;\n    /*0 px border width drawn as 1 px, so decrement the bwidth*/\n    bwidth--;\n\n#if LV_ANTIALIAS\n    bwidth--;    /*Because of anti-aliasing the border seems one pixel ticker*/\n#endif\n\n    lv_coord_t width = lv_area_get_width(coords);\n    lv_coord_t height = lv_area_get_height(coords);\n\n    radius = lv_draw_cont_radius_corr(radius, width, height);\n\n    lv_point_t lt_origo;   /*Left  Top    origo*/\n    lv_point_t lb_origo;   /*Left  Bottom origo*/\n    lv_point_t rt_origo;   /*Right Top    origo*/\n    lv_point_t rb_origo;   /*Left  Bottom origo*/\n\n    lt_origo.x = coords->x1 + radius + LV_ANTIALIAS;\n    lt_origo.y = coords->y1 + radius + LV_ANTIALIAS;\n\n    lb_origo.x = coords->x1 + radius + LV_ANTIALIAS;\n    lb_origo.y = coords->y2 - radius - LV_ANTIALIAS;\n\n    rt_origo.x = coords->x2 - radius - LV_ANTIALIAS;\n    rt_origo.y = coords->y1 + radius + LV_ANTIALIAS;\n\n    rb_origo.x = coords->x2 - radius - LV_ANTIALIAS;\n    rb_origo.y = coords->y2 - radius - LV_ANTIALIAS;\n\n    lv_point_t cir_out;\n    lv_coord_t tmp_out;\n    lv_circ_init(&cir_out, &tmp_out, radius);\n\n    lv_point_t cir_in;\n    lv_coord_t tmp_in;\n    lv_coord_t radius_in = radius - bwidth;\n\n    if(radius_in < 0) {\n        radius_in = 0;\n    }\n\n    lv_circ_init(&cir_in, &tmp_in, radius_in);\n\n    lv_area_t circ_area;\n    lv_coord_t act_w1;\n    lv_coord_t act_w2;\n\n#if LV_ANTIALIAS\n    /*Store some internal states for anti-aliasing*/\n    lv_coord_t out_y_seg_start = 0;\n    lv_coord_t out_y_seg_end = 0;\n    lv_coord_t out_x_last = radius;\n\n\n    lv_coord_t in_y_seg_start = 0;\n    lv_coord_t in_y_seg_end = 0;\n    lv_coord_t in_x_last = radius - bwidth;\n#endif\n\n    while(cir_out.y <= cir_out.x) {\n\n        /*Calculate the actual width to avoid overwriting pixels*/\n        if(cir_in.y < cir_in.x) {\n            act_w1 = cir_out.x - cir_in.x;\n            act_w2 = act_w1;\n        } else {\n            act_w1 = cir_out.x - cir_out.y;\n            act_w2 = act_w1 - 1;\n        }\n\n#if LV_ANTIALIAS != 0\n        /*New step in y on the outter circle*/\n        if(out_x_last != cir_out.x) {\n            out_y_seg_end = cir_out.y;\n            lv_coord_t seg_size = out_y_seg_end - out_y_seg_start;\n            lv_point_t aa_p;\n\n            aa_p.x = out_x_last;\n            aa_p.y = out_y_seg_start;\n\n            lv_coord_t i;\n            for(i = 0; i  < seg_size; i++) {\n                lv_opa_t aa_opa;\n\n                if(seg_size > CIRCLE_AA_NON_LINEAR_OPA_THRESHOLD) {    /*Use non-linear opa mapping on the first segment*/\n                    aa_opa = antialias_get_opa_circ(seg_size, i, opa);\n                } else {\n                    aa_opa = opa - lv_draw_aa_get_opa(seg_size, i, opa);\n                }\n\n                if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {\n                    px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) + 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, style->body.border.color, aa_opa);\n                    px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);\n                }\n\n                if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {\n                    px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);\n                    px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) - 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, style->body.border.color, aa_opa);\n                }\n\n\n                if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {\n                    px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) - 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, style->body.border.color, aa_opa);\n                    px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);\n                }\n\n                if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {\n                    px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);\n                    px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) + 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, style->body.border.color, aa_opa);\n                }\n            }\n\n            out_x_last = cir_out.x;\n            out_y_seg_start = out_y_seg_end;\n        }\n\n        /*New step in y on the inner circle*/\n        if(in_x_last != cir_in.x) {\n            in_y_seg_end = cir_out.y;\n            lv_coord_t seg_size = in_y_seg_end - in_y_seg_start;\n            lv_point_t aa_p;\n\n            aa_p.x = in_x_last;\n            aa_p.y = in_y_seg_start;\n\n            lv_coord_t i;\n            for(i = 0; i  < seg_size; i++) {\n                lv_opa_t aa_opa;\n\n                if(seg_size > CIRCLE_AA_NON_LINEAR_OPA_THRESHOLD) {    /*Use non-linear opa mapping on the first segment*/\n                    aa_opa = opa - antialias_get_opa_circ(seg_size, i, opa);\n                } else {\n                    aa_opa = lv_draw_aa_get_opa(seg_size, i, opa);\n                }\n\n                if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {\n                    px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) - 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, style->body.border.color, aa_opa);\n                }\n\n                if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {\n                    px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);\n                }\n\n                if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {\n                    px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) + 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, style->body.border.color, aa_opa);\n                }\n\n                if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {\n                    px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);\n                }\n\n                /*Be sure the pixels on the middle are not drawn twice*/\n                if(LV_CIRC_OCT1_X(aa_p) - 1 != LV_CIRC_OCT2_X(aa_p) + i) {\n                    if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {\n                        px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);\n                    }\n\n                    if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {\n                        px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) + 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, style->body.border.color, aa_opa);\n                    }\n\n                    if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {\n                        px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);\n                    }\n\n                    if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {\n                        px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) - 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, style->body.border.color, aa_opa);\n                    }\n                }\n\n            }\n\n            in_x_last = cir_in.x;\n            in_y_seg_start = in_y_seg_end;\n\n        }\n\n#endif\n\n\n        /*Draw the octets to the right bottom corner*/\n        if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {\n            circ_area.x1 = rb_origo.x + LV_CIRC_OCT1_X(cir_out) - act_w2;\n            circ_area.x2 = rb_origo.x + LV_CIRC_OCT1_X(cir_out);\n            circ_area.y1 = rb_origo.y + LV_CIRC_OCT1_Y(cir_out);\n            circ_area.y2 = rb_origo.y + LV_CIRC_OCT1_Y(cir_out);\n            fill_fp(&circ_area, mask, color, opa);\n\n            circ_area.x1 = rb_origo.x + LV_CIRC_OCT2_X(cir_out);\n            circ_area.x2 = rb_origo.x + LV_CIRC_OCT2_X(cir_out);\n            circ_area.y1 = rb_origo.y + LV_CIRC_OCT2_Y(cir_out) - act_w1;\n            circ_area.y2 = rb_origo.y + LV_CIRC_OCT2_Y(cir_out);\n            fill_fp(&circ_area, mask, color, opa);\n        }\n\n        /*Draw the octets to the left bottom corner*/\n        if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {\n            circ_area.x1 = lb_origo.x + LV_CIRC_OCT3_X(cir_out);\n            circ_area.x2 = lb_origo.x + LV_CIRC_OCT3_X(cir_out);\n            circ_area.y1 = lb_origo.y + LV_CIRC_OCT3_Y(cir_out) - act_w2;\n            circ_area.y2 = lb_origo.y + LV_CIRC_OCT3_Y(cir_out);\n            fill_fp(&circ_area, mask, color, opa);\n\n            circ_area.x1 = lb_origo.x + LV_CIRC_OCT4_X(cir_out);\n            circ_area.x2 = lb_origo.x + LV_CIRC_OCT4_X(cir_out) + act_w1;\n            circ_area.y1 = lb_origo.y + LV_CIRC_OCT4_Y(cir_out);\n            circ_area.y2 = lb_origo.y + LV_CIRC_OCT4_Y(cir_out);\n            fill_fp(&circ_area, mask, color, opa);\n        }\n\n        /*Draw the octets to the left top corner*/\n        if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {\n            if(lb_origo.y + LV_CIRC_OCT4_Y(cir_out) > lt_origo.y + LV_CIRC_OCT5_Y(cir_out)) {\n                /*Don't draw if the lines are common in the middle*/\n                circ_area.x1 = lt_origo.x + LV_CIRC_OCT5_X(cir_out);\n                circ_area.x2 = lt_origo.x + LV_CIRC_OCT5_X(cir_out) + act_w2;\n                circ_area.y1 = lt_origo.y + LV_CIRC_OCT5_Y(cir_out);\n                circ_area.y2 = lt_origo.y + LV_CIRC_OCT5_Y(cir_out);\n                fill_fp(&circ_area, mask, color, opa);\n            }\n\n            circ_area.x1 = lt_origo.x + LV_CIRC_OCT6_X(cir_out);\n            circ_area.x2 = lt_origo.x + LV_CIRC_OCT6_X(cir_out);\n            circ_area.y1 = lt_origo.y + LV_CIRC_OCT6_Y(cir_out);\n            circ_area.y2 = lt_origo.y + LV_CIRC_OCT6_Y(cir_out) + act_w1;\n            fill_fp(&circ_area, mask, color, opa);\n        }\n\n        /*Draw the octets to the right top corner*/\n        if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {\n            circ_area.x1 = rt_origo.x + LV_CIRC_OCT7_X(cir_out);\n            circ_area.x2 = rt_origo.x + LV_CIRC_OCT7_X(cir_out);\n            circ_area.y1 = rt_origo.y + LV_CIRC_OCT7_Y(cir_out);\n            circ_area.y2 = rt_origo.y + LV_CIRC_OCT7_Y(cir_out) + act_w2;\n            fill_fp(&circ_area, mask, color, opa);\n\n            /*Don't draw if the lines are common in the middle*/\n            if(rb_origo.y + LV_CIRC_OCT1_Y(cir_out) > rt_origo.y + LV_CIRC_OCT8_Y(cir_out)) {\n                circ_area.x1 = rt_origo.x + LV_CIRC_OCT8_X(cir_out) - act_w1;\n                circ_area.x2 = rt_origo.x + LV_CIRC_OCT8_X(cir_out);\n                circ_area.y1 = rt_origo.y + LV_CIRC_OCT8_Y(cir_out);\n                circ_area.y2 = rt_origo.y + LV_CIRC_OCT8_Y(cir_out);\n                fill_fp(&circ_area, mask, color, opa);\n            }\n        }\n        lv_circ_next(&cir_out, &tmp_out);\n\n        /*The internal circle will be ready faster\n         * so check it! */\n        if(cir_in.y < cir_in.x) {\n            lv_circ_next(&cir_in, &tmp_in);\n        }\n    }\n\n\n#if LV_ANTIALIAS != 0\n\n    /*Last parts of the outer anti-alias*/\n    out_y_seg_end = cir_out.y;\n    lv_coord_t seg_size = out_y_seg_end - out_y_seg_start;\n    lv_point_t aa_p;\n\n    aa_p.x = out_x_last;\n    aa_p.y = out_y_seg_start;\n\n    lv_coord_t i;\n    for(i = 0; i  < seg_size; i++) {\n        lv_opa_t aa_opa = opa - lv_draw_aa_get_opa(seg_size, i, opa);\n        if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {\n            px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) + 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, style->body.border.color, aa_opa);\n            px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);\n        }\n\n        if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {\n            px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);\n            px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) - 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, style->body.border.color, aa_opa);\n        }\n\n        if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {\n            px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) - 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, style->body.border.color, aa_opa);\n            px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);\n        }\n\n        if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {\n            px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);\n            px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) + 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, style->body.border.color, aa_opa);\n        }\n    }\n\n    /*In some cases the last pixel in the outer middle is not drawn*/\n    if(LV_MATH_ABS(aa_p.x - aa_p.y) == seg_size) {\n        aa_p.x = out_x_last;\n        aa_p.y = out_x_last;\n\n        lv_opa_t aa_opa = opa >> 1;\n\n        if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {\n            px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p), rb_origo.y + LV_CIRC_OCT2_Y(aa_p), mask, style->body.border.color, aa_opa);\n        }\n\n        if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {\n            px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p), lb_origo.y + LV_CIRC_OCT4_Y(aa_p), mask, style->body.border.color, aa_opa);\n        }\n\n        if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {\n            px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p), lt_origo.y + LV_CIRC_OCT6_Y(aa_p), mask, style->body.border.color, aa_opa);\n        }\n\n        if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {\n            px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p), rt_origo.y + LV_CIRC_OCT8_Y(aa_p), mask, style->body.border.color, aa_opa);\n        }\n    }\n\n    /*Last parts of the inner anti-alias*/\n    in_y_seg_end = cir_in.y;\n    aa_p.x = in_x_last;\n    aa_p.y = in_y_seg_start;\n    seg_size = in_y_seg_end - in_y_seg_start;\n\n    for(i = 0; i  < seg_size; i++) {\n        lv_opa_t aa_opa =  lv_draw_aa_get_opa(seg_size, i, opa);\n        if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {\n            px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) - 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, style->body.border.color, aa_opa);\n        }\n\n        if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {\n            px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);\n        }\n\n        if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {\n            px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) + 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, style->body.border.color, aa_opa);\n        }\n\n        if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {\n            px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);\n        }\n\n        if(LV_CIRC_OCT1_X(aa_p) - 1 != LV_CIRC_OCT2_X(aa_p) + i) {\n            if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {\n                px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);\n            }\n\n            if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {\n                px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) + 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, style->body.border.color, aa_opa);\n            }\n\n            if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {\n                px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);\n            }\n\n            if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {\n                px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) - 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, style->body.border.color, aa_opa);\n            }\n        }\n    }\n\n#endif\n\n}\n\n#if USE_LV_SHADOW && LV_VDB_SIZE\n\n/**\n * Draw a shadow\n * @param rect pointer to rectangle object\n * @param mask pointer to a mask area (from the design functions)\n * @param opa_scale scale down all opacities by the factor\n */\nstatic void lv_draw_shadow(const lv_area_t * coords, const lv_area_t * mask, const  lv_style_t * style, lv_opa_t opa_scale)\n{\n    /* If mask is in the middle of cords do not draw shadow*/\n    lv_coord_t radius = style->body.radius;\n    lv_coord_t width = lv_area_get_width(coords);\n    lv_coord_t height = lv_area_get_height(coords);\n    radius = lv_draw_cont_radius_corr(radius, width, height);\n    lv_area_t area_tmp;\n\n    /*Check horizontally without radius*/\n    lv_area_copy(&area_tmp, coords);\n    area_tmp.x1 += radius;\n    area_tmp.x2 -= radius;\n    if(lv_area_is_in(mask, &area_tmp) != false) return;\n\n    /*Check vertically without radius*/\n    lv_area_copy(&area_tmp, coords);\n    area_tmp.y1 += radius;\n    area_tmp.y2 -= radius;\n    if(lv_area_is_in(mask, &area_tmp) != false) return;\n\n    if(style->body.shadow.type == LV_SHADOW_FULL) {\n        lv_draw_shadow_full(coords, mask, style, opa_scale);\n    } else if(style->body.shadow.type == LV_SHADOW_BOTTOM) {\n        lv_draw_shadow_bottom(coords, mask, style, opa_scale);\n    }\n}\n\nstatic void lv_draw_shadow_full(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)\n{\n\n    /* KNOWN ISSUE\n     * The algorithm calculates the shadow only above the middle point of the radius (speaking about the left top corner).\n     * It causes an error because it doesn't consider how long the straight edge is which effects the value of bottom of the corner shadow.\n     * In addition the straight shadow is drawn from the middles point of the radius however\n     * the ends of the straight parts still should be effected by the corner shadow.\n     * It also causes an issue in opacity. A smaller radius means smaller average shadow opacity.\n     * The solution should be to start `line` from `- swidth` and handle if the straight part is short (or zero) and the value is taken from\n     * the other corner. `col` also should start from `- swidth`\n     */\n\n\n    lv_coord_t radius = style->body.radius;\n    lv_coord_t swidth = style->body.shadow.width;\n\n    lv_coord_t width = lv_area_get_width(coords);\n    lv_coord_t height = lv_area_get_height(coords);\n\n    radius = lv_draw_cont_radius_corr(radius, width, height);\n\n    radius += LV_ANTIALIAS;\n\n#if LV_COMPILER_VLA_SUPPORTED\n    lv_coord_t curve_x[radius + swidth + 1];     /*Stores the 'x' coordinates of a quarter circle.*/\n#else\n# if LV_HOR_RES > LV_VER_RES\n    lv_coord_t curve_x[LV_HOR_RES];\n# else\n    lv_coord_t curve_x[LV_VER_RES];\n# endif\n#endif\n    memset(curve_x, 0, sizeof(curve_x));\n    lv_point_t circ;\n    lv_coord_t circ_tmp;\n    lv_circ_init(&circ, &circ_tmp, radius);\n    while(lv_circ_cont(&circ)) {\n        curve_x[LV_CIRC_OCT1_Y(circ)] = LV_CIRC_OCT1_X(circ);\n        curve_x[LV_CIRC_OCT2_Y(circ)] = LV_CIRC_OCT2_X(circ);\n        lv_circ_next(&circ, &circ_tmp);\n    }\n    int16_t line;\n\n    int16_t filter_width = 2 * swidth + 1;\n#if LV_COMPILER_VLA_SUPPORTED\n    uint32_t line_1d_blur[filter_width];\n#else\n# if LV_HOR_RES > LV_VER_RES\n    uint32_t line_1d_blur[LV_HOR_RES];\n# else\n    uint32_t line_1d_blur[LV_VER_RES];\n# endif\n#endif\n    /*1D Blur horizontally*/\n    lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8;\n    for(line = 0; line < filter_width; line++) {\n        line_1d_blur[line] = (uint32_t)((uint32_t)(filter_width - line) * (opa * 2)  << SHADOW_OPA_EXTRA_PRECISION) / (filter_width * filter_width);\n    }\n\n    uint16_t col;\n#if LV_COMPILER_VLA_SUPPORTED\n    lv_opa_t line_2d_blur[radius + swidth + 1];\n#else\n# if LV_HOR_RES > LV_VER_RES\n    lv_opa_t line_2d_blur[LV_HOR_RES];\n# else\n    lv_opa_t line_2d_blur[LV_VER_RES];\n# endif\n#endif\n\n    lv_point_t point_rt;\n    lv_point_t point_rb;\n    lv_point_t point_lt;\n    lv_point_t point_lb;\n    lv_point_t ofs_rb;\n    lv_point_t ofs_rt;\n    lv_point_t ofs_lb;\n    lv_point_t ofs_lt;\n    ofs_rb.x = coords->x2 - radius - LV_ANTIALIAS;\n    ofs_rb.y = coords->y2 - radius - LV_ANTIALIAS;\n\n    ofs_rt.x = coords->x2 - radius - LV_ANTIALIAS;\n    ofs_rt.y = coords->y1 + radius + LV_ANTIALIAS;\n\n    ofs_lb.x = coords->x1 + radius + LV_ANTIALIAS;\n    ofs_lb.y = coords->y2 - radius - LV_ANTIALIAS;\n\n    ofs_lt.x = coords->x1 + radius + LV_ANTIALIAS;\n    ofs_lt.y = coords->y1 + radius + LV_ANTIALIAS;\n    bool line_ready;\n    for(line = 0; line <= radius + swidth; line++) {        /*Check all rows and make the 1D blur to 2D*/\n        line_ready = false;\n        for(col = 0; col <= radius + swidth; col++) {        /*Check all pixels in a 1D blur line (from the origo to last shadow pixel (radius + swidth))*/\n\n            /*Sum the opacities from the lines above and below this 'row'*/\n            int16_t line_rel;\n            uint32_t px_opa_sum = 0;\n            for(line_rel = -swidth; line_rel <= swidth; line_rel ++) {\n                /*Get the relative x position of the 'line_rel' to 'line'*/\n                int16_t col_rel;\n                if(line + line_rel < 0) {                       /*Below the radius, here is the blur of the edge */\n                    col_rel = radius - curve_x[line] - col;\n                } else if(line + line_rel > radius) {           /*Above the radius, here won't be more 1D blur*/\n                    break;\n                } else {                                        /*Blur from the curve*/\n                    col_rel = curve_x[line + line_rel] - curve_x[line] - col;\n                }\n\n                /*Add the value of the 1D blur on 'col_rel' position*/\n                if(col_rel < -swidth) {                         /*Outside of the blurred area. */\n                    if(line_rel == -swidth) line_ready = true;  /*If no data even on the very first line then it wont't be anything else in this line*/\n                    break;                                      /*Break anyway because only smaller 'col_rel' values will come */\n                } else if(col_rel > swidth) px_opa_sum += line_1d_blur[0];      /*Inside the not blurred area*/\n                else px_opa_sum += line_1d_blur[swidth - col_rel];              /*On the 1D blur (+ swidth to align to the center)*/\n            }\n\n            line_2d_blur[col] = px_opa_sum >> SHADOW_OPA_EXTRA_PRECISION;\n            if(line_ready) {\n                col++;      /*To make this line to the last one ( drawing will go to '< col')*/\n                break;\n            }\n\n        }\n\n        /*Flush the line*/\n        point_rt.x = curve_x[line] + ofs_rt.x + 1;\n        point_rt.y = ofs_rt.y - line;\n\n        point_rb.x = curve_x[line] + ofs_rb.x + 1;\n        point_rb.y = ofs_rb.y + line;\n\n        point_lt.x = ofs_lt.x -  curve_x[line] - 1;\n        point_lt.y = ofs_lt.y - line;\n\n        point_lb.x = ofs_lb.x - curve_x[line] - 1;\n        point_lb.y = ofs_lb.y + line;\n\n        uint16_t d;\n        for(d = 1; d < col; d++) {\n\n            if(point_lt.x < ofs_lt.x && point_lt.y < ofs_lt.y) {\n                px_fp(point_lt.x, point_lt.y, mask, style->body.shadow.color, line_2d_blur[d]);\n            }\n\n            if(point_lb.x < ofs_lb.x && point_lb.y > ofs_lb.y) {\n                px_fp(point_lb.x, point_lb.y, mask, style->body.shadow.color, line_2d_blur[d]);\n            }\n\n            if(point_rt.x > ofs_rt.x && point_rt.y < ofs_rt.y) {\n                px_fp(point_rt.x, point_rt.y, mask, style->body.shadow.color, line_2d_blur[d]);\n            }\n\n            if(point_rb.x > ofs_rb.x && point_rb.y > ofs_rb.y) {\n                px_fp(point_rb.x, point_rb.y, mask, style->body.shadow.color, line_2d_blur[d]);\n            }\n\n            point_rb.x++;\n            point_lb.x--;\n\n            point_rt.x++;\n            point_lt.x--;\n        }\n\n        /* Put the first line to the edges too.\n         * It is not correct because blur should be done below the corner too\n         * but is is simple, fast and gives a good enough result*/\n        if(line == 0) lv_draw_shadow_full_straight(coords, mask, style, line_2d_blur);\n    }\n}\n\n\nstatic void lv_draw_shadow_bottom(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)\n{\n    lv_coord_t radius = style->body.radius;\n    lv_coord_t swidth = style->body.shadow.width;\n    lv_coord_t width = lv_area_get_width(coords);\n    lv_coord_t height = lv_area_get_height(coords);\n\n    radius = lv_draw_cont_radius_corr(radius, width, height);\n    radius += LV_ANTIALIAS * SHADOW_BOTTOM_AA_EXTRA_RADIUS;\n    swidth += LV_ANTIALIAS;\n#if LV_COMPILER_VLA_SUPPORTED\n    lv_coord_t curve_x[radius + 1];             /*Stores the 'x' coordinates of a quarter circle.*/\n#else\n# if LV_HOR_RES > LV_VER_RES\n    lv_coord_t curve_x[LV_HOR_RES];\n# else\n    lv_coord_t curve_x[LV_VER_RES];\n# endif\n#endif\n    lv_point_t circ;\n    lv_coord_t circ_tmp;\n    lv_circ_init(&circ, &circ_tmp, radius);\n    while(lv_circ_cont(&circ)) {\n        curve_x[LV_CIRC_OCT1_Y(circ)] = LV_CIRC_OCT1_X(circ);\n        curve_x[LV_CIRC_OCT2_Y(circ)] = LV_CIRC_OCT2_X(circ);\n        lv_circ_next(&circ, &circ_tmp);\n    }\n\n    int16_t col;\n#if LV_COMPILER_VLA_SUPPORTED\n    lv_opa_t line_1d_blur[swidth];\n#else\n# if LV_HOR_RES > LV_VER_RES\n    lv_opa_t line_1d_blur[LV_HOR_RES];\n# else\n    lv_opa_t line_1d_blur[LV_VER_RES];\n# endif\n#endif\n\n    lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->body.opa : (uint16_t)((uint16_t) style->body.opa * opa_scale) >> 8;\n    for(col = 0; col < swidth; col++) {\n        line_1d_blur[col] = (uint32_t)((uint32_t)(swidth - col) * opa / 2) / (swidth);\n    }\n\n    lv_point_t point_l;\n    lv_point_t point_r;\n    lv_area_t area_mid;\n    lv_point_t ofs_l;\n    lv_point_t ofs_r;\n\n    ofs_l.x = coords->x1 + radius;\n    ofs_l.y = coords->y2 - radius + 1 - LV_ANTIALIAS;\n\n    ofs_r.x = coords->x2 - radius;\n    ofs_r.y = coords->y2 - radius + 1 - LV_ANTIALIAS;\n\n    for(col = 0; col <= radius; col++) {\n        point_l.x = ofs_l.x - col ;\n        point_l.y = ofs_l.y + curve_x[col];\n\n        point_r.x = ofs_r.x + col;\n        point_r.y = ofs_r.y + curve_x[col];\n\n        lv_opa_t px_opa;\n        int16_t diff = col == 0 ? 0 : curve_x[col - 1] - curve_x[col];\n        uint16_t d;\n        for(d = 0; d < swidth; d++) {\n            /*When stepping a pixel in y calculate the average with the pixel from the prev. column to make a blur */\n            if(diff == 0) {\n                px_opa = line_1d_blur[d];\n            } else {\n                px_opa = (uint16_t)((uint16_t)line_1d_blur[d] + line_1d_blur[d - diff]) >> 1;\n            }\n            px_fp(point_l.x, point_l.y, mask, style->body.shadow.color, px_opa);\n            point_l.y ++;\n\n            /*Don't overdraw the pixel on the middle*/\n            if(point_r.x > ofs_l.x) {\n                px_fp(point_r.x, point_r.y, mask, style->body.shadow.color, px_opa);\n            }\n            point_r.y ++;\n        }\n\n    }\n\n    area_mid.x1 = ofs_l.x + 1;\n    area_mid.y1 = ofs_l.y + radius;\n    area_mid.x2 = ofs_r.x - 1;\n    area_mid.y2 = area_mid.y1;\n\n    uint16_t d;\n    for(d = 0; d < swidth; d++) {\n        fill_fp(&area_mid, mask, style->body.shadow.color, line_1d_blur[d]);\n        area_mid.y1 ++;\n        area_mid.y2 ++;\n    }\n}\n\nstatic void lv_draw_shadow_full_straight(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, const lv_opa_t * map)\n{\n    lv_coord_t radius = style->body.radius;\n    lv_coord_t swidth = style->body.shadow.width;// + LV_ANTIALIAS;\n    lv_coord_t width = lv_area_get_width(coords);\n    lv_coord_t height = lv_area_get_height(coords);\n\n    radius = lv_draw_cont_radius_corr(radius, width, height);\n    radius += LV_ANTIALIAS;\n\n    lv_area_t right_area;\n    right_area.x1 = coords->x2 + 1 - LV_ANTIALIAS;\n    right_area.y1 = coords->y1 + radius + LV_ANTIALIAS;\n    right_area.x2 = right_area.x1;\n    right_area.y2 = coords->y2 - radius - LV_ANTIALIAS;\n\n    lv_area_t left_area;\n    left_area.x1 = coords->x1 - 1 + LV_ANTIALIAS;\n    left_area.y1 = coords->y1 + radius + LV_ANTIALIAS;\n    left_area.x2 = left_area.x1;\n    left_area.y2 = coords->y2 - radius - LV_ANTIALIAS;\n\n    lv_area_t top_area;\n    top_area.x1 = coords->x1 + radius + LV_ANTIALIAS;\n    top_area.y1 = coords->y1 - 1 + LV_ANTIALIAS;\n    top_area.x2 = coords->x2 - radius - LV_ANTIALIAS;\n    top_area.y2 = top_area.y1;\n\n    lv_area_t bottom_area;\n    bottom_area.x1 = coords->x1 + radius + LV_ANTIALIAS;\n    bottom_area.y1 = coords->y2 + 1 - LV_ANTIALIAS;\n    bottom_area.x2 = coords->x2 - radius - LV_ANTIALIAS;\n    bottom_area.y2 = bottom_area.y1;\n\n    lv_opa_t opa_act;\n    int16_t d;\n    for(d = 1 /*+ LV_ANTIALIAS*/; d <= swidth/* - LV_ANTIALIAS*/; d++) {\n        opa_act = map[d];\n\n        fill_fp(&right_area, mask, style->body.shadow.color, opa_act);\n        right_area.x1++;\n        right_area.x2++;\n\n        fill_fp(&left_area, mask, style->body.shadow.color, opa_act);\n        left_area.x1--;\n        left_area.x2--;\n\n        fill_fp(&top_area, mask, style->body.shadow.color, opa_act);\n        top_area.y1--;\n        top_area.y2--;\n\n        fill_fp(&bottom_area, mask, style->body.shadow.color, opa_act);\n        bottom_area.y1++;\n        bottom_area.y2++;\n    }\n}\n\n#endif\n\n\nstatic uint16_t lv_draw_cont_radius_corr(uint16_t r, lv_coord_t w, lv_coord_t h)\n{\n    if(r >= (w >> 1)) {\n        r = (w >> 1);\n        if(r != 0) r--;\n    }\n    if(r >= (h >> 1)) {\n        r = (h >> 1);\n        if(r != 0) r--;\n    }\n\n    if(r > 0) r -= LV_ANTIALIAS;\n\n    return r;\n}\n\n#if LV_ANTIALIAS\n\n/**\n * Approximate the opacity for anti-aliasing.\n * Used  the first segment of a circle which is the longest and have the most non-linearity (cos)\n * @param seg length of the line segment\n * @param px_id index of pixel on the line segment\n * @param line_opa opacity of the lien (it will be the max opacity)\n * @return the desired opacity of the pixel\n */\nstatic lv_opa_t antialias_get_opa_circ(lv_coord_t seg, lv_coord_t px_id, lv_opa_t opa)\n{\n    static const  lv_opa_t opa_map[8] = {250, 242, 221, 196, 163, 122, 74, 18};\n\n    if(seg == 0) return LV_OPA_TRANSP;\n    else if(seg == 1) return LV_OPA_80;\n    else {\n\n        uint8_t id = (uint32_t)((uint32_t)px_id * (sizeof(opa_map) - 1)) / (seg - 1);\n        return (uint32_t)((uint32_t) opa_map[id] * opa) >> 8;\n\n    }\n\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_draw/lv_draw_rect.h",
    "content": "/**\n * @file lv_draw_rect.h\n *\n */\n\n#ifndef LV_DRAW_RECT_H\n#define LV_DRAW_RECT_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_draw.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Draw a rectangle\n * @param coords the coordinates of the rectangle\n * @param mask the rectangle will be drawn only in this mask\n * @param style pointer to a style\n * @param opa_scale scale down all opacities by the factor\n */\nvoid lv_draw_rect(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale);\n\n/**********************\n *      MACROS\n **********************/\n\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_DRAW_RECT_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_draw/lv_draw_triangle.c",
    "content": "/**\n * @file lv_draw_triangle.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_draw_triangle.h\"\n#include \"../lv_misc/lv_math.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic void point_swap(lv_point_t * p1, lv_point_t * p2);\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n#if USE_LV_TRIANGLE != 0\n/**\n *\n * @param points pointer to an array with 3 points\n * @param mask the triangle will be drawn only in this mask\n * @param color color of the triangle\n */\nvoid lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, lv_color_t color)\n{\n    lv_point_t tri[3];\n\n    memcpy(tri, points, sizeof(tri));\n\n    /*Sort the vertices according to their y coordinate (0: y max, 1: y mid, 2:y min)*/\n    if(tri[1].y < tri[0].y) point_swap(&tri[1], &tri[0]);\n    if(tri[2].y < tri[1].y) point_swap(&tri[2], &tri[1]);\n    if(tri[1].y < tri[0].y) point_swap(&tri[1], &tri[0]);\n\n    /*Return is the triangle is degenerated*/\n    if(tri[0].x == tri[1].x && tri[0].y == tri[1].y) return;\n    if(tri[1].x == tri[2].x && tri[1].y == tri[2].y) return;\n    if(tri[0].x == tri[2].x && tri[0].y == tri[2].y) return;\n\n    if(tri[0].x == tri[1].x && tri[1].x == tri[2].x) return;\n    if(tri[0].y == tri[1].y && tri[1].y == tri[2].y) return;\n\n    /*Draw the triangle*/\n    lv_point_t edge1;\n    lv_coord_t dx1 = LV_MATH_ABS(tri[0].x - tri[1].x);\n    lv_coord_t sx1 = tri[0].x < tri[1].x ? 1 : -1;\n    lv_coord_t dy1 = LV_MATH_ABS(tri[0].y - tri[1].y);\n    lv_coord_t sy1 = tri[0].y < tri[1].y ? 1 : -1;\n    lv_coord_t err1 = (dx1 > dy1 ? dx1 : -dy1) / 2;\n    lv_coord_t err_tmp1;\n\n    lv_point_t edge2;\n    lv_coord_t dx2 = LV_MATH_ABS(tri[0].x - tri[2].x);\n    lv_coord_t sx2 = tri[0].x < tri[2].x ? 1 : -1;\n    lv_coord_t dy2 = LV_MATH_ABS(tri[0].y - tri[2].y);\n    lv_coord_t sy2 = tri[0].y < tri[2].y ? 1 : -1;\n    lv_coord_t err2 = (dx1 > dy2 ? dx2 : -dy2) / 2;\n    lv_coord_t err_tmp2;\n\n    lv_coord_t y1_tmp;\n    lv_coord_t y2_tmp;\n\n    edge1.x = tri[0].x;\n    edge1.y = tri[0].y;\n    edge2.x = tri[0].x;\n    edge2.y = tri[0].y;\n    lv_area_t act_area;\n    lv_area_t draw_area;\n\n    while(1) {\n        act_area.x1 = edge1.x;\n        act_area.x2 = edge2.x ;\n        act_area.y1 = edge1.y;\n        act_area.y2 = edge2.y ;\n\n\n        draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2);\n        draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2);\n        draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2);\n        draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2);\n        draw_area.x2--; /*Do not draw most right pixel because it will be drawn by the adjacent triangle*/\n        fill_fp(&draw_area, mask, color, LV_OPA_50);\n\n        /*Calc. the next point of edge1*/\n        y1_tmp = edge1.y;\n        do {\n            if(edge1.x == tri[1].x && edge1.y == tri[1].y) {\n\n                dx1 = LV_MATH_ABS(tri[1].x - tri[2].x);\n                sx1 = tri[1].x < tri[2].x ? 1 : -1;\n                dy1 = LV_MATH_ABS(tri[1].y - tri[2].y);\n                sy1 = tri[1].y < tri[2].y ? 1 : -1;\n                err1 = (dx1 > dy1 ? dx1 : -dy1) / 2;\n            } else if(edge1.x == tri[2].x && edge1.y == tri[2].y) return;\n            err_tmp1 = err1;\n            if(err_tmp1 > -dx1) {\n                err1 -= dy1;\n                edge1.x += sx1;\n            }\n            if(err_tmp1 < dy1) {\n                err1 += dx1;\n                edge1.y += sy1;\n            }\n        } while(edge1.y == y1_tmp);\n\n        /*Calc. the next point of edge2*/\n        y2_tmp = edge2.y;\n        do {\n            if(edge2.x == tri[2].x && edge2.y == tri[2].y) return;\n            err_tmp2 = err2;\n            if(err_tmp2 > -dx2) {\n                err2 -= dy2;\n                edge2.x += sx2;\n            }\n            if(err_tmp2 < dy2) {\n                err2 += dx2;\n                edge2.y += sy2;\n            }\n        } while(edge2.y == y2_tmp);\n    }\n}\n#endif\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n\n#if USE_LV_TRIANGLE != 0\n/**\n * Swap two points\n * p1 pointer to the first point\n * p2 pointer to the second point\n */\nstatic void point_swap(lv_point_t * p1, lv_point_t * p2)\n{\n    lv_point_t tmp;\n    tmp.x = p1->x;\n    tmp.y = p1->y;\n\n    p1->x = p2->x;\n    p1->y = p2->y;\n\n    p2->x = tmp.x;\n    p2->y = tmp.y;\n\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_draw/lv_draw_triangle.h",
    "content": "/**\n * @file lv_draw_triangle.h\n *\n */\n\n#ifndef LV_DRAW_TRIANGLE_H\n#define LV_DRAW_TRIANGLE_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_draw.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n/*Experimental use for 3D modeling*/\n#define USE_LV_TRIANGLE 1\n\n#if USE_LV_TRIANGLE != 0\n/**\n *\n * @param points pointer to an array with 3 points\n * @param mask the triangle will be drawn only in this mask\n * @param color color of the triangle\n */\nvoid lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, lv_color_t color);\n#endif\n\n/**********************\n *      MACROS\n **********************/\n\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_DRAW_TRIANGLE_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_draw/lv_draw_vbasic.c",
    "content": "/**\n * @file lv_vdraw.c\n *\n */\n\n#include \"lv_draw_vbasic.h\"\n\n#include <stdint.h>\n#include <string.h>\n\n#include \"../lv_hal/lv_hal_disp.h\"\n#include \"../lv_misc/lv_area.h\"\n#include \"../lv_misc/lv_font.h\"\n#include \"../lv_misc/lv_color.h\"\n#include \"../lv_misc/lv_log.h\"\n\n#if LV_VDB_SIZE != 0\n\n#include <stddef.h>\n#include \"../lv_core/lv_vdb.h\"\n#include \"lv_draw.h\"\n\n/*********************\n *      INCLUDES\n *********************/\n\n/*********************\n *      DEFINES\n *********************/\n#define VFILL_HW_ACC_SIZE_LIMIT    50      /*Always fill < 50 px with 'sw_color_fill' because of the hw. init overhead*/\n\n#ifndef LV_ATTRIBUTE_MEM_ALIGN\n#define LV_ATTRIBUTE_MEM_ALIGN\n#endif\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic void sw_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa);\nstatic void sw_color_fill(lv_area_t * mem_area, lv_color_t * mem, const lv_area_t * fill_area, lv_color_t color, lv_opa_t opa);\n\n#if LV_COLOR_SCREEN_TRANSP\nstatic inline lv_color_t color_mix_2_alpha(lv_color_t bg_color, lv_opa_t bg_opa, lv_color_t fg_color, lv_opa_t fg_opa);\n#endif\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Put a pixel in the Virtual Display Buffer\n * @param x pixel x coordinate\n * @param y pixel y coordinate\n * @param mask_p fill only on this mask (truncated to VDB area)\n * @param color pixel color\n * @param opa opacity of the area (0..255)\n */\nvoid lv_vpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa)\n{\n    if(opa < LV_OPA_MIN) return;\n    if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;\n\n    lv_vdb_t * vdb_p = lv_vdb_get();\n    if(!vdb_p) {\n        LV_LOG_WARN(\"Invalid VDB pointer\");\n        return;\n    }\n\n    /*Pixel out of the mask*/\n    if(x < mask_p->x1 || x > mask_p->x2 ||\n            y < mask_p->y1 || y > mask_p->y2) {\n        return;\n    }\n\n    uint32_t vdb_width = lv_area_get_width(&vdb_p->area);\n\n    /*Make the coordinates relative to VDB*/\n    x -= vdb_p->area.x1;\n    y -= vdb_p->area.y1;\n\n    lv_disp_t * disp = lv_disp_get_active();\n    if(disp->driver.vdb_wr) {\n        disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width, x, y, color, opa);\n    } else {\n        lv_color_t * vdb_px_p = vdb_p->buf + y * vdb_width + x;\n#if LV_COLOR_SCREEN_TRANSP == 0\n        if(opa == LV_OPA_COVER) {\n            *vdb_px_p = color;\n        } else {\n            *vdb_px_p = lv_color_mix(color, *vdb_px_p, opa);\n        }\n#else\n        *vdb_px_p = color_mix_2_alpha(*vdb_px_p, (*vdb_px_p).alpha, color, opa);\n#endif\n    }\n}\n\n\n/**\n * Fill an area in the Virtual Display Buffer\n * @param cords_p coordinates of the area to fill\n * @param mask_p fill only o this mask  (truncated to VDB area)\n * @param color fill color\n * @param opa opacity of the area (0..255)\n */\nvoid lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p,\n              lv_color_t color, lv_opa_t opa)\n{\n    if(opa < LV_OPA_MIN) return;\n    if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;\n\n    lv_area_t res_a;\n    bool union_ok;\n    lv_vdb_t * vdb_p = lv_vdb_get();\n    if(!vdb_p) {\n        LV_LOG_WARN(\"Invalid VDB pointer\");\n        return;\n    }\n\n    /*Get the union of cord and mask*/\n    /* The mask is already truncated to the vdb size\n     * in 'lv_refr_area_with_vdb' function */\n    union_ok = lv_area_intersect(&res_a, cords_p, mask_p);\n\n    /*If there are common part of the three area then draw to the vdb*/\n    if(union_ok == false) return;\n\n    lv_area_t vdb_rel_a;   /*Stores relative coordinates on vdb*/\n    vdb_rel_a.x1 = res_a.x1 - vdb_p->area.x1;\n    vdb_rel_a.y1 = res_a.y1 - vdb_p->area.y1;\n    vdb_rel_a.x2 = res_a.x2 - vdb_p->area.x1;\n    vdb_rel_a.y2 = res_a.y2 - vdb_p->area.y1;\n\n    lv_color_t * vdb_buf_tmp = vdb_p->buf;\n    uint32_t vdb_width = lv_area_get_width(&vdb_p->area);\n    /*Move the vdb_tmp to the first row*/\n    vdb_buf_tmp += vdb_width * vdb_rel_a.y1;\n\n\n#if USE_LV_GPU\n    static LV_ATTRIBUTE_MEM_ALIGN lv_color_t color_array_tmp[LV_HOR_RES];       /*Used by 'lv_disp_mem_blend'*/\n    static lv_coord_t last_width = -1;\n\n    lv_coord_t w = lv_area_get_width(&vdb_rel_a);\n    /*Don't use hw. acc. for every small fill (because of the init overhead)*/\n    if(w < VFILL_HW_ACC_SIZE_LIMIT) {\n        sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa);\n    }\n    /*Not opaque fill*/\n    else if(opa == LV_OPA_COVER) {\n        /*Use hw fill if present*/\n        if(lv_disp_is_mem_fill_supported()) {\n            lv_coord_t row;\n            for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) {\n                lv_disp_mem_fill(&vdb_buf_tmp[vdb_rel_a.x1], w, color);\n                vdb_buf_tmp += vdb_width;\n            }\n        }\n        /*Use hw blend if present and the area is not too small*/\n        else if(lv_area_get_height(&vdb_rel_a) > VFILL_HW_ACC_SIZE_LIMIT &&\n                lv_disp_is_mem_blend_supported()) {\n            /*Fill a  one line sized buffer with a color and blend this later*/\n            if(color_array_tmp[0].full != color.full || last_width != w) {\n                uint16_t i;\n                for(i = 0; i < w; i++) {\n                    color_array_tmp[i].full = color.full;\n                }\n                last_width = w;\n            }\n\n            /*Blend the filled line to every line VDB line-by-line*/\n            lv_coord_t row;\n            for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) {\n                lv_disp_mem_blend(&vdb_buf_tmp[vdb_rel_a.x1], color_array_tmp, w, opa);\n                vdb_buf_tmp += vdb_width;\n            }\n\n        }\n        /*Else use sw fill if no better option*/\n        else {\n            sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa);\n        }\n\n    }\n    /*Fill with opacity*/\n    else {\n        /*Use hw blend if present*/\n        if(lv_disp_is_mem_blend_supported()) {\n            if(color_array_tmp[0].full != color.full || last_width != w) {\n                uint16_t i;\n                for(i = 0; i < w; i++) {\n                    color_array_tmp[i].full = color.full;\n                }\n\n                last_width = w;\n            }\n            lv_coord_t row;\n            for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) {\n                lv_disp_mem_blend(&vdb_buf_tmp[vdb_rel_a.x1], color_array_tmp, w, opa);\n                vdb_buf_tmp += vdb_width;\n            }\n\n        }\n        /*Use sw fill with opa if no better option*/\n        else {\n            sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa);\n        }\n\n    }\n#else\n    sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa);\n#endif\n}\n\n/**\n * Draw a letter in the Virtual Display Buffer\n * @param pos_p left-top coordinate of the latter\n * @param mask_p the letter will be drawn only on this area  (truncated to VDB area)\n * @param font_p pointer to font\n * @param letter a letter to draw\n * @param color color of letter\n * @param opa opacity of letter (0..255)\n */\nvoid lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p,\n                const lv_font_t * font_p, uint32_t letter,\n                lv_color_t color, lv_opa_t opa)\n{\n    const uint8_t bpp1_opa_table[2] =  {0, 255};                   /*Opacity mapping with bpp = 1 (Just for compatibility)*/\n    const uint8_t bpp2_opa_table[4] =  {0, 85, 170, 255};          /*Opacity mapping with bpp = 2*/\n    const uint8_t bpp4_opa_table[16] = {0,   17,  34,  51,         /*Opacity mapping with bpp = 4*/\n                                        68,  85,  102, 119,\n                                        136, 153, 170, 187,\n                                        204, 221, 238, 255\n                                       };\n    if(opa < LV_OPA_MIN) return;\n    if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;\n\n    if(font_p == NULL) {\n        LV_LOG_WARN(\"Font: character's bitmap not found\");\n        return;\n    }\n\n    lv_coord_t pos_x = pos_p->x;\n    lv_coord_t pos_y = pos_p->y;\n    uint8_t letter_w = lv_font_get_real_width(font_p, letter);\n    uint8_t letter_h = lv_font_get_height(font_p);\n    uint8_t bpp = lv_font_get_bpp(font_p, letter);  /*Bit per pixel (1,2, 4 or 8)*/\n    const uint8_t * bpp_opa_table;\n    uint8_t mask_init;\n    uint8_t mask;\n\n    if(lv_font_is_monospace(font_p, letter)) {\n        pos_x += (lv_font_get_width(font_p, letter) - letter_w) / 2;\n    }\n\n\n    switch(bpp) {\n        case 1:\n            bpp_opa_table = bpp1_opa_table;\n            mask_init = 0x80;\n            break;\n        case 2:\n            bpp_opa_table = bpp2_opa_table;\n            mask_init = 0xC0;\n            break;\n        case 4:\n            bpp_opa_table = bpp4_opa_table;\n            mask_init = 0xF0;\n            break;\n        case 8:\n            bpp_opa_table = NULL;\n            mask_init = 0xFF;\n            break;             /*No opa table, pixel value will be used directly*/\n        default:\n            return;        /*Invalid bpp. Can't render the letter*/\n    }\n\n    const uint8_t * map_p = lv_font_get_bitmap(font_p, letter);\n\n    if(map_p == NULL) return;\n\n    /*If the letter is completely out of mask don't draw it */\n    if(pos_x + letter_w < mask_p->x1 || pos_x > mask_p->x2 ||\n            pos_y + letter_h < mask_p->y1 || pos_y > mask_p->y2) return;\n\n    lv_vdb_t * vdb_p = lv_vdb_get();\n    if(!vdb_p) {\n        LV_LOG_WARN(\"Invalid VDB pointer\");\n        return;\n    }\n\n    lv_coord_t vdb_width = lv_area_get_width(&vdb_p->area);\n    lv_color_t * vdb_buf_tmp = vdb_p->buf;\n    lv_coord_t col, row;\n    uint8_t col_bit;\n    uint8_t col_byte_cnt;\n    uint8_t width_byte_scr = letter_w >> 3;      /*Width in bytes (on the screen finally) (e.g. w = 11 -> 2 bytes wide)*/\n    if(letter_w & 0x7) width_byte_scr++;\n    uint8_t width_byte_bpp = (letter_w * bpp) >> 3;    /*Letter width in byte. Real width in the font*/\n    if((letter_w * bpp) & 0x7) width_byte_bpp++;\n\n    /* Calculate the col/row start/end on the map*/\n    lv_coord_t col_start = pos_x >= mask_p->x1 ? 0 : mask_p->x1 - pos_x;\n    lv_coord_t col_end = pos_x + letter_w <= mask_p->x2 ? letter_w : mask_p->x2 - pos_x + 1;\n    lv_coord_t row_start = pos_y >= mask_p->y1 ? 0 : mask_p->y1 - pos_y;\n    lv_coord_t row_end  = pos_y + letter_h <= mask_p->y2 ? letter_h : mask_p->y2 - pos_y + 1;\n\n    /*Set a pointer on VDB to the first pixel of the letter*/\n    vdb_buf_tmp += ((pos_y - vdb_p->area.y1) * vdb_width)\n                   + pos_x - vdb_p->area.x1;\n\n    /*If the letter is partially out of mask the move there on VDB*/\n    vdb_buf_tmp += (row_start * vdb_width) + col_start;\n\n    /*Move on the map too*/\n    map_p += (row_start * width_byte_bpp) + ((col_start * bpp) >> 3);\n\n    lv_disp_t * disp = lv_disp_get_active();\n\n    uint8_t letter_px;\n    lv_opa_t px_opa;\n    for(row = row_start; row < row_end; row ++) {\n        col_byte_cnt = 0;\n        col_bit = (col_start * bpp) % 8;\n        mask = mask_init >> col_bit;\n        for(col = col_start; col < col_end; col ++) {\n            letter_px = (*map_p & mask) >> (8 - col_bit - bpp);\n            if(letter_px != 0) {\n                if(opa == LV_OPA_COVER) {\n                    px_opa = bpp == 8 ? letter_px : bpp_opa_table[letter_px];\n                } else {\n                    px_opa = bpp == 8 ?\n                             (uint16_t)((uint16_t)letter_px * opa) >> 8 :\n                             (uint16_t)((uint16_t)bpp_opa_table[letter_px] * opa) >> 8;\n                }\n\n                if(disp->driver.vdb_wr) {\n                    disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width,\n                                        (col + pos_x) - vdb_p->area.x1, (row + pos_y) - vdb_p->area.y1,\n                                        color, px_opa);\n                } else {\n#if LV_COLOR_SCREEN_TRANSP == 0\n                    *vdb_buf_tmp = lv_color_mix(color, *vdb_buf_tmp, px_opa);\n#else\n                    *vdb_buf_tmp = color_mix_2_alpha(*vdb_buf_tmp, (*vdb_buf_tmp).alpha, color, px_opa);\n#endif\n                }\n            }\n\n            vdb_buf_tmp++;\n\n            if(col_bit < 8 - bpp) {\n                col_bit += bpp;\n                mask = mask >> bpp;\n            } else {\n                col_bit = 0;\n                col_byte_cnt ++;\n                mask = mask_init;\n                map_p ++;\n            }\n        }\n\n        map_p += (width_byte_bpp) - col_byte_cnt;\n        vdb_buf_tmp += vdb_width  - (col_end - col_start); /*Next row in VDB*/\n    }\n}\n\n/**\n * Draw a color map to the display (image)\n * @param cords_p coordinates the color map\n * @param mask_p the map will drawn only on this area  (truncated to VDB area)\n * @param map_p pointer to a lv_color_t array\n * @param opa opacity of the map\n * @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels\n * @param alpha_byte true: extra alpha byte is inserted for every pixel\n * @param recolor mix the pixels with this color\n * @param recolor_opa the intense of recoloring\n */\nvoid lv_vmap(const lv_area_t * cords_p, const lv_area_t * mask_p,\n             const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte,\n             lv_color_t recolor, lv_opa_t recolor_opa)\n{\n\n    if(opa < LV_OPA_MIN) return;\n    if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;\n\n    lv_area_t masked_a;\n    bool union_ok;\n    lv_vdb_t * vdb_p = lv_vdb_get();\n    if(!vdb_p) {\n        LV_LOG_WARN(\"Invalid VDB pointer\");\n        return;\n    }\n\n    /*Get the union of map size and mask*/\n    /* The mask is already truncated to the vdb size\n    * in 'lv_refr_area_with_vdb' function */\n    union_ok = lv_area_intersect(&masked_a, cords_p, mask_p);\n\n    /*If there are common part of the three area then draw to the vdb*/\n    if(union_ok == false)  return;\n\n    /*The pixel size in byte is different if an alpha byte is added too*/\n    uint8_t px_size_byte = alpha_byte ? LV_IMG_PX_SIZE_ALPHA_BYTE : sizeof(lv_color_t);\n\n    /*If the map starts OUT of the masked area then calc. the first pixel*/\n    lv_coord_t map_width = lv_area_get_width(cords_p);\n    if(cords_p->y1 < masked_a.y1) {\n        map_p += (uint32_t) map_width * ((masked_a.y1 - cords_p->y1)) * px_size_byte;\n    }\n    if(cords_p->x1 < masked_a.x1) {\n        map_p += (masked_a.x1 - cords_p->x1) * px_size_byte;\n    }\n\n    /*Stores coordinates relative to the current VDB*/\n    masked_a.x1 = masked_a.x1 - vdb_p->area.x1;\n    masked_a.y1 = masked_a.y1 - vdb_p->area.y1;\n    masked_a.x2 = masked_a.x2 - vdb_p->area.x1;\n    masked_a.y2 = masked_a.y2 - vdb_p->area.y1;\n\n    lv_coord_t vdb_width = lv_area_get_width(&vdb_p->area);\n    lv_color_t * vdb_buf_tmp = vdb_p->buf;\n    vdb_buf_tmp += (uint32_t) vdb_width * masked_a.y1; /*Move to the first row*/\n    vdb_buf_tmp += (uint32_t) masked_a.x1; /*Move to the first col*/\n\n    lv_coord_t row;\n    lv_coord_t map_useful_w = lv_area_get_width(&masked_a);\n\n    lv_disp_t * disp = lv_disp_get_active();\n\n    /*The simplest case just copy the pixels into the VDB*/\n    if(chroma_key == false && alpha_byte == false && opa == LV_OPA_COVER && recolor_opa == LV_OPA_TRANSP) {\n\n        /*Use the custom VDB write function is exists*/\n        if(disp->driver.vdb_wr) {\n            lv_coord_t col;\n            for(row = masked_a.y1; row <= masked_a.y2; row++) {\n                for(col = 0; col < map_useful_w; col++) {\n                    lv_color_t px_color = *((lv_color_t *)&map_p[(uint32_t)col * px_size_byte]);\n                    disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width, col + masked_a.x1, row, px_color, opa);\n                }\n                map_p += map_width * px_size_byte;  /*Next row on the map*/\n            }\n        }\n        /*Normal native VDB*/\n        else {\n            for(row = masked_a.y1; row <= masked_a.y2; row++) {\n#if USE_LV_GPU\n                if(lv_disp_is_mem_blend_supported() == false) {\n                    sw_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);\n                } else {\n                    lv_disp_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);\n                }\n#else\n                sw_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);\n#endif\n                map_p += map_width * px_size_byte;               /*Next row on the map*/\n                vdb_buf_tmp += vdb_width;                        /*Next row on the VDB*/\n            }\n        }\n    }\n\n    /*In the other cases every pixel need to be checked one-by-one*/\n    else {\n        lv_color_t chroma_key_color = LV_COLOR_TRANSP;\n        lv_coord_t col;\n        lv_color_t last_img_px = LV_COLOR_BLACK;\n        lv_color_t recolored_px = lv_color_mix(recolor, last_img_px, recolor_opa);\n        for(row = masked_a.y1; row <= masked_a.y2; row++) {\n            for(col = 0; col < map_useful_w; col++) {\n                lv_opa_t opa_result = opa;\n                uint8_t * px_color_p = (uint8_t *) &map_p[(uint32_t)col * px_size_byte];\n                lv_color_t px_color;\n\n                /*Calculate with the pixel level alpha*/\n                if(alpha_byte) {\n#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1\n                    px_color.full = px_color_p[0];\n#elif LV_COLOR_DEPTH == 16\n                    /*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/\n                    px_color.full = px_color_p[0] + (px_color_p[1] << 8);\n#elif LV_COLOR_DEPTH == 32\n                    px_color = *((lv_color_t *)px_color_p);\n#endif\n                    lv_opa_t px_opa = *(px_color_p + LV_IMG_PX_SIZE_ALPHA_BYTE - 1);\n                    if(px_opa == LV_OPA_TRANSP) continue;\n                    else if(px_opa != LV_OPA_COVER) opa_result = (uint32_t)((uint32_t)px_opa * opa_result) >> 8;\n                } else {\n                    px_color = *((lv_color_t *)px_color_p);\n                }\n\n                /*Handle chroma key*/\n                if(chroma_key && px_color.full == chroma_key_color.full) continue;\n\n                /*Re-color the pixel if required*/\n                if(recolor_opa != LV_OPA_TRANSP) {\n                    if(last_img_px.full != px_color.full) {     /*Minor acceleration: calculate only for new colors (save the last)*/\n                        last_img_px = px_color;\n                        recolored_px = lv_color_mix(recolor, last_img_px, recolor_opa);\n                    }\n                    /*Handle custom VDB write is present*/\n                    if(disp->driver.vdb_wr) {\n                        disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width, col + masked_a.x1, row, recolored_px, opa_result);\n                    }\n                    /*Normal native VDB write*/\n                    else {\n                        if(opa_result == LV_OPA_COVER) vdb_buf_tmp[col].full = recolored_px.full;\n                        else vdb_buf_tmp[col] = lv_color_mix(recolored_px, vdb_buf_tmp[col], opa_result);\n                    }\n                } else {\n                    /*Handle custom VDB write is present*/\n                    if(disp->driver.vdb_wr) {\n                        disp->driver.vdb_wr((uint8_t *)vdb_p->buf, vdb_width, col + masked_a.x1, row, px_color, opa_result);\n                    }\n                    /*Normal native VDB write*/\n                    else {\n                        if(opa_result == LV_OPA_COVER) vdb_buf_tmp[col] = px_color;\n                        else {\n#if LV_COLOR_SCREEN_TRANSP == 0\n                            vdb_buf_tmp[col] = lv_color_mix(px_color, vdb_buf_tmp[col], opa_result);\n#else\n                            vdb_buf_tmp[col] = color_mix_2_alpha(vdb_buf_tmp[col], vdb_buf_tmp[col].alpha, px_color,  opa_result);\n#endif\n                        }\n                    }\n                }\n            }\n\n            map_p += map_width * px_size_byte;  /*Next row on the map*/\n            vdb_buf_tmp += vdb_width;           /*Next row on the VDB*/\n        }\n    }\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Blend pixels to destination memory using opacity\n * @param dest a memory address. Copy 'src' here.\n * @param src pointer to pixel map. Copy it to 'dest'.\n * @param length number of pixels in 'src'\n * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover)\n */\nstatic void sw_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa)\n{\n    if(opa == LV_OPA_COVER) {\n        memcpy(dest, src, length * sizeof(lv_color_t));\n    } else {\n        uint32_t col;\n        for(col = 0; col < length; col++) {\n            dest[col] = lv_color_mix(src[col], dest[col], opa);\n        }\n    }\n}\n\n/**\n *\n * @param mem_area coordinates of 'mem' memory area\n * @param mem a memory address. Considered to a rectangular window according to 'mem_area'\n * @param fill_area coordinates of an area to fill. Relative to 'mem_area'.\n * @param color fill color\n * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover)\n */\nstatic void sw_color_fill(lv_area_t * mem_area, lv_color_t * mem, const lv_area_t * fill_area, lv_color_t color, lv_opa_t opa)\n{\n    /*Set all row in vdb to the given color*/\n    lv_coord_t row;\n    lv_coord_t col;\n    lv_coord_t mem_width = lv_area_get_width(mem_area);\n\n    lv_disp_t * disp = lv_disp_get_active();\n    if(disp->driver.vdb_wr) {\n        for(col = fill_area->x1; col <= fill_area->x2; col++) {\n            for(row = fill_area->y1; row <= fill_area->y2; row++) {\n                disp->driver.vdb_wr((uint8_t *)mem, mem_width, col, row, color, opa);\n            }\n        }\n    } else {\n        mem += fill_area->y1 * mem_width;  /*Go to the first row*/\n\n        /*Run simpler function without opacity*/\n        if(opa == LV_OPA_COVER) {\n\n            /*Fill the first row with 'color'*/\n            for(col = fill_area->x1; col <= fill_area->x2; col++) {\n                mem[col] = color;\n            }\n\n            /*Copy the first row to all other rows*/\n            lv_color_t * mem_first = &mem[fill_area->x1];\n            lv_coord_t copy_size = (fill_area->x2 - fill_area->x1 + 1) * sizeof(lv_color_t);\n            mem += mem_width;\n\n            for(row = fill_area->y1 + 1; row <= fill_area->y2; row++) {\n                memcpy(&mem[fill_area->x1], mem_first, copy_size);\n                mem += mem_width;\n            }\n        }\n        /*Calculate with alpha too*/\n        else {\n\n#if LV_COLOR_SCREEN_TRANSP == 0\n            lv_color_t bg_tmp = LV_COLOR_BLACK;\n            lv_color_t opa_tmp = lv_color_mix(color, bg_tmp, opa);\n#endif\n            for(row = fill_area->y1; row <= fill_area->y2; row++) {\n                for(col = fill_area->x1; col <= fill_area->x2; col++) {\n#if LV_COLOR_SCREEN_TRANSP == 0\n                    /*If the bg color changed recalculate the result color*/\n                    if(mem[col].full != bg_tmp.full) {\n                        bg_tmp = mem[col];\n                        opa_tmp = lv_color_mix(color, bg_tmp, opa);\n                    }\n\n                    mem[col] = opa_tmp;\n\n#else\n                    mem[col] = color_mix_2_alpha(mem[col], mem[col].alpha, color, opa);\n#endif\n                }\n                mem += mem_width;\n            }\n        }\n    }\n}\n\n#if LV_COLOR_SCREEN_TRANSP\n\n/**\n * Mix two colors. Both color can have alpha value. It requires ARGB888 colors.\n * @param bg_color background color\n * @param bg_opa alpha of the background color\n * @param fg_color foreground color\n * @param fg_opa alpha of the foreground color\n * @return the mixed color. the alpha channel (color.alpha) contains the result alpha\n */\nstatic inline lv_color_t color_mix_2_alpha(lv_color_t bg_color, lv_opa_t bg_opa, lv_color_t fg_color, lv_opa_t fg_opa)\n{\n    /* Pick the foreground if it's fully opaque or the Background is fully transparent*/\n    if(fg_opa == LV_OPA_COVER && bg_opa <= LV_OPA_MIN) {\n        fg_color.alpha = fg_opa;\n        return fg_color;\n    }\n    /*Transparent foreground: use the Background*/\n    else if(fg_opa <= LV_OPA_MIN) {\n        return bg_color;\n    }\n    /*Opaque background: use simple mix*/\n    else if(bg_opa >= LV_OPA_MAX) {\n        return lv_color_mix(fg_color, bg_color, fg_opa);\n    }\n    /*Both colors have alpha. Expensive calculation need to be applied*/\n    else {\n        /*Save the parameters and the result. If they will be asked again don't compute again*/\n        static lv_opa_t fg_opa_save = 0;\n        static lv_opa_t bg_opa_save = 0;\n        static lv_color_t c = {{0}};\n\n        if(fg_opa != fg_opa_save || bg_opa != bg_opa_save) {\n            fg_opa_save = fg_opa;\n            bg_opa_save = bg_opa;\n            /*Info: https://en.wikipedia.org/wiki/Alpha_compositing#Analytical_derivation_of_the_over_operator*/\n            lv_opa_t alpha_res = 255 - ((uint16_t)((uint16_t)(255 - fg_opa) * (255 - bg_opa)) >> 8);\n            if(alpha_res == 0) {\n                while(1);\n            }\n            lv_opa_t ratio = (uint16_t)((uint16_t) fg_opa * 255) / alpha_res;\n            c = lv_color_mix(fg_color, bg_color, ratio);\n            c.alpha = alpha_res;\n        }\n        return c;\n\n    }\n}\n#endif /*LV_COLOR_SCREEN_TRANSP*/\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_draw/lv_draw_vbasic.h",
    "content": "/**\n * @file lv_draw_vbasic.h\n *\n */\n\n#ifndef LV_DRAW_VBASIC_H\n#define LV_DRAW_VBASIC_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if LV_VDB_SIZE != 0\n\n#include \"../lv_misc/lv_color.h\"\n#include \"../lv_misc/lv_area.h\"\n#include \"../lv_misc/lv_font.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\nvoid lv_vpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa);\n/**\n * Fill an area in the Virtual Display Buffer\n * @param cords_p coordinates of the area to fill\n * @param mask_p fill only o this mask\n * @param color fill color\n * @param opa opacity of the area (0..255)\n */\nvoid lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p,\n              lv_color_t color, lv_opa_t opa);\n\n/**\n * Draw a letter in the Virtual Display Buffer\n * @param pos_p left-top coordinate of the latter\n * @param mask_p the letter will be drawn only on this area\n * @param font_p pointer to font\n * @param letter a letter to draw\n * @param color color of letter\n * @param opa opacity of letter (0..255)\n */\nvoid lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p,\n                const lv_font_t * font_p, uint32_t letter,\n                lv_color_t color, lv_opa_t opa);\n\n/**\n * Draw a color map to the display (image)\n * @param cords_p coordinates the color map\n * @param mask_p the map will drawn only on this area  (truncated to VDB area)\n * @param map_p pointer to a lv_color_t array\n * @param opa opacity of the map\n * @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels\n * @param alpha_byte true: extra alpha byte is inserted for every pixel\n * @param recolor mix the pixels with this color\n * @param recolor_opa the intense of recoloring\n */\nvoid lv_vmap(const lv_area_t * cords_p, const lv_area_t * mask_p,\n             const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte,\n             lv_color_t recolor, lv_opa_t recolor_opa);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*LV_VDB_SIZE != 0*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_DRAW_RBASIC_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_fonts/hekate_symbol_120.c",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include \"../lv_misc/lv_font.h\"\n\n#include <memory_map.h>\n\n#if USE_HEKATE_SYMBOL_120 != 0\t/*Can be enabled in lv_conf.h*/\n\n/***********************************************************************************\n * hekate-symbols-huge.ttf 120 px Font in U+f002 () .. U+f007 ()  range with all bpp\n * Sparse font with only these characters: \n***********************************************************************************/\n\n/*Store the glyph descriptions*/\nstatic const lv_font_glyph_dsc_t hekate_symbol_120_glyph_dsc[] =\n{\n#if USE_HEKATE_SYMBOL_120 == 8\n  {.w_px = 103,\t.glyph_index = 0},\t/*Unicode: U+f002 ()*/\n  {.w_px = 103,\t.glyph_index = 12360},\t/*Unicode: U+f003 ()*/\n  {.w_px = 103,\t.glyph_index = 24720},\t/*Unicode: U+f005 ()*/\n  {.w_px = 103,\t.glyph_index = 37080},\t/*Unicode: U+f007 ()*/\n\n#endif\n};\n\nlv_font_t hekate_symbol_120 =\n{\n    .unicode_first = LV_SYMBOL_GLYPH_FIRST,\t/*First Unicode letter in this font*/\n    .unicode_last = LV_SYMBOL_GLYPH_LAST,\t/*Last Unicode letter in this font*/\n    .h_px = 120,\t\t\t\t/*Font height in pixels*/\n    .glyph_bitmap = (const uint8_t *)(NYX_RES_ADDR + 0x36E00),\t/*Bitmap of glyphs*/\n    .glyph_dsc = hekate_symbol_120_glyph_dsc,\t\t/*Description of glyphs*/\n    .glyph_cnt = 4,\t\t\t/*Number of glyphs in the font*/\n    .unicode_list = NULL,\t/*List of unicode characters*/\n    .get_bitmap = lv_font_get_bitmap_continuous,\t/*Function pointer to get glyph's bitmap*/\n    .get_width = lv_font_get_width_continuous,\t/*Function pointer to get glyph's width*/\n#if USE_HEKATE_SYMBOL_120 == 8\n    .bpp = 8,\t\t\t\t/*Bit per pixel*/\n#endif\n    .monospace = 0,\t\t\t\t/*Fix width (0: if not used)*/\n    .next_page = NULL,\t\t/*Pointer to a font extension*/\n};\n\n#endif /*USE_HEKATE_SYMBOL_100*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_fonts/hekate_symbol_20.c",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include \"../lv_misc/lv_font.h\"\n\n#include <memory_map.h>\n\n#if USE_HEKATE_SYMBOL_20 != 0\t/*Can be enabled in lv_conf.h*/\n\n/***********************************************************************************\n * hekate-symbols.ttf 20 px Font in U+f000 () .. U+f2ee ()  range with all bpp\n * Sparse font with only these characters: \n***********************************************************************************/\n\n/*Store the glyph descriptions*/\nstatic const lv_font_glyph_dsc_t hekate_symbol_20_glyph_dsc[] =\n{\n#if USE_HEKATE_SYMBOL_20 == 4\n  {.w_px = 5,\t.glyph_index = 0},\t/*Unicode: U+f001 ()*/\n  {.w_px = 16,\t.glyph_index = 60},\t/*Unicode: U+f008 ()*/\n  {.w_px = 20,\t.glyph_index = 220},\t/*Unicode: U+f00b ()*/\n  {.w_px = 22,\t.glyph_index = 420},\t/*Unicode: U+f00c ()*/\n  {.w_px = 16,\t.glyph_index = 640},\t/*Unicode: U+f00d ()*/\n  {.w_px = 18,\t.glyph_index = 800},\t/*Unicode: U+f011 ()*/\n  {.w_px = 18,\t.glyph_index = 980},\t/*Unicode: U+f013 ()*/\n  {.w_px = 16,\t.glyph_index = 1160},\t/*Unicode: U+f014 ()*/\n  {.w_px = 23,\t.glyph_index = 1320},\t/*Unicode: U+f015 ()*/\n  {.w_px = 18,\t.glyph_index = 1560},\t/*Unicode: U+f019 ()*/\n  {.w_px = 23,\t.glyph_index = 1740},\t/*Unicode: U+f01c ()*/\n  {.w_px = 18,\t.glyph_index = 1980},\t/*Unicode: U+f021 ()*/\n  {.w_px = 18,\t.glyph_index = 2160},\t/*Unicode: U+f026 ()*/\n  {.w_px = 18,\t.glyph_index = 2340},\t/*Unicode: U+f027 ()*/\n  {.w_px = 13,\t.glyph_index = 2520},\t/*Unicode: U+f028 ()*/\n  {.w_px = 13,\t.glyph_index = 2660},\t/*Unicode: U+f03e ()*/\n  {.w_px = 16,\t.glyph_index = 2800},\t/*Unicode: U+f040 ()*/\n  {.w_px = 13,\t.glyph_index = 2960},\t/*Unicode: U+f048 ()*/\n  {.w_px = 13,\t.glyph_index = 3100},\t/*Unicode: U+f04b ()*/\n  {.w_px = 13,\t.glyph_index = 3240},\t/*Unicode: U+f04c ()*/\n  {.w_px = 9,\t.glyph_index = 3380},\t/*Unicode: U+f04d ()*/\n  {.w_px = 23,\t.glyph_index = 3480},\t/*Unicode: U+f051 ()*/\n  {.w_px = 21,\t.glyph_index = 3720},\t/*Unicode: U+f052 ()*/\n  {.w_px = 11,\t.glyph_index = 3940},\t/*Unicode: U+f053 ()*/\n  {.w_px = 11,\t.glyph_index = 4060},\t/*Unicode: U+f054 ()*/\n  {.w_px = 18,\t.glyph_index = 4180},\t/*Unicode: U+f067 ()*/\n  {.w_px = 18,\t.glyph_index = 4360},\t/*Unicode: U+f068 ()*/\n  {.w_px = 20,\t.glyph_index = 4540},\t/*Unicode: U+f071 ()*/\n  {.w_px = 20,\t.glyph_index = 4740},\t/*Unicode: U+f074 ()*/\n  {.w_px = 18,\t.glyph_index = 4940},\t/*Unicode: U+f077 ()*/\n  {.w_px = 18,\t.glyph_index = 5120},\t/*Unicode: U+f078 ()*/\n  {.w_px = 18,\t.glyph_index = 5300},\t/*Unicode: U+f079 ()*/\n  {.w_px = 20,\t.glyph_index = 5480},\t/*Unicode: U+f07b ()*/\n  {.w_px = 18,\t.glyph_index = 5680},\t/*Unicode: U+f093 ()*/\n  {.w_px = 25,\t.glyph_index = 5860},\t/*Unicode: U+f095 ()*/\n  {.w_px = 18,\t.glyph_index = 6120},\t/*Unicode: U+f0c4 ()*/\n  {.w_px = 16,\t.glyph_index = 6300},\t/*Unicode: U+f0c5 ()*/\n  {.w_px = 17,\t.glyph_index = 6460},\t/*Unicode: U+f0c7 ()*/\n  {.w_px = 8,\t.glyph_index = 6640},\t/*Unicode: U+f0e7 ()*/\n  {.w_px = 12,\t.glyph_index = 6720},\t/*Unicode: U+f0f3 ()*/\n  {.w_px = 23,\t.glyph_index = 6840},\t/*Unicode: U+f11c ()*/\n  {.w_px = 18,\t.glyph_index = 7080},\t/*Unicode: U+f124 ()*/\n  {.w_px = 13,\t.glyph_index = 7260},\t/*Unicode: U+f15b ()*/\n  {.w_px = 20,\t.glyph_index = 7400},\t/*Unicode: U+f1eb ()*/\n  {.w_px = 26,\t.glyph_index = 7600},\t/*Unicode: U+f240 ()*/\n  {.w_px = 26,\t.glyph_index = 7860},\t/*Unicode: U+f241 ()*/\n  {.w_px = 26,\t.glyph_index = 8120},\t/*Unicode: U+f242 ()*/\n  {.w_px = 26,\t.glyph_index = 8380},\t/*Unicode: U+f243 ()*/\n  {.w_px = 26,\t.glyph_index = 8640},\t/*Unicode: U+f244 ()*/\n  {.w_px = 20,\t.glyph_index = 8900},\t/*Unicode: U+f293 ()*/\n\n#elif USE_HEKATE_SYMBOL_20 == 8\n  {.w_px = 5,\t.glyph_index = 0},\t/*Unicode: U+f001 ()*/\n  {.w_px = 16,\t.glyph_index = 100},\t/*Unicode: U+f008 ()*/\n  {.w_px = 20,\t.glyph_index = 420},\t/*Unicode: U+f00b ()*/\n  {.w_px = 22,\t.glyph_index = 820},\t/*Unicode: U+f00c ()*/\n  {.w_px = 16,\t.glyph_index = 1260},\t/*Unicode: U+f00d ()*/\n  {.w_px = 18,\t.glyph_index = 1580},\t/*Unicode: U+f011 ()*/\n  {.w_px = 18,\t.glyph_index = 1940},\t/*Unicode: U+f013 ()*/\n  {.w_px = 16,\t.glyph_index = 2300},\t/*Unicode: U+f014 ()*/\n  {.w_px = 23,\t.glyph_index = 2620},\t/*Unicode: U+f015 ()*/\n  {.w_px = 18,\t.glyph_index = 3080},\t/*Unicode: U+f019 ()*/\n  {.w_px = 23,\t.glyph_index = 3440},\t/*Unicode: U+f01c ()*/\n  {.w_px = 18,\t.glyph_index = 3900},\t/*Unicode: U+f021 ()*/\n  {.w_px = 18,\t.glyph_index = 4260},\t/*Unicode: U+f026 ()*/\n  {.w_px = 18,\t.glyph_index = 4620},\t/*Unicode: U+f027 ()*/\n  {.w_px = 13,\t.glyph_index = 4980},\t/*Unicode: U+f028 ()*/\n  {.w_px = 13,\t.glyph_index = 5240},\t/*Unicode: U+f03e ()*/\n  {.w_px = 16,\t.glyph_index = 5500},\t/*Unicode: U+f040 ()*/\n  {.w_px = 13,\t.glyph_index = 5820},\t/*Unicode: U+f048 ()*/\n  {.w_px = 13,\t.glyph_index = 6080},\t/*Unicode: U+f04b ()*/\n  {.w_px = 13,\t.glyph_index = 6340},\t/*Unicode: U+f04c ()*/\n  {.w_px = 9,\t.glyph_index = 6600},\t/*Unicode: U+f04d ()*/\n  {.w_px = 23,\t.glyph_index = 6780},\t/*Unicode: U+f051 ()*/\n  {.w_px = 21,\t.glyph_index = 7240},\t/*Unicode: U+f052 ()*/\n  {.w_px = 11,\t.glyph_index = 7660},\t/*Unicode: U+f053 ()*/\n  {.w_px = 11,\t.glyph_index = 7880},\t/*Unicode: U+f054 ()*/\n  {.w_px = 18,\t.glyph_index = 8100},\t/*Unicode: U+f067 ()*/\n  {.w_px = 18,\t.glyph_index = 8460},\t/*Unicode: U+f068 ()*/\n  {.w_px = 20,\t.glyph_index = 8820},\t/*Unicode: U+f071 ()*/\n  {.w_px = 20,\t.glyph_index = 9220},\t/*Unicode: U+f074 ()*/\n  {.w_px = 18,\t.glyph_index = 9620},\t/*Unicode: U+f077 ()*/\n  {.w_px = 18,\t.glyph_index = 9980},\t/*Unicode: U+f078 ()*/\n  {.w_px = 18,\t.glyph_index = 10340},\t/*Unicode: U+f079 ()*/\n  {.w_px = 20,\t.glyph_index = 10700},\t/*Unicode: U+f07b ()*/\n  {.w_px = 18,\t.glyph_index = 11100},\t/*Unicode: U+f093 ()*/\n  {.w_px = 25,\t.glyph_index = 11460},\t/*Unicode: U+f095 ()*/\n  {.w_px = 18,\t.glyph_index = 11960},\t/*Unicode: U+f0c4 ()*/\n  {.w_px = 16,\t.glyph_index = 12320},\t/*Unicode: U+f0c5 ()*/\n  {.w_px = 17,\t.glyph_index = 12640},\t/*Unicode: U+f0c7 ()*/\n  {.w_px = 8,\t.glyph_index = 12980},\t/*Unicode: U+f0e7 ()*/\n  {.w_px = 12,\t.glyph_index = 13140},\t/*Unicode: U+f0f3 ()*/\n  {.w_px = 23,\t.glyph_index = 13380},\t/*Unicode: U+f11c ()*/\n  {.w_px = 18,\t.glyph_index = 13840},\t/*Unicode: U+f124 ()*/\n  {.w_px = 13,\t.glyph_index = 14200},\t/*Unicode: U+f15b ()*/\n  {.w_px = 20,\t.glyph_index = 14460},\t/*Unicode: U+f1eb ()*/\n  {.w_px = 26,\t.glyph_index = 14860},\t/*Unicode: U+f240 ()*/\n  {.w_px = 26,\t.glyph_index = 15380},\t/*Unicode: U+f241 ()*/\n  {.w_px = 26,\t.glyph_index = 15900},\t/*Unicode: U+f242 ()*/\n  {.w_px = 26,\t.glyph_index = 16420},\t/*Unicode: U+f243 ()*/\n  {.w_px = 26,\t.glyph_index = 16940},\t/*Unicode: U+f244 ()*/\n  {.w_px = 20,\t.glyph_index = 17460},\t/*Unicode: U+f293 ()*/\n\n#endif\n};\n\nlv_font_t hekate_symbol_20 =\n{\n    .unicode_first = LV_SYMBOL_GLYPH_FIRST,\t/*First Unicode letter in this font*/\n    .unicode_last = LV_SYMBOL_GLYPH_LAST,\t/*Last Unicode letter in this font*/\n    .h_px = 20,\t\t\t\t/*Font height in pixels*/\n    //.glyph_bitmap = hekate_symbol_20_glyph_bitmap,\t/*Bitmap of glyphs*/\n    .glyph_bitmap = (const uint8_t *)(NYX_RES_ADDR + 0xFC00),\n    .glyph_dsc = hekate_symbol_20_glyph_dsc,\t\t/*Description of glyphs*/\n    .glyph_cnt = 50,\t\t\t/*Number of glyphs in the font*/\n    .unicode_list = NULL,\t/*List of unicode characters*/\n    .get_bitmap = lv_font_get_bitmap_continuous,\t/*Function pointer to get glyph's bitmap*/\n    .get_width = lv_font_get_width_continuous,\t/*Function pointer to get glyph's width*/\n#if USE_HEKATE_SYMBOL_20 == 4\n    .bpp = 4,\t\t\t\t/*Bit per pixel*/\n#elif USE_HEKATE_SYMBOL_20 == 8\n    .bpp = 8,\t\t\t\t/*Bit per pixel*/\n#endif\n    .monospace = 0,\t\t\t\t/*Fix width (0: if not used)*/\n    .next_page = NULL,\t\t/*Pointer to a font extension*/\n};\n\n#endif /*USE_HEKATE_SYMBOL_20*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_fonts/hekate_symbol_30.c",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include \"../lv_misc/lv_font.h\"\n\n#include <memory_map.h>\n\n#if USE_HEKATE_SYMBOL_30 != 0\t/*Can be enabled in lv_conf.h*/\n\n/***********************************************************************************\n * hekate-symbols.ttf 30 px Font in U+f000 () .. U+f2ee ()  range with all bpp\n * Sparse font with only these characters: \n***********************************************************************************/\n\n/*Store the glyph descriptions*/\nstatic const lv_font_glyph_dsc_t hekate_symbol_30_glyph_dsc[] =\n{\n#if USE_HEKATE_SYMBOL_30 == 4\n  {.w_px = 7,\t.glyph_index = 0},\t/*Unicode: U+f001 ()*/\n  {.w_px = 25,\t.glyph_index = 120},\t/*Unicode: U+f008 ()*/\n  {.w_px = 27,\t.glyph_index = 510},\t/*Unicode: U+f00b ()*/\n  {.w_px = 31,\t.glyph_index = 930},\t/*Unicode: U+f00c ()*/\n  {.w_px = 22,\t.glyph_index = 1410},\t/*Unicode: U+f00d ()*/\n  {.w_px = 25,\t.glyph_index = 1740},\t/*Unicode: U+f011 ()*/\n  {.w_px = 25,\t.glyph_index = 2130},\t/*Unicode: U+f013 ()*/\n  {.w_px = 23,\t.glyph_index = 2520},\t/*Unicode: U+f014 ()*/\n  {.w_px = 34,\t.glyph_index = 2880},\t/*Unicode: U+f015 ()*/\n  {.w_px = 25,\t.glyph_index = 3390},\t/*Unicode: U+f019 ()*/\n  {.w_px = 32,\t.glyph_index = 3780},\t/*Unicode: U+f01c ()*/\n  {.w_px = 25,\t.glyph_index = 4260},\t/*Unicode: U+f021 ()*/\n  {.w_px = 25,\t.glyph_index = 4650},\t/*Unicode: U+f026 ()*/\n  {.w_px = 25,\t.glyph_index = 5040},\t/*Unicode: U+f027 ()*/\n  {.w_px = 20,\t.glyph_index = 5430},\t/*Unicode: U+f028 ()*/\n  {.w_px = 20,\t.glyph_index = 5730},\t/*Unicode: U+f03e ()*/\n  {.w_px = 25,\t.glyph_index = 6030},\t/*Unicode: U+f040 ()*/\n  {.w_px = 20,\t.glyph_index = 6420},\t/*Unicode: U+f048 ()*/\n  {.w_px = 20,\t.glyph_index = 6720},\t/*Unicode: U+f04b ()*/\n  {.w_px = 20,\t.glyph_index = 7020},\t/*Unicode: U+f04c ()*/\n  {.w_px = 13,\t.glyph_index = 7320},\t/*Unicode: U+f04d ()*/\n  {.w_px = 32,\t.glyph_index = 7530},\t/*Unicode: U+f051 ()*/\n  {.w_px = 30,\t.glyph_index = 8010},\t/*Unicode: U+f052 ()*/\n  {.w_px = 16,\t.glyph_index = 8460},\t/*Unicode: U+f053 ()*/\n  {.w_px = 16,\t.glyph_index = 8700},\t/*Unicode: U+f054 ()*/\n  {.w_px = 25,\t.glyph_index = 8940},\t/*Unicode: U+f067 ()*/\n  {.w_px = 25,\t.glyph_index = 9330},\t/*Unicode: U+f068 ()*/\n  {.w_px = 27,\t.glyph_index = 9720},\t/*Unicode: U+f071 ()*/\n  {.w_px = 29,\t.glyph_index = 10140},\t/*Unicode: U+f074 ()*/\n  {.w_px = 26,\t.glyph_index = 10590},\t/*Unicode: U+f077 ()*/\n  {.w_px = 26,\t.glyph_index = 10980},\t/*Unicode: U+f078 ()*/\n  {.w_px = 25,\t.glyph_index = 11370},\t/*Unicode: U+f079 ()*/\n  {.w_px = 29,\t.glyph_index = 11760},\t/*Unicode: U+f07b ()*/\n  {.w_px = 25,\t.glyph_index = 12210},\t/*Unicode: U+f093 ()*/\n  {.w_px = 37,\t.glyph_index = 12600},\t/*Unicode: U+f095 ()*/\n  {.w_px = 25,\t.glyph_index = 13170},\t/*Unicode: U+f0c4 ()*/\n  {.w_px = 23,\t.glyph_index = 13560},\t/*Unicode: U+f0c5 ()*/\n  {.w_px = 24,\t.glyph_index = 13920},\t/*Unicode: U+f0c7 ()*/\n  {.w_px = 13,\t.glyph_index = 14280},\t/*Unicode: U+f0e7 ()*/\n  {.w_px = 18,\t.glyph_index = 14490},\t/*Unicode: U+f0f3 ()*/\n  {.w_px = 33,\t.glyph_index = 14760},\t/*Unicode: U+f11c ()*/\n  {.w_px = 25,\t.glyph_index = 15270},\t/*Unicode: U+f124 ()*/\n  {.w_px = 20,\t.glyph_index = 15660},\t/*Unicode: U+f15b ()*/\n  {.w_px = 29,\t.glyph_index = 15960},\t/*Unicode: U+f1eb ()*/\n  {.w_px = 38,\t.glyph_index = 16410},\t/*Unicode: U+f240 ()*/\n  {.w_px = 38,\t.glyph_index = 16980},\t/*Unicode: U+f241 ()*/\n  {.w_px = 38,\t.glyph_index = 17550},\t/*Unicode: U+f242 ()*/\n  {.w_px = 38,\t.glyph_index = 18120},\t/*Unicode: U+f243 ()*/\n  {.w_px = 38,\t.glyph_index = 18690},\t/*Unicode: U+f244 ()*/\n  {.w_px = 29,\t.glyph_index = 19260},\t/*Unicode: U+f293 ()*/\n\n#elif USE_HEKATE_SYMBOL_30 == 8\n  {.w_px = 7,\t.glyph_index = 0},\t/*Unicode: U+f001 ()*/\n  {.w_px = 25,\t.glyph_index = 210},\t/*Unicode: U+f008 ()*/\n  {.w_px = 27,\t.glyph_index = 960},\t/*Unicode: U+f00b ()*/\n  {.w_px = 31,\t.glyph_index = 1770},\t/*Unicode: U+f00c ()*/\n  {.w_px = 22,\t.glyph_index = 2700},\t/*Unicode: U+f00d ()*/\n  {.w_px = 25,\t.glyph_index = 3360},\t/*Unicode: U+f011 ()*/\n  {.w_px = 25,\t.glyph_index = 4110},\t/*Unicode: U+f013 ()*/\n  {.w_px = 23,\t.glyph_index = 4860},\t/*Unicode: U+f014 ()*/\n  {.w_px = 34,\t.glyph_index = 5550},\t/*Unicode: U+f015 ()*/\n  {.w_px = 25,\t.glyph_index = 6570},\t/*Unicode: U+f019 ()*/\n  {.w_px = 32,\t.glyph_index = 7320},\t/*Unicode: U+f01c ()*/\n  {.w_px = 25,\t.glyph_index = 8280},\t/*Unicode: U+f021 ()*/\n  {.w_px = 25,\t.glyph_index = 9030},\t/*Unicode: U+f026 ()*/\n  {.w_px = 25,\t.glyph_index = 9780},\t/*Unicode: U+f027 ()*/\n  {.w_px = 20,\t.glyph_index = 10530},\t/*Unicode: U+f028 ()*/\n  {.w_px = 20,\t.glyph_index = 11130},\t/*Unicode: U+f03e ()*/\n  {.w_px = 25,\t.glyph_index = 11730},\t/*Unicode: U+f040 ()*/\n  {.w_px = 20,\t.glyph_index = 12480},\t/*Unicode: U+f048 ()*/\n  {.w_px = 20,\t.glyph_index = 13080},\t/*Unicode: U+f04b ()*/\n  {.w_px = 20,\t.glyph_index = 13680},\t/*Unicode: U+f04c ()*/\n  {.w_px = 13,\t.glyph_index = 14280},\t/*Unicode: U+f04d ()*/\n  {.w_px = 32,\t.glyph_index = 14670},\t/*Unicode: U+f051 ()*/\n  {.w_px = 30,\t.glyph_index = 15630},\t/*Unicode: U+f052 ()*/\n  {.w_px = 16,\t.glyph_index = 16530},\t/*Unicode: U+f053 ()*/\n  {.w_px = 16,\t.glyph_index = 17010},\t/*Unicode: U+f054 ()*/\n  {.w_px = 25,\t.glyph_index = 17490},\t/*Unicode: U+f067 ()*/\n  {.w_px = 25,\t.glyph_index = 18240},\t/*Unicode: U+f068 ()*/\n  {.w_px = 27,\t.glyph_index = 18990},\t/*Unicode: U+f071 ()*/\n  {.w_px = 29,\t.glyph_index = 19800},\t/*Unicode: U+f074 ()*/\n  {.w_px = 26,\t.glyph_index = 20670},\t/*Unicode: U+f077 ()*/\n  {.w_px = 26,\t.glyph_index = 21450},\t/*Unicode: U+f078 ()*/\n  {.w_px = 25,\t.glyph_index = 22230},\t/*Unicode: U+f079 ()*/\n  {.w_px = 29,\t.glyph_index = 22980},\t/*Unicode: U+f07b ()*/\n  {.w_px = 25,\t.glyph_index = 23850},\t/*Unicode: U+f093 ()*/\n  {.w_px = 37,\t.glyph_index = 24600},\t/*Unicode: U+f095 ()*/\n  {.w_px = 25,\t.glyph_index = 25710},\t/*Unicode: U+f0c4 ()*/\n  {.w_px = 23,\t.glyph_index = 26460},\t/*Unicode: U+f0c5 ()*/\n  {.w_px = 24,\t.glyph_index = 27150},\t/*Unicode: U+f0c7 ()*/\n  {.w_px = 13,\t.glyph_index = 27870},\t/*Unicode: U+f0e7 ()*/\n  {.w_px = 18,\t.glyph_index = 28260},\t/*Unicode: U+f0f3 ()*/\n  {.w_px = 33,\t.glyph_index = 28800},\t/*Unicode: U+f11c ()*/\n  {.w_px = 25,\t.glyph_index = 29790},\t/*Unicode: U+f124 ()*/\n  {.w_px = 20,\t.glyph_index = 30540},\t/*Unicode: U+f15b ()*/\n  {.w_px = 29,\t.glyph_index = 31140},\t/*Unicode: U+f1eb ()*/\n  {.w_px = 38,\t.glyph_index = 32010},\t/*Unicode: U+f240 ()*/\n  {.w_px = 38,\t.glyph_index = 33150},\t/*Unicode: U+f241 ()*/\n  {.w_px = 38,\t.glyph_index = 34290},\t/*Unicode: U+f242 ()*/\n  {.w_px = 38,\t.glyph_index = 35430},\t/*Unicode: U+f243 ()*/\n  {.w_px = 38,\t.glyph_index = 36570},\t/*Unicode: U+f244 ()*/\n  {.w_px = 29,\t.glyph_index = 37710},\t/*Unicode: U+f293 ()*/\n\n#endif\n};\n\nlv_font_t hekate_symbol_30 =\n{\n    .unicode_first = LV_SYMBOL_GLYPH_FIRST,\t/*First Unicode letter in this font*/\n    .unicode_last = LV_SYMBOL_GLYPH_LAST,\t/*Last Unicode letter in this font*/\n    .h_px = 30,\t\t\t\t/*Font height in pixels*/\n    //.glyph_bitmap = hekate_symbol_30_glyph_bitmap,\t/*Bitmap of glyphs*/\n    .glyph_bitmap = (const uint8_t *)(NYX_RES_ADDR + 0x14200),\n    .glyph_dsc = hekate_symbol_30_glyph_dsc,\t\t/*Description of glyphs*/\n    .glyph_cnt = 50,\t\t\t/*Number of glyphs in the font*/\n    .unicode_list = NULL,\t/*List of unicode characters*/\n    .get_bitmap = lv_font_get_bitmap_continuous,\t/*Function pointer to get glyph's bitmap*/\n    .get_width = lv_font_get_width_continuous,\t/*Function pointer to get glyph's width*/\n#if USE_HEKATE_SYMBOL_30 == 4\n    .bpp = 4,\t\t\t\t/*Bit per pixel*/\n #elif USE_HEKATE_SYMBOL_30 == 8\n    .bpp = 8,\t\t\t\t/*Bit per pixel*/\n#endif\n    .monospace = 0,\t\t\t\t/*Fix width (0: if not used)*/\n    .next_page = NULL,\t\t/*Pointer to a font extension*/\n};\n\n#endif /*USE_HEKATE_SYMBOL_30*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_fonts/interui_20.c",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include \"../lv_misc/lv_font.h\"\n\n#include <memory_map.h>\n\n#if USE_INTERUI_20 != 0\t/*Can be enabled in lv_conf.h*/\n\n/***********************************************************************************\n * Inter-UI-Regular-stretched.ttf 20 px Font in U+0020 ( ) .. U+007e (~)  range with all bpp\n***********************************************************************************/\n\n/*Store the glyph descriptions*/\nstatic const lv_font_glyph_dsc_t interui_20_glyph_dsc[] =\n{\n#if USE_INTERUI_20 == 4\n  {.w_px = 6,\t.glyph_index = 0},\t/*Unicode: U+0020 ( )*/\n  {.w_px = 3,\t.glyph_index = 60},\t/*Unicode: U+0021 (!)*/\n  {.w_px = 5,\t.glyph_index = 100},\t/*Unicode: U+0022 (\")*/\n  {.w_px = 8,\t.glyph_index = 160},\t/*Unicode: U+0023 (#)*/\n  {.w_px = 9,\t.glyph_index = 240},\t/*Unicode: U+0024 ($)*/\n  {.w_px = 14,\t.glyph_index = 340},\t/*Unicode: U+0025 (%)*/\n  {.w_px = 12,\t.glyph_index = 480},\t/*Unicode: U+0026 (&)*/\n  {.w_px = 3,\t.glyph_index = 600},\t/*Unicode: U+0027 (')*/\n  {.w_px = 5,\t.glyph_index = 640},\t/*Unicode: U+0028 (()*/\n  {.w_px = 5,\t.glyph_index = 700},\t/*Unicode: U+0029 ())*/\n  {.w_px = 7,\t.glyph_index = 760},\t/*Unicode: U+002a (*)*/\n  {.w_px = 10,\t.glyph_index = 840},\t/*Unicode: U+002b (+)*/\n  {.w_px = 3,\t.glyph_index = 940},\t/*Unicode: U+002c (,)*/\n  {.w_px = 5,\t.glyph_index = 980},\t/*Unicode: U+002d (-)*/\n  {.w_px = 3,\t.glyph_index = 1040},\t/*Unicode: U+002e (.)*/\n  {.w_px = 8,\t.glyph_index = 1080},\t/*Unicode: U+002f (/)*/\n  {.w_px = 10,\t.glyph_index = 1160},\t/*Unicode: U+0030 (0)*/\n  {.w_px = 5,\t.glyph_index = 1260},\t/*Unicode: U+0031 (1)*/\n  {.w_px = 9,\t.glyph_index = 1320},\t/*Unicode: U+0032 (2)*/\n  {.w_px = 10,\t.glyph_index = 1420},\t/*Unicode: U+0033 (3)*/\n  {.w_px = 9,\t.glyph_index = 1520},\t/*Unicode: U+0034 (4)*/\n  {.w_px = 9,\t.glyph_index = 1620},\t/*Unicode: U+0035 (5)*/\n  {.w_px = 10,\t.glyph_index = 1720},\t/*Unicode: U+0036 (6)*/\n  {.w_px = 8,\t.glyph_index = 1820},\t/*Unicode: U+0037 (7)*/\n  {.w_px = 10,\t.glyph_index = 1900},\t/*Unicode: U+0038 (8)*/\n  {.w_px = 10,\t.glyph_index = 2000},\t/*Unicode: U+0039 (9)*/\n  {.w_px = 3,\t.glyph_index = 2100},\t/*Unicode: U+003a (:)*/\n  {.w_px = 3,\t.glyph_index = 2140},\t/*Unicode: U+003b (;)*/\n  {.w_px = 12,\t.glyph_index = 2180},\t/*Unicode: U+003c (<)*/\n  {.w_px = 10,\t.glyph_index = 2300},\t/*Unicode: U+003d (=)*/\n  {.w_px = 12,\t.glyph_index = 2400},\t/*Unicode: U+003e (>)*/\n  {.w_px = 8,\t.glyph_index = 2520},\t/*Unicode: U+003f (?)*/\n  {.w_px = 14,\t.glyph_index = 2600},\t/*Unicode: U+0040 (@)*/\n  {.w_px = 12,\t.glyph_index = 2740},\t/*Unicode: U+0041 (A)*/\n  {.w_px = 10,\t.glyph_index = 2860},\t/*Unicode: U+0042 (B)*/\n  {.w_px = 11,\t.glyph_index = 2960},\t/*Unicode: U+0043 (C)*/\n  {.w_px = 12,\t.glyph_index = 3080},\t/*Unicode: U+0044 (D)*/\n  {.w_px = 9,\t.glyph_index = 3200},\t/*Unicode: U+0045 (E)*/\n  {.w_px = 8,\t.glyph_index = 3300},\t/*Unicode: U+0046 (F)*/\n  {.w_px = 12,\t.glyph_index = 3380},\t/*Unicode: U+0047 (G)*/\n  {.w_px = 10,\t.glyph_index = 3500},\t/*Unicode: U+0048 (H)*/\n  {.w_px = 3,\t.glyph_index = 3600},\t/*Unicode: U+0049 (I)*/\n  {.w_px = 7,\t.glyph_index = 3640},\t/*Unicode: U+004a (J)*/\n  {.w_px = 10,\t.glyph_index = 3720},\t/*Unicode: U+004b (K)*/\n  {.w_px = 7,\t.glyph_index = 3820},\t/*Unicode: U+004c (L)*/\n  {.w_px = 15,\t.glyph_index = 3900},\t/*Unicode: U+004d (M)*/\n  {.w_px = 12,\t.glyph_index = 4060},\t/*Unicode: U+004e (N)*/\n  {.w_px = 14,\t.glyph_index = 4180},\t/*Unicode: U+004f (O)*/\n  {.w_px = 9,\t.glyph_index = 4320},\t/*Unicode: U+0050 (P)*/\n  {.w_px = 14,\t.glyph_index = 4420},\t/*Unicode: U+0051 (Q)*/\n  {.w_px = 9,\t.glyph_index = 4560},\t/*Unicode: U+0052 (R)*/\n  {.w_px = 9,\t.glyph_index = 4660},\t/*Unicode: U+0053 (S)*/\n  {.w_px = 9,\t.glyph_index = 4760},\t/*Unicode: U+0054 (T)*/\n  {.w_px = 12,\t.glyph_index = 4860},\t/*Unicode: U+0055 (U)*/\n  {.w_px = 12,\t.glyph_index = 4980},\t/*Unicode: U+0056 (V)*/\n  {.w_px = 18,\t.glyph_index = 5100},\t/*Unicode: U+0057 (W)*/\n  {.w_px = 10,\t.glyph_index = 5280},\t/*Unicode: U+0058 (X)*/\n  {.w_px = 10,\t.glyph_index = 5380},\t/*Unicode: U+0059 (Y)*/\n  {.w_px = 10,\t.glyph_index = 5480},\t/*Unicode: U+005a (Z)*/\n  {.w_px = 5,\t.glyph_index = 5580},\t/*Unicode: U+005b ([)*/\n  {.w_px = 8,\t.glyph_index = 5640},\t/*Unicode: U+005c (\\)*/\n  {.w_px = 5,\t.glyph_index = 5720},\t/*Unicode: U+005d (])*/\n  {.w_px = 9,\t.glyph_index = 5780},\t/*Unicode: U+005e (^)*/\n  {.w_px = 8,\t.glyph_index = 5880},\t/*Unicode: U+005f (_)*/\n  {.w_px = 4,\t.glyph_index = 5960},\t/*Unicode: U+0060 (`)*/\n  {.w_px = 9,\t.glyph_index = 6000},\t/*Unicode: U+0061 (a)*/\n  {.w_px = 10,\t.glyph_index = 6100},\t/*Unicode: U+0062 (b)*/\n  {.w_px = 8,\t.glyph_index = 6200},\t/*Unicode: U+0063 (c)*/\n  {.w_px = 10,\t.glyph_index = 6280},\t/*Unicode: U+0064 (d)*/\n  {.w_px = 9,\t.glyph_index = 6380},\t/*Unicode: U+0065 (e)*/\n  {.w_px = 4,\t.glyph_index = 6480},\t/*Unicode: U+0066 (f)*/\n  {.w_px = 9,\t.glyph_index = 6520},\t/*Unicode: U+0067 (g)*/\n  {.w_px = 9,\t.glyph_index = 6620},\t/*Unicode: U+0068 (h)*/\n  {.w_px = 3,\t.glyph_index = 6720},\t/*Unicode: U+0069 (i)*/\n  {.w_px = 5,\t.glyph_index = 6760},\t/*Unicode: U+006a (j)*/\n  {.w_px = 8,\t.glyph_index = 6820},\t/*Unicode: U+006b (k)*/\n  {.w_px = 4,\t.glyph_index = 6900},\t/*Unicode: U+006c (l)*/\n  {.w_px = 13,\t.glyph_index = 6940},\t/*Unicode: U+006d (m)*/\n  {.w_px = 9,\t.glyph_index = 7080},\t/*Unicode: U+006e (n)*/\n  {.w_px = 10,\t.glyph_index = 7180},\t/*Unicode: U+006f (o)*/\n  {.w_px = 10,\t.glyph_index = 7280},\t/*Unicode: U+0070 (p)*/\n  {.w_px = 10,\t.glyph_index = 7380},\t/*Unicode: U+0071 (q)*/\n  {.w_px = 5,\t.glyph_index = 7480},\t/*Unicode: U+0072 (r)*/\n  {.w_px = 8,\t.glyph_index = 7540},\t/*Unicode: U+0073 (s)*/\n  {.w_px = 5,\t.glyph_index = 7620},\t/*Unicode: U+0074 (t)*/\n  {.w_px = 9,\t.glyph_index = 7680},\t/*Unicode: U+0075 (u)*/\n  {.w_px = 8,\t.glyph_index = 7780},\t/*Unicode: U+0076 (v)*/\n  {.w_px = 14,\t.glyph_index = 7860},\t/*Unicode: U+0077 (w)*/\n  {.w_px = 8,\t.glyph_index = 8000},\t/*Unicode: U+0078 (x)*/\n  {.w_px = 8,\t.glyph_index = 8080},\t/*Unicode: U+0079 (y)*/\n  {.w_px = 7,\t.glyph_index = 8160},\t/*Unicode: U+007a (z)*/\n  {.w_px = 4,\t.glyph_index = 8240},\t/*Unicode: U+007b ({)*/\n  {.w_px = 3,\t.glyph_index = 8280},\t/*Unicode: U+007c (|)*/\n  {.w_px = 4,\t.glyph_index = 8320},\t/*Unicode: U+007d (})*/\n  {.w_px = 6,\t.glyph_index = 8360},\t/*Unicode: U+007e (~)*/\n\n#elif USE_INTERUI_20 == 8\n  {.w_px = 6,\t.glyph_index = 0},\t/*Unicode: U+0020 ( )*/\n  {.w_px = 3,\t.glyph_index = 120},\t/*Unicode: U+0021 (!)*/\n  {.w_px = 5,\t.glyph_index = 180},\t/*Unicode: U+0022 (\")*/\n  {.w_px = 8,\t.glyph_index = 280},\t/*Unicode: U+0023 (#)*/\n  {.w_px = 9,\t.glyph_index = 440},\t/*Unicode: U+0024 ($)*/\n  {.w_px = 14,\t.glyph_index = 620},\t/*Unicode: U+0025 (%)*/\n  {.w_px = 12,\t.glyph_index = 900},\t/*Unicode: U+0026 (&)*/\n  {.w_px = 3,\t.glyph_index = 1140},\t/*Unicode: U+0027 (')*/\n  {.w_px = 5,\t.glyph_index = 1200},\t/*Unicode: U+0028 (()*/\n  {.w_px = 5,\t.glyph_index = 1300},\t/*Unicode: U+0029 ())*/\n  {.w_px = 7,\t.glyph_index = 1400},\t/*Unicode: U+002a (*)*/\n  {.w_px = 10,\t.glyph_index = 1540},\t/*Unicode: U+002b (+)*/\n  {.w_px = 3,\t.glyph_index = 1740},\t/*Unicode: U+002c (,)*/\n  {.w_px = 5,\t.glyph_index = 1800},\t/*Unicode: U+002d (-)*/\n  {.w_px = 3,\t.glyph_index = 1900},\t/*Unicode: U+002e (.)*/\n  {.w_px = 8,\t.glyph_index = 1960},\t/*Unicode: U+002f (/)*/\n  {.w_px = 10,\t.glyph_index = 2120},\t/*Unicode: U+0030 (0)*/\n  {.w_px = 5,\t.glyph_index = 2320},\t/*Unicode: U+0031 (1)*/\n  {.w_px = 9,\t.glyph_index = 2420},\t/*Unicode: U+0032 (2)*/\n  {.w_px = 10,\t.glyph_index = 2600},\t/*Unicode: U+0033 (3)*/\n  {.w_px = 9,\t.glyph_index = 2800},\t/*Unicode: U+0034 (4)*/\n  {.w_px = 9,\t.glyph_index = 2980},\t/*Unicode: U+0035 (5)*/\n  {.w_px = 10,\t.glyph_index = 3160},\t/*Unicode: U+0036 (6)*/\n  {.w_px = 8,\t.glyph_index = 3360},\t/*Unicode: U+0037 (7)*/\n  {.w_px = 10,\t.glyph_index = 3520},\t/*Unicode: U+0038 (8)*/\n  {.w_px = 10,\t.glyph_index = 3720},\t/*Unicode: U+0039 (9)*/\n  {.w_px = 3,\t.glyph_index = 3920},\t/*Unicode: U+003a (:)*/\n  {.w_px = 3,\t.glyph_index = 3980},\t/*Unicode: U+003b (;)*/\n  {.w_px = 12,\t.glyph_index = 4040},\t/*Unicode: U+003c (<)*/\n  {.w_px = 10,\t.glyph_index = 4280},\t/*Unicode: U+003d (=)*/\n  {.w_px = 12,\t.glyph_index = 4480},\t/*Unicode: U+003e (>)*/\n  {.w_px = 8,\t.glyph_index = 4720},\t/*Unicode: U+003f (?)*/\n  {.w_px = 14,\t.glyph_index = 4880},\t/*Unicode: U+0040 (@)*/\n  {.w_px = 12,\t.glyph_index = 5160},\t/*Unicode: U+0041 (A)*/\n  {.w_px = 10,\t.glyph_index = 5400},\t/*Unicode: U+0042 (B)*/\n  {.w_px = 11,\t.glyph_index = 5600},\t/*Unicode: U+0043 (C)*/\n  {.w_px = 12,\t.glyph_index = 5820},\t/*Unicode: U+0044 (D)*/\n  {.w_px = 9,\t.glyph_index = 6060},\t/*Unicode: U+0045 (E)*/\n  {.w_px = 8,\t.glyph_index = 6240},\t/*Unicode: U+0046 (F)*/\n  {.w_px = 12,\t.glyph_index = 6400},\t/*Unicode: U+0047 (G)*/\n  {.w_px = 10,\t.glyph_index = 6640},\t/*Unicode: U+0048 (H)*/\n  {.w_px = 3,\t.glyph_index = 6840},\t/*Unicode: U+0049 (I)*/\n  {.w_px = 7,\t.glyph_index = 6900},\t/*Unicode: U+004a (J)*/\n  {.w_px = 10,\t.glyph_index = 7040},\t/*Unicode: U+004b (K)*/\n  {.w_px = 7,\t.glyph_index = 7240},\t/*Unicode: U+004c (L)*/\n  {.w_px = 15,\t.glyph_index = 7380},\t/*Unicode: U+004d (M)*/\n  {.w_px = 12,\t.glyph_index = 7680},\t/*Unicode: U+004e (N)*/\n  {.w_px = 14,\t.glyph_index = 7920},\t/*Unicode: U+004f (O)*/\n  {.w_px = 9,\t.glyph_index = 8200},\t/*Unicode: U+0050 (P)*/\n  {.w_px = 14,\t.glyph_index = 8380},\t/*Unicode: U+0051 (Q)*/\n  {.w_px = 9,\t.glyph_index = 8660},\t/*Unicode: U+0052 (R)*/\n  {.w_px = 9,\t.glyph_index = 8840},\t/*Unicode: U+0053 (S)*/\n  {.w_px = 9,\t.glyph_index = 9020},\t/*Unicode: U+0054 (T)*/\n  {.w_px = 12,\t.glyph_index = 9200},\t/*Unicode: U+0055 (U)*/\n  {.w_px = 12,\t.glyph_index = 9440},\t/*Unicode: U+0056 (V)*/\n  {.w_px = 18,\t.glyph_index = 9680},\t/*Unicode: U+0057 (W)*/\n  {.w_px = 10,\t.glyph_index = 10040},\t/*Unicode: U+0058 (X)*/\n  {.w_px = 10,\t.glyph_index = 10240},\t/*Unicode: U+0059 (Y)*/\n  {.w_px = 10,\t.glyph_index = 10440},\t/*Unicode: U+005a (Z)*/\n  {.w_px = 5,\t.glyph_index = 10640},\t/*Unicode: U+005b ([)*/\n  {.w_px = 8,\t.glyph_index = 10740},\t/*Unicode: U+005c (\\)*/\n  {.w_px = 5,\t.glyph_index = 10900},\t/*Unicode: U+005d (])*/\n  {.w_px = 9,\t.glyph_index = 11000},\t/*Unicode: U+005e (^)*/\n  {.w_px = 8,\t.glyph_index = 11180},\t/*Unicode: U+005f (_)*/\n  {.w_px = 4,\t.glyph_index = 11340},\t/*Unicode: U+0060 (`)*/\n  {.w_px = 9,\t.glyph_index = 11420},\t/*Unicode: U+0061 (a)*/\n  {.w_px = 10,\t.glyph_index = 11600},\t/*Unicode: U+0062 (b)*/\n  {.w_px = 8,\t.glyph_index = 11800},\t/*Unicode: U+0063 (c)*/\n  {.w_px = 10,\t.glyph_index = 11960},\t/*Unicode: U+0064 (d)*/\n  {.w_px = 9,\t.glyph_index = 12160},\t/*Unicode: U+0065 (e)*/\n  {.w_px = 4,\t.glyph_index = 12340},\t/*Unicode: U+0066 (f)*/\n  {.w_px = 9,\t.glyph_index = 12420},\t/*Unicode: U+0067 (g)*/\n  {.w_px = 9,\t.glyph_index = 12600},\t/*Unicode: U+0068 (h)*/\n  {.w_px = 3,\t.glyph_index = 12780},\t/*Unicode: U+0069 (i)*/\n  {.w_px = 5,\t.glyph_index = 12840},\t/*Unicode: U+006a (j)*/\n  {.w_px = 8,\t.glyph_index = 12940},\t/*Unicode: U+006b (k)*/\n  {.w_px = 4,\t.glyph_index = 13100},\t/*Unicode: U+006c (l)*/\n  {.w_px = 13,\t.glyph_index = 13180},\t/*Unicode: U+006d (m)*/\n  {.w_px = 9,\t.glyph_index = 13440},\t/*Unicode: U+006e (n)*/\n  {.w_px = 10,\t.glyph_index = 13620},\t/*Unicode: U+006f (o)*/\n  {.w_px = 10,\t.glyph_index = 13820},\t/*Unicode: U+0070 (p)*/\n  {.w_px = 10,\t.glyph_index = 14020},\t/*Unicode: U+0071 (q)*/\n  {.w_px = 5,\t.glyph_index = 14220},\t/*Unicode: U+0072 (r)*/\n  {.w_px = 8,\t.glyph_index = 14320},\t/*Unicode: U+0073 (s)*/\n  {.w_px = 5,\t.glyph_index = 14480},\t/*Unicode: U+0074 (t)*/\n  {.w_px = 9,\t.glyph_index = 14580},\t/*Unicode: U+0075 (u)*/\n  {.w_px = 8,\t.glyph_index = 14760},\t/*Unicode: U+0076 (v)*/\n  {.w_px = 14,\t.glyph_index = 14920},\t/*Unicode: U+0077 (w)*/\n  {.w_px = 8,\t.glyph_index = 15200},\t/*Unicode: U+0078 (x)*/\n  {.w_px = 8,\t.glyph_index = 15360},\t/*Unicode: U+0079 (y)*/\n  {.w_px = 7,\t.glyph_index = 15520},\t/*Unicode: U+007a (z)*/\n  {.w_px = 4,\t.glyph_index = 15660},\t/*Unicode: U+007b ({)*/\n  {.w_px = 3,\t.glyph_index = 15740},\t/*Unicode: U+007c (|)*/\n  {.w_px = 4,\t.glyph_index = 15800},\t/*Unicode: U+007d (})*/\n  {.w_px = 6,\t.glyph_index = 15880},\t/*Unicode: U+007e (~)*/\n\n#endif\n};\n\nlv_font_t interui_20 =\n{\n    .unicode_first = 32,\t/*First Unicode letter in this font*/\n    .unicode_last = 126,\t/*Last Unicode letter in this font*/\n    .h_px = 20,\t\t\t\t/*Font height in pixels*/\n    //.glyph_bitmap = interui_20_glyph_bitmap,\t/*Bitmap of glyphs*/\n    .glyph_bitmap = (const uint8_t *)(NYX_RES_ADDR + 0x3A00),\n    .glyph_dsc = interui_20_glyph_dsc,\t\t/*Description of glyphs*/\n    .glyph_cnt = 95,\t\t\t/*Number of glyphs in the font*/\n    .unicode_list = NULL,\t/*Every character in the font from 'unicode_first' to 'unicode_last'*/\n    .get_bitmap = lv_font_get_bitmap_continuous,\t/*Function pointer to get glyph's bitmap*/\n    .get_width = lv_font_get_width_continuous,\t/*Function pointer to get glyph's width*/\n#if USE_INTERUI_20 == 4\n    .bpp = 4,\t\t\t\t/*Bit per pixel*/\n#elif USE_INTERUI_20 == 8\n    .bpp = 8,\t\t\t\t/*Bit per pixel*/\n#endif\n    .monospace = 0,\t\t\t\t/*Fix width (0: if not used)*/\n    .next_page = NULL,\t\t/*Pointer to a font extension*/\n};\n\n#endif /*USE_INTERUI_20*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_fonts/interui_30.c",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include \"../lv_misc/lv_font.h\"\n\n#include <memory_map.h>\n\n#if USE_INTERUI_30 != 0\t/*Can be enabled in lv_conf.h*/\n\n/***********************************************************************************\n * Inter-UI-Regular-stretched.ttf 30 px Font in U+0020 ( ) .. U+007e (~)  range with all bpp\n***********************************************************************************/\n\n/*Store the glyph descriptions*/\nstatic const lv_font_glyph_dsc_t interui_30_glyph_dsc[] =\n{\n#if USE_INTERUI_30 == 4\n  {.w_px = 8,\t.glyph_index = 0},\t/*Unicode: U+0020 ( )*/\n  {.w_px = 3,\t.glyph_index = 120},\t/*Unicode: U+0021 (!)*/\n  {.w_px = 6,\t.glyph_index = 180},\t/*Unicode: U+0022 (\")*/\n  {.w_px = 13,\t.glyph_index = 270},\t/*Unicode: U+0023 (#)*/\n  {.w_px = 12,\t.glyph_index = 480},\t/*Unicode: U+0024 ($)*/\n  {.w_px = 18,\t.glyph_index = 660},\t/*Unicode: U+0025 (%)*/\n  {.w_px = 16,\t.glyph_index = 930},\t/*Unicode: U+0026 (&)*/\n  {.w_px = 3,\t.glyph_index = 1170},\t/*Unicode: U+0027 (')*/\n  {.w_px = 6,\t.glyph_index = 1230},\t/*Unicode: U+0028 (()*/\n  {.w_px = 7,\t.glyph_index = 1320},\t/*Unicode: U+0029 ())*/\n  {.w_px = 9,\t.glyph_index = 1440},\t/*Unicode: U+002a (*)*/\n  {.w_px = 16,\t.glyph_index = 1590},\t/*Unicode: U+002b (+)*/\n  {.w_px = 3,\t.glyph_index = 1830},\t/*Unicode: U+002c (,)*/\n  {.w_px = 8,\t.glyph_index = 1890},\t/*Unicode: U+002d (-)*/\n  {.w_px = 3,\t.glyph_index = 2010},\t/*Unicode: U+002e (.)*/\n  {.w_px = 11,\t.glyph_index = 2070},\t/*Unicode: U+002f (/)*/\n  {.w_px = 13,\t.glyph_index = 2250},\t/*Unicode: U+0030 (0)*/\n  {.w_px = 7,\t.glyph_index = 2460},\t/*Unicode: U+0031 (1)*/\n  {.w_px = 13,\t.glyph_index = 2580},\t/*Unicode: U+0032 (2)*/\n  {.w_px = 14,\t.glyph_index = 2790},\t/*Unicode: U+0033 (3)*/\n  {.w_px = 13,\t.glyph_index = 3000},\t/*Unicode: U+0034 (4)*/\n  {.w_px = 14,\t.glyph_index = 3210},\t/*Unicode: U+0035 (5)*/\n  {.w_px = 13,\t.glyph_index = 3420},\t/*Unicode: U+0036 (6)*/\n  {.w_px = 13,\t.glyph_index = 3630},\t/*Unicode: U+0037 (7)*/\n  {.w_px = 13,\t.glyph_index = 3840},\t/*Unicode: U+0038 (8)*/\n  {.w_px = 13,\t.glyph_index = 4050},\t/*Unicode: U+0039 (9)*/\n  {.w_px = 3,\t.glyph_index = 4260},\t/*Unicode: U+003a (:)*/\n  {.w_px = 3,\t.glyph_index = 4320},\t/*Unicode: U+003b (;)*/\n  {.w_px = 18,\t.glyph_index = 4380},\t/*Unicode: U+003c (<)*/\n  {.w_px = 16,\t.glyph_index = 4650},\t/*Unicode: U+003d (=)*/\n  {.w_px = 18,\t.glyph_index = 4890},\t/*Unicode: U+003e (>)*/\n  {.w_px = 12,\t.glyph_index = 5160},\t/*Unicode: U+003f (?)*/\n  {.w_px = 18,\t.glyph_index = 5340},\t/*Unicode: U+0040 (@)*/\n  {.w_px = 17,\t.glyph_index = 5610},\t/*Unicode: U+0041 (A)*/\n  {.w_px = 13,\t.glyph_index = 5880},\t/*Unicode: U+0042 (B)*/\n  {.w_px = 15,\t.glyph_index = 6090},\t/*Unicode: U+0043 (C)*/\n  {.w_px = 17,\t.glyph_index = 6330},\t/*Unicode: U+0044 (D)*/\n  {.w_px = 12,\t.glyph_index = 6600},\t/*Unicode: U+0045 (E)*/\n  {.w_px = 11,\t.glyph_index = 6780},\t/*Unicode: U+0046 (F)*/\n  {.w_px = 17,\t.glyph_index = 6960},\t/*Unicode: U+0047 (G)*/\n  {.w_px = 14,\t.glyph_index = 7230},\t/*Unicode: U+0048 (H)*/\n  {.w_px = 3,\t.glyph_index = 7440},\t/*Unicode: U+0049 (I)*/\n  {.w_px = 11,\t.glyph_index = 7500},\t/*Unicode: U+004a (J)*/\n  {.w_px = 14,\t.glyph_index = 7680},\t/*Unicode: U+004b (K)*/\n  {.w_px = 9,\t.glyph_index = 7890},\t/*Unicode: U+004c (L)*/\n  {.w_px = 23,\t.glyph_index = 8040},\t/*Unicode: U+004d (M)*/\n  {.w_px = 16,\t.glyph_index = 8400},\t/*Unicode: U+004e (N)*/\n  {.w_px = 19,\t.glyph_index = 8640},\t/*Unicode: U+004f (O)*/\n  {.w_px = 11,\t.glyph_index = 8940},\t/*Unicode: U+0050 (P)*/\n  {.w_px = 19,\t.glyph_index = 9120},\t/*Unicode: U+0051 (Q)*/\n  {.w_px = 13,\t.glyph_index = 9420},\t/*Unicode: U+0052 (R)*/\n  {.w_px = 12,\t.glyph_index = 9630},\t/*Unicode: U+0053 (S)*/\n  {.w_px = 14,\t.glyph_index = 9810},\t/*Unicode: U+0054 (T)*/\n  {.w_px = 16,\t.glyph_index = 10020},\t/*Unicode: U+0055 (U)*/\n  {.w_px = 18,\t.glyph_index = 10260},\t/*Unicode: U+0056 (V)*/\n  {.w_px = 27,\t.glyph_index = 10530},\t/*Unicode: U+0057 (W)*/\n  {.w_px = 15,\t.glyph_index = 10950},\t/*Unicode: U+0058 (X)*/\n  {.w_px = 15,\t.glyph_index = 11190},\t/*Unicode: U+0059 (Y)*/\n  {.w_px = 15,\t.glyph_index = 11430},\t/*Unicode: U+005a (Z)*/\n  {.w_px = 6,\t.glyph_index = 11670},\t/*Unicode: U+005b ([)*/\n  {.w_px = 11,\t.glyph_index = 11760},\t/*Unicode: U+005c (\\)*/\n  {.w_px = 7,\t.glyph_index = 11940},\t/*Unicode: U+005d (])*/\n  {.w_px = 13,\t.glyph_index = 12060},\t/*Unicode: U+005e (^)*/\n  {.w_px = 12,\t.glyph_index = 12270},\t/*Unicode: U+005f (_)*/\n  {.w_px = 6,\t.glyph_index = 12450},\t/*Unicode: U+0060 (`)*/\n  {.w_px = 12,\t.glyph_index = 12540},\t/*Unicode: U+0061 (a)*/\n  {.w_px = 13,\t.glyph_index = 12720},\t/*Unicode: U+0062 (b)*/\n  {.w_px = 11,\t.glyph_index = 12930},\t/*Unicode: U+0063 (c)*/\n  {.w_px = 13,\t.glyph_index = 13110},\t/*Unicode: U+0064 (d)*/\n  {.w_px = 12,\t.glyph_index = 13320},\t/*Unicode: U+0065 (e)*/\n  {.w_px = 6,\t.glyph_index = 13500},\t/*Unicode: U+0066 (f)*/\n  {.w_px = 12,\t.glyph_index = 13590},\t/*Unicode: U+0067 (g)*/\n  {.w_px = 11,\t.glyph_index = 13770},\t/*Unicode: U+0068 (h)*/\n  {.w_px = 3,\t.glyph_index = 13950},\t/*Unicode: U+0069 (i)*/\n  {.w_px = 7,\t.glyph_index = 14010},\t/*Unicode: U+006a (j)*/\n  {.w_px = 12,\t.glyph_index = 14130},\t/*Unicode: U+006b (k)*/\n  {.w_px = 4,\t.glyph_index = 14310},\t/*Unicode: U+006c (l)*/\n  {.w_px = 19,\t.glyph_index = 14370},\t/*Unicode: U+006d (m)*/\n  {.w_px = 11,\t.glyph_index = 14670},\t/*Unicode: U+006e (n)*/\n  {.w_px = 14,\t.glyph_index = 14850},\t/*Unicode: U+006f (o)*/\n  {.w_px = 13,\t.glyph_index = 15060},\t/*Unicode: U+0070 (p)*/\n  {.w_px = 13,\t.glyph_index = 15270},\t/*Unicode: U+0071 (q)*/\n  {.w_px = 7,\t.glyph_index = 15480},\t/*Unicode: U+0072 (r)*/\n  {.w_px = 11,\t.glyph_index = 15600},\t/*Unicode: U+0073 (s)*/\n  {.w_px = 8,\t.glyph_index = 15780},\t/*Unicode: U+0074 (t)*/\n  {.w_px = 11,\t.glyph_index = 15900},\t/*Unicode: U+0075 (u)*/\n  {.w_px = 12,\t.glyph_index = 16080},\t/*Unicode: U+0076 (v)*/\n  {.w_px = 21,\t.glyph_index = 16260},\t/*Unicode: U+0077 (w)*/\n  {.w_px = 13,\t.glyph_index = 16590},\t/*Unicode: U+0078 (x)*/\n  {.w_px = 13,\t.glyph_index = 16800},\t/*Unicode: U+0079 (y)*/\n  {.w_px = 10,\t.glyph_index = 17010},\t/*Unicode: U+007a (z)*/\n  {.w_px = 6,\t.glyph_index = 17160},\t/*Unicode: U+007b ({)*/\n  {.w_px = 3,\t.glyph_index = 17250},\t/*Unicode: U+007c (|)*/\n  {.w_px = 5,\t.glyph_index = 17310},\t/*Unicode: U+007d (})*/\n  {.w_px = 8,\t.glyph_index = 17400},\t/*Unicode: U+007e (~)*/\n\n#elif USE_INTERUI_30 == 8\n  {.w_px = 8,\t.glyph_index = 0},\t/*Unicode: U+0020 ( )*/\n  {.w_px = 3,\t.glyph_index = 240},\t/*Unicode: U+0021 (!)*/\n  {.w_px = 6,\t.glyph_index = 330},\t/*Unicode: U+0022 (\")*/\n  {.w_px = 13,\t.glyph_index = 510},\t/*Unicode: U+0023 (#)*/\n  {.w_px = 12,\t.glyph_index = 900},\t/*Unicode: U+0024 ($)*/\n  {.w_px = 18,\t.glyph_index = 1260},\t/*Unicode: U+0025 (%)*/\n  {.w_px = 16,\t.glyph_index = 1800},\t/*Unicode: U+0026 (&)*/\n  {.w_px = 3,\t.glyph_index = 2280},\t/*Unicode: U+0027 (')*/\n  {.w_px = 6,\t.glyph_index = 2370},\t/*Unicode: U+0028 (()*/\n  {.w_px = 7,\t.glyph_index = 2550},\t/*Unicode: U+0029 ())*/\n  {.w_px = 9,\t.glyph_index = 2760},\t/*Unicode: U+002a (*)*/\n  {.w_px = 16,\t.glyph_index = 3030},\t/*Unicode: U+002b (+)*/\n  {.w_px = 3,\t.glyph_index = 3510},\t/*Unicode: U+002c (,)*/\n  {.w_px = 8,\t.glyph_index = 3600},\t/*Unicode: U+002d (-)*/\n  {.w_px = 3,\t.glyph_index = 3840},\t/*Unicode: U+002e (.)*/\n  {.w_px = 11,\t.glyph_index = 3930},\t/*Unicode: U+002f (/)*/\n  {.w_px = 13,\t.glyph_index = 4260},\t/*Unicode: U+0030 (0)*/\n  {.w_px = 7,\t.glyph_index = 4650},\t/*Unicode: U+0031 (1)*/\n  {.w_px = 13,\t.glyph_index = 4860},\t/*Unicode: U+0032 (2)*/\n  {.w_px = 14,\t.glyph_index = 5250},\t/*Unicode: U+0033 (3)*/\n  {.w_px = 13,\t.glyph_index = 5670},\t/*Unicode: U+0034 (4)*/\n  {.w_px = 14,\t.glyph_index = 6060},\t/*Unicode: U+0035 (5)*/\n  {.w_px = 13,\t.glyph_index = 6480},\t/*Unicode: U+0036 (6)*/\n  {.w_px = 13,\t.glyph_index = 6870},\t/*Unicode: U+0037 (7)*/\n  {.w_px = 13,\t.glyph_index = 7260},\t/*Unicode: U+0038 (8)*/\n  {.w_px = 13,\t.glyph_index = 7650},\t/*Unicode: U+0039 (9)*/\n  {.w_px = 3,\t.glyph_index = 8040},\t/*Unicode: U+003a (:)*/\n  {.w_px = 3,\t.glyph_index = 8130},\t/*Unicode: U+003b (;)*/\n  {.w_px = 18,\t.glyph_index = 8220},\t/*Unicode: U+003c (<)*/\n  {.w_px = 16,\t.glyph_index = 8760},\t/*Unicode: U+003d (=)*/\n  {.w_px = 18,\t.glyph_index = 9240},\t/*Unicode: U+003e (>)*/\n  {.w_px = 12,\t.glyph_index = 9780},\t/*Unicode: U+003f (?)*/\n  {.w_px = 18,\t.glyph_index = 10140},\t/*Unicode: U+0040 (@)*/\n  {.w_px = 17,\t.glyph_index = 10680},\t/*Unicode: U+0041 (A)*/\n  {.w_px = 13,\t.glyph_index = 11190},\t/*Unicode: U+0042 (B)*/\n  {.w_px = 15,\t.glyph_index = 11580},\t/*Unicode: U+0043 (C)*/\n  {.w_px = 17,\t.glyph_index = 12030},\t/*Unicode: U+0044 (D)*/\n  {.w_px = 12,\t.glyph_index = 12540},\t/*Unicode: U+0045 (E)*/\n  {.w_px = 11,\t.glyph_index = 12900},\t/*Unicode: U+0046 (F)*/\n  {.w_px = 17,\t.glyph_index = 13230},\t/*Unicode: U+0047 (G)*/\n  {.w_px = 14,\t.glyph_index = 13740},\t/*Unicode: U+0048 (H)*/\n  {.w_px = 3,\t.glyph_index = 14160},\t/*Unicode: U+0049 (I)*/\n  {.w_px = 11,\t.glyph_index = 14250},\t/*Unicode: U+004a (J)*/\n  {.w_px = 14,\t.glyph_index = 14580},\t/*Unicode: U+004b (K)*/\n  {.w_px = 9,\t.glyph_index = 15000},\t/*Unicode: U+004c (L)*/\n  {.w_px = 23,\t.glyph_index = 15270},\t/*Unicode: U+004d (M)*/\n  {.w_px = 16,\t.glyph_index = 15960},\t/*Unicode: U+004e (N)*/\n  {.w_px = 19,\t.glyph_index = 16440},\t/*Unicode: U+004f (O)*/\n  {.w_px = 11,\t.glyph_index = 17010},\t/*Unicode: U+0050 (P)*/\n  {.w_px = 19,\t.glyph_index = 17340},\t/*Unicode: U+0051 (Q)*/\n  {.w_px = 13,\t.glyph_index = 17910},\t/*Unicode: U+0052 (R)*/\n  {.w_px = 12,\t.glyph_index = 18300},\t/*Unicode: U+0053 (S)*/\n  {.w_px = 14,\t.glyph_index = 18660},\t/*Unicode: U+0054 (T)*/\n  {.w_px = 16,\t.glyph_index = 19080},\t/*Unicode: U+0055 (U)*/\n  {.w_px = 18,\t.glyph_index = 19560},\t/*Unicode: U+0056 (V)*/\n  {.w_px = 27,\t.glyph_index = 20100},\t/*Unicode: U+0057 (W)*/\n  {.w_px = 15,\t.glyph_index = 20910},\t/*Unicode: U+0058 (X)*/\n  {.w_px = 15,\t.glyph_index = 21360},\t/*Unicode: U+0059 (Y)*/\n  {.w_px = 15,\t.glyph_index = 21810},\t/*Unicode: U+005a (Z)*/\n  {.w_px = 6,\t.glyph_index = 22260},\t/*Unicode: U+005b ([)*/\n  {.w_px = 11,\t.glyph_index = 22440},\t/*Unicode: U+005c (\\)*/\n  {.w_px = 7,\t.glyph_index = 22770},\t/*Unicode: U+005d (])*/\n  {.w_px = 13,\t.glyph_index = 22980},\t/*Unicode: U+005e (^)*/\n  {.w_px = 12,\t.glyph_index = 23370},\t/*Unicode: U+005f (_)*/\n  {.w_px = 6,\t.glyph_index = 23730},\t/*Unicode: U+0060 (`)*/\n  {.w_px = 12,\t.glyph_index = 23910},\t/*Unicode: U+0061 (a)*/\n  {.w_px = 13,\t.glyph_index = 24270},\t/*Unicode: U+0062 (b)*/\n  {.w_px = 11,\t.glyph_index = 24660},\t/*Unicode: U+0063 (c)*/\n  {.w_px = 13,\t.glyph_index = 24990},\t/*Unicode: U+0064 (d)*/\n  {.w_px = 12,\t.glyph_index = 25380},\t/*Unicode: U+0065 (e)*/\n  {.w_px = 6,\t.glyph_index = 25740},\t/*Unicode: U+0066 (f)*/\n  {.w_px = 12,\t.glyph_index = 25920},\t/*Unicode: U+0067 (g)*/\n  {.w_px = 11,\t.glyph_index = 26280},\t/*Unicode: U+0068 (h)*/\n  {.w_px = 3,\t.glyph_index = 26610},\t/*Unicode: U+0069 (i)*/\n  {.w_px = 7,\t.glyph_index = 26700},\t/*Unicode: U+006a (j)*/\n  {.w_px = 12,\t.glyph_index = 26910},\t/*Unicode: U+006b (k)*/\n  {.w_px = 4,\t.glyph_index = 27270},\t/*Unicode: U+006c (l)*/\n  {.w_px = 19,\t.glyph_index = 27390},\t/*Unicode: U+006d (m)*/\n  {.w_px = 11,\t.glyph_index = 27960},\t/*Unicode: U+006e (n)*/\n  {.w_px = 14,\t.glyph_index = 28290},\t/*Unicode: U+006f (o)*/\n  {.w_px = 13,\t.glyph_index = 28710},\t/*Unicode: U+0070 (p)*/\n  {.w_px = 13,\t.glyph_index = 29100},\t/*Unicode: U+0071 (q)*/\n  {.w_px = 7,\t.glyph_index = 29490},\t/*Unicode: U+0072 (r)*/\n  {.w_px = 11,\t.glyph_index = 29700},\t/*Unicode: U+0073 (s)*/\n  {.w_px = 8,\t.glyph_index = 30030},\t/*Unicode: U+0074 (t)*/\n  {.w_px = 11,\t.glyph_index = 30270},\t/*Unicode: U+0075 (u)*/\n  {.w_px = 12,\t.glyph_index = 30600},\t/*Unicode: U+0076 (v)*/\n  {.w_px = 21,\t.glyph_index = 30960},\t/*Unicode: U+0077 (w)*/\n  {.w_px = 13,\t.glyph_index = 31590},\t/*Unicode: U+0078 (x)*/\n  {.w_px = 13,\t.glyph_index = 31980},\t/*Unicode: U+0079 (y)*/\n  {.w_px = 10,\t.glyph_index = 32370},\t/*Unicode: U+007a (z)*/\n  {.w_px = 6,\t.glyph_index = 32670},\t/*Unicode: U+007b ({)*/\n  {.w_px = 3,\t.glyph_index = 32850},\t/*Unicode: U+007c (|)*/\n  {.w_px = 5,\t.glyph_index = 32940},\t/*Unicode: U+007d (})*/\n  {.w_px = 8,\t.glyph_index = 33090},\t/*Unicode: U+007e (~)*/\n\n#endif\n};\n\nlv_font_t interui_30 =\n{\n    .unicode_first = 32,\t/*First Unicode letter in this font*/\n    .unicode_last = 126,\t/*Last Unicode letter in this font*/\n    .h_px = 30,\t\t\t\t/*Font height in pixels*/\n    //.glyph_bitmap = interui_30_glyph_bitmap,\t/*Bitmap of glyphs*/\n    .glyph_bitmap = (const uint8_t *)(NYX_RES_ADDR + 0x7900),\n    .glyph_dsc = interui_30_glyph_dsc,\t\t/*Description of glyphs*/\n    .glyph_cnt = 95,\t\t\t/*Number of glyphs in the font*/\n    .unicode_list = NULL,\t/*Every character in the font from 'unicode_first' to 'unicode_last'*/\n    .get_bitmap = lv_font_get_bitmap_continuous,\t/*Function pointer to get glyph's bitmap*/\n    .get_width = lv_font_get_width_continuous,\t/*Function pointer to get glyph's width*/\n#if USE_INTERUI_30 == 4\n    .bpp = 4,\t\t\t\t/*Bit per pixel*/\n#elif USE_INTERUI_30 == 8\n    .bpp = 8,\t\t\t\t/*Bit per pixel*/\n#endif\n    .monospace = 0,\t\t\t\t/*Fix width (0: if not used)*/\n    .next_page = NULL,\t\t/*Pointer to a font extension*/\n};\n\n#endif /*USE_INTERUI_30*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_fonts/lv_font_builtin.c",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * @file lv_font_built_in.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_font_builtin.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Initialize the built-in fonts\n */\nvoid lv_font_builtin_init(void)\n{\n    /*InterUI 20*/\n#if USE_INTERUI_20 != 0\n    lv_font_add(&interui_20, NULL);\n#endif\n\n    /*SYMBOL 20*/\n#if USE_HEKATE_SYMBOL_20 != 0\n#if USE_INTERUI_20 != 0\n    lv_font_add(&hekate_symbol_20, &interui_20);\n#else\n    lv_font_add(&hekate_symbol_20, NULL);\n#endif\n#endif\n\n    /*InterUI 30*/\n#if USE_INTERUI_30 != 0\n    lv_font_add(&interui_30, NULL);\n#endif\n\n    /*SYMBOL 30*/\n#if USE_HEKATE_SYMBOL_30 != 0\n#if USE_INTERUI_30 != 0\n    lv_font_add(&hekate_symbol_30, &interui_30);\n#else\n    lv_font_add(&hekate_symbol_30, NULL);\n#endif\n#endif\n\n\t/*MONO 12*/\n#if USE_UBUNTU_MONO != 0\n\tlv_font_add(&ubuntu_mono, NULL);\n#if USE_INTERUI_20 != 0\n    lv_font_add(&hekate_symbol_20, &ubuntu_mono);\n#endif\n#endif\n\n\t/*Symbol 120*/\n#if USE_HEKATE_SYMBOL_120 != 0\n\tlv_font_add(&hekate_symbol_120, NULL);\n#endif\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_fonts/lv_font_builtin.h",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * @file lv_font_builtin.h\n *\n */\n\n#ifndef LV_FONT_BUILTIN_H\n#define LV_FONT_BUILTIN_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *     INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#include \"../lv_misc/lv_font.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Initialize the built-in fonts\n */\nvoid lv_font_builtin_init(void);\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *  FONT DECLARATIONS\n **********************/\n\n/*20 px */\n#if USE_INTERUI_20\nLV_FONT_DECLARE(interui_20);\n#endif\n\n#if USE_HEKATE_SYMBOL_20\nLV_FONT_DECLARE(hekate_symbol_20);\n#endif\n\n/*30 px */\n#if USE_INTERUI_30\nLV_FONT_DECLARE(interui_30);\n#endif\n\n#if USE_HEKATE_SYMBOL_30\nLV_FONT_DECLARE(hekate_symbol_30);\n#endif\n\n#if USE_UBUNTU_MONO\nLV_FONT_DECLARE(ubuntu_mono);\n#endif\n\n#if USE_HEKATE_SYMBOL_120\nLV_FONT_DECLARE(hekate_symbol_120);\n#endif\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_FONT_BUILTIN_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_fonts/lv_fonts.mk",
    "content": "CSRCS += lv_font_builtin.c\nCSRCS += hekate_symbol_10.c\nCSRCS += hekate_symbol_20.c\nCSRCS += hekate_symbol_30.c\nCSRCS += hekate_symbol_40.c\nCSRCS += interui_12.c\nCSRCS += interui_20.c\nCSRCS += interui_30.c\nCSRCS += interui_40.c\n\nDEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_fonts\nVPATH += :$(LVGL_DIR)/lvgl/lv_fonts\n\nCFLAGS += \"-I$(LVGL_DIR)/lvgl/lv_fonts\"\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_fonts/ubuntu_mono.c",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include \"../lv_misc/lv_font.h\"\n\n#include <memory_map.h>\n\n#if USE_UBUNTU_MONO != 0\t/*Can be enabled in lv_conf.h*/\n\n/***********************************************************************************\n * UbuntuMono-B.ttf 20 px Font in U+0020 ( ) .. U+007e (~)  range with all bpp\n***********************************************************************************/\n\n/*Store the glyph descriptions*/\nstatic const lv_font_glyph_dsc_t ubuntu_mono_glyph_dsc[] =\n{\n#if USE_UBUNTU_MONO == 4\n  {.w_px = 6,\t.glyph_index = 0},\t/*Unicode: U+0020 ( )*/\n  {.w_px = 2,\t.glyph_index = 60},\t/*Unicode: U+0021 (!)*/\n  {.w_px = 5,\t.glyph_index = 80},\t/*Unicode: U+0022 (\")*/\n  {.w_px = 10,\t.glyph_index = 140},\t/*Unicode: U+0023 (#)*/\n  {.w_px = 8,\t.glyph_index = 240},\t/*Unicode: U+0024 ($)*/\n  {.w_px = 10,\t.glyph_index = 320},\t/*Unicode: U+0025 (%)*/\n  {.w_px = 10,\t.glyph_index = 420},\t/*Unicode: U+0026 (&)*/\n  {.w_px = 2,\t.glyph_index = 520},\t/*Unicode: U+0027 (')*/\n  {.w_px = 6,\t.glyph_index = 540},\t/*Unicode: U+0028 (()*/\n  {.w_px = 6,\t.glyph_index = 600},\t/*Unicode: U+0029 ())*/\n  {.w_px = 9,\t.glyph_index = 660},\t/*Unicode: U+002a (*)*/\n  {.w_px = 8,\t.glyph_index = 760},\t/*Unicode: U+002b (+)*/\n  {.w_px = 4,\t.glyph_index = 840},\t/*Unicode: U+002c (,)*/\n  {.w_px = 5,\t.glyph_index = 880},\t/*Unicode: U+002d (-)*/\n  {.w_px = 4,\t.glyph_index = 940},\t/*Unicode: U+002e (.)*/\n  {.w_px = 8,\t.glyph_index = 980},\t/*Unicode: U+002f (/)*/\n  {.w_px = 8,\t.glyph_index = 1060},\t/*Unicode: U+0030 (0)*/\n  {.w_px = 7,\t.glyph_index = 1140},\t/*Unicode: U+0031 (1)*/\n  {.w_px = 8,\t.glyph_index = 1220},\t/*Unicode: U+0032 (2)*/\n  {.w_px = 8,\t.glyph_index = 1300},\t/*Unicode: U+0033 (3)*/\n  {.w_px = 8,\t.glyph_index = 1380},\t/*Unicode: U+0034 (4)*/\n  {.w_px = 8,\t.glyph_index = 1460},\t/*Unicode: U+0035 (5)*/\n  {.w_px = 8,\t.glyph_index = 1540},\t/*Unicode: U+0036 (6)*/\n  {.w_px = 7,\t.glyph_index = 1620},\t/*Unicode: U+0037 (7)*/\n  {.w_px = 8,\t.glyph_index = 1700},\t/*Unicode: U+0038 (8)*/\n  {.w_px = 8,\t.glyph_index = 1780},\t/*Unicode: U+0039 (9)*/\n  {.w_px = 4,\t.glyph_index = 1860},\t/*Unicode: U+003a (:)*/\n  {.w_px = 4,\t.glyph_index = 1900},\t/*Unicode: U+003b (;)*/\n  {.w_px = 9,\t.glyph_index = 1940},\t/*Unicode: U+003c (<)*/\n  {.w_px = 8,\t.glyph_index = 2040},\t/*Unicode: U+003d (=)*/\n  {.w_px = 8,\t.glyph_index = 2120},\t/*Unicode: U+003e (>)*/\n  {.w_px = 8,\t.glyph_index = 2200},\t/*Unicode: U+003f (?)*/\n  {.w_px = 9,\t.glyph_index = 2280},\t/*Unicode: U+0040 (@)*/\n  {.w_px = 10,\t.glyph_index = 2380},\t/*Unicode: U+0041 (A)*/\n  {.w_px = 8,\t.glyph_index = 2480},\t/*Unicode: U+0042 (B)*/\n  {.w_px = 8,\t.glyph_index = 2560},\t/*Unicode: U+0043 (C)*/\n  {.w_px = 8,\t.glyph_index = 2640},\t/*Unicode: U+0044 (D)*/\n  {.w_px = 8,\t.glyph_index = 2720},\t/*Unicode: U+0045 (E)*/\n  {.w_px = 8,\t.glyph_index = 2800},\t/*Unicode: U+0046 (F)*/\n  {.w_px = 8,\t.glyph_index = 2880},\t/*Unicode: U+0047 (G)*/\n  {.w_px = 8,\t.glyph_index = 2960},\t/*Unicode: U+0048 (H)*/\n  {.w_px = 8,\t.glyph_index = 3040},\t/*Unicode: U+0049 (I)*/\n  {.w_px = 8,\t.glyph_index = 3120},\t/*Unicode: U+004a (J)*/\n  {.w_px = 9,\t.glyph_index = 3200},\t/*Unicode: U+004b (K)*/\n  {.w_px = 8,\t.glyph_index = 3300},\t/*Unicode: U+004c (L)*/\n  {.w_px = 9,\t.glyph_index = 3380},\t/*Unicode: U+004d (M)*/\n  {.w_px = 8,\t.glyph_index = 3480},\t/*Unicode: U+004e (N)*/\n  {.w_px = 8,\t.glyph_index = 3560},\t/*Unicode: U+004f (O)*/\n  {.w_px = 8,\t.glyph_index = 3640},\t/*Unicode: U+0050 (P)*/\n  {.w_px = 8,\t.glyph_index = 3720},\t/*Unicode: U+0051 (Q)*/\n  {.w_px = 8,\t.glyph_index = 3800},\t/*Unicode: U+0052 (R)*/\n  {.w_px = 8,\t.glyph_index = 3880},\t/*Unicode: U+0053 (S)*/\n  {.w_px = 8,\t.glyph_index = 3960},\t/*Unicode: U+0054 (T)*/\n  {.w_px = 8,\t.glyph_index = 4040},\t/*Unicode: U+0055 (U)*/\n  {.w_px = 9,\t.glyph_index = 4120},\t/*Unicode: U+0056 (V)*/\n  {.w_px = 9,\t.glyph_index = 4220},\t/*Unicode: U+0057 (W)*/\n  {.w_px = 10,\t.glyph_index = 4320},\t/*Unicode: U+0058 (X)*/\n  {.w_px = 10,\t.glyph_index = 4420},\t/*Unicode: U+0059 (Y)*/\n  {.w_px = 8,\t.glyph_index = 4520},\t/*Unicode: U+005a (Z)*/\n  {.w_px = 6,\t.glyph_index = 4600},\t/*Unicode: U+005b ([)*/\n  {.w_px = 8,\t.glyph_index = 4660},\t/*Unicode: U+005c (\\)*/\n  {.w_px = 6,\t.glyph_index = 4740},\t/*Unicode: U+005d (])*/\n  {.w_px = 10,\t.glyph_index = 4800},\t/*Unicode: U+005e (^)*/\n  {.w_px = 10,\t.glyph_index = 4900},\t/*Unicode: U+005f (_)*/\n  {.w_px = 4,\t.glyph_index = 5000},\t/*Unicode: U+0060 (`)*/\n  {.w_px = 8,\t.glyph_index = 5040},\t/*Unicode: U+0061 (a)*/\n  {.w_px = 8,\t.glyph_index = 5120},\t/*Unicode: U+0062 (b)*/\n  {.w_px = 8,\t.glyph_index = 5200},\t/*Unicode: U+0063 (c)*/\n  {.w_px = 8,\t.glyph_index = 5280},\t/*Unicode: U+0064 (d)*/\n  {.w_px = 9,\t.glyph_index = 5360},\t/*Unicode: U+0065 (e)*/\n  {.w_px = 9,\t.glyph_index = 5460},\t/*Unicode: U+0066 (f)*/\n  {.w_px = 8,\t.glyph_index = 5560},\t/*Unicode: U+0067 (g)*/\n  {.w_px = 8,\t.glyph_index = 5640},\t/*Unicode: U+0068 (h)*/\n  {.w_px = 9,\t.glyph_index = 5720},\t/*Unicode: U+0069 (i)*/\n  {.w_px = 7,\t.glyph_index = 5820},\t/*Unicode: U+006a (j)*/\n  {.w_px = 9,\t.glyph_index = 5900},\t/*Unicode: U+006b (k)*/\n  {.w_px = 8,\t.glyph_index = 6000},\t/*Unicode: U+006c (l)*/\n  {.w_px = 8,\t.glyph_index = 6080},\t/*Unicode: U+006d (m)*/\n  {.w_px = 8,\t.glyph_index = 6160},\t/*Unicode: U+006e (n)*/\n  {.w_px = 8,\t.glyph_index = 6240},\t/*Unicode: U+006f (o)*/\n  {.w_px = 8,\t.glyph_index = 6320},\t/*Unicode: U+0070 (p)*/\n  {.w_px = 8,\t.glyph_index = 6400},\t/*Unicode: U+0071 (q)*/\n  {.w_px = 7,\t.glyph_index = 6480},\t/*Unicode: U+0072 (r)*/\n  {.w_px = 8,\t.glyph_index = 6560},\t/*Unicode: U+0073 (s)*/\n  {.w_px = 8,\t.glyph_index = 6640},\t/*Unicode: U+0074 (t)*/\n  {.w_px = 8,\t.glyph_index = 6720},\t/*Unicode: U+0075 (u)*/\n  {.w_px = 9,\t.glyph_index = 6800},\t/*Unicode: U+0076 (v)*/\n  {.w_px = 10,\t.glyph_index = 6900},\t/*Unicode: U+0077 (w)*/\n  {.w_px = 10,\t.glyph_index = 7000},\t/*Unicode: U+0078 (x)*/\n  {.w_px = 9,\t.glyph_index = 7100},\t/*Unicode: U+0079 (y)*/\n  {.w_px = 8,\t.glyph_index = 7200},\t/*Unicode: U+007a (z)*/\n  {.w_px = 7,\t.glyph_index = 7280},\t/*Unicode: U+007b ({)*/\n  {.w_px = 2,\t.glyph_index = 7360},\t/*Unicode: U+007c (|)*/\n  {.w_px = 8,\t.glyph_index = 7380},\t/*Unicode: U+007d (})*/\n  {.w_px = 9,\t.glyph_index = 7460},\t/*Unicode: U+007e (~)*/\n\n#elif USE_UBUNTU_MONO == 8\n  {.w_px = 6,\t.glyph_index = 0},\t/*Unicode: U+0020 ( )*/\n  {.w_px = 2,\t.glyph_index = 120},\t/*Unicode: U+0021 (!)*/\n  {.w_px = 5,\t.glyph_index = 160},\t/*Unicode: U+0022 (\")*/\n  {.w_px = 10,\t.glyph_index = 260},\t/*Unicode: U+0023 (#)*/\n  {.w_px = 8,\t.glyph_index = 460},\t/*Unicode: U+0024 ($)*/\n  {.w_px = 10,\t.glyph_index = 620},\t/*Unicode: U+0025 (%)*/\n  {.w_px = 10,\t.glyph_index = 820},\t/*Unicode: U+0026 (&)*/\n  {.w_px = 2,\t.glyph_index = 1020},\t/*Unicode: U+0027 (')*/\n  {.w_px = 6,\t.glyph_index = 1060},\t/*Unicode: U+0028 (()*/\n  {.w_px = 6,\t.glyph_index = 1180},\t/*Unicode: U+0029 ())*/\n  {.w_px = 9,\t.glyph_index = 1300},\t/*Unicode: U+002a (*)*/\n  {.w_px = 8,\t.glyph_index = 1480},\t/*Unicode: U+002b (+)*/\n  {.w_px = 4,\t.glyph_index = 1640},\t/*Unicode: U+002c (,)*/\n  {.w_px = 5,\t.glyph_index = 1720},\t/*Unicode: U+002d (-)*/\n  {.w_px = 4,\t.glyph_index = 1820},\t/*Unicode: U+002e (.)*/\n  {.w_px = 8,\t.glyph_index = 1900},\t/*Unicode: U+002f (/)*/\n  {.w_px = 8,\t.glyph_index = 2060},\t/*Unicode: U+0030 (0)*/\n  {.w_px = 7,\t.glyph_index = 2220},\t/*Unicode: U+0031 (1)*/\n  {.w_px = 8,\t.glyph_index = 2360},\t/*Unicode: U+0032 (2)*/\n  {.w_px = 8,\t.glyph_index = 2520},\t/*Unicode: U+0033 (3)*/\n  {.w_px = 8,\t.glyph_index = 2680},\t/*Unicode: U+0034 (4)*/\n  {.w_px = 8,\t.glyph_index = 2840},\t/*Unicode: U+0035 (5)*/\n  {.w_px = 8,\t.glyph_index = 3000},\t/*Unicode: U+0036 (6)*/\n  {.w_px = 7,\t.glyph_index = 3160},\t/*Unicode: U+0037 (7)*/\n  {.w_px = 8,\t.glyph_index = 3300},\t/*Unicode: U+0038 (8)*/\n  {.w_px = 8,\t.glyph_index = 3460},\t/*Unicode: U+0039 (9)*/\n  {.w_px = 4,\t.glyph_index = 3620},\t/*Unicode: U+003a (:)*/\n  {.w_px = 4,\t.glyph_index = 3700},\t/*Unicode: U+003b (;)*/\n  {.w_px = 9,\t.glyph_index = 3780},\t/*Unicode: U+003c (<)*/\n  {.w_px = 8,\t.glyph_index = 3960},\t/*Unicode: U+003d (=)*/\n  {.w_px = 8,\t.glyph_index = 4120},\t/*Unicode: U+003e (>)*/\n  {.w_px = 8,\t.glyph_index = 4280},\t/*Unicode: U+003f (?)*/\n  {.w_px = 9,\t.glyph_index = 4440},\t/*Unicode: U+0040 (@)*/\n  {.w_px = 10,\t.glyph_index = 4620},\t/*Unicode: U+0041 (A)*/\n  {.w_px = 8,\t.glyph_index = 4820},\t/*Unicode: U+0042 (B)*/\n  {.w_px = 8,\t.glyph_index = 4980},\t/*Unicode: U+0043 (C)*/\n  {.w_px = 8,\t.glyph_index = 5140},\t/*Unicode: U+0044 (D)*/\n  {.w_px = 8,\t.glyph_index = 5300},\t/*Unicode: U+0045 (E)*/\n  {.w_px = 8,\t.glyph_index = 5460},\t/*Unicode: U+0046 (F)*/\n  {.w_px = 8,\t.glyph_index = 5620},\t/*Unicode: U+0047 (G)*/\n  {.w_px = 8,\t.glyph_index = 5780},\t/*Unicode: U+0048 (H)*/\n  {.w_px = 8,\t.glyph_index = 5940},\t/*Unicode: U+0049 (I)*/\n  {.w_px = 8,\t.glyph_index = 6100},\t/*Unicode: U+004a (J)*/\n  {.w_px = 9,\t.glyph_index = 6260},\t/*Unicode: U+004b (K)*/\n  {.w_px = 8,\t.glyph_index = 6440},\t/*Unicode: U+004c (L)*/\n  {.w_px = 9,\t.glyph_index = 6600},\t/*Unicode: U+004d (M)*/\n  {.w_px = 8,\t.glyph_index = 6780},\t/*Unicode: U+004e (N)*/\n  {.w_px = 8,\t.glyph_index = 6940},\t/*Unicode: U+004f (O)*/\n  {.w_px = 8,\t.glyph_index = 7100},\t/*Unicode: U+0050 (P)*/\n  {.w_px = 8,\t.glyph_index = 7260},\t/*Unicode: U+0051 (Q)*/\n  {.w_px = 8,\t.glyph_index = 7420},\t/*Unicode: U+0052 (R)*/\n  {.w_px = 8,\t.glyph_index = 7580},\t/*Unicode: U+0053 (S)*/\n  {.w_px = 8,\t.glyph_index = 7740},\t/*Unicode: U+0054 (T)*/\n  {.w_px = 8,\t.glyph_index = 7900},\t/*Unicode: U+0055 (U)*/\n  {.w_px = 9,\t.glyph_index = 8060},\t/*Unicode: U+0056 (V)*/\n  {.w_px = 9,\t.glyph_index = 8240},\t/*Unicode: U+0057 (W)*/\n  {.w_px = 10,\t.glyph_index = 8420},\t/*Unicode: U+0058 (X)*/\n  {.w_px = 10,\t.glyph_index = 8620},\t/*Unicode: U+0059 (Y)*/\n  {.w_px = 8,\t.glyph_index = 8820},\t/*Unicode: U+005a (Z)*/\n  {.w_px = 6,\t.glyph_index = 8980},\t/*Unicode: U+005b ([)*/\n  {.w_px = 8,\t.glyph_index = 9100},\t/*Unicode: U+005c (\\)*/\n  {.w_px = 6,\t.glyph_index = 9260},\t/*Unicode: U+005d (])*/\n  {.w_px = 10,\t.glyph_index = 9380},\t/*Unicode: U+005e (^)*/\n  {.w_px = 10,\t.glyph_index = 9580},\t/*Unicode: U+005f (_)*/\n  {.w_px = 4,\t.glyph_index = 9780},\t/*Unicode: U+0060 (`)*/\n  {.w_px = 8,\t.glyph_index = 9860},\t/*Unicode: U+0061 (a)*/\n  {.w_px = 8,\t.glyph_index = 10020},\t/*Unicode: U+0062 (b)*/\n  {.w_px = 8,\t.glyph_index = 10180},\t/*Unicode: U+0063 (c)*/\n  {.w_px = 8,\t.glyph_index = 10340},\t/*Unicode: U+0064 (d)*/\n  {.w_px = 9,\t.glyph_index = 10500},\t/*Unicode: U+0065 (e)*/\n  {.w_px = 9,\t.glyph_index = 10680},\t/*Unicode: U+0066 (f)*/\n  {.w_px = 8,\t.glyph_index = 10860},\t/*Unicode: U+0067 (g)*/\n  {.w_px = 8,\t.glyph_index = 11020},\t/*Unicode: U+0068 (h)*/\n  {.w_px = 9,\t.glyph_index = 11180},\t/*Unicode: U+0069 (i)*/\n  {.w_px = 7,\t.glyph_index = 11360},\t/*Unicode: U+006a (j)*/\n  {.w_px = 9,\t.glyph_index = 11500},\t/*Unicode: U+006b (k)*/\n  {.w_px = 8,\t.glyph_index = 11680},\t/*Unicode: U+006c (l)*/\n  {.w_px = 8,\t.glyph_index = 11840},\t/*Unicode: U+006d (m)*/\n  {.w_px = 8,\t.glyph_index = 12000},\t/*Unicode: U+006e (n)*/\n  {.w_px = 8,\t.glyph_index = 12160},\t/*Unicode: U+006f (o)*/\n  {.w_px = 8,\t.glyph_index = 12320},\t/*Unicode: U+0070 (p)*/\n  {.w_px = 8,\t.glyph_index = 12480},\t/*Unicode: U+0071 (q)*/\n  {.w_px = 7,\t.glyph_index = 12640},\t/*Unicode: U+0072 (r)*/\n  {.w_px = 8,\t.glyph_index = 12780},\t/*Unicode: U+0073 (s)*/\n  {.w_px = 8,\t.glyph_index = 12940},\t/*Unicode: U+0074 (t)*/\n  {.w_px = 8,\t.glyph_index = 13100},\t/*Unicode: U+0075 (u)*/\n  {.w_px = 9,\t.glyph_index = 13260},\t/*Unicode: U+0076 (v)*/\n  {.w_px = 10,\t.glyph_index = 13440},\t/*Unicode: U+0077 (w)*/\n  {.w_px = 10,\t.glyph_index = 13640},\t/*Unicode: U+0078 (x)*/\n  {.w_px = 9,\t.glyph_index = 13840},\t/*Unicode: U+0079 (y)*/\n  {.w_px = 8,\t.glyph_index = 14020},\t/*Unicode: U+007a (z)*/\n  {.w_px = 7,\t.glyph_index = 14180},\t/*Unicode: U+007b ({)*/\n  {.w_px = 2,\t.glyph_index = 14320},\t/*Unicode: U+007c (|)*/\n  {.w_px = 8,\t.glyph_index = 14360},\t/*Unicode: U+007d (})*/\n  {.w_px = 9,\t.glyph_index = 14520},\t/*Unicode: U+007e (~)*/\n\n#endif\n};\n\nlv_font_t ubuntu_mono =\n{\n    .unicode_first = 32,\t/*First Unicode letter in this font*/\n    .unicode_last = 126,\t/*Last Unicode letter in this font*/\n    .h_px = 20,\t\t\t\t/*Font height in pixels*/\n    //.glyph_bitmap = ubuntu_mono_glyph_bitmap,\t/*Bitmap of glyphs*/\n    .glyph_bitmap = (const uint8_t *)(NYX_RES_ADDR),\n    .glyph_dsc = ubuntu_mono_glyph_dsc,\t\t/*Description of glyphs*/\n    .glyph_cnt = 95,\t\t\t/*Number of glyphs in the font*/\n    .unicode_list = NULL,\t/*Every character in the font from 'unicode_first' to 'unicode_last'*/\n    .get_bitmap = lv_font_get_bitmap_continuous,\t/*Function pointer to get glyph's bitmap*/\n    .get_width = lv_font_get_width_continuous,\t/*Function pointer to get glyph's width*/\n#if USE_UBUNTU_MONO == 4\n    .bpp = 4,\t\t\t\t/*Bit per pixel*/\n#elif USE_UBUNTU_MONO == 8\n    .bpp = 8,\t\t\t\t/*Bit per pixel*/\n#endif\n    .monospace = 10,\t\t/*Fix width (0: if not used)*/\n    .next_page = NULL,\t\t/*Pointer to a font extension*/\n};\n\n#endif /*USE_UBUNTU_MONO*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_hal/lv_hal.h",
    "content": "/**\n * @file hal.h\n *\n */\n\n#ifndef HAL_H\n#define HAL_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_hal_disp.h\"\n#include \"lv_hal_indev.h\"\n#include \"lv_hal_tick.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**********************\n *      MACROS\n **********************/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_hal/lv_hal.mk",
    "content": "CSRCS += lv_hal_disp.c\nCSRCS += lv_hal_indev.c\nCSRCS += lv_hal_tick.c\n\nDEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_hal\nVPATH += :$(LVGL_DIR)/lvgl/lv_hal\n\nCFLAGS += \"-I$(LVGL_DIR)/lvgl/lv_hal\"\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_hal/lv_hal_disp.c",
    "content": "\n/**\n * @file hal_disp.c\n *\n * @description HAL layer for display driver\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include <stdint.h>\n#include <stddef.h>\n#include \"../lv_hal/lv_hal_disp.h\"\n#include \"../lv_misc/lv_mem.h\"\n#include \"../lv_core/lv_obj.h\"\n#include \"../lv_misc/lv_gc.h\"\n\n#if defined(LV_GC_INCLUDE)\n#   include LV_GC_INCLUDE\n#endif /* LV_ENABLE_GC */\n\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_disp_t * active;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Initialize a display driver with default values.\n * It is used to surly have known values in the fields ant not memory junk.\n * After it you can set the fields.\n * @param driver pointer to driver variable to initialize\n */\nvoid lv_disp_drv_init(lv_disp_drv_t * driver)\n{\n    driver->disp_fill = NULL;\n    driver->disp_map = NULL;\n    driver->disp_flush = NULL;\n\n#if USE_LV_GPU\n    driver->mem_blend = NULL;\n    driver->mem_fill = NULL;\n#endif\n\n#if LV_VDB_SIZE\n    driver->vdb_wr = NULL;\n#endif\n}\n\n/**\n * Register an initialized display driver.\n * Automatically set the first display as active.\n * @param driver pointer to an initialized 'lv_disp_drv_t' variable (can be local variable)\n * @return pointer to the new display or NULL on error\n */\nlv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver)\n{\n    lv_disp_t * node;\n\n    node = lv_mem_alloc(sizeof(lv_disp_t));\n    lv_mem_assert(node);\n    if(node == NULL) return NULL;\n\n    memcpy(&node->driver, driver, sizeof(lv_disp_drv_t));\n    node->next = NULL;\n\n    /* Set first display as active by default */\n    if(LV_GC_ROOT(_lv_disp_list) == NULL) {\n        LV_GC_ROOT(_lv_disp_list) = node;\n        active = node;\n        lv_obj_invalidate(lv_scr_act());\n    } else {\n        ((lv_disp_t*)LV_GC_ROOT(_lv_disp_list))->next = node;\n    }\n\n    return node;\n}\n\n\n/**\n * Set the active display\n * @param disp pointer to a display (return value of 'lv_disp_register')\n */\nvoid lv_disp_set_active(lv_disp_t * disp)\n{\n    active = disp;\n    lv_obj_invalidate(lv_scr_act());\n}\n\n/**\n * Get a pointer to the active display\n * @return pointer to the active display\n */\nlv_disp_t * lv_disp_get_active(void)\n{\n    return active;\n}\n\n/**\n * Get the next display.\n * @param disp pointer to the current display. NULL to initialize.\n * @return the next display or NULL if no more. Give the first display when the parameter is NULL\n */\nlv_disp_t * lv_disp_next(lv_disp_t * disp)\n{\n    if(disp == NULL) {\n        return LV_GC_ROOT(_lv_disp_list);\n    } else {\n        if(((lv_disp_t*)LV_GC_ROOT(_lv_disp_list))->next == NULL) return NULL;\n        else return ((lv_disp_t*)LV_GC_ROOT(_lv_disp_list))->next;\n    }\n}\n\n/**\n * Write the content of the internal buffer (VDB) to the display\n * @param x1 left coordinate of the rectangle\n * @param x2 right coordinate of the rectangle\n * @param y1 top coordinate of the rectangle\n * @param y2 bottom coordinate of the rectangle\n * @param color_p fill color\n */\nvoid lv_disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color)\n{\n    if(active == NULL) return;\n    if(active->driver.disp_fill != NULL) active->driver.disp_fill(x1, y1, x2, y2, color);\n}\n\n/**\n * Fill a rectangular area with a color on the active display\n * @param x1 left coordinate of the rectangle\n * @param x2 right coordinate of the rectangle\n * @param y1 top coordinate of the rectangle\n * @param y2 bottom coordinate of the rectangle\n * @param color_p pointer to an array of colors\n */\nvoid lv_disp_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t * color_p)\n{\n    if(active == NULL) return;\n    if(active->driver.disp_flush != NULL) {\n\n        LV_LOG_TRACE(\"disp flush  started\");\n        active->driver.disp_flush(x1, y1, x2, y2, color_p);\n        LV_LOG_TRACE(\"disp flush ready\");\n\n    } else {\n        LV_LOG_WARN(\"disp flush function registered\");\n    }\n}\n\n/**\n * Put a color map to a rectangular area on the active display\n * @param x1 left coordinate of the rectangle\n * @param x2 right coordinate of the rectangle\n * @param y1 top coordinate of the rectangle\n * @param y2 bottom coordinate of the rectangle\n * @param color_map pointer to an array of colors\n */\nvoid lv_disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_map)\n{\n    if(active == NULL) return;\n    if(active->driver.disp_map != NULL)  active->driver.disp_map(x1, y1, x2, y2, color_map);\n}\n\n#if USE_LV_GPU\n\n/**\n * Blend pixels to a destination memory from a source memory\n * In 'lv_disp_drv_t' 'mem_blend' is optional. (NULL if not available)\n * @param dest a memory address. Blend 'src' here.\n * @param src pointer to pixel map. Blend it to 'dest'.\n * @param length number of pixels in 'src'\n * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover)\n */\nvoid lv_disp_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa)\n{\n    if(active == NULL) return;\n    if(active->driver.mem_blend != NULL) active->driver.mem_blend(dest, src, length, opa);\n}\n\n/**\n * Fill a memory with a color (GPUs may support it)\n * In 'lv_disp_drv_t' 'mem_fill' is optional. (NULL if not available)\n * @param dest a memory address. Copy 'src' here.\n * @param src pointer to pixel map. Copy it to 'dest'.\n * @param length number of pixels in 'src'\n * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover)\n */\nvoid lv_disp_mem_fill(lv_color_t * dest, uint32_t length, lv_color_t color)\n{\n    if(active == NULL) return;\n    if(active->driver.mem_fill != NULL) active->driver.mem_fill(dest, length, color);\n}\n\n/**\n * Shows if memory blending (by GPU) is supported or not\n * @return false: 'mem_blend' is not supported in the driver; true: 'mem_blend' is supported in the driver\n */\nbool lv_disp_is_mem_blend_supported(void)\n{\n    if(active == NULL) return false;\n    if(active->driver.mem_blend) return true;\n    else return false;\n}\n\n/**\n * Shows if memory fill (by GPU) is supported or not\n * @return false: 'mem_fill' is not supported in the drover; true: 'mem_fill' is supported in the driver\n */\nbool lv_disp_is_mem_fill_supported(void)\n{\n    if(active == NULL) return false;\n    if(active->driver.mem_fill) return true;\n    else return false;\n}\n\n#endif\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_hal/lv_hal_disp.h",
    "content": "/**\n * @file hal_disp.h\n *\n * @description Display Driver HAL interface header file\n *\n */\n\n#ifndef HAL_DISP_H\n#define HAL_DISP_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#include <stdint.h>\n#include \"lv_hal.h\"\n#include \"../lv_misc/lv_color.h\"\n#include \"../lv_misc/lv_area.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**\n * Display Driver structure to be registered by HAL\n */\ntypedef struct _disp_drv_t {\n    /*Write the internal buffer (VDB) to the display. 'lv_flush_ready()' has to be called when finished*/\n    void (*disp_flush)(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p);\n\n    /*Fill an area with a color on the display*/\n    void (*disp_fill)(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color);\n\n    /*Write pixel map (e.g. image) to the display*/\n    void (*disp_map)(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p);\n\n    /*Optional interface functions to use GPU*/\n#if USE_LV_GPU\n    /*Blend two memories using opacity (GPU only)*/\n    void (*mem_blend)(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa);\n\n    /*Fill a memory with a color (GPU only)*/\n    void (*mem_fill)(lv_color_t * dest, uint32_t length, lv_color_t color);\n#endif\n\n#if LV_VDB_SIZE\n    /*Optional: Set a pixel in a buffer according to the requirements of the display*/\n    void (*vdb_wr)(uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa);\n#endif\n} lv_disp_drv_t;\n\ntypedef struct _disp_t {\n    lv_disp_drv_t driver;\n    struct _disp_t *next;\n} lv_disp_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Initialize a display driver with default values.\n * It is used to surly have known values in the fields ant not memory junk.\n * After it you can set the fields.\n * @param driver pointer to driver variable to initialize\n */\nvoid lv_disp_drv_init(lv_disp_drv_t *driver);\n\n/**\n * Register an initialized display driver.\n * Automatically set the first display as active.\n * @param driver pointer to an initialized 'lv_disp_drv_t' variable (can be local variable)\n * @return pointer to the new display or NULL on error\n */\nlv_disp_t * lv_disp_drv_register(lv_disp_drv_t *driver);\n\n/**\n * Set the active display\n * @param disp pointer to a display (return value of 'lv_disp_register')\n */\nvoid lv_disp_set_active(lv_disp_t * disp);\n\n/**\n * Get a pointer to the active display\n * @return pointer to the active display\n */\nlv_disp_t * lv_disp_get_active(void);\n\n/**\n * Get the next display.\n * @param disp pointer to the current display. NULL to initialize.\n * @return the next display or NULL if no more. Give the first display when the parameter is NULL\n */\nlv_disp_t * lv_disp_next(lv_disp_t * disp);\n\n/**\n * Fill a rectangular area with a color on the active display\n * @param x1 left coordinate of the rectangle\n * @param x2 right coordinate of the rectangle\n * @param y1 top coordinate of the rectangle\n * @param y2 bottom coordinate of the rectangle\n * @param color_p pointer to an array of colors\n */\nvoid lv_disp_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t *color_p);\n\n/**\n * Fill a rectangular area with a color on the active display\n * @param x1 left coordinate of the rectangle\n * @param x2 right coordinate of the rectangle\n * @param y1 top coordinate of the rectangle\n * @param y2 bottom coordinate of the rectangle\n * @param color fill color\n */\nvoid lv_disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color);\n\n/**\n * Put a color map to a rectangular area on the active display\n * @param x1 left coordinate of the rectangle\n * @param x2 right coordinate of the rectangle\n * @param y1 top coordinate of the rectangle\n * @param y2 bottom coordinate of the rectangle\n * @param color_map pointer to an array of colors\n */\nvoid lv_disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_map);\n\n#if USE_LV_GPU\n/**\n * Blend pixels to a destination memory from a source memory\n * In 'lv_disp_drv_t' 'mem_blend' is optional. (NULL if not available)\n * @param dest a memory address. Blend 'src' here.\n * @param src pointer to pixel map. Blend it to 'dest'.\n * @param length number of pixels in 'src'\n * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover)\n */\nvoid lv_disp_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa);\n\n/**\n * Fill a memory with a color (GPUs may support it)\n * In 'lv_disp_drv_t' 'mem_fill' is optional. (NULL if not available)\n * @param dest a memory address. Copy 'src' here.\n * @param src pointer to pixel map. Copy it to 'dest'.\n * @param length number of pixels in 'src'\n * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover)\n */\nvoid lv_disp_mem_fill(lv_color_t * dest, uint32_t length, lv_color_t color);\n/**\n * Shows if memory blending (by GPU) is supported or not\n * @return false: 'mem_blend' is not supported in the driver; true: 'mem_blend' is supported in the driver\n */\nbool lv_disp_is_mem_blend_supported(void);\n\n/**\n * Shows if memory fill (by GPU) is supported or not\n * @return false: 'mem_fill' is not supported in the drover; true: 'mem_fill' is supported in the driver\n */\nbool lv_disp_is_mem_fill_supported(void);\n#endif\n/**********************\n *      MACROS\n **********************/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_hal/lv_hal_indev.c",
    "content": "/**\n * @file hal_indev.c\n *\n * @description Input device HAL interface\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"../lv_hal/lv_hal_indev.h\"\n#include \"../lv_misc/lv_mem.h\"\n#include \"../lv_misc/lv_gc.h\"\n\n#if defined(LV_GC_INCLUDE)\n#   include LV_GC_INCLUDE\n#endif /* LV_ENABLE_GC */\n\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Initialize an input device driver with default values.\n * It is used to surly have known values in the fields ant not memory junk.\n * After it you can set the fields.\n * @param driver pointer to driver variable to initialize\n */\nvoid lv_indev_drv_init(lv_indev_drv_t * driver)\n{\n    driver->read = NULL;\n    driver->type = LV_INDEV_TYPE_NONE;\n    driver->user_data = NULL;\n}\n\n/**\n * Register an initialized input device driver.\n * @param driver pointer to an initialized 'lv_indev_drv_t' variable (can be local variable)\n * @return pointer to the new input device or NULL on error\n */\nlv_indev_t * lv_indev_drv_register(lv_indev_drv_t * driver)\n{\n    lv_indev_t * node;\n\n    node = lv_mem_alloc(sizeof(lv_indev_t));\n    if(!node) return NULL;\n\n    memset(node, 0, sizeof(lv_indev_t));\n    memcpy(&node->driver, driver, sizeof(lv_indev_drv_t));\n\n    node->next = NULL;\n    node->proc.reset_query = 1;\n    node->cursor = NULL;\n    node->group = NULL;\n    node->btn_points = NULL;\n\n    if(LV_GC_ROOT(_lv_indev_list) == NULL) {\n        LV_GC_ROOT(_lv_indev_list) = node;\n    } else {\n        lv_indev_t * last = LV_GC_ROOT(_lv_indev_list);\n        while(last->next)\n            last = last->next;\n\n        last->next = node;\n    }\n\n    return node;\n}\n\n/**\n * Get the next input device.\n * @param indev pointer to the current input device. NULL to initialize.\n * @return the next input devise or NULL if no more. Give the first input device when the parameter is NULL\n */\nlv_indev_t * lv_indev_next(lv_indev_t * indev)\n{\n\n    if(indev == NULL) {\n        return LV_GC_ROOT(_lv_indev_list);\n    } else {\n        if(indev->next == NULL) return NULL;\n        else return indev->next;\n    }\n}\n\n/**\n * Read data from an input device.\n * @param indev pointer to an input device\n * @param data input device will write its data here\n * @return false: no more data; true: there more data to read (buffered)\n */\nbool lv_indev_read(lv_indev_t * indev, lv_indev_data_t * data)\n{\n    bool cont = false;\n\n    memset(data, 0, sizeof(lv_indev_data_t));\n    data->state = LV_INDEV_STATE_REL;\n\n    if(indev->driver.read) {\n        data->user_data = indev->driver.user_data;\n\n        LV_LOG_TRACE(\"idnev read started\");\n        cont = indev->driver.read(data);\n        LV_LOG_TRACE(\"idnev read finished\");\n    } else {\n        LV_LOG_WARN(\"indev function registered\");\n    }\n\n    return cont;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_hal/lv_hal_indev.h",
    "content": "/**\n * @file hal_indev.h\n *\n * @description Input Device HAL interface layer header file\n *\n */\n\n#ifndef HAL_INDEV_H\n#define HAL_INDEV_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#include <stdint.h>\n#include \"lv_hal.h\"\n#include <utils/types.h>\n#include \"../lv_misc/lv_area.h\"\n#include \"../lv_core/lv_obj.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/*Possible input device types*/\nenum {\n    LV_INDEV_TYPE_NONE,        /*Show uninitialized state*/\n    LV_INDEV_TYPE_POINTER,     /*Touch pad, mouse, external button*/\n    LV_INDEV_TYPE_KEYPAD,      /*Keypad or keyboard*/\n    LV_INDEV_TYPE_BUTTON,      /*External (hardware button) which is assinged to a specific point of the screen*/\n    LV_INDEV_TYPE_ENCODER,     /*Encoder with only Left, Right turn and a Button*/\n};\ntypedef uint8_t lv_hal_indev_type_t;\n\n/*States for input devices*/\nenum {\n    LV_INDEV_STATE_REL = 0,\n    LV_INDEV_STATE_PR\n};\ntypedef uint8_t lv_indev_state_t;\n\n/*Data type when an input device is read */\ntypedef struct {\n    union {\n        lv_point_t point;      /*For LV_INDEV_TYPE_POINTER the currently pressed point*/\n        uint32_t key;          /*For LV_INDEV_TYPE_KEYPAD the currently pressed key*/\n        uint32_t btn;          /*For LV_INDEV_TYPE_BUTTON the currently pressed button*/\n        int16_t enc_diff;      /*For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/\n    };\n    void *user_data;           /*'lv_indev_drv_t.priv' for this driver*/\n    lv_indev_state_t state;    /*LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/\n} lv_indev_data_t;\n\n/*Initialized by the user and registered by 'lv_indev_add()'*/\ntypedef struct {\n    lv_hal_indev_type_t type;                   /*Input device type*/\n    bool (*read)(lv_indev_data_t *data);        /*Function pointer to read data. Return 'true' if there is still data to be read (buffered)*/\n    void *user_data;                            /*Pointer to user defined data, passed in 'lv_indev_data_t' on read*/\n} lv_indev_drv_t;\n\nstruct _lv_obj_t;\n\n/*Run time data of input devices*/\ntypedef struct _lv_indev_proc_t {\n    lv_indev_state_t state;\n    union {\n        struct {    /*Pointer and button data*/\n            lv_point_t act_point;\n            lv_point_t last_point;\n            lv_point_t vect;\n            lv_point_t drag_sum;                /*Count the dragged pixels to check LV_INDEV_DRAG_LIMIT*/\n            struct _lv_obj_t * act_obj;\n            struct _lv_obj_t * last_obj;\n\n            /*Flags*/\n            uint8_t drag_range_out      :1;\n            uint8_t drag_in_prog        :1;\n            uint8_t wait_unil_release   :1;\n        };\n        struct {    /*Keypad data*/\n            lv_indev_state_t last_state;\n            uint32_t last_key;\n        };\n    };\n\n    uint32_t pr_timestamp;          /*Pressed time stamp*/\n    uint32_t longpr_rep_timestamp;  /*Long press repeat time stamp*/\n\n    /*Flags*/\n    uint8_t long_pr_sent        :1;\n    uint8_t reset_query         :1;\n    uint8_t disabled            :1;\n} lv_indev_proc_t;\n\nstruct _lv_indev_t;\n\ntypedef void (*lv_indev_feedback_t)(struct _lv_indev_t *, lv_signal_t);\n\nstruct _lv_obj_t;\nstruct _lv_group_t;\n\n/*The main input device descriptor with driver, runtime data ('proc') and some additional information*/\ntypedef struct _lv_indev_t {\n    lv_indev_drv_t driver;\n    lv_indev_proc_t proc;\n    lv_indev_feedback_t feedback;\n    uint32_t last_activity_time;\n    union {\n        struct _lv_obj_t *cursor;       /*Cursor for LV_INPUT_TYPE_POINTER*/\n        struct _lv_group_t *group;      /*Keypad destination group*/\n        const lv_point_t * btn_points;      /*Array points assigned to the button ()screen will be pressed here by the buttons*/\n\n    };\n    struct _lv_indev_t *next;\n} lv_indev_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Initialize an input device driver with default values.\n * It is used to surly have known values in the fields ant not memory junk.\n * After it you can set the fields.\n * @param driver pointer to driver variable to initialize\n */\nvoid lv_indev_drv_init(lv_indev_drv_t *driver);\n\n/**\n * Register an initialized input device driver.\n * @param driver pointer to an initialized 'lv_indev_drv_t' variable (can be local variable)\n * @return pointer to the new input device or NULL on error\n */\nlv_indev_t * lv_indev_drv_register(lv_indev_drv_t *driver);\n\n/**\n * Get the next input device.\n * @param indev pointer to the current input device. NULL to initialize.\n * @return the next input devise or NULL if no more. Gives the first input device when the parameter is NULL\n */\nlv_indev_t * lv_indev_next(lv_indev_t * indev);\n\n/**\n * Read data from an input device.\n * @param indev pointer to an input device\n * @param data input device will write its data here\n * @return false: no more data; true: there more data to read (buffered)\n */\nbool lv_indev_read(lv_indev_t * indev, lv_indev_data_t *data);\n\n/**********************\n *      MACROS\n **********************/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_hal/lv_hal_tick.c",
    "content": "/**\n * @file systick.c\n * Provide access to the system tick with 1 millisecond resolution\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#include \"lv_hal_tick.h\"\n#include <stddef.h>\n\n#if LV_TICK_CUSTOM == 1\n#include LV_TICK_CUSTOM_INCLUDE\n#endif\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic uint32_t sys_time = 0;\nstatic volatile uint8_t tick_irq_flag;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * You have to call this function periodically\n * @param tick_period the call period of this function in milliseconds\n */\nLV_ATTRIBUTE_TICK_INC void lv_tick_inc(uint32_t tick_period)\n{\n    tick_irq_flag = 0;\n    sys_time += tick_period;\n}\n\n/**\n * Get the elapsed milliseconds since start up\n * @return the elapsed milliseconds\n */\nuint32_t lv_tick_get(void)\n{\n#if LV_TICK_CUSTOM == 0\n    uint32_t result;\n    do {\n        tick_irq_flag = 1;\n        result = sys_time;\n    } while(!tick_irq_flag);     /*'lv_tick_inc()' clears this flag which can be in an interrupt. Continue until make a non interrupted cycle */\n\n    return result;\n#else\n    return LV_TICK_CUSTOM_SYS_TIME_EXPR;\n#endif\n}\n\n/**\n * Get the elapsed milliseconds since a previous time stamp\n * @param prev_tick a previous time stamp (return value of systick_get() )\n * @return the elapsed milliseconds since 'prev_tick'\n */\nuint32_t lv_tick_elaps(uint32_t prev_tick)\n{\n    uint32_t act_time = lv_tick_get();\n\n    /*If there is no overflow in sys_time simple subtract*/\n    if(act_time >= prev_tick) {\n        prev_tick = act_time - prev_tick;\n    } else {\n        prev_tick = UINT32_MAX - prev_tick + 1;\n        prev_tick += act_time;\n    }\n\n    return prev_tick;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_hal/lv_hal_tick.h",
    "content": "/**\n * @file lv_hal_tick.h\n * Provide access to the system tick with 1 millisecond resolution\n */\n\n#ifndef LV_HAL_TICK_H\n#define LV_HAL_TICK_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n#include <stdint.h>\n\n/*********************\n *      DEFINES\n *********************/\n#ifndef LV_ATTRIBUTE_TICK_INC\n#define LV_ATTRIBUTE_TICK_INC\n#endif\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * You have to call this function periodically\n * @param tick_period the call period of this function in milliseconds\n */\nLV_ATTRIBUTE_TICK_INC void lv_tick_inc(uint32_t tick_period);\n\n/**\n * Get the elapsed milliseconds since start up\n * @return the elapsed milliseconds\n */\nuint32_t lv_tick_get(void);\n\n/**\n * Get the elapsed milliseconds since a previous time stamp\n * @param prev_tick a previous time stamp (return value of systick_get() )\n * @return the elapsed milliseconds since 'prev_tick'\n */\nuint32_t lv_tick_elaps(uint32_t prev_tick);\n\n/**********************\n *      MACROS\n **********************/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_HAL_TICK_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_anim.c",
    "content": "/**\n * @file anim.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_anim.h\"\n\n#if USE_LV_ANIMATION\n#include <stddef.h>\n#include <string.h>\n#include \"../lv_hal/lv_hal_tick.h\"\n#include \"lv_task.h\"\n#include \"lv_math.h\"\n#include \"lv_gc.h\"\n\n#if defined(LV_GC_INCLUDE)\n#   include LV_GC_INCLUDE\n#endif /* LV_ENABLE_GC */\n\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_ANIM_RESOLUTION      1024\n#define LV_ANIM_RES_SHIFT       10\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic void anim_task(void * param);\nstatic bool anim_ready_handler(lv_anim_t * a);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic uint32_t last_task_run;\nstatic bool anim_list_changed;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Init. the animation module\n */\nvoid lv_anim_init(void)\n{\n    lv_ll_init(&LV_GC_ROOT(_lv_anim_ll), sizeof(lv_anim_t));\n    last_task_run = lv_tick_get();\n    lv_task_create(anim_task, LV_REFR_PERIOD, LV_TASK_PRIO_MID, NULL);\n}\n\n/**\n * Create an animation\n * @param anim_p an initialized 'anim_t' variable. Not required after call.\n */\nvoid lv_anim_create(lv_anim_t * anim_p)\n{\n    LV_LOG_TRACE(\"animation create started\")\n    /* Do not let two animations for the  same 'var' with the same 'fp'*/\n    if(anim_p->fp != NULL) lv_anim_del(anim_p->var, anim_p->fp);       /*fp == NULL would delete all animations of var*/\n\n    /*Add the new animation to the animation linked list*/\n    lv_anim_t * new_anim = lv_ll_ins_head(&LV_GC_ROOT(_lv_anim_ll));\n    lv_mem_assert(new_anim);\n    if(new_anim == NULL) return;\n\n    /*Initialize the animation descriptor*/\n    anim_p->playback_now = 0;\n    memcpy(new_anim, anim_p, sizeof(lv_anim_t));\n\n    /*Set the start value*/\n    if(new_anim->fp != NULL) new_anim->fp(new_anim->var, new_anim->start);\n\n    /* Creating an animation changed the linked list.\n     * It's important if it happens in a ready callback. (see `anim_task`)*/\n    anim_list_changed = true;\n\n    LV_LOG_TRACE(\"animation created\")\n}\n\n/**\n * Delete an animation for a variable with a given animator function\n * @param var pointer to variable\n * @param fp a function pointer which is animating 'var',\n *           or NULL to delete all animations of 'var'\n * @return true: at least 1 animation is deleted, false: no animation is deleted\n */\nbool lv_anim_del(void * var, lv_anim_fp_t fp)\n{\n    lv_anim_t * a;\n    lv_anim_t * a_next;\n    bool del = false;\n    a = lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll));\n    while(a != NULL) {\n        /*'a' might be deleted, so get the next object while 'a' is valid*/\n        a_next = lv_ll_get_next(&LV_GC_ROOT(_lv_anim_ll), a);\n\n        if(a->var == var && (a->fp == fp || fp == NULL)) {\n            lv_ll_rem(&LV_GC_ROOT(_lv_anim_ll), a);\n            lv_mem_free(a);\n            anim_list_changed = true;       /*Read by `anim_task`. It need to know if a delete occurred in the linked list*/\n            del = true;\n        }\n\n        a = a_next;\n    }\n\n    return del;\n}\n\n/**\n * Get the number of currently running animations\n * @return the number of running animations\n */\nuint16_t lv_anim_count_running(void)\n{\n    uint16_t cnt = 0;\n    lv_anim_t * a;\n    LL_READ(LV_GC_ROOT(_lv_anim_ll), a) cnt++;\n\n    return cnt++;\n}\n\n/**\n * Calculate the time of an animation with a given speed and the start and end values\n * @param speed speed of animation in unit/sec\n * @param start start value of the animation\n * @param end end value of the animation\n * @return the required time [ms] for the animation with the given parameters\n */\nuint16_t lv_anim_speed_to_time(uint16_t speed, int32_t start, int32_t end)\n{\n    int32_t d = LV_MATH_ABS((int32_t) start - end);\n    uint32_t time = (int32_t)((int32_t)(d * 1000) / speed);\n\n    if(time > UINT16_MAX) time = UINT16_MAX;\n\n    if(time == 0) {\n        time++;\n    }\n\n    return time;\n}\n\n/**\n * Calculate the current value of an animation applying linear characteristic\n * @param a pointer to an animation\n * @return the current value to set\n */\nint32_t lv_anim_path_linear(const lv_anim_t * a)\n{\n    /*Calculate the current step*/\n    uint16_t step;\n    if(a->time == a->act_time) step = LV_ANIM_RESOLUTION; /*Use the last value if the time fully elapsed*/\n    else step = (a->act_time * LV_ANIM_RESOLUTION) / a->time;\n\n    /* Get the new value which will be proportional to `step`\n     * and the `start` and `end` values*/\n    int32_t new_value;\n    new_value = (int32_t) step * (a->end - a->start);\n    new_value = new_value >> LV_ANIM_RES_SHIFT;\n    new_value += a->start;\n\n    return new_value;\n}\n\n/**\n * Calculate the current value of an animation slowing down the start phase\n * @param a pointer to an animation\n * @return the current value to set\n */\nint32_t lv_anim_path_ease_in(const lv_anim_t * a)\n{\n    /*Calculate the current step*/\n    uint32_t t;\n    if(a->time == a->act_time) t = 1024;\n    else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time;\n\n    int32_t step = lv_bezier3(t, 0, 1, 1, 1024);\n\n    int32_t new_value;\n    new_value = (int32_t) step * (a->end - a->start);\n    new_value = new_value >> 10;\n    new_value += a->start;\n\n\n    return new_value;\n}\n\n/**\n * Calculate the current value of an animation slowing down the end phase\n * @param a pointer to an animation\n * @return the current value to set\n */\nint32_t lv_anim_path_ease_out(const lv_anim_t * a)\n{\n    /*Calculate the current step*/\n\n    uint32_t t;\n    if(a->time == a->act_time) t = 1024;\n    else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time;\n\n    int32_t step = lv_bezier3(t, 0, 1023, 1023, 1024);\n\n    int32_t new_value;\n    new_value = (int32_t) step * (a->end - a->start);\n    new_value = new_value >> 10;\n    new_value += a->start;\n\n\n    return new_value;\n}\n\n/**\n * Calculate the current value of an animation applying an \"S\" characteristic (cosine)\n * @param a pointer to an animation\n * @return the current value to set\n */\nint32_t lv_anim_path_ease_in_out(const lv_anim_t * a)\n{\n    /*Calculate the current step*/\n\n    uint32_t t;\n    if(a->time == a->act_time) t = 1024;\n    else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time;\n\n    int32_t step = lv_bezier3(t, 0, 100, 924, 1024);\n\n    int32_t new_value;\n    new_value = (int32_t) step * (a->end - a->start);\n    new_value = new_value >> 10;\n    new_value += a->start;\n\n\n    return new_value;\n}\n\n/**\n * Calculate the current value of an animation with overshoot at the end\n * @param a pointer to an animation\n * @return the current value to set\n */\nint32_t lv_anim_path_overshoot(const lv_anim_t * a)\n{\n    /*Calculate the current step*/\n\n    uint32_t t;\n    if(a->time == a->act_time) t = 1024;\n    else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time;\n\n    int32_t step = lv_bezier3(t, 0, 600, 1300, 1024);\n\n    int32_t new_value;\n    new_value = (int32_t) step * (a->end - a->start);\n    new_value = new_value >> 10;\n    new_value += a->start;\n\n\n    return new_value;\n}\n\n/**\n * Calculate the current value of an animation with 3 bounces\n * @param a pointer to an animation\n * @return the current value to set\n */\nint32_t lv_anim_path_bounce(const lv_anim_t * a)\n{\n    /*Calculate the current step*/\n    uint32_t t;\n    if(a->time == a->act_time) t = 1024;\n    else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time;\n\n    int32_t diff = (a->end - a->start);\n\n    /*3 bounces has 5 parts: 3 down and 2 up. One part is t / 5 long*/\n\n    if(t < 408){\n        /*Go down*/\n        t = (t * 2500) >> 10;      /*[0..1024] range*/\n    }\n    else if(t >= 408 && t < 614) {\n        /*First bounce back*/\n        t -= 408;\n        t = t * 5;      /*to [0..1024] range*/\n        t = 1024 - t;\n        diff = diff / 6;\n    }\n    else if(t >= 614 && t < 819) {\n        /*Fall back*/\n        t -= 614;\n        t = t * 5;      /*to [0..1024] range*/\n        diff = diff / 6;\n    }\n    else if(t >= 819 && t < 921) {\n        /*Second bounce back*/\n        t -= 819;\n        t = t * 10;      /*to [0..1024] range*/\n        t = 1024 - t;\n        diff = diff / 16;\n    }\n    else if(t >= 921 && t <= 1024) {\n        /*Fall back*/\n        t -= 921;\n        t = t * 10;      /*to [0..1024] range*/\n        diff = diff / 16;\n    }\n\n    if(t > 1024) t = 1024;\n\n    int32_t step = lv_bezier3(t, 1024, 1024, 800, 0);\n\n    int32_t new_value;\n\n    new_value = (int32_t) step * diff;\n    new_value = new_value >> 10;\n    new_value = a->end - new_value;\n\n\n    return new_value;\n}\n\n/**\n * Calculate the current value of an animation applying step characteristic.\n * (Set end value on the end of the animation)\n * @param a pointer to an animation\n * @return the current value to set\n */\nint32_t lv_anim_path_step(const lv_anim_t * a)\n{\n    if(a->act_time >= a->time) return a->end;\n    else return a->start;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Periodically handle the animations.\n * @param param unused\n */\nstatic void anim_task(void * param)\n{\n    (void)param;\n\n    lv_anim_t * a;\n    LL_READ(LV_GC_ROOT(_lv_anim_ll), a) {\n        a->has_run = 0;\n    }\n\n    uint32_t elaps = lv_tick_elaps(last_task_run);\n    a = lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll));\n\n    while(a != NULL) {\n        /*It can be set by `lv_anim_del()` typically in `end_cb`. If set then an animation delete happened in `anim_ready_handler`\n         * which could make this linked list reading corrupt because the list is changed meanwhile\n         */\n        anim_list_changed = false;\n\n        if(!a->has_run) {\n            a->has_run = 1;         /*The list readying might be reseted so need to know which anim has run already*/\n            a->act_time += elaps;\n            if(a->act_time >= 0) {\n                if(a->act_time > a->time) a->act_time = a->time;\n\n                int32_t new_value;\n                new_value = a->path(a);\n\n                if(a->fp != NULL) a->fp(a->var, new_value); /*Apply the calculated value*/\n\n                /*If the time is elapsed the animation is ready*/\n                if(a->act_time >= a->time) {\n                    anim_ready_handler(a);\n                }\n            }\n        }\n\n        /* If the linked list changed due to anim. delete then it's not safe to continue\n         * the reading of the list from here -> start from the head*/\n        if(anim_list_changed) a = lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll));\n        else a = lv_ll_get_next(&LV_GC_ROOT(_lv_anim_ll), a);\n    }\n\n    last_task_run = lv_tick_get();\n}\n\n/**\n * Called when an animation is ready to do the necessary thinks\n * e.g. repeat, play back, delete etc.\n * @param a pointer to an animation descriptor\n * @return true: animation delete occurred nnd the `LV_GC_ROOT(_lv_anim_ll)` has changed\n * */\nstatic bool anim_ready_handler(lv_anim_t * a)\n{\n\n    /*Delete the animation if\n     * - no repeat and no play back (simple one shot animation)\n     * - no repeat, play back is enabled and play back is ready */\n    if((a->repeat == 0 && a->playback == 0) ||\n            (a->repeat == 0 && a->playback == 1 && a->playback_now == 1)) {\n        void (*cb)(void *) = a->end_cb;\n        void * p = a->var;\n        lv_ll_rem(&LV_GC_ROOT(_lv_anim_ll), a);\n        lv_mem_free(a);\n        anim_list_changed = true;\n\n        /* Call the callback function at the end*/\n        /* Check if an animation is deleted in the cb function\n         * if yes then the caller function has to know this*/\n        if(cb != NULL) cb(p);\n    }\n    /*If the animation is not deleted then restart it*/\n    else {\n        a->act_time = - a->repeat_pause;    /*Restart the animation*/\n        /*Swap the start and end values in play back mode*/\n        if(a->playback != 0) {\n            /*If now turning back use the 'playback_pause*/\n            if(a->playback_now == 0) a->act_time = - a->playback_pause;\n\n            /*Toggle the play back state*/\n            a->playback_now = a->playback_now == 0 ? 1 : 0;\n            /*Swap the start and end values*/\n            int32_t tmp;\n            tmp = a->start;\n            a->start = a->end;\n            a->end = tmp;\n        }\n    }\n\n    return anim_list_changed;\n}\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_anim.h",
    "content": "/**\n * @file anim.h\n *\n */\n\n#ifndef ANIM_H\n#define ANIM_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_ANIMATION\n\n#include <stdint.h>\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\nstruct _lv_anim_t;\n\ntypedef int32_t(*lv_anim_path_t)(const struct _lv_anim_t*);\n\ntypedef void (*lv_anim_fp_t)(void *, int32_t);\ntypedef void (*lv_anim_cb_t)(void *);\n\ntypedef struct _lv_anim_t\n{\n    void * var;                     /*Variable to animate*/\n    lv_anim_fp_t fp;                /*Animator function*/\n    lv_anim_cb_t end_cb;            /*Call it when the animation is ready*/\n    lv_anim_path_t path;            /*An array with the steps of animations*/\n    int32_t start;                  /*Start value*/\n    int32_t end;                    /*End value*/\n    uint16_t time;                  /*Animation time in ms*/\n    int16_t act_time;               /*Current time in animation. Set to negative to make delay.*/\n    uint16_t playback_pause;        /*Wait before play back*/\n    uint16_t repeat_pause;          /*Wait before repeat*/\n    uint8_t playback :1;            /*When the animation is ready play it back*/\n    uint8_t repeat :1;              /*Repeat the animation infinitely*/\n    /*Animation system use these - user shouldn't set*/\n    uint8_t playback_now :1;        /*Play back is in progress*/\n    uint32_t has_run     :1;        /*Indicates the animation has run it this round*/\n} lv_anim_t;\n\n/*Example initialization\nlv_anim_t a;\na.var = obj;\na.start = lv_obj_get_height(obj);\na.end = new_height;\na.fp = (lv_anim_fp_t)lv_obj_set_height;\na.path = lv_anim_path_linear;\na.end_cb = NULL;\na.act_time = 0;\na.time = 200;\na.playback = 0;\na.playback_pause = 0;\na.repeat = 0;\na.repeat_pause = 0;\nlv_anim_create(&a);\n */\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Init. the animation module\n */\nvoid lv_anim_init(void);\n\n/**\n * Create an animation\n * @param anim_p an initialized 'anim_t' variable. Not required after call.\n */\nvoid lv_anim_create(lv_anim_t * anim_p);\n\n/**\n * Delete an animation for a variable with a given animatior function\n * @param var pointer to variable\n * @param fp a function pointer which is animating 'var',\n *           or NULL to ignore it and delete all animation with 'var\n * @return true: at least 1 animation is deleted, false: no animation is deleted\n */\nbool lv_anim_del(void * var, lv_anim_fp_t fp);\n\n/**\n * Get the number of currently running animations\n * @return the number of running animations\n */\nuint16_t lv_anim_count_running(void);\n\n/**\n * Calculate the time of an animation with a given speed and the start and end values\n * @param speed speed of animation in unit/sec\n * @param start start value of the animation\n * @param end end value of the animation\n * @return the required time [ms] for the animation with the given parameters\n */\nuint16_t lv_anim_speed_to_time(uint16_t speed, int32_t start, int32_t end);\n\n/**\n * Calculate the current value of an animation applying linear characteristic\n * @param a pointer to an animation\n * @return the current value to set\n */\nint32_t lv_anim_path_linear(const lv_anim_t *a);\n\n/**\n * Calculate the current value of an animation slowing down the start phase\n * @param a pointer to an animation\n * @return the current value to set\n */\nint32_t lv_anim_path_ease_in(const lv_anim_t * a);\n\n/**\n * Calculate the current value of an animation slowing down the end phase\n * @param a pointer to an animation\n * @return the current value to set\n */\nint32_t lv_anim_path_ease_out(const lv_anim_t * a);\n\n/**\n * Calculate the current value of an animation applying an \"S\" characteristic (cosine)\n * @param a pointer to an animation\n * @return the current value to set\n */\nint32_t lv_anim_path_ease_in_out(const lv_anim_t *a);\n\n/**\n * Calculate the current value of an animation with overshoot at the end\n * @param a pointer to an animation\n * @return the current value to set\n */\nint32_t lv_anim_path_overshoot(const lv_anim_t * a);\n\n/**\n * Calculate the current value of an animation with 3 bounces\n * @param a pointer to an animation\n * @return the current value to set\n */\nint32_t lv_anim_path_bounce(const lv_anim_t * a);\n\n/**\n * Calculate the current value of an animation applying step characteristic.\n * (Set end value on the end of the animation)\n * @param a pointer to an animation\n * @return the current value to set\n */\nint32_t lv_anim_path_step(const lv_anim_t *a);\n/**********************\n *      MACROS\n **********************/\n\n#endif /*USE_LV_ANIMATION == 0*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_ANIM_H*/\n\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_area.c",
    "content": "/**\n * @file lv_area.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_area.h\"\n#include \"lv_math.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Initialize an area\n * @param area_p pointer to an area\n * @param x1 left coordinate of the area\n * @param y1 top coordinate of the area\n * @param x2 right coordinate of the area\n * @param y2 bottom coordinate of the area\n */\nvoid lv_area_set(lv_area_t * area_p, lv_coord_t x1, lv_coord_t y1, lv_coord_t x2, lv_coord_t y2)\n{\n    area_p->x1 = x1;\n    area_p->y1 = y1;\n    area_p->x2 = x2;\n    area_p->y2 = y2;\n}\n\n/**\n * Set the width of an area\n * @param area_p pointer to an area\n * @param w the new width of the area (w == 1 makes x1 == x2)\n */\nvoid lv_area_set_width(lv_area_t * area_p, lv_coord_t w)\n{\n    area_p->x2 = area_p->x1 + w - 1;\n}\n\n/**\n * Set the height of an area\n * @param area_p pointer to an area\n * @param h the new height of the area (h == 1 makes y1 == y2)\n */\nvoid lv_area_set_height(lv_area_t * area_p, lv_coord_t h)\n{\n    area_p->y2 = area_p->y1 + h - 1;\n}\n\n/**\n * Set the position of an area (width and height will be kept)\n * @param area_p pointer to an area\n * @param x the new x coordinate of the area\n * @param y the new y coordinate of the area\n */\nvoid lv_area_set_pos(lv_area_t * area_p, lv_coord_t x, lv_coord_t y)\n{\n    lv_coord_t w = lv_area_get_width(area_p);\n    lv_coord_t h = lv_area_get_height(area_p);\n    area_p->x1 = x;\n    area_p->y1 = y;\n    lv_area_set_width(area_p, w);\n    lv_area_set_height(area_p, h);\n}\n\n/**\n * Return with area of an area (x * y)\n * @param area_p pointer to an area\n * @return size of area\n */\nuint32_t lv_area_get_size(const lv_area_t * area_p)\n{\n    uint32_t size;\n\n    size = (uint32_t)(area_p->x2 - area_p->x1 + 1) *\n           (area_p->y2 - area_p->y1 + 1);\n\n    return size;\n}\n\n/**\n * Get the common parts of two areas\n * @param res_p pointer to an area, the result will be stored here\n * @param a1_p pointer to the first area\n * @param a2_p pointer to the second area\n * @return false: the two area has NO common parts, res_p is invalid\n */\nbool lv_area_intersect(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_t * a2_p)\n{\n    /* Get the smaller area from 'a1_p' and 'a2_p' */\n    res_p->x1 = LV_MATH_MAX(a1_p->x1, a2_p->x1);\n    res_p->y1 = LV_MATH_MAX(a1_p->y1, a2_p->y1);\n    res_p->x2 = LV_MATH_MIN(a1_p->x2, a2_p->x2);\n    res_p->y2 = LV_MATH_MIN(a1_p->y2, a2_p->y2);\n\n    /*If x1 or y1 greater then x2 or y2 then the areas union is empty*/\n    bool union_ok = true;\n    if((res_p->x1 > res_p->x2) ||\n            (res_p->y1 > res_p->y2)) {\n        union_ok = false;\n    }\n\n    return union_ok;\n}\n/**\n * Join two areas into a third which involves the other two\n * @param res_p pointer to an area, the result will be stored here\n * @param a1_p pointer to the first area\n * @param a2_p pointer to the second area\n */\nvoid lv_area_join(lv_area_t * a_res_p, const lv_area_t * a1_p, const lv_area_t * a2_p)\n{\n    a_res_p->x1 = LV_MATH_MIN(a1_p->x1, a2_p->x1);\n    a_res_p->y1 = LV_MATH_MIN(a1_p->y1, a2_p->y1);\n    a_res_p->x2 = LV_MATH_MAX(a1_p->x2, a2_p->x2);\n    a_res_p->y2 = LV_MATH_MAX(a1_p->y2, a2_p->y2);\n}\n\n/**\n * Check if a point is on an area\n * @param a_p pointer to an area\n * @param p_p pointer to a point\n * @return false:the point is out of the area\n */\nbool lv_area_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p)\n{\n    bool is_on = false;\n\n    if((p_p->x >= a_p->x1 && p_p->x <= a_p->x2) &&\n            ((p_p->y >= a_p->y1 && p_p->y <= a_p->y2))) {\n        is_on = true;\n    }\n\n    return is_on;\n}\n\n/**\n * Check if two area has common parts\n * @param a1_p pointer to an area.\n * @param a2_p pointer to an other area\n * @return false: a1_p and a2_p has no common parts\n */\nbool lv_area_is_on(const lv_area_t * a1_p, const lv_area_t * a2_p)\n{\n    if((a1_p->x1 <= a2_p->x2) &&\n            (a1_p->x2 >= a2_p->x1) &&\n            (a1_p->y1 <= a2_p->y2) &&\n            (a1_p->y2 >= a2_p->y1)) {\n        return true;\n    } else {\n        return false;\n    }\n\n}\n\n/**\n * Check if an area is fully on an other\n * @param ain_p pointer to an area which could be in 'aholder_p'\n * @param aholder pointer to an area which could involve 'ain_p'\n * @return\n */\nbool lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p)\n{\n    bool is_in = false;\n\n    if(ain_p->x1  >= aholder_p->x1 &&\n            ain_p->y1  >= aholder_p->y1 &&\n            ain_p->x2  <= aholder_p->x2 &&\n            ain_p->y2  <= aholder_p->y2) {\n        is_in = true;\n    }\n\n    return is_in;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_area.h",
    "content": "/**\n * @file lv_area.h\n *\n */\n\n#ifndef LV_AREA_H\n#define LV_AREA_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n/*********************\n *      INCLUDES\n *********************/\n#include <string.h>\n#include <utils/types.h>\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_COORD_MAX     (16383)    /*To avoid overflow don't let the max [-32,32k] range */\n#define LV_COORD_MIN     (-16384)\n\n/**********************\n *      TYPEDEFS\n **********************/\ntypedef int16_t lv_coord_t;\n\ntypedef struct\n{\n    lv_coord_t x;\n    lv_coord_t y;\n} lv_point_t;\n\ntypedef struct\n{\n    lv_coord_t x1;\n    lv_coord_t y1;\n    lv_coord_t x2;\n    lv_coord_t y2;\n} lv_area_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Initialize an area\n * @param area_p pointer to an area\n * @param x1 left coordinate of the area\n * @param y1 top coordinate of the area\n * @param x2 right coordinate of the area\n * @param y2 bottom coordinate of the area\n */\nvoid lv_area_set(lv_area_t * area_p, lv_coord_t x1, lv_coord_t y1, lv_coord_t x2, lv_coord_t y2);\n\n/**\n * Copy an area\n * @param dest pointer to the destination area\n * @param src pointer to the source area\n */\ninline static void lv_area_copy(lv_area_t * dest, const lv_area_t * src)\n{\n    memcpy(dest, src, sizeof(lv_area_t));\n}\n\n/**\n * Get the width of an area\n * @param area_p pointer to an area\n * @return the width of the area (if x1 == x2 -> width = 1)\n */\nstatic inline lv_coord_t lv_area_get_width(const lv_area_t * area_p)\n{\n    return area_p->x2 - area_p->x1 + 1;\n}\n\n/**\n * Get the height of an area\n * @param area_p pointer to an area\n * @return the height of the area (if y1 == y2 -> height = 1)\n */\nstatic inline lv_coord_t lv_area_get_height(const lv_area_t * area_p)\n{\n    return area_p->y2 - area_p->y1 + 1;\n}\n\n/**\n * Set the width of an area\n * @param area_p pointer to an area\n * @param w the new width of the area (w == 1 makes x1 == x2)\n */\nvoid lv_area_set_width(lv_area_t * area_p, lv_coord_t w);\n\n/**\n * Set the height of an area\n * @param area_p pointer to an area\n * @param h the new height of the area (h == 1 makes y1 == y2)\n */\nvoid lv_area_set_height(lv_area_t * area_p, lv_coord_t h);\n\n/**\n * Set the position of an area (width and height will be kept)\n * @param area_p pointer to an area\n * @param x the new x coordinate of the area\n * @param y the new y coordinate of the area\n */\nvoid lv_area_set_pos(lv_area_t * area_p, lv_coord_t x, lv_coord_t y);\n\n/**\n * Return with area of an area (x * y)\n * @param area_p pointer to an area\n * @return size of area\n */\nuint32_t lv_area_get_size(const lv_area_t * area_p);\n\n/**\n * Get the common parts of two areas\n * @param res_p pointer to an area, the result will be stored her\n * @param a1_p pointer to the first area\n * @param a2_p pointer to the second area\n * @return false: the two area has NO common parts, res_p is invalid\n */\nbool lv_area_intersect(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_t * a2_p);\n\n/**\n * Join two areas into a third which involves the other two\n * @param res_p pointer to an area, the result will be stored here\n * @param a1_p pointer to the first area\n * @param a2_p pointer to the second area\n */\nvoid lv_area_join(lv_area_t * a_res_p, const lv_area_t * a1_p, const lv_area_t * a2_p);\n\n/**\n * Check if a point is on an area\n * @param a_p pointer to an area\n * @param p_p pointer to a point\n * @return false:the point is out of the area\n */\nbool lv_area_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p);\n\n/**\n * Check if two area has common parts\n * @param a1_p pointer to an area.\n * @param a2_p pointer to an other area\n * @return false: a1_p and a2_p has no common parts\n */\nbool lv_area_is_on(const lv_area_t * a1_p, const lv_area_t * a2_p);\n\n/**\n * Check if an area is fully on an other\n * @param ain_p pointer to an area which could be on aholder_p\n * @param aholder pointer to an area which could involve ain_p\n * @return\n */\nbool lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p);\n\n/**********************\n *      MACROS\n **********************/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_circ.c",
    "content": "/**\n * @file lv_circ.c\n * Circle drawing algorithm (with Bresenham)\n * Only a 1/8 circle is calculated. Use CIRC_OCT1_X, CIRC_OCT1_Y macros to get\n * the other octets.\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_circ.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Initialize the circle drawing\n * @param c pointer to a point. The coordinates will be calculated here\n * @param tmp point to a variable. It will store temporary data\n * @param radius radius of the circle\n */\nvoid lv_circ_init(lv_point_t * c, lv_coord_t * tmp, lv_coord_t radius)\n{\n    c->x = radius;\n    c->y = 0;\n    *tmp = 1 - radius;\n}\n\n/**\n * Test the circle drawing is ready or not\n * @param c same as in circ_init\n * @return true if the circle is not ready yet\n */\nbool lv_circ_cont(lv_point_t * c)\n{\n    return c->y <= c->x ? true : false;\n}\n\n/**\n * Get the next point from the circle\n * @param c same as in circ_init. The next point stored here.\n * @param tmp same as in circ_init.\n */\nvoid lv_circ_next(lv_point_t * c, lv_coord_t * tmp)\n{\n    c->y++;\n\n    if(*tmp <= 0) {\n        (*tmp) += 2 * c->y + 1;   // Change in decision criterion for y -> y+1\n    } else {\n        c->x--;\n        (*tmp) += 2 * (c->y - c->x) + 1;   // Change for y -> y+1, x -> x-1\n    }\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_circ.h",
    "content": "/**\n * @file lv_circ.h\n *\n */\n\n#ifndef LV_CIRC_H\n#define LV_CIRC_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n/*********************\n *      INCLUDES\n *********************/\n#include <stddef.h>\n#include \"lv_area.h\"\n#include <utils/types.h>\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_CIRC_OCT1_X(p) (p.x)\n#define LV_CIRC_OCT1_Y(p) (p.y)\n#define LV_CIRC_OCT2_X(p) (p.y)\n#define LV_CIRC_OCT2_Y(p) (p.x)\n#define LV_CIRC_OCT3_X(p) (-p.y)\n#define LV_CIRC_OCT3_Y(p) (p.x)\n#define LV_CIRC_OCT4_X(p) (-p.x)\n#define LV_CIRC_OCT4_Y(p) (p.y)\n#define LV_CIRC_OCT5_X(p) (-p.x)\n#define LV_CIRC_OCT5_Y(p) (-p.y)\n#define LV_CIRC_OCT6_X(p) (-p.y)\n#define LV_CIRC_OCT6_Y(p) (-p.x)\n#define LV_CIRC_OCT7_X(p) (p.y)\n#define LV_CIRC_OCT7_Y(p) (-p.x)\n#define LV_CIRC_OCT8_X(p) (p.x)\n#define LV_CIRC_OCT8_Y(p) (-p.y)\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Initialize the circle drawing\n * @param c pointer to a point. The coordinates will be calculated here\n * @param tmp point to a variable. It will store temporary data\n * @param radius radius of the circle\n */\nvoid lv_circ_init(lv_point_t * c, lv_coord_t * tmp, lv_coord_t radius);\n\n/**\n * Test the circle drawing is ready or not\n * @param c same as in circ_init\n * @return true if the circle is not ready yet\n */\nbool lv_circ_cont(lv_point_t * c);\n\n/**\n * Get the next point from the circle\n * @param c same as in circ_init. The next point stored here.\n * @param tmp same as in circ_init.\n */\nvoid lv_circ_next(lv_point_t * c, lv_coord_t * tmp);\n\n/**********************\n *      MACROS\n **********************/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_color.c",
    "content": "/*\n * Copyright (c) 2019-2020 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * @file lv_color.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_color.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n#define HUE_DEGREE 512\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Convert a HSV color to RGB\n * @param h hue [0..359]\n * @param s saturation [0..100]\n * @param v value [0..100]\n * @return the given RGB color in RGB (with LV_COLOR_DEPTH depth)\n */\nlv_color_t lv_color_hsv_to_rgb(uint16_t hue, uint8_t sat, uint8_t val)\n{\n    uint8_t r, g, b;\n\n    uint32_t h = (hue * 360 * HUE_DEGREE -1) / 360;\n    uint32_t s = sat * 255 / 100;\n    uint32_t v = val * 255 / 100;\n    uint32_t p = (256 * v - s * v) / 256;\n    uint32_t region = h / (60 * 512);\n    \n    if(sat == 0)\n        return LV_COLOR_MAKE(v, v, v);\n\n    if (region & 1)\n    {\n        uint32_t q = (256 * 60 * HUE_DEGREE * v - h * s * v + 60 * HUE_DEGREE * s * v * region) /\n            (256 * 60 * HUE_DEGREE);\n\n        switch (region)\n        {\n        case 1:\n            r = q;\n            g = v;\n            b = p;\n            break;\n        case 3:\n            r = p;\n            g = q;\n            b = v;\n            break;\n        case 5:\n        default:\n            r = v;\n            g = p;\n            b = q;\n            break;\n        }\n    }\n    else\n    {\n        uint32_t t = (256 * 60 * HUE_DEGREE * v + h * s * v - 60 * HUE_DEGREE * s * v * (region + 1)) /\n            (256 * 60 * HUE_DEGREE);\n\n        switch (region)\n        {\n        case 0:\n            r = v;\n            g = t;\n            b = p;\n            break;\n        case 2:\n            r = p;\n            g = v;\n            b = t;\n            break;\n        case 4:\n        default:\n            r = t;\n            g = p;\n            b = v;\n            break;\n        }\n    }\n\n    return LV_COLOR_MAKE(r, g, b);\n}\n\n/**\n * Convert an RGB color to HSV\n * @param r red\n * @param g green\n * @param b blue\n * @return the given RGB color n HSV\n */\nlv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r, uint8_t g, uint8_t b)\n{\n    lv_color_hsv_t hsv;\n    uint8_t rgbMin, rgbMax;\n\n    rgbMin = r < g ? (r < b ? r : b) : (g < b ? g : b);\n    rgbMax = r > g ? (r > b ? r : b) : (g > b ? g : b);\n\n    hsv.v = rgbMax;\n    if(hsv.v == 0) {\n        hsv.h = 0;\n        hsv.s = 0;\n        return hsv;\n    }\n\n    hsv.s = 255 * (long)(rgbMax - rgbMin) / hsv.v;\n    if(hsv.s == 0) {\n        hsv.h = 0;\n        return hsv;\n    }\n\n    if(rgbMax == r)\n        hsv.h = 0 + 43 * (g - b) / (rgbMax - rgbMin);\n    else if(rgbMax == g)\n        hsv.h = 85 + 43 * (b - r) / (rgbMax - rgbMin);\n    else\n        hsv.h = 171 + 43 * (r - g) / (rgbMax - rgbMin);\n\n    return hsv;\n}\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_color.h",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * @file lv_color.h\n *\n */\n\n#ifndef LV_COLOR_H\n#define LV_COLOR_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n/*Error checking*/\n#if LV_COLOR_DEPTH == 24\n#error \"LV_COLOR_DEPTH  24 is deprecated. Use LV_COLOR_DEPTH  32 instead (lv_conf.h)\"\n#endif\n\n#if LV_COLOR_DEPTH != 32 && LV_COLOR_SCREEN_TRANSP != 0\n#error \"LV_COLOR_SCREEN_TRANSP requires LV_COLOR_DEPTH == 32. Set it in lv_conf.h\"\n#endif\n\n#if LV_COLOR_DEPTH != 16 && LV_COLOR_16_SWAP != 0\n#error \"LV_COLOR_16_SWAP requires LV_COLOR_DEPTH == 16. Set it in lv_conf.h\"\n#endif\n\n\n#include <stdint.h>\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_COLOR_WHITE   LV_COLOR_MAKE(0xFF,0xFF,0xFF)\n#define LV_COLOR_SILVER  LV_COLOR_MAKE(0xC0,0xC0,0xC0)\n#define LV_COLOR_GRAY    LV_COLOR_MAKE(0x80,0x80,0x80)\n#define LV_COLOR_BLACK   LV_COLOR_MAKE(0x00,0x00,0x00)\n#define LV_COLOR_RED     LV_COLOR_MAKE(0xFF,0x00,0x00)\n#define LV_COLOR_MAROON  LV_COLOR_MAKE(0x80,0x00,0x00)\n#define LV_COLOR_YELLOW  LV_COLOR_MAKE(0xFF,0xFF,0x00)\n#define LV_COLOR_OLIVE   LV_COLOR_MAKE(0x80,0x80,0x00)\n#define LV_COLOR_LIME    LV_COLOR_MAKE(0x00,0xFF,0x00)\n#define LV_COLOR_GREEN   LV_COLOR_MAKE(0x00,0x80,0x00)\n#define LV_COLOR_CYAN    LV_COLOR_MAKE(0x00,0xFF,0xFF)\n#define LV_COLOR_AQUA    LV_COLOR_CYAN\n#define LV_COLOR_TEAL    LV_COLOR_MAKE(0x00,0x80,0x80)\n#define LV_COLOR_BLUE    LV_COLOR_MAKE(0x00,0x00,0xFF)\n#define LV_COLOR_NAVY    LV_COLOR_MAKE(0x00,0x00,0x80)\n#define LV_COLOR_MAGENTA LV_COLOR_MAKE(0xFF,0x00,0xFF)\n#define LV_COLOR_PURPLE  LV_COLOR_MAKE(0x80,0x00,0x80)\n#define LV_COLOR_ORANGE  LV_COLOR_MAKE(0xFF,0xA5,0x00)\n\nenum {\n    LV_OPA_TRANSP =  0,\n    LV_OPA_0      =  0,\n    LV_OPA_10     =  25,\n    LV_OPA_20     =  51,\n    LV_OPA_30     =  76,\n    LV_OPA_40     =  102,\n    LV_OPA_50     =  127,\n    LV_OPA_60     =  153,\n    LV_OPA_70     =  178,\n    LV_OPA_80     =  204,\n    LV_OPA_90     =  229,\n    LV_OPA_100    =  255,\n    LV_OPA_COVER  =  255,\n};\n\n#define LV_OPA_MIN      16      /*Opacities below this will be transparent*/\n#define LV_OPA_MAX      251     /*Opacities above this will fully cover*/\n\n#if LV_COLOR_DEPTH == 1\n#define LV_COLOR_SIZE           8\n#elif LV_COLOR_DEPTH == 8\n#define LV_COLOR_SIZE           8\n#elif LV_COLOR_DEPTH == 16\n#define LV_COLOR_SIZE           16\n#elif LV_COLOR_DEPTH == 32\n#define LV_COLOR_SIZE           32\n#else\n#error \"Invalid LV_COLOR_DEPTH in lv_conf.h! Set it to 1, 8, 16 or 32!\"\n#endif\n\n/**********************\n *      TYPEDEFS\n **********************/\n\ntypedef union\n{\n    uint8_t blue  :1;\n    uint8_t green :1;\n    uint8_t red   :1;\n    uint8_t full  :1;\n} lv_color1_t;\n\ntypedef union\n{\n    struct\n    {\n        uint8_t blue  :2;\n        uint8_t green :3;\n        uint8_t red   :3;\n    };\n    uint8_t full;\n} lv_color8_t;\n\ntypedef union\n{\n    struct\n    {\n#if LV_COLOR_16_SWAP == 0\n        uint16_t blue  :5;\n        uint16_t green :6;\n        uint16_t red   :5;\n#else\n        uint16_t green_h :3;\n        uint16_t red   :5;\n        uint16_t blue  :5;\n        uint16_t green_l :3;\n#endif\n    };\n    uint16_t full;\n} lv_color16_t;\n\ntypedef union\n{\n    struct\n    {\n        uint8_t blue;\n        uint8_t green;\n        uint8_t red;\n        uint8_t alpha;\n    };\n    uint32_t full;\n} lv_color32_t;\n\n#if LV_COLOR_DEPTH == 1\ntypedef uint8_t lv_color_int_t;\ntypedef lv_color1_t lv_color_t;\n#elif LV_COLOR_DEPTH == 8\ntypedef uint8_t lv_color_int_t;\ntypedef lv_color8_t lv_color_t;\n#elif LV_COLOR_DEPTH == 16\ntypedef uint16_t lv_color_int_t;\ntypedef lv_color16_t lv_color_t;\n#elif LV_COLOR_DEPTH == 32\ntypedef uint32_t lv_color_int_t;\ntypedef lv_color32_t lv_color_t;\n#else\n#error \"Invalid LV_COLOR_DEPTH in lv_conf.h! Set it to 1, 8, 16 or 32!\"\n#endif\n\ntypedef uint8_t lv_opa_t;\n\ntypedef struct\n{\n    uint16_t h;\n    uint8_t s;\n    uint8_t v;\n} lv_color_hsv_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/*In color conversations:\n * - When converting to bigger color type the LSB weight of 1 LSB is calculated\n *   E.g. 16 bit Red has 5 bits\n *         8 bit Red has 2 bits\n *        ----------------------\n *        8 bit red LSB = (2^5 - 1) / (2^2 - 1) = 31 / 3 = 10\n *\n * - When calculating to smaller color type simply shift out the LSBs\n *   E.g.  8 bit Red has 2 bits\n *        16 bit Red has 5 bits\n *        ----------------------\n *         Shift right with 5 - 3 = 2\n */\n\nstatic inline uint8_t lv_color_to1(lv_color_t color)\n{\n#if LV_COLOR_DEPTH == 1\n    return color.full;\n#elif LV_COLOR_DEPTH == 8\n    if((color.red   & 0x4) ||\n            (color.green & 0x4) ||\n            (color.blue  & 0x2)) {\n        return 1;\n    } else {\n        return 0;\n    }\n#elif LV_COLOR_DEPTH == 16\n#  if LV_COLOR_16_SWAP == 0\n    if((color.red   & 0x10) ||\n            (color.green & 0x20) ||\n            (color.blue  & 0x10)) {\n        return 1;\n#  else\n    if((color.red   & 0x10) ||\n            (color.green_h & 0x20) ||\n            (color.blue  & 0x10)) {\n        return 1;\n#  endif\n    } else {\n        return 0;\n    }\n#elif LV_COLOR_DEPTH == 32\n    if((color.red   & 0x80) ||\n            (color.green & 0x80) ||\n            (color.blue  & 0x80)) {\n        return 1;\n    } else {\n        return 0;\n    }\n#endif\n}\n\nstatic inline uint8_t lv_color_to8(lv_color_t color)\n{\n#if LV_COLOR_DEPTH == 1\n    if(color.full == 0) return 0;\n    else return 0xFF;\n#elif LV_COLOR_DEPTH == 8\n    return color.full;\n#elif LV_COLOR_DEPTH == 16\n\n#  if LV_COLOR_16_SWAP == 0\n    lv_color8_t ret;\n    ret.red = color.red >> 2;       /* 5 - 3  = 2*/\n    ret.green = color.green >> 3;   /* 6 - 3  = 3*/\n    ret.blue = color.blue >> 3;     /* 5 - 2  = 3*/\n    return ret.full;\n#  else\n    lv_color8_t ret;\n    ret.red = color.red >> 2;       /* 5 - 3  = 2*/\n    ret.green = color.green_h;      /* 6 - 3  = 3*/\n    ret.blue = color.blue >> 3;     /* 5 - 2  = 3*/\n    return ret.full;\n#  endif\n#elif LV_COLOR_DEPTH == 32\n    lv_color8_t ret;\n    ret.red = color.red >> 5;       /* 8 - 3  = 5*/\n    ret.green = color.green >> 5;   /* 8 - 3  = 5*/\n    ret.blue = color.blue >> 6;     /* 8 - 2  = 6*/\n    return ret.full;\n#endif\n}\n\nstatic inline uint16_t lv_color_to16(lv_color_t color)\n{\n#if LV_COLOR_DEPTH == 1\n    if(color.full == 0) return 0;\n    else return 0xFFFF;\n#elif LV_COLOR_DEPTH == 8\n    lv_color16_t ret;\n#  if LV_COLOR_16_SWAP == 0\n    ret.red = color.red * 4;       /*(2^5 - 1)/(2^3 - 1) = 31/7 = 4*/\n    ret.green = color.green * 9;   /*(2^6 - 1)/(2^3 - 1) = 63/7 = 9*/\n    ret.blue = color.blue * 10;    /*(2^5 - 1)/(2^2 - 1) = 31/3 = 10*/\n#  else\n    ret.red = color.red * 4;\n    uint8_t g_tmp = color.green * 9;\n    ret.green_h = (g_tmp & 0x1F) >> 3;\n    ret.green_l = g_tmp & 0x07;\n    ret.blue = color.blue * 10;\n#  endif\n    return ret.full;\n#elif LV_COLOR_DEPTH == 16\n    return color.full;\n#elif LV_COLOR_DEPTH == 32\n    lv_color16_t ret;\n#  if LV_COLOR_16_SWAP == 0\n    ret.red = color.red >> 3;       /* 8 - 5  = 3*/\n    ret.green = color.green >> 2;   /* 8 - 6  = 2*/\n    ret.blue = color.blue >> 3;     /* 8 - 5  = 3*/\n#  else\n    ret.red = color.red >> 3;\n    ret.green_h = (color.green & 0xE0) >> 5;\n    ret.green_l = (color.green & 0x1C) >> 2;\n    ret.blue = color.blue >> 3;\n#  endif\n    return ret.full;\n#endif\n}\n\nstatic inline uint32_t lv_color_to32(lv_color_t color)\n{\n#if LV_COLOR_DEPTH == 1\n    if(color.full == 0) return 0;\n    else return 0xFFFFFFFF;\n#elif LV_COLOR_DEPTH == 8\n    lv_color32_t ret;\n    ret.red = color.red * 36;        /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/\n    ret.green = color.green * 36;    /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/\n    ret.blue = color.blue * 85;      /*(2^8 - 1)/(2^2 - 1) = 255/3 = 85*/\n    ret.alpha = 0xFF;\n    return ret.full;\n#elif LV_COLOR_DEPTH == 16\n#  if LV_COLOR_16_SWAP == 0\n    lv_color32_t ret;\n    ret.red = color.red * 8;       /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/\n    ret.green = color.green * 4;   /*(2^8 - 1)/(2^6 - 1) = 255/63 = 4*/\n    ret.blue = color.blue * 8;     /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/\n    ret.alpha = 0xFF;\n    return ret.full;\n#  else\n    lv_color32_t ret;\n    ret.red = color.red * 8;                                    /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/\n    ret.green = ((color.green_h << 3) + color.green_l) * 4;     /*(2^8 - 1)/(2^6 - 1) = 255/63 = 4*/\n    ret.blue = color.blue * 8;                                   /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/\n    ret.alpha = 0xFF;\n    return ret.full;\n#  endif\n#elif LV_COLOR_DEPTH == 32\n    return color.full;\n#endif\n}\n\nstatic inline lv_color_t lv_color_mix(const lv_color_t c1, const lv_color_t c2, uint8_t mix)\n{\n    lv_color_t ret;\n#if LV_COLOR_DEPTH != 1 && LV_COLOR_DEPTH != 32\n    /*LV_COLOR_DEPTH == 8, 16 or 32*/\n    ret.red =   (uint16_t)((uint16_t) c1.red * mix + (c2.red * (255 - mix))) >> 8;\n#  if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP\n    /*If swapped Green is in 2 parts*/\n    uint16_t g_1 = (c1.green_h << 3) + c1.green_l;\n    uint16_t g_2 = (c2.green_h << 3) + c2.green_l;\n    uint16_t g_out = (uint16_t)((uint16_t) g_1 * mix + (g_2 * (255 - mix))) >> 8;\n    ret.green_h = g_out >> 3;\n    ret.green_l = g_out & 0x7;\n#  else\n    ret.green = (uint16_t)((uint16_t) c1.green * mix + (c2.green * (255 - mix))) >> 8;\n#  endif\n    ret.blue =  (uint16_t)((uint16_t) c1.blue * mix + (c2.blue * (255 - mix))) >> 8;\n#else\n#   if LV_COLOR_DEPTH == 32\n    uint32_t rb = (((c1.full & 0x00FF00FF) * mix) + ((c2.full & 0x00FF00FF) * (255 - mix))) >> 8;\n    uint32_t g = (((((c1.full & 0x0000FF00) >> 8) * mix) + (((c2.full & 0x0000FF00) >> 8) * (255 - mix))) >> 8) << 8;\n    ret.full = 0xFF000000 | (0x00FF00FF & rb) | (0x0000FF00 & g);\n#   else\n    /*LV_COLOR_DEPTH == 1*/\n    ret.full = mix > LV_OPA_50 ? c1.full : c2.full;\n#   endif\n#endif\n\n    return ret;\n}\n\n/**\n * Get the brightness of a color\n * @param color a color\n * @return the brightness [0..255]\n */\nstatic inline uint8_t lv_color_brightness(lv_color_t color)\n{\n    lv_color32_t c32;\n    c32.full = lv_color_to32(color);\n    uint16_t bright = 3 * c32.red + c32.blue + 4 * c32.green;\n    return (uint16_t) bright >> 3;\n}\n\n/* The most simple macro to create a color from R,G and B values\n * The order of bit field is different on Big-endian and Little-endian machines*/\n#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n#if LV_COLOR_DEPTH == 1\n#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){(b8 >> 7 | g8 >> 7 | r8 >> 7)})\n#elif LV_COLOR_DEPTH == 8\n#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8 >> 6, g8 >> 5, r8 >> 5}})\n#elif LV_COLOR_DEPTH == 16\n#  if LV_COLOR_16_SWAP == 0\n#    define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8 >> 3, g8 >> 2, r8 >> 3}})\n#  else\n#    define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{g8 >> 5, r8 >> 3, b8 >> 3, (g8 >> 2) & 0x7}})\n#  endif\n#elif LV_COLOR_DEPTH == 32\n#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8, g8, r8, 0xff}})            /*Fix 0xff alpha*/\n#endif\n#else\n#if LV_COLOR_DEPTH == 1\n#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){(r8 >> 7 | g8 >> 7 | b8 >> 7)})\n#elif LV_COLOR_DEPTH == 8\n#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{r8 >> 6, g8 >> 5, b8 >> 5}})\n#elif LV_COLOR_DEPTH == 16\n#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{r8 >> 3, g8 >> 2, b8 >> 3}})\n#elif LV_COLOR_DEPTH == 32\n#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{0xff, r8, g8, b8}})            /*Fix 0xff alpha*/\n#endif\n#endif\n\n#if LV_COLOR_DEPTH == 32 // Concatenate into one 32-bit set. \n#define LV_COLOR_HEX(c) ((lv_color_t){.full = ((c) | 0xFF000000)})\n#else\n#define LV_COLOR_HEX(c) LV_COLOR_MAKE(((uint32_t)((uint32_t)(c) >> 16) & 0xFF), \\\n                                ((uint32_t)((uint32_t)(c) >> 8) & 0xFF), \\\n                                ((uint32_t) (c) & 0xFF))\n#endif\n\n/*Usage LV_COLOR_HEX3(0x16C) which means LV_COLOR_HEX(0x1166CC)*/\n#define LV_COLOR_HEX3(c) LV_COLOR_MAKE(((((c) >> 4) & 0xF0) | (((c) >> 8) & 0xF)),   \\\n                                ((uint32_t)((c) & 0xF0)       | (((c) & 0xF0) >> 4)), \\\n                                ((uint32_t)((c) & 0xF)         | (((c) & 0xF) << 4)))\n\n\n/**\n * Convert a HSV color to RGB\n * @param h hue [0..359]\n * @param s saturation [0..100]\n * @param v value [0..100]\n * @return the given RGB color in RGB (with LV_COLOR_DEPTH depth)\n */\nlv_color_t lv_color_hsv_to_rgb(uint16_t hue, uint8_t sat, uint8_t val);\n\n/**\n * Convert an RGB color to HSV\n * @param r red\n * @param g green\n * @param b blue\n * @return the given RGB color n HSV\n */\nlv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r, uint8_t g, uint8_t b);\n\n\n/**********************\n *      MACROS\n **********************/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*USE_COLOR*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_font.c",
    "content": "/**\n * @file lv_font.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include <stddef.h>\n#include \"lv_font.h\"\n#include \"lv_log.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Initialize the fonts\n */\nvoid lv_font_init(void)\n{\n    lv_font_builtin_init();\n}\n\n/**\n * Add a font to an other to extend the character set.\n * @param child the font to add\n * @param parent this font will be extended. Using it later will contain the characters from `child`\n */\nvoid lv_font_add(lv_font_t * child, lv_font_t * parent)\n{\n    if(parent == NULL) return;\n\n    while(parent->next_page != NULL) {\n        parent = parent->next_page; /*Got to the last page and add the new font there*/\n    }\n\n    parent->next_page = child;\n\n}\n\n/**\n * Remove a font from a character set.\n * @param child the font to remove\n * @param parent remove `child` from here\n */\nvoid lv_font_remove(lv_font_t * child, lv_font_t * parent)\n{\n    if(parent == NULL) return;\n    if(child == NULL) return;\n\n    while(parent->next_page != child) {\n        parent = parent->next_page; /*Got to the last page and add the new font there*/\n    }\n\n    parent->next_page = child->next_page;\n}\n\n\n/**\n * Tells if font which contains `letter` is monospace or not\n * @param font_p point to font\n * @param letter an UNICODE character code\n * @return true: the letter is monospace; false not monospace\n */\nbool lv_font_is_monospace(const lv_font_t * font_p, uint32_t letter)\n{\n    const lv_font_t * font_i = font_p;\n    int16_t w;\n    while(font_i != NULL) {\n        w = font_i->get_width(font_i, letter);\n        if(w >= 0) {\n            /*Glyph found*/\n            if(font_i->monospace) return true;\n            return false;\n        }\n\n        font_i = font_i->next_page;\n    }\n\n    return 0;\n}\n\n/**\n * Return with the bitmap of a font.\n * @param font_p pointer to a font\n * @param letter an UNICODE character code\n * @return  pointer to the bitmap of the letter\n */\nconst uint8_t * lv_font_get_bitmap(const lv_font_t * font_p, uint32_t letter)\n{\n    const lv_font_t * font_i = font_p;\n    while(font_i != NULL) {\n        const uint8_t * bitmap = font_i->get_bitmap(font_i, letter);\n        if(bitmap) return bitmap;\n\n        font_i = font_i->next_page;\n    }\n\n    return NULL;\n}\n\n/**\n * Get the width of a letter in a font. If `monospace` is set then return with it.\n * @param font_p pointer to a font\n * @param letter an UNICODE character code\n * @return the width of a letter\n */\nuint8_t lv_font_get_width(const lv_font_t * font_p, uint32_t letter)\n{\n    const lv_font_t * font_i = font_p;\n    int16_t w;\n    while(font_i != NULL) {\n        w = font_i->get_width(font_i, letter);\n        if(w >= 0) {\n            /*Glyph found*/\n            uint8_t m = font_i->monospace;\n            if(m) w = m;\n            return w;\n        }\n\n        font_i = font_i->next_page;\n    }\n\n    return 0;\n\n}\n\n/**\n * Get the width of the letter without overwriting it with the `monospace` attribute\n * @param font_p pointer to a font\n * @param letter an UNICODE character code\n * @return the width of a letter\n */\nuint8_t lv_font_get_real_width(const lv_font_t * font_p, uint32_t letter)\n{\n    const lv_font_t * font_i = font_p;\n    int16_t w;\n    while(font_i != NULL) {\n        w = font_i->get_width(font_i, letter);\n        if(w >= 0) return w;\n\n        font_i = font_i->next_page;\n    }\n\n    return 0;\n}\n\n/**\n * Get the bit-per-pixel of font\n * @param font pointer to font\n * @param letter a letter from font (font extensions can have different bpp)\n * @return bpp of the font (or font extension)\n */\nuint8_t lv_font_get_bpp(const lv_font_t * font, uint32_t letter)\n{\n    const lv_font_t * font_i = font;\n    while(font_i != NULL) {\n        if(letter >= font_i->unicode_first && letter <= font_i->unicode_last) {\n            return font_i->bpp;\n        }\n        font_i = font_i->next_page;\n    }\n\n    return 0;\n\n}\n\n/**\n * Generic bitmap get function used in 'font->get_bitmap' when the font contains all characters in the range\n * @param font pointer to font\n * @param unicode_letter an unicode letter which bitmap should be get\n * @return pointer to the bitmap or NULL if not found\n */\nconst uint8_t * lv_font_get_bitmap_continuous(const lv_font_t * font, uint32_t unicode_letter)\n{\n    /*Check the range*/\n    if(unicode_letter < font->unicode_first || unicode_letter > font->unicode_last) return NULL;\n\n    uint32_t index = (unicode_letter - font->unicode_first);\n    return &font->glyph_bitmap[font->glyph_dsc[index].glyph_index];\n}\n\n/**\n * Generic bitmap get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse)\n * @param font pointer to font\n * @param unicode_letter an unicode letter which bitmap should be get\n * @return pointer to the bitmap or NULL if not found\n */\nconst uint8_t * lv_font_get_bitmap_sparse(const lv_font_t * font, uint32_t unicode_letter)\n{\n    /*Check the range*/\n    if(unicode_letter < font->unicode_first || unicode_letter > font->unicode_last) return NULL;\n\n    uint32_t i;\n    for(i = 0; font->unicode_list[i] != 0; i++) {\n        if(font->unicode_list[i] == unicode_letter) {\n            return &font->glyph_bitmap[font->glyph_dsc[i].glyph_index];\n        }\n    }\n\n    return NULL;\n}\n\n/**\n * Generic glyph width get function used in 'font->get_width' when the font contains all characters in the range\n * @param font pointer to font\n * @param unicode_letter an unicode letter which width should be get\n * @return width of the gylph or -1 if not found\n */\nint16_t lv_font_get_width_continuous(const lv_font_t * font, uint32_t unicode_letter)\n{\n    /*Check the range*/\n    if(unicode_letter < font->unicode_first || unicode_letter > font->unicode_last) {\n        return -1;\n    }\n\n    uint32_t index = (unicode_letter - font->unicode_first);\n    return font->glyph_dsc[index].w_px;\n}\n\n/**\n * Generic glyph width get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse)\n * @param font pointer to font\n * @param unicode_letter an unicode letter which width should be get\n * @return width of the glyph or -1 if not found\n */\nint16_t lv_font_get_width_sparse(const lv_font_t * font, uint32_t unicode_letter)\n{\n    /*Check the range*/\n    if(unicode_letter < font->unicode_first || unicode_letter > font->unicode_last) return -1;\n\n    uint32_t i;\n    for(i = 0; font->unicode_list[i] != 0; i++) {\n        if(font->unicode_list[i] == unicode_letter) {\n            return font->glyph_dsc[i].w_px;\n        }\n    }\n\n    return -1;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_font.h",
    "content": "/**\n * @file lv_font.h\n *\n */\n\n#ifndef LV_FONT_H\n#define LV_FONT_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#include <stdint.h>\n#include <stddef.h>\n\n#include \"lv_symbol_def.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\ntypedef struct\n{\n    uint32_t w_px         :8;\n    uint32_t glyph_index  :24;\n} lv_font_glyph_dsc_t;\n\ntypedef struct\n{\n    uint32_t unicode         :21;\n    uint32_t glyph_dsc_index :11;\n} lv_font_unicode_map_t;\n\ntypedef struct _lv_font_struct\n{\n    uint32_t unicode_first;\n    uint32_t unicode_last;\n    const uint8_t * glyph_bitmap;\n    const lv_font_glyph_dsc_t * glyph_dsc;\n    const uint32_t * unicode_list;\n    const uint8_t * (*get_bitmap)(const struct _lv_font_struct *,uint32_t);     /*Get a glyph's  bitmap from a font*/\n    int16_t (*get_width)(const struct _lv_font_struct *,uint32_t);        /*Get a glyph's with with a given font*/\n    struct _lv_font_struct * next_page;    /*Pointer to a font extension*/\n    uint32_t h_px       :8;\n    uint32_t bpp        :4;                /*Bit per pixel: 1, 2 or 4*/\n    uint32_t monospace  :8;                /*Fix width (0: normal width)*/\n    uint16_t glyph_cnt;                    /*Number of glyphs (letters) in the font*/\n} lv_font_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Initialize the fonts\n */\nvoid lv_font_init(void);\n\n/**\n * Add a font to an other to extend the character set.\n * @param child the font to add\n * @param parent this font will be extended. Using it later will contain the characters from `child`\n */\nvoid lv_font_add(lv_font_t *child, lv_font_t *parent);\n\n/**\n * Remove a font from a character set.\n * @param child the font to remove\n * @param parent remove `child` from here\n */\nvoid lv_font_remove(lv_font_t * child, lv_font_t * parent);\n\n/**\n * Tells if font which contains `letter` is monospace or not\n * @param font_p point to font\n * @param letter an UNICODE character code\n * @return true: the letter is monospace; false not monospace\n */\nbool lv_font_is_monospace(const lv_font_t * font_p, uint32_t letter);\n\n/**\n * Return with the bitmap of a font.\n * @param font_p pointer to a font\n * @param letter an UNICODE character code\n * @return  pointer to the bitmap of the letter\n */\nconst uint8_t * lv_font_get_bitmap(const lv_font_t * font_p, uint32_t letter);\n\n/**\n * Get the width of a letter in a font. If `monospace` is set then return with it.\n * @param font_p pointer to a font\n * @param letter an UNICODE character code\n * @return the width of a letter\n */\nuint8_t lv_font_get_width(const lv_font_t * font_p, uint32_t letter);\n\n\n/**\n * Get the width of the letter without overwriting it with the `monospace` attribute\n * @param font_p pointer to a font\n * @param letter an UNICODE character code\n * @return the width of a letter\n */\nuint8_t lv_font_get_real_width(const lv_font_t * font_p, uint32_t letter);\n\n/**\n * Get the height of a font\n * @param font_p pointer to a font\n * @return the height of a font\n */\nstatic inline uint8_t lv_font_get_height(const lv_font_t * font_p)\n{\n    return font_p->h_px;\n}\n\n/**\n * Get the bit-per-pixel of font\n * @param font pointer to font\n * @param letter a letter from font (font extensions can have different bpp)\n * @return bpp of the font (or font extension)\n */\nuint8_t lv_font_get_bpp(const lv_font_t * font, uint32_t letter);\n\n/**\n * Generic bitmap get function used in 'font->get_bitmap' when the font contains all characters in the range\n * @param font pointer to font\n * @param unicode_letter an unicode letter which bitmap should be get\n * @return pointer to the bitmap or NULL if not found\n */\nconst uint8_t * lv_font_get_bitmap_continuous(const lv_font_t * font, uint32_t unicode_letter);\n\n/**\n * Generic bitmap get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse)\n * @param font pointer to font\n * @param unicode_letter an unicode letter which bitmap should be get\n * @return pointer to the bitmap or NULL if not found\n */\nconst uint8_t * lv_font_get_bitmap_sparse(const lv_font_t * font, uint32_t unicode_letter);\n/**\n * Generic glyph width get function used in 'font->get_width' when the font contains all characters in the range\n * @param font pointer to font\n * @param unicode_letter an unicode letter which width should be get\n * @return width of the gylph or -1 if not found\n */\nint16_t lv_font_get_width_continuous(const lv_font_t * font, uint32_t unicode_letter);\n\n/**\n * Generic glyph width get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse)\n * @param font pointer to font\n * @param unicode_letter an unicode letter which width should be get\n * @return width of the glyph or -1 if not found\n */\nint16_t lv_font_get_width_sparse(const lv_font_t * font, uint32_t unicode_letter);\n\n/**********************\n *      MACROS\n **********************/\n\n#define LV_FONT_DECLARE(font_name) extern lv_font_t font_name;\n\n\n/**********************\n * ADD BUILT IN FONTS\n **********************/\n#include \"../lv_fonts/lv_font_builtin.h\"\n\n/*Declare the custom (user defined) fonts*/\n#ifdef LV_FONT_CUSTOM_DECLARE\nLV_FONT_CUSTOM_DECLARE\n#endif\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*USE_FONT*/\n\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_fs.c",
    "content": "/**\n * @file lv_fs.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_fs.h\"\n#if USE_LV_FILESYSTEM\n\n#include \"lv_ll.h\"\n#include <string.h>\n#include \"lv_gc.h\"\n\n#if defined(LV_GC_INCLUDE)\n#   include LV_GC_INCLUDE\n#endif /* LV_ENABLE_GC */\n\n/*********************\n *      DEFINES\n *********************/\n\n/* \"free\" is used as a function pointer (in lv_fs_drv_t).\n * We must make sure \"free\" was not defined to a platform specific\n * free function, otherwise compilation would fail.\n */\n#ifdef free\n#undef free\n#endif\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic const char * lv_fs_get_real_path(const char * path);\nstatic lv_fs_drv_t * lv_fs_get_drv(char letter);\n\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Initialize the File system interface\n */\nvoid lv_fs_init(void)\n{\n    lv_ll_init(&LV_GC_ROOT(_lv_drv_ll), sizeof(lv_fs_drv_t));\n}\n\n/**\n * Test if a drive is rady or not. If the `ready` function was not initialized `true` will be returned.\n * @param letter letter of the drive\n * @return true: drive is ready; false: drive is not ready\n */\nbool lv_fs_is_ready(char letter)\n{\n    lv_fs_drv_t * drv = lv_fs_get_drv(letter);\n\n    if(drv == NULL) return false;                      /*An unknown driver in not ready*/\n\n    if(drv->ready == NULL) return true;                /*Assume the driver is always ready if no handler provided*/\n\n    return drv->ready();\n}\n\n/**\n * Open a file\n * @param file_p pointer to a lv_fs_file_t variable\n * @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt)\n * @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mode)\n{\n    file_p->drv = NULL;\n    file_p->file_d = NULL;\n\n    if(path == NULL) return LV_FS_RES_INV_PARAM;\n\n    char letter = path[0];\n\n    file_p->drv = lv_fs_get_drv(letter);\n\n    if(file_p->drv == NULL) {\n        file_p->file_d = NULL;\n        return LV_FS_RES_NOT_EX;\n    }\n\n    if(file_p->drv->ready != NULL) {\n        if(file_p->drv->ready() == false) {\n            file_p->drv = NULL;\n            file_p->file_d = NULL;\n            return LV_FS_RES_HW_ERR;\n        }\n    }\n\n    file_p->file_d = lv_mem_alloc(file_p->drv->file_size);\n    lv_mem_assert(file_p->file_d);\n    if(file_p->file_d == NULL) {\n        file_p->drv = NULL;\n        return LV_FS_RES_OUT_OF_MEM;  /* Out of memory */\n    }\n\n    if(file_p->drv->open == NULL) {\n        return LV_FS_RES_NOT_IMP;\n    }\n\n    const char * real_path = lv_fs_get_real_path(path);\n    lv_fs_res_t res = file_p->drv->open(file_p->file_d, real_path, mode);\n\n    if(res != LV_FS_RES_OK) {\n        lv_mem_free(file_p->file_d);\n        file_p->file_d = NULL;\n        file_p->drv = NULL;\n    }\n\n    return res;\n}\n\n/**\n * Close an already opened file\n * @param file_p pointer to a lv_fs_file_t variable\n * @return  LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_close(lv_fs_file_t * file_p)\n{\n    if(file_p->drv == NULL) {\n        return LV_FS_RES_INV_PARAM;\n    }\n\n    if(file_p->drv->close == NULL) {\n        return LV_FS_RES_NOT_IMP;\n    }\n\n    lv_fs_res_t res = file_p->drv->close(file_p->file_d);\n\n    lv_mem_free(file_p->file_d);   /*Clean up*/\n    file_p->file_d = NULL;\n    file_p->drv = NULL;\n    file_p->file_d = NULL;\n\n    return res;\n}\n\n/**\n * Delete a file\n * @param path path of the file to delete\n * @return  LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_remove(const char * path)\n{\n    if(path == NULL) return LV_FS_RES_INV_PARAM;\n    lv_fs_drv_t * drv = NULL;\n\n    char letter = path[0];\n\n    drv = lv_fs_get_drv(letter);\n    if(drv == NULL) return LV_FS_RES_NOT_EX;\n    if(drv->ready != NULL) {\n        if(drv->ready() == false) return LV_FS_RES_HW_ERR;\n    }\n\n    if(drv->remove == NULL) return LV_FS_RES_NOT_IMP;\n\n    const char * real_path = lv_fs_get_real_path(path);\n    lv_fs_res_t res = drv->remove(real_path);\n\n    return res;\n}\n\n/**\n * Read from a file\n * @param file_p pointer to a lv_fs_file_t variable\n * @param buf pointer to a buffer where the read bytes are stored\n * @param btr Bytes To Read\n * @param br the number of real read bytes (Bytes Read). NULL if unused.\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_read(lv_fs_file_t * file_p, void * buf, uint32_t btr, uint32_t * br)\n{\n    if(br != NULL) *br = 0;\n    if(file_p->drv == NULL) return LV_FS_RES_INV_PARAM;\n    if(file_p->drv->read == NULL) return LV_FS_RES_NOT_IMP;\n\n    uint32_t br_tmp = 0;\n    lv_fs_res_t res = file_p->drv->read(file_p->file_d, buf, btr, &br_tmp);\n    if(br != NULL) *br = br_tmp;\n\n    return res;\n}\n\n/**\n * Write into a file\n * @param file_p pointer to a lv_fs_file_t variable\n * @param buf pointer to a buffer with the bytes to write\n * @param btr Bytes To Write\n * @param br the number of real written bytes (Bytes Written). NULL if unused.\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_write(lv_fs_file_t * file_p, const void * buf, uint32_t btw, uint32_t * bw)\n{\n    if(bw != NULL) *bw = 0;\n\n    if(file_p->drv == NULL) {\n        return LV_FS_RES_INV_PARAM;\n    }\n\n    if(file_p->drv->write == NULL) {\n        return LV_FS_RES_NOT_IMP;\n    }\n\n    uint32_t bw_tmp = 0;\n    lv_fs_res_t res = file_p->drv->write(file_p->file_d, buf, btw, &bw_tmp);\n    if(bw != NULL)  *bw = bw_tmp;\n\n    return res;\n}\n\n/**\n * Set the position of the 'cursor' (read write pointer) in a file\n * @param file_p pointer to a lv_fs_file_t variable\n * @param pos the new position expressed in bytes index (0: start of file)\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_seek(lv_fs_file_t * file_p, uint32_t pos)\n{\n    if(file_p->drv == NULL) {\n        return LV_FS_RES_INV_PARAM;\n    }\n\n    if(file_p->drv->seek == NULL) {\n        return LV_FS_RES_NOT_IMP;\n    }\n\n    lv_fs_res_t res = file_p->drv->seek(file_p->file_d, pos);\n\n    return res;\n}\n\n/**\n * Give the position of the read write pointer\n * @param file_p pointer to a lv_fs_file_t variable\n * @param pos_p pointer to store the position of the read write pointer\n * @return LV_FS_RES_OK or any error from 'fs_res_t'\n */\nlv_fs_res_t lv_fs_tell(lv_fs_file_t * file_p, uint32_t  * pos)\n{\n    if(file_p->drv == NULL) {\n        pos = 0;\n        return LV_FS_RES_INV_PARAM;\n    }\n\n    if(file_p->drv->tell == NULL) {\n        pos = 0;\n        return LV_FS_RES_NOT_IMP;\n    }\n\n    lv_fs_res_t res = file_p->drv->tell(file_p->file_d, pos);\n\n    return res;\n}\n\n/**\n * Truncate the file size to the current position of the read write pointer\n * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_fs_open )\n * @return LV_FS_RES_OK: no error, the file is read\n *         any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_trunc(lv_fs_file_t * file_p)\n{\n    if(file_p->drv == NULL) {\n        return LV_FS_RES_INV_PARAM;\n    }\n\n    if(file_p->drv->tell == NULL) {\n        return LV_FS_RES_NOT_IMP;\n    }\n\n    lv_fs_res_t res = file_p->drv->trunc(file_p->file_d);\n\n    return res;\n}\n/**\n * Give the size of a file bytes\n * @param file_p pointer to a lv_fs_file_t variable\n * @param size pointer to a variable to store the size\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_size(lv_fs_file_t * file_p, uint32_t * size)\n{\n    if(file_p->drv == NULL) {\n        return LV_FS_RES_INV_PARAM;\n    }\n\n    if(file_p->drv->size == NULL) return LV_FS_RES_NOT_IMP;\n\n\n    if(size == NULL) return LV_FS_RES_INV_PARAM;\n\n    lv_fs_res_t res = file_p->drv->size(file_p->file_d, size);\n\n    return res;\n}\n\n/**\n * Rename a file\n * @param oldname path to the file\n * @param newname path with the new name\n * @return LV_FS_RES_OK or any error from 'fs_res_t'\n */\nlv_fs_res_t lv_fs_rename(const char * oldname, const char * newname)\n{\n    if(!oldname || !newname) return LV_FS_RES_INV_PARAM;\n\n    char letter = oldname[0];\n\n    lv_fs_drv_t * drv = lv_fs_get_drv(letter);\n\n    if(!drv) {\n        return LV_FS_RES_NOT_EX;\n    }\n\n    if(drv->ready != NULL) {\n        if(drv->ready() == false) {\n            return LV_FS_RES_HW_ERR;\n        }\n    }\n\n    if(drv->rename == NULL) return LV_FS_RES_NOT_IMP;\n\n    const char * old_real = lv_fs_get_real_path(oldname);\n    const char * new_real = lv_fs_get_real_path(newname);\n    lv_fs_res_t res = drv->rename(old_real, new_real);\n\n    return res;\n}\n\n\n/**\n * Initialize a 'fs_read_dir_t' variable for directory reading\n * @param rddir_p pointer to a 'fs_read_dir_t' variable\n * @param path path to a directory\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path)\n{\n    if(path == NULL) return LV_FS_RES_INV_PARAM;\n\n    char letter = path[0];\n\n    rddir_p->drv = lv_fs_get_drv(letter);\n\n    if(rddir_p->drv == NULL) {\n        rddir_p->dir_d = NULL;\n        return LV_FS_RES_NOT_EX;\n    }\n\n    rddir_p->dir_d = lv_mem_alloc(rddir_p->drv->rddir_size);\n    lv_mem_assert(rddir_p->dir_d);\n    if(rddir_p->dir_d == NULL) {\n        rddir_p->dir_d = NULL;\n        return LV_FS_RES_OUT_OF_MEM;  /* Out of memory */\n    }\n\n    if(rddir_p->drv->dir_open == NULL) {\n        return LV_FS_RES_NOT_IMP;\n    }\n\n    const char * real_path = lv_fs_get_real_path(path);\n    lv_fs_res_t res = rddir_p->drv->dir_open(rddir_p->dir_d, real_path);\n\n    return res;\n}\n\n/**\n * Read the next filename form a directory.\n * The name of the directories will begin with '/'\n * @param rddir_p pointer to an initialized 'fs_read_dir_t' variable\n * @param fn pointer to a buffer to store the filename\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_dir_read(lv_fs_dir_t * rddir_p, char * fn)\n{\n    if(rddir_p->drv == NULL || rddir_p->dir_d == NULL) {\n        fn[0] = '\\0';\n        return LV_FS_RES_INV_PARAM;\n    }\n\n    if(rddir_p->drv->dir_read == NULL) {\n        return LV_FS_RES_NOT_IMP;\n    }\n\n    lv_fs_res_t res = rddir_p->drv->dir_read(rddir_p->dir_d, fn);\n\n    return res;\n}\n\n/**\n * Close the directory reading\n * @param rddir_p pointer to an initialized 'fs_read_dir_t' variable\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_dir_close(lv_fs_dir_t * rddir_p)\n{\n    if(rddir_p->drv == NULL || rddir_p->dir_d == NULL) {\n        return LV_FS_RES_INV_PARAM;\n    }\n\n    lv_fs_res_t res;\n\n    if(rddir_p->drv->dir_close == NULL) {\n        res =  LV_FS_RES_NOT_IMP;\n    } else {\n        res = rddir_p->drv->dir_close(rddir_p->dir_d);\n    }\n\n    lv_mem_free(rddir_p->dir_d);   /*Clean up*/\n    rddir_p->dir_d = NULL;\n    rddir_p->drv = NULL;\n    rddir_p->dir_d = NULL;\n\n    return res;\n}\n\n/**\n * Get the free and total size of a driver in kB\n * @param letter the driver letter\n * @param total_p pointer to store the total size [kB]\n * @param free_p pointer to store the free size [kB]\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_free(char letter, uint32_t * total_p, uint32_t * free_p)\n{\n    lv_fs_drv_t * drv = lv_fs_get_drv(letter);\n\n    if(drv == NULL) {\n        return LV_FS_RES_INV_PARAM;\n    }\n\n    lv_fs_res_t res;\n\n    if(drv->free == NULL) {\n        res =  LV_FS_RES_NOT_IMP;\n    } else {\n        uint32_t total_tmp = 0;\n        uint32_t free_tmp = 0;\n        res = drv->free(&total_tmp, &free_tmp);\n\n        if(total_p != NULL) *total_p = total_tmp;\n        if(free_p != NULL) *free_p = free_tmp;\n    }\n\n    return res;\n}\n\n/**\n * Add a new drive\n * @param drv_p pointer to an lv_fs_drv_t structure which is inited with the\n * corresponding function pointers. The data will be copied so the variable can be local.\n */\nvoid lv_fs_add_drv(lv_fs_drv_t * drv_p)\n{\n    /*Save the new driver*/\n    lv_fs_drv_t * new_drv;\n    new_drv =  lv_ll_ins_head(&LV_GC_ROOT(_lv_drv_ll));\n    lv_mem_assert(new_drv);\n    if(new_drv == NULL) return;\n\n    memcpy(new_drv, drv_p, sizeof(lv_fs_drv_t));\n}\n\n/**\n * Fill a buffer with the letters of existing drivers\n * @param buf buffer to store the letters ('\\0' added after the last letter)\n * @return the buffer\n */\nchar  * lv_fs_get_letters(char * buf)\n{\n    lv_fs_drv_t * drv;\n    uint8_t i = 0;\n\n    LL_READ(LV_GC_ROOT(_lv_drv_ll), drv) {\n        buf[i] = drv->letter;\n        i++;\n    }\n\n    buf[i] = '\\0';\n\n    return buf;\n}\n\n\n/**\n * Return with the extension of the filename\n * @param fn string with a filename\n * @return pointer to the beginning extension or empty string if no extension\n */\nconst char * lv_fs_get_ext(const char * fn)\n{\n    uint16_t i;\n    for(i = strlen(fn); i > 0; i --) {\n        if(fn[i] == '.') {\n            return &fn[i + 1];\n        } else if(fn[i] == '/' || fn[i] == '\\\\') {\n            return \"\";  /*No extension if a '\\' or '/' found*/\n        }\n    }\n\n    return \"\"; /*Empty string if no '.' in the file name. */\n}\n\n/**\n * Step up one level\n * @param path pointer to a file name\n * @return the truncated file name\n */\nchar * lv_fs_up(char * path)\n{\n    uint16_t len = strlen(path);\n    if(len == 0) return path;\n\n    len --; /*Go before the trailing '\\0'*/\n\n    /*Ignore trailing '/' or '\\'*/\n    while(path[len] == '/' || path[len] == '\\\\') {\n        path[len] = '\\0';\n        if(len > 0) len --;\n        else return path;\n    }\n\n    uint16_t i;\n    for(i = len; i > 0; i --) {\n        if(path[i] == '/' || path[i] == '\\\\') break;\n    }\n\n    if(i > 0) path[i] = '\\0';\n\n    return path;\n}\n\n/**\n * Get the last element of a path (e.g. U:/folder/file -> file)\n * @param path a character sting with the path to search in\n * @return pointer to the beginning of the last element in the path\n */\nconst char * lv_fs_get_last(const char * path)\n{\n    uint16_t len = strlen(path);\n    if(len == 0) return path;\n\n    len --; /*Go before the trailing '\\0'*/\n\n    /*Ignore trailing '/' or '\\'*/\n    while(path[len] == '/' || path[len] == '\\\\') {\n        if(len > 0) len --;\n        else return path;\n    }\n\n    uint16_t i;\n    for(i = len; i > 0; i --) {\n        if(path[i] == '/' || path[i] == '\\\\') break;\n    }\n\n    /*No '/' or '\\' in the path so return with path itself*/\n    if(i == 0) return path;\n\n    return &path[i + 1];\n}\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Leave the driver letters and / or \\ letters from beginning of the path\n * @param path path string (E.g. S:/folder/file.txt)\n * @return pointer to the beginning of the real path (E.g. folder/file.txt)\n */\nstatic const char * lv_fs_get_real_path(const char * path)\n{\n    /* Example path: \"S:/folder/file.txt\"\n     * Leave the letter and the : / \\ characters*/\n\n    path ++; /*Ignore the driver letter*/\n\n    while(*path != '\\0') {\n        if(*path == ':' || *path == '\\\\' || *path == '/') {\n            path ++;\n        } else {\n            break;\n        }\n    }\n\n    return path;\n}\n\n/**\n * Give a pointer to a driver from its letter\n * @param letter the driver letter\n * @return pointer to a driver or NULL if not found\n */\nstatic lv_fs_drv_t * lv_fs_get_drv(char letter)\n{\n    lv_fs_drv_t * drv;\n\n    LL_READ(LV_GC_ROOT(_lv_drv_ll), drv) {\n        if(drv->letter == letter) {\n            return drv;\n        }\n    }\n\n    return NULL;\n}\n\n#endif /*USE_LV_FILESYSTEM*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_fs.h",
    "content": "/**\n * @file lv_fs.h\n *\n */\n\n#ifndef LV_FS_H\n#define LV_FS_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_FILESYSTEM\n\n#include <stdint.h>\n#include \"lv_mem.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_FS_MAX_FN_LENGTH  64\n\n/**********************\n *      TYPEDEFS\n **********************/\nenum\n{\n    LV_FS_RES_OK = 0,\n    LV_FS_RES_HW_ERR,      /*Low level hardware error*/\n    LV_FS_RES_FS_ERR,      /*Error in the file system structure */\n    LV_FS_RES_NOT_EX,      /*Driver, file or directory is not exists*/\n    LV_FS_RES_FULL,        /*Disk full*/\n    LV_FS_RES_LOCKED,      /*The file is already opened*/\n    LV_FS_RES_DENIED,      /*Access denied. Check 'fs_open' modes and write protect*/\n    LV_FS_RES_BUSY,        /*The file system now can't handle it, try later*/\n    LV_FS_RES_TOUT,        /*Process time outed*/\n    LV_FS_RES_NOT_IMP,     /*Requested function is not implemented*/\n    LV_FS_RES_OUT_OF_MEM,  /*Not enough memory for an internal operation*/\n    LV_FS_RES_INV_PARAM,   /*Invalid parameter among arguments*/\n    LV_FS_RES_UNKNOWN,     /*Other unknown error*/\n};\ntypedef uint8_t lv_fs_res_t;\n\nstruct __lv_fs_drv_t;\n\ntypedef struct\n{\n    void * file_d;\n    struct __lv_fs_drv_t* drv;\n} lv_fs_file_t;\n\n\ntypedef struct\n{\n    void * dir_d;\n    struct __lv_fs_drv_t * drv;\n} lv_fs_dir_t;\n\nenum\n{\n    LV_FS_MODE_WR = 0x01,\n    LV_FS_MODE_RD = 0x02,\n};\ntypedef uint8_t lv_fs_mode_t;\n\ntypedef struct __lv_fs_drv_t\n{\n    char letter;\n    uint16_t file_size;\n    uint16_t rddir_size;\n    bool (*ready) (void);\n\n    lv_fs_res_t (*open) (void * file_p, const char * path, lv_fs_mode_t mode);\n    lv_fs_res_t (*close) (void * file_p);\n    lv_fs_res_t (*remove) (const char * fn);\n    lv_fs_res_t (*read) (void * file_p, void * buf, uint32_t btr, uint32_t * br);\n    lv_fs_res_t (*write) (void * file_p, const void * buf, uint32_t btw, uint32_t * bw);\n    lv_fs_res_t (*seek) (void * file_p, uint32_t pos);\n    lv_fs_res_t (*tell) (void * file_p, uint32_t * pos_p);\n    lv_fs_res_t (*trunc) (void * file_p);\n    lv_fs_res_t (*size) (void * file_p, uint32_t * size_p);\n    lv_fs_res_t (*rename) (const char * oldname, const char * newname);\n    lv_fs_res_t (*free) (uint32_t * total_p, uint32_t * free_p);\n\n    lv_fs_res_t (*dir_open) (void * rddir_p, const char * path);\n    lv_fs_res_t (*dir_read) (void * rddir_p, char * fn);\n    lv_fs_res_t (*dir_close) (void * rddir_p);\n} lv_fs_drv_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Initialize the File system interface\n */\nvoid lv_fs_init(void);\n\n/**\n * Add a new drive\n * @param drv_p pointer to an lv_fs_drv_t structure which is inited with the\n * corresponding function pointers. The data will be copied so the variable can be local.\n */\nvoid lv_fs_add_drv(lv_fs_drv_t * drv_p);\n\n/**\n * Test if a drive is rady or not. If the `ready` function was not initialized `true` will be returned.\n * @param letter letter of the drive\n * @return true: drive is ready; false: drive is not ready\n */\nbool lv_fs_is_ready(char letter);\n\n/**\n * Open a file\n * @param file_p pointer to a lv_fs_file_t variable\n * @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt)\n * @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_open (lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mode);\n\n/**\n * Close an already opened file\n * @param file_p pointer to a lv_fs_file_t variable\n * @return  LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_close (lv_fs_file_t * file_p);\n\n/**\n * Delete a file\n * @param path path of the file to delete\n * @return  LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_remove (const char * path);\n\n/**\n * Read from a file\n * @param file_p pointer to a lv_fs_file_t variable\n * @param buf pointer to a buffer where the read bytes are stored\n * @param btr Bytes To Read\n * @param br the number of real read bytes (Bytes Read). NULL if unused.\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_read (lv_fs_file_t * file_p, void * buf, uint32_t btr, uint32_t * br);\n\n/**\n * Write into a file\n * @param file_p pointer to a lv_fs_file_t variable\n * @param buf pointer to a buffer with the bytes to write\n * @param btr Bytes To Write\n * @param br the number of real written bytes (Bytes Written). NULL if unused.\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_write (lv_fs_file_t * file_p, const void * buf, uint32_t btw, uint32_t * bw);\n\n/**\n * Set the position of the 'cursor' (read write pointer) in a file\n * @param file_p pointer to a lv_fs_file_t variable\n * @param pos the new position expressed in bytes index (0: start of file)\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_seek (lv_fs_file_t * file_p, uint32_t pos);\n\n/**\n * Give the position of the read write pointer\n * @param file_p pointer to a lv_fs_file_t variable\n * @param pos_p pointer to store the position of the read write pointer\n * @return LV_FS_RES_OK or any error from 'fs_res_t'\n */\nlv_fs_res_t lv_fs_tell (lv_fs_file_t * file_p, uint32_t  * pos);\n\n/**\n * Truncate the file size to the current position of the read write pointer\n * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_fs_open )\n * @return LV_FS_RES_OK: no error, the file is read\n *         any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_trunc (lv_fs_file_t * file_p);\n\n/**\n * Give the size of a file bytes\n * @param file_p pointer to a lv_fs_file_t variable\n * @param size pointer to a variable to store the size\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_size (lv_fs_file_t * file_p, uint32_t * size);\n\n/**\n * Rename a file\n * @param oldname path to the file\n * @param newname path with the new name\n * @return LV_FS_RES_OK or any error from 'fs_res_t'\n */\nlv_fs_res_t lv_fs_rename (const char * oldname, const char * newname);\n\n/**\n * Initialize a 'fs_dir_t' variable for directory reading\n * @param rddir_p pointer to a 'fs_read_dir_t' variable\n * @param path path to a directory\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path);\n\n/**\n * Read the next filename form a directory.\n * The name of the directories will begin with '/'\n * @param rddir_p pointer to an initialized 'fs_rdir_t' variable\n * @param fn pointer to a buffer to store the filename\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_dir_read (lv_fs_dir_t * rddir_p, char * fn);\n\n/**\n * Close the directory reading\n * @param rddir_p pointer to an initialized 'fs_dir_t' variable\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_dir_close (lv_fs_dir_t * rddir_p);\n\n/**\n * Get the free and total size of a driver in kB\n * @param letter the driver letter\n * @param total_p pointer to store the total size [kB]\n * @param free_p pointer to store the free size [kB]\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_fs_free (char letter, uint32_t * total_p, uint32_t * free_p);\n\n/**\n * Fill a buffer with the letters of existing drivers\n * @param buf buffer to store the letters ('\\0' added after the last letter)\n * @return the buffer\n */\nchar *  lv_fs_get_letters(char * buf);\n\n/**\n * Return with the extension of the filename\n * @param fn string with a filename\n * @return pointer to the beginning extension or empty string if no extension\n */\nconst char * lv_fs_get_ext(const char * fn);\n\n/**\n * Step up one level\n * @param path pointer to a file name\n * @return the truncated file name\n */\nchar * lv_fs_up(char * path);\n\n/**\n * Get the last element of a path (e.g. U:/folder/file -> file)\n * @param buf buffer to store the letters ('\\0' added after the last letter)\n * @return pointer to the beginning of the last element in the path\n */\nconst char * lv_fs_get_last(const char * path);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif /*USE_LV_FILESYSTEM*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_FS_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_gc.c",
    "content": "/**\n * @file lv_gc.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n\n#include \"lv_gc.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n#if (!defined(LV_ENABLE_GC)) || LV_ENABLE_GC == 0\nLV_ROOTS\n#endif /* LV_ENABLE_GC */\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_gc.h",
    "content": "/**\n * @file lv_gc.h\n *\n */\n\n#ifndef LV_GC_H\n#define LV_GC_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#include <stdint.h>\n#include \"lv_mem.h\"\n#include \"lv_ll.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n#define LV_GC_ROOTS(prefix) \\\n    prefix lv_ll_t _lv_task_ll;      /*Linked list to store the lv_tasks*/ \\\n    prefix lv_ll_t _lv_scr_ll;          /*Linked list of screens*/ \\\n    prefix lv_ll_t _lv_drv_ll;\\\n    prefix lv_ll_t _lv_file_ll;\\\n    prefix lv_ll_t _lv_anim_ll;\\\n    prefix void * _lv_def_scr;\\\n    prefix void * _lv_act_scr;\\\n    prefix void * _lv_top_layer;\\\n    prefix void * _lv_sys_layer;\\\n    prefix void * _lv_task_act;\\\n    prefix void * _lv_indev_list;\\\n    prefix void * _lv_disp_list;\\\n\n#define LV_NO_PREFIX\n#define LV_ROOTS LV_GC_ROOTS(LV_NO_PREFIX)\n\n#if LV_ENABLE_GC == 1\n#   if LV_MEM_CUSTOM != 1\n#       error \"GC requires CUSTOM_MEM\"\n#   endif /* LV_MEM_CUSTOM */\n#else /* LV_ENABLE_GC */\n#   define LV_GC_ROOT(x) x\n    LV_GC_ROOTS(extern)\n#endif /* LV_ENABLE_GC */\n\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**********************\n *      MACROS\n **********************/\n\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_GC_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_ll.c",
    "content": "/**\n * @file lv_ll.c\n * Handle linked lists.\n * The nodes are dynamically allocated by the 'lv_mem' module,\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include <stdint.h>\n#include <string.h>\n\n#include \"lv_ll.h\"\n#include \"lv_mem.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define LL_NODE_META_SIZE (sizeof(lv_ll_node_t*) + sizeof(lv_ll_node_t*))\n#define LL_PREV_P_OFFSET(ll_p) (ll_p->n_size)\n#define LL_NEXT_P_OFFSET(ll_p) (ll_p->n_size + sizeof(lv_ll_node_t*))\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic void node_set_prev(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * prev);\nstatic void node_set_next(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * next);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Initialize linked list\n * @param ll_dsc pointer to ll_dsc variable\n * @param node_size the size of 1 node in bytes\n */\nvoid lv_ll_init(lv_ll_t * ll_p, uint32_t node_size)\n{\n    ll_p->head = NULL;\n    ll_p->tail = NULL;\n#ifdef LV_MEM_ENV64\n    /*Round the size up to 8*/\n    if(node_size & 0x7) {\n        node_size = node_size & (~0x7);\n        node_size += 8;\n    }\n#else\n    /*Round the size up to 4*/\n    if(node_size & 0x3) {\n        node_size = node_size & (~0x3);\n        node_size += 4;\n    }\n#endif\n\n    ll_p->n_size = node_size;\n}\n\n/**\n * Add a new head to a linked list\n * @param ll_p pointer to linked list\n * @return pointer to the new head\n */\nvoid * lv_ll_ins_head(lv_ll_t * ll_p)\n{\n    lv_ll_node_t * n_new;\n\n    n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE);\n\n    if(n_new != NULL) {\n        node_set_prev(ll_p, n_new, NULL);           /*No prev. before the new head*/\n        node_set_next(ll_p, n_new, ll_p->head);     /*After new comes the old head*/\n\n        if(ll_p->head != NULL) { /*If there is old head then before it goes the new*/\n            node_set_prev(ll_p, ll_p->head, n_new);\n        }\n\n        ll_p->head = n_new;         /*Set the new head in the dsc.*/\n        if(ll_p->tail == NULL) {/*If there is no tail (1. node) set the tail too*/\n            ll_p->tail = n_new;\n        }\n    }\n\n    return n_new;\n}\n\n/**\n * Insert a new node in front of the n_act node\n * @param ll_p pointer to linked list\n * @param n_act pointer a node\n * @return pointer to the new head\n */\nvoid * lv_ll_ins_prev(lv_ll_t * ll_p, void * n_act)\n{\n    lv_ll_node_t * n_new;\n    lv_ll_node_t * n_prev;\n\n    if(NULL == ll_p || NULL == n_act) return NULL;\n\n    if(lv_ll_get_head(ll_p) == n_act) {\n        n_new = lv_ll_ins_head(ll_p);\n        if(n_new == NULL) return NULL;\n    } else {\n        n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE);\n        if(n_new == NULL) return NULL;\n\n        n_prev = lv_ll_get_prev(ll_p, n_act);\n        node_set_next(ll_p, n_prev, n_new);\n        node_set_prev(ll_p, n_new, n_prev);\n        node_set_prev(ll_p, n_act, n_new);\n        node_set_next(ll_p, n_new, n_act);\n    }\n\n    return n_new;\n}\n\n/**\n * Add a new tail to a linked list\n * @param ll_p pointer to linked list\n * @return pointer to the new tail\n */\nvoid * lv_ll_ins_tail(lv_ll_t * ll_p)\n{\n    lv_ll_node_t * n_new;\n\n    n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE);\n    if(n_new == NULL) return NULL;\n\n    if(n_new != NULL) {\n        node_set_next(ll_p, n_new, NULL); /*No next after the new tail*/\n        node_set_prev(ll_p, n_new, ll_p->tail); /*The prev. before new is tho old tail*/\n        if(ll_p->tail != NULL) {    /*If there is old tail then the new comes after it*/\n            node_set_next(ll_p, ll_p->tail, n_new);\n        }\n\n        ll_p->tail = n_new;      /*Set the new tail in the dsc.*/\n        if(ll_p->head == NULL) { /*If there is no head (1. node) set the head too*/\n            ll_p->head = n_new;\n        }\n    }\n\n    return n_new;\n}\n\n\n/**\n * Remove the node 'node_p' from 'll_p' linked list.\n * It does not free the the memory of node.\n * @param ll_p pointer to the linked list of 'node_p'\n * @param node_p pointer to node in 'll_p' linked list\n */\nvoid lv_ll_rem(lv_ll_t  * ll_p, void * node_p)\n{\n    if(lv_ll_get_head(ll_p) == node_p) {\n        /*The new head will be the node after 'n_act'*/\n        ll_p->head = lv_ll_get_next(ll_p, node_p);\n        if(ll_p->head == NULL) {\n            ll_p->tail = NULL;\n        } else {\n            node_set_prev(ll_p, ll_p->head, NULL);\n        }\n    } else if(lv_ll_get_tail(ll_p) == node_p) {\n        /*The new tail will be the  node before 'n_act'*/\n        ll_p->tail = lv_ll_get_prev(ll_p, node_p);\n        if(ll_p->tail == NULL) {\n            ll_p->head = NULL;\n        } else {\n            node_set_next(ll_p, ll_p->tail, NULL);\n        }\n    } else {\n        lv_ll_node_t * n_prev = lv_ll_get_prev(ll_p, node_p);\n        lv_ll_node_t * n_next = lv_ll_get_next(ll_p, node_p);\n\n        node_set_next(ll_p, n_prev, n_next);\n        node_set_prev(ll_p, n_next, n_prev);\n    }\n}\n\n/**\n * Remove and free all elements from a linked list. The list remain valid but become empty.\n * @param ll_p pointer to linked list\n */\nvoid lv_ll_clear(lv_ll_t * ll_p)\n{\n    void * i;\n    void * i_next;\n\n    i = lv_ll_get_head(ll_p);\n    i_next = NULL;\n\n    while(i != NULL) {\n        i_next = lv_ll_get_next(ll_p, i);\n\n        lv_ll_rem(ll_p, i);\n        lv_mem_free(i);\n\n        i = i_next;\n    }\n}\n\n/**\n * Move a node to a new linked list\n * @param ll_ori_p pointer to the original (old) linked list\n * @param ll_new_p pointer to the new linked list\n * @param node pointer to a node\n * @return head changed\n */\nbool lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node)\n{\n    bool changed = ll_new_p->head != node;\n\n    lv_ll_rem(ll_ori_p, node);\n\n    /*Set node as head*/\n    node_set_prev(ll_new_p, node, NULL);\n    node_set_next(ll_new_p, node, ll_new_p->head);\n\n    if(ll_new_p->head != NULL) { /*If there is old head then before it goes the new*/\n        node_set_prev(ll_new_p, ll_new_p->head, node);\n    }\n\n    ll_new_p->head = node;        /*Set the new head in the dsc.*/\n    if(ll_new_p->tail == NULL) {     /*If there is no tail (first node) set the tail too*/\n        ll_new_p->tail = node;\n    }\n\n    return changed;\n}\n\n/**\n * Return with head node of the linked list\n * @param ll_p pointer to linked list\n * @return pointer to the head of 'll_p'\n */\nvoid * lv_ll_get_head(const lv_ll_t * ll_p)\n{\n    void * head = NULL;\n\n    if(ll_p != NULL)    {\n        head = ll_p->head;\n    }\n\n    return head;\n}\n\n/**\n * Return with tail node of the linked list\n * @param ll_p pointer to linked list\n * @return pointer to the head of 'll_p'\n */\nvoid * lv_ll_get_tail(const lv_ll_t * ll_p)\n{\n    void * tail = NULL;\n\n    if(ll_p != NULL)    {\n        tail = ll_p->tail;\n    }\n\n    return tail;\n}\n\n/**\n * Return with the pointer of the next node after 'n_act'\n * @param ll_p pointer to linked list\n * @param n_act pointer a node\n * @return pointer to the next node\n */\nvoid * lv_ll_get_next(const lv_ll_t * ll_p, const  void * n_act)\n{\n    void * next = NULL;\n\n    if(ll_p != NULL)    {\n        const lv_ll_node_t * n_act_d = n_act;\n        memcpy(&next, n_act_d + LL_NEXT_P_OFFSET(ll_p), sizeof(void *));\n    }\n\n    return next;\n}\n\n/**\n * Return with the pointer of the previous node after 'n_act'\n * @param ll_p pointer to linked list\n * @param n_act pointer a node\n * @return pointer to the previous node\n */\nvoid * lv_ll_get_prev(const lv_ll_t * ll_p, const  void * n_act)\n{\n    void * prev = NULL;\n\n    if(ll_p != NULL) {\n        const lv_ll_node_t * n_act_d = n_act;\n        memcpy(&prev, n_act_d + LL_PREV_P_OFFSET(ll_p), sizeof(void *));\n    }\n\n    return prev;\n}\n\nvoid lv_ll_swap(lv_ll_t * ll_p, void * n1_p, void * n2_p)\n{\n    (void)(ll_p);\n    (void)(n1_p);\n    (void)(n2_p);\n    /*TODO*/\n}\n\n/**\n * Move a nodw before an other node in the same linked list\n * @param ll_p pointer to a linked list\n * @param n_act pointer to node to move\n * @param n_after pointer to a node which should be after `n_act`\n */\nvoid lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after)\n{\n    if(n_act == n_after) return;    /*Can't move before itself*/\n\n\n    void * n_before;\n    if(n_after != NULL) n_before = lv_ll_get_prev(ll_p, n_after);\n    else n_before = lv_ll_get_tail(ll_p);        /*if `n_after` is NULL `n_act` should be the new tail*/\n\n    if(n_act == n_before) return;   /*Already before `n_after`*/\n\n    /*It's much easier to remove from the list and add again*/\n    lv_ll_rem(ll_p, n_act);\n\n    /*Add again by setting the prev. and next nodes*/\n    node_set_next(ll_p, n_before, n_act);\n    node_set_prev(ll_p, n_act, n_before);\n    node_set_prev(ll_p, n_after, n_act);\n    node_set_next(ll_p, n_act, n_after);\n\n    /*If `n_act` was moved before NULL then it become the new tail*/\n    if(n_after == NULL) ll_p->tail = n_act;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Set the 'pervious node pointer' of a node\n * @param ll_p pointer to linked list\n * @param act pointer to a node which prev. node pointer should be set\n * @param prev pointer to a node which should be the previous node before 'act'\n */\nstatic void node_set_prev(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * prev)\n{\n    if(act == NULL) return;     /*Can't set the prev node of `NULL`*/\n\n    uint32_t node_p_size = sizeof(lv_ll_node_t *);\n    if(prev) memcpy(act + LL_PREV_P_OFFSET(ll_p), &prev, node_p_size);\n    else memset(act + LL_PREV_P_OFFSET(ll_p), 0, node_p_size);\n}\n\n/**\n * Set the 'next node pointer' of a node\n * @param ll_p pointer to linked list\n * @param act pointer to a node which next node pointer should be set\n * @param next pointer to a node which should be the next node before 'act'\n */\nstatic void node_set_next(lv_ll_t * ll_p, lv_ll_node_t * act, lv_ll_node_t * next)\n{\n    if(act == NULL) return;     /*Can't set the next node of `NULL`*/\n\n    uint32_t node_p_size = sizeof(lv_ll_node_t *);\n    if(next) memcpy(act + LL_NEXT_P_OFFSET(ll_p), &next, node_p_size);\n    else memset(act + LL_NEXT_P_OFFSET(ll_p), 0, node_p_size);\n}\n\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_ll.h",
    "content": "/**\n * @file lv_ll.c\n * Handle linked lists. The nodes are dynamically allocated by the 'lv_mem' module.\n */\n\n#ifndef LV_LL_H\n#define LV_LL_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_mem.h\"\n#include <stdint.h>\n#include <stddef.h>\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/*Dummy type to make handling easier*/\ntypedef uint8_t lv_ll_node_t;\n\n/*Description of a linked list*/\ntypedef struct\n{\n    uint32_t n_size;\n    lv_ll_node_t* head;\n    lv_ll_node_t* tail;\n} lv_ll_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Initialize linked list\n * @param ll_dsc pointer to ll_dsc variable\n * @param node_size the size of 1 node in bytes\n */\nvoid lv_ll_init(lv_ll_t * ll_p, uint32_t node_size);\n\n/**\n * Add a new head to a linked list\n * @param ll_p pointer to linked list\n * @return pointer to the new head\n */\nvoid * lv_ll_ins_head(lv_ll_t * ll_p);\n\n/**\n * Insert a new node in front of the n_act node\n * @param ll_p pointer to linked list\n * @param n_act pointer a node\n * @return pointer to the new head\n */\nvoid * lv_ll_ins_prev(lv_ll_t * ll_p, void * n_act);\n\n/**\n * Add a new tail to a linked list\n * @param ll_p pointer to linked list\n * @return pointer to the new tail\n */\nvoid * lv_ll_ins_tail(lv_ll_t * ll_p);\n\n/**\n * Remove the node 'node_p' from 'll_p' linked list.\n * It does not free the the memory of node.\n * @param ll_p pointer to the linked list of 'node_p'\n * @param node_p pointer to node in 'll_p' linked list\n */\nvoid lv_ll_rem(lv_ll_t  * ll_p, void * node_p);\n\n/**\n * Remove and free all elements from a linked list. The list remain valid but become empty.\n * @param ll_p pointer to linked list\n */\nvoid lv_ll_clear(lv_ll_t * ll_p);\n\n/**\n * Move a node to a new linked list\n * @param ll_ori_p pointer to the original (old) linked list\n * @param ll_new_p pointer to the new linked list\n * @param node pointer to a node\n * @return head changed\n */\nbool lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node);\n\n/**\n * Return with head node of the linked list\n * @param ll_p pointer to linked list\n * @return pointer to the head of 'll_p'\n */\nvoid * lv_ll_get_head(const lv_ll_t * ll_p);\n\n/**\n * Return with tail node of the linked list\n * @param ll_p pointer to linked list\n * @return pointer to the head of 'll_p'\n */\nvoid * lv_ll_get_tail(const lv_ll_t * ll_p);\n\n/**\n * Return with the pointer of the next node after 'n_act'\n * @param ll_p pointer to linked list\n * @param n_act pointer a node\n * @return pointer to the next node\n */\nvoid * lv_ll_get_next(const lv_ll_t * ll_p, const void * n_act);\n\n/**\n * Return with the pointer of the previous node after 'n_act'\n * @param ll_p pointer to linked list\n * @param n_act pointer a node\n * @return pointer to the previous node\n */\nvoid * lv_ll_get_prev(const lv_ll_t * ll_p, const void * n_act);\n\n/**\n * Move a nodw before an other node in the same linked list\n * @param ll_p pointer to a linked list\n * @param n_act pointer to node to move\n * @param n_after pointer to a node which should be after `n_act`\n */\nvoid lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after);\n\n/**********************\n *      MACROS\n **********************/\n\n#define LL_READ(list, i) for(i = lv_ll_get_head(&list); i != NULL; i = lv_ll_get_next(&list, i))\n\n#define LL_READ_BACK(list, i) for(i = lv_ll_get_tail(&list); i != NULL; i = lv_ll_get_prev(&list, i))\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_log.c",
    "content": "/**\n * @file lv_log.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_log.h\"\n#if USE_LV_LOG\n\n#if LV_LOG_PRINTF\n#include <string.h>\n#include <mem/heap.h>\n#include <soc/uart.h>\n#include <utils/sprintf.h>\n#endif\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic void (*print_cb)(lv_log_level_t, const char *, uint32_t,  const char *);\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Register custom print (or anything else) function to call when log is added\n * @param f a function pointer:\n *          `void my_print (lv_log_level_t level, const char * file, uint32_t line, const char * dsc)`\n */\nvoid lv_log_register_print(void f(lv_log_level_t, const char *, uint32_t,  const char *))\n{\n    print_cb = f;\n}\n\n/**\n * Add a log\n * @param level the level of log. (From `lv_log_level_t` enum)\n * @param file name of the file when the log added\n * @param line line number in the source code where the log added\n * @param dsc description of the log\n */\nvoid lv_log_add(lv_log_level_t level, const char * file, int line, const char * dsc)\n{\n    if(level >= _LV_LOG_LEVEL_NUM) return;      /*Invalid level*/\n\n    if(level >= LV_LOG_LEVEL) {\n\n#if LV_LOG_PRINTF && defined(DEBUG_UART_PORT)\n        static const char * lvl_prefix[] = {\"Trace\", \"Info\", \"Warn\", \"Error\"};\n        char *log = (char *)malloc(0x1000);\n        s_printf(log, \"%s: %s \\t(%s #%d)\\r\\n\", lvl_prefix[level], dsc,  file, line);\n        uart_send(DEBUG_UART_PORT, (u8 *)log, strlen(log) + 1);\n        //gfx_printf(\"%s: %s \\t(%s #%d)\\n\", lvl_prefix[level], dsc,  file, line);\n#else\n        if(print_cb) print_cb(level, file, line, dsc);\n#endif\n    }\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n#endif /*USE_LV_LOG*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_log.h",
    "content": "/**\n * @file lv_log.h\n *\n */\n\n#ifndef LV_LOG_H\n#define LV_LOG_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n#include <stdint.h>\n\n/*********************\n *      DEFINES\n *********************/\n\n/*Possible log level. For compatibility declare it independently from `USE_LV_LOG`*/\n\n#define LV_LOG_LEVEL_TRACE 0     /*A lot of logs to give detailed information*/\n#define LV_LOG_LEVEL_INFO  1     /*Log important events*/\n#define LV_LOG_LEVEL_WARN  2     /*Log if something unwanted happened but didn't caused problem*/\n#define LV_LOG_LEVEL_ERROR 3     /*Only critical issue, when the system may fail*/\n#define _LV_LOG_LEVEL_NUM  4\n\ntypedef int8_t lv_log_level_t;\n\n#if USE_LV_LOG\n/**********************\n *      TYPEDEFS\n **********************/\n\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Register custom print (or anything else) function to call when log is added\n * @param f a function pointer:\n *          `void my_print (lv_log_level_t level, const char * file, uint32_t line, const char * dsc)`\n */\nvoid lv_log_register_print(void f(lv_log_level_t, const char *, uint32_t,  const char *));\n\n/**\n * Add a log\n * @param level the level of log. (From `lv_log_level_t` enum)\n * @param file name of the file when the log added\n * @param line line number in the source code where the log added\n * @param dsc description of the log\n */\nvoid lv_log_add(lv_log_level_t level, const char * file, int line, const char * dsc);\n\n/**********************\n *      MACROS\n **********************/\n\n#define LV_LOG_TRACE(dsc)   lv_log_add(LV_LOG_LEVEL_TRACE, __FILE__, __LINE__, dsc);\n#define LV_LOG_INFO(dsc)    lv_log_add(LV_LOG_LEVEL_INFO, __FILE__, __LINE__, dsc);\n#define LV_LOG_WARN(dsc)    lv_log_add(LV_LOG_LEVEL_WARN, __FILE__, __LINE__, dsc);\n#define LV_LOG_ERROR(dsc)   lv_log_add(LV_LOG_LEVEL_ERROR, __FILE__, __LINE__, dsc);\n\n#else /*USE_LV_LOG*/\n\n/*Do nothing if `USE_LV_LOG  0`*/\n#define lv_log_add(level, file, line, dsc) {;}\n#define LV_LOG_TRACE(dsc) {;}\n#define LV_LOG_INFO(dsc) {;}\n#define LV_LOG_WARN(dsc) {;}\n#define LV_LOG_ERROR(dsc) {;}\n#endif /*USE_LV_LOG*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_LOG_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_math.c",
    "content": "/**\n * @file lv_math.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_math.h\"\n#include <stdbool.h>\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic int16_t sin0_90_table[] = {\n    0,     572,    1144,   1715,   2286,   2856,   3425,   3993,   4560,   5126,\n    5690,  6252,   6813,   7371,   7927,   8481,   9032,   9580,   10126,  10668,\n    11207, 11743,  12275,  12803,  13328,  13848,  14364,  14876,  15383,  15886,\n    16383, 16876,  17364,  17846,  18323,  18794,  19260,  19720,  20173,  20621,\n    21062, 21497,  21925,  22347,  22762,  23170,  23571,  23964,  24351,  24730,\n    25101, 25465,  25821,  26169,  26509,  26841,  27165,  27481,  27788,  28087,\n    28377, 28659,  28932,  29196,  29451,  29697,  29934,  30162,  30381,  30591,\n    30791, 30982,  31163,  31335,  31498,  31650,  31794,  31927,  32051,  32165,\n    32269, 32364,  32448,  32523,  32587,  32642,  32687,  32722,  32747,  32762,\n\t32767\n};\n\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Convert a number to string\n * @param num a number\n * @param buf pointer to a `char` buffer. The result will be stored here (max 10 elements)\n * @return same as `buf` (just for convenience)\n */\nchar * lv_math_num_to_str(int32_t num, char * buf)\n{\n    char * buf_ori = buf;\n    if(num == 0) {\n        buf[0] = '0';\n        buf[1] = '\\0';\n        return buf;\n    } else if(num < 0) {\n        (*buf) = '-';\n        buf++;\n        num = LV_MATH_ABS(num);\n    }\n    uint32_t output = 0;\n    int8_t i;\n\n    for(i = 31; i >= 0; i--) {\n        if((output & 0xF) >= 5)\n            output += 3;\n        if(((output & 0xF0) >> 4) >= 5)\n            output += (3 << 4);\n        if(((output & 0xF00) >> 8) >= 5)\n            output += (3 << 8);\n        if(((output & 0xF000) >> 12) >= 5)\n            output += (3 << 12);\n        if(((output & 0xF0000) >> 16) >= 5)\n            output += (3 << 16);\n        if(((output & 0xF00000) >> 20) >= 5)\n            output += (3 << 20);\n        if(((output & 0xF000000) >> 24) >= 5)\n            output += (3 << 24);\n        if(((output & 0xF0000000) >> 28) >= 5)\n            output += (3 << 28);\n        output = (output << 1) | ((num >> i) & 1);\n    }\n\n    uint8_t digit;\n    bool leading_zero_ready = false;\n    for(i = 28; i >= 0; i -= 4) {\n        digit = ((output >> i) & 0xF) + '0';\n        if(digit == '0' && leading_zero_ready == false) continue;\n\n        leading_zero_ready = true;\n        (*buf) = digit;\n        buf++;\n    }\n\n    (*buf) = '\\0';\n\n    return buf_ori;\n}\n\n/**\n * Return with sinus of an angle\n * @param angle\n * @return sinus of 'angle'. sin(-90) = -32767, sin(90) = 32767\n */\nint16_t lv_trigo_sin(int16_t angle)\n{\n    int16_t ret = 0;\n    angle = angle % 360;\n\n    if(angle < 0) angle = 360 + angle;\n\n    if(angle < 90) {\n        ret = sin0_90_table[angle];\n    } else if(angle >= 90 && angle < 180) {\n        angle = 180 - angle;\n        ret = sin0_90_table[angle];\n    } else if(angle >= 180 && angle < 270) {\n        angle = angle - 180;\n        ret = - sin0_90_table[angle];\n    } else { /*angle >=270*/\n        angle = 360 - angle;\n        ret = - sin0_90_table[angle];\n    }\n\n    return ret;\n}\n\n/**\n * Calculate a value of a Cubic Bezier function.\n * @param t time in range of [0..LV_BEZIER_VAL_MAX]\n * @param u0 start values in range of [0..LV_BEZIER_VAL_MAX]\n * @param u1 control value 1 values in range of [0..LV_BEZIER_VAL_MAX]\n * @param u2 control value 2 in range of [0..LV_BEZIER_VAL_MAX]\n * @param u3 end values in range of [0..LV_BEZIER_VAL_MAX]\n * @return the value calculated from the given parameters in range of [0..LV_BEZIER_VAL_MAX]\n */\nint32_t lv_bezier3(uint32_t t, int32_t u0, int32_t u1, int32_t u2, int32_t u3)\n{\n    uint32_t t_rem = 1024 - t;\n    uint32_t t_rem2 = (t_rem * t_rem) >> 10;\n    uint32_t t_rem3 = (t_rem2 * t_rem) >> 10;\n    uint32_t t2 = (t * t) >> 10;\n    uint32_t t3 = (t2 * t) >> 10;\n\n\n    uint32_t v1 = ((uint32_t)t_rem3 * u0) >> 10;\n    uint32_t v2 = ((uint32_t)3 * t_rem2 * t * u1) >> 20;\n    uint32_t v3 = ((uint32_t)3 * t_rem * t2 * u2) >> 20;\n    uint32_t v4 = ((uint32_t)t3 * u3) >> 10;\n\n    return v1 + v2 + v3 + v4;\n\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_math.h",
    "content": "/**\n * @file math_base.h\n *\n */\n\n#ifndef LV_MATH_H\n#define LV_MATH_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n/*********************\n *      INCLUDES\n *********************/\n#include <stdint.h>\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_MATH_MIN(a,b) ((a) < (b) ? (a) : (b))\n#define LV_MATH_MAX(a,b) ((a) > (b) ? (a) : (b))\n#define LV_MATH_ABS(x) ((x) > 0 ? (x) : (-(x)))\n\n#define LV_TRIGO_SIN_MAX    32767\n#define LV_TRIGO_SHIFT      15      /* >> LV_TRIGO_SHIFT to normalize*/\n\n#define LV_BEZIER_VAL_MAX       1024    /*Max time in Bezier functions (not [0..1] to use integers) */\n#define LV_BEZIER_VAL_SHIFT     10      /*log2(LV_BEZIER_VAL_MAX): used to normalize up scaled values*/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n/**\n * Convert a number to string\n * @param num a number\n * @param buf pointer to a `char` buffer. The result will be stored here (max 10 elements)\n * @return same as `buf` (just for convenience)\n */\nchar * lv_math_num_to_str(int32_t num, char * buf);\n\n/**\n * Return with sinus of an angle\n * @param angle\n * @return sinus of 'angle'. sin(-90) = -32767, sin(90) = 32767\n */\nint16_t lv_trigo_sin(int16_t angle);\n\n/**\n * Calculate a value of a Cubic Bezier function.\n * @param t time in range of [0..LV_BEZIER_VAL_MAX]\n * @param u0 start values in range of [0..LV_BEZIER_VAL_MAX]\n * @param u1 control value 1 values in range of [0..LV_BEZIER_VAL_MAX]\n * @param u2 control value 2 in range of [0..LV_BEZIER_VAL_MAX]\n * @param u3 end values in range of [0..LV_BEZIER_VAL_MAX]\n * @return the value calculated from the given parameters in range of [0..LV_BEZIER_VAL_MAX]\n */\nint32_t lv_bezier3(uint32_t t, int32_t u0, int32_t u1, int32_t u2, int32_t u3);\n\n/**********************\n *      MACROS\n **********************/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_mem.c",
    "content": "/*\n * Copyright (c) 2019-2020 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * @file lv_mem.c\n * General and portable implementation of malloc and free.\n * The dynamic memory monitoring is also supported.\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_mem.h\"\n#include \"lv_math.h\"\n#include <string.h>\n\n#include <assert.h>\n\n#if LV_MEM_CUSTOM != 0\n#include LV_MEM_CUSTOM_INCLUDE\n#endif\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_MEM_ADD_JUNK     0   /*Add memory junk on alloc (0xaa) and free(0xbb) (just for testing purposes)*/\n\n\n#ifdef LV_MEM_ENV64\n# define MEM_UNIT uint64_t\n#else\n# define MEM_UNIT uint32_t\n#endif\n\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n#if LV_ENABLE_GC == 0 /*gc custom allocations must not include header*/\n\n/*The size of this union must be 32 bytes (uint32_t * 8)*/\ntypedef union {\n    struct {\n        MEM_UNIT used: 1;       //1: if the entry is used\n        MEM_UNIT d_size: 31;    //Size of the data\n    };\n    MEM_UNIT header;            //The header (used + d_size)\n    MEM_UNIT align[8];          //Align header size to MEM_UNIT * 8 bytes\n} lv_mem_header_t;\n\nstatic_assert(sizeof(lv_mem_header_t) == 32, \"Node header must be 32 bytes!\");\n\ntypedef struct {\n    lv_mem_header_t header;\n    uint8_t first_data;        /*First data byte in the allocated data (Just for easily create a pointer)*/\n} lv_mem_ent_t;\n\n#endif /* LV_ENABLE_GC */\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n#if LV_MEM_CUSTOM == 0\nstatic lv_mem_ent_t  * ent_get_next(lv_mem_ent_t * act_e);\nstatic void * ent_alloc(lv_mem_ent_t * e, uint32_t size);\nstatic void ent_trunc(lv_mem_ent_t * e, uint32_t size);\n#endif\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n#if LV_MEM_CUSTOM == 0\nstatic uint8_t * work_mem;\n#endif\n\nstatic uint32_t zero_mem;       /*Give the address of this variable if 0 byte should be allocated*/\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Initiaiize the dyn_mem module (work memory and other variables)\n */\nvoid lv_mem_init(void)\n{\n#if LV_MEM_CUSTOM == 0\n\n#if LV_MEM_ADR == 0\n    /*Allocate a large array to store the dynamically allocated data*/\n    static LV_MEM_ATTR MEM_UNIT work_mem_int[LV_MEM_SIZE / sizeof(MEM_UNIT)];\n    work_mem = (uint8_t *) work_mem_int;\n#else\n    work_mem = (uint8_t *) LV_MEM_ADR;\n#endif\n\n    lv_mem_ent_t * full = (lv_mem_ent_t *)work_mem;\n    full->header.used = 0;\n    /*The total mem size id reduced by the first header and the close patterns */\n    full->header.d_size = LV_MEM_SIZE - sizeof(lv_mem_header_t);\n#endif\n}\n\n/**\n * Allocate a memory dynamically\n * @param size size of the memory to allocate in bytes\n * @return pointer to the allocated memory\n */\nvoid * lv_mem_alloc(uint32_t size)\n{\n    if(size == 0) {\n        return &zero_mem;\n    }\n\n    /*Round the size to lv_mem_header_t*/\n    if(size & (sizeof(lv_mem_header_t) - 1)) {\n        size = size & (~(sizeof(lv_mem_header_t) - 1));\n        size += sizeof(lv_mem_header_t);\n    }\n\n    void * alloc = NULL;\n\n#if LV_MEM_CUSTOM == 0 /*Use the allocation from dyn_mem*/\n    lv_mem_ent_t * e = NULL;\n\n    //Search for a appropriate entry\n    do {\n        //Get the next entry\n        e = ent_get_next(e);\n\n        /*If there is next entry then try to allocate there*/\n        if(e != NULL) {\n            alloc = ent_alloc(e, size);\n        }\n        //End if there is not next entry OR the alloc. is successful\n    } while(e != NULL && alloc == NULL);\n\n\n#else  /*Use custom, user defined malloc function*/\n#if LV_ENABLE_GC == 1 /*gc must not include header*/\n    alloc = LV_MEM_CUSTOM_ALLOC(size);\n#else /* LV_ENABLE_GC */\n    /*Allocate a header too to store the size*/\n    alloc = LV_MEM_CUSTOM_ALLOC(size + sizeof(lv_mem_header_t));\n    if(alloc != NULL) {\n        ((lv_mem_ent_t *) alloc)->header.d_size = size;\n        ((lv_mem_ent_t *) alloc)->header.used = 1;\n        alloc = &((lv_mem_ent_t *) alloc)->first_data;\n    }\n#endif /* LV_ENABLE_GC */\n#endif /* LV_MEM_CUSTOM */\n\n#if LV_MEM_ADD_JUNK\n    if(alloc != NULL) memset(alloc, 0xaa, size);\n#endif\n\n    if(alloc == NULL) LV_LOG_WARN(\"Couldn't allocate memory\");\n\n    return alloc;\n}\n\n/**\n * Free an allocated data\n * @param data pointer to an allocated memory\n */\nvoid lv_mem_free(const void * data)\n{\n    if(data == &zero_mem) return;\n    if(data == NULL) return;\n\n\n#if LV_MEM_ADD_JUNK\n    memset((void *)data, 0xbb, lv_mem_get_size(data));\n#endif\n\n#if LV_ENABLE_GC==0\n    /*e points to the header*/\n    lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data - sizeof(lv_mem_header_t));\n    e->header.used = 0;\n#endif\n\n#if LV_MEM_CUSTOM == 0\n#if LV_MEM_AUTO_DEFRAG\n    /* Make a simple defrag.\n     * Join the following free entries after this*/\n    lv_mem_ent_t * e_next;\n    e_next = ent_get_next(e);\n    while(e_next != NULL) {\n        if(e_next->header.used == 0) {\n            e->header.d_size += e_next->header.d_size + sizeof(e->header);\n        } else {\n            break;\n        }\n        e_next = ent_get_next(e_next);\n    }\n#endif\n#else /*Use custom, user defined free function*/\n#if LV_ENABLE_GC==0\n    LV_MEM_CUSTOM_FREE(e);\n#else\n    LV_MEM_CUSTOM_FREE((void*)data);\n#endif /*LV_ENABLE_GC*/\n#endif\n}\n\n/**\n * Reallocate a memory with a new size. The old content will be kept.\n * @param data pointer to an allocated memory.\n * Its content will be copied to the new memory block and freed\n * @param new_size the desired new size in byte\n * @return pointer to the new memory\n */\n\n#if LV_ENABLE_GC==0\n\nvoid * lv_mem_realloc(void * data_p, uint32_t new_size)\n{\n    /*Round the size to lv_mem_header_t*/\n    if(new_size & (sizeof(lv_mem_header_t) - 1)) {\n        new_size = new_size & (~(sizeof(lv_mem_header_t) - 1));\n        new_size += sizeof(lv_mem_header_t);\n    }\n\n    /*data_p could be previously freed pointer (in this case it is invalid)*/\n    if(data_p != NULL) {\n        lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data_p - sizeof(lv_mem_header_t));\n        if(e->header.used == 0) {\n            data_p = NULL;\n        }\n    }\n\n    uint32_t old_size = lv_mem_get_size(data_p);\n    if(old_size == new_size) return data_p;     /*Also avoid reallocating the same memory*/\n\n#if LV_MEM_CUSTOM == 0\n    /* Only truncate the memory is possible\n     * If the 'old_size' was extended by a header size in 'ent_trunc' it avoids reallocating this same memory */\n    if(new_size < old_size) {\n        lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data_p - sizeof(lv_mem_header_t));\n        ent_trunc(e, new_size);\n        return &e->first_data;\n    }\n#endif\n\n    void * new_p;\n    new_p = lv_mem_alloc(new_size);\n\n    if(new_p != NULL && data_p != NULL) {\n        /*Copy the old data to the new. Use the smaller size*/\n        if(old_size != 0) {\n            memcpy(new_p, data_p, LV_MATH_MIN(new_size, old_size));\n            lv_mem_free(data_p);\n        }\n    }\n\n\n    if(new_p == NULL) LV_LOG_WARN(\"Couldn't allocate memory\");\n\n    return new_p;\n}\n\n#else /* LV_ENABLE_GC */\n\nvoid * lv_mem_realloc(void * data_p, uint32_t new_size)\n{\n    void * new_p = LV_MEM_CUSTOM_REALLOC(data_p, new_size);\n    if(new_p == NULL) LV_LOG_WARN(\"Couldn't allocate memory\");\n    return new_p;\n}\n\n#endif /* lv_enable_gc */\n\n/**\n * Join the adjacent free memory blocks\n */\nvoid lv_mem_defrag(void)\n{\n#if LV_MEM_CUSTOM == 0\n    lv_mem_ent_t * e_free;\n    lv_mem_ent_t * e_next;\n    e_free = ent_get_next(NULL);\n\n    while(1) {\n        /*Search the next free entry*/\n        while(e_free != NULL) {\n            if(e_free->header.used != 0) {\n                e_free = ent_get_next(e_free);\n            } else {\n                break;\n            }\n        }\n\n        if(e_free == NULL) return;\n\n        /*Joint the following free entries to the free*/\n        e_next = ent_get_next(e_free);\n        while(e_next != NULL) {\n            if(e_next->header.used == 0) {\n                e_free->header.d_size += e_next->header.d_size + sizeof(e_next->header);\n            } else {\n                break;\n            }\n\n            e_next = ent_get_next(e_next);\n        }\n\n        if(e_next == NULL) return;\n\n        /*Continue from the lastly checked entry*/\n        e_free = e_next;\n    }\n#endif\n}\n\n/**\n * Give information about the work memory of dynamic allocation\n * @param mon_p pointer to a dm_mon_p variable,\n *              the result of the analysis will be stored here\n */\nvoid lv_mem_monitor(lv_mem_monitor_t * mon_p)\n{\n    /*Init the data*/\n    memset(mon_p, 0, sizeof(lv_mem_monitor_t));\n#if LV_MEM_CUSTOM == 0\n    lv_mem_ent_t * e;\n    e = NULL;\n\n    e = ent_get_next(e);\n\n    while(e != NULL)  {\n        if(e->header.used == 0) {\n            mon_p->free_cnt++;\n            mon_p->free_size += e->header.d_size;\n            if(e->header.d_size > mon_p->free_biggest_size) {\n                mon_p->free_biggest_size = e->header.d_size;\n            }\n        } else {\n            mon_p->used_cnt++;\n        }\n\n        e = ent_get_next(e);\n    }\n    mon_p->total_size = LV_MEM_SIZE;\n    mon_p->used_pct = 100 - ((uint64_t)100U * mon_p->free_size) / mon_p->total_size;\n    mon_p->frag_pct = (uint32_t)mon_p->free_biggest_size * 100U / mon_p->free_size;\n    mon_p->frag_pct = 100 - mon_p->frag_pct;\n#endif\n}\n\n/**\n * Give the size of an allocated memory\n * @param data pointer to an allocated memory\n * @return the size of data memory in bytes\n */\n\n#if LV_ENABLE_GC==0\n\nuint32_t lv_mem_get_size(const void * data)\n{\n    if(data == NULL) return 0;\n    if(data == &zero_mem) return 0;\n\n    lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *) data - sizeof(lv_mem_header_t));\n\n    return e->header.d_size;\n}\n\n#else /* LV_ENABLE_GC */\n\nuint32_t lv_mem_get_size(const void * data)\n{\n    return LV_MEM_CUSTOM_GET_SIZE(data);\n}\n\n#endif /*LV_ENABLE_GC*/\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n#if LV_MEM_CUSTOM == 0\n/**\n * Give the next entry after 'act_e'\n * @param act_e pointer to an entry\n * @return pointer to an entry after 'act_e'\n */\nstatic lv_mem_ent_t * ent_get_next(lv_mem_ent_t * act_e)\n{\n    lv_mem_ent_t * next_e = NULL;\n\n    if(act_e == NULL) { /*NULL means: get the first entry*/\n        next_e = (lv_mem_ent_t *) work_mem;\n    } else { /*Get the next entry */\n        uint8_t * data = &act_e->first_data;\n        next_e = (lv_mem_ent_t *)&data[act_e->header.d_size];\n\n        if(&next_e->first_data >= &work_mem[LV_MEM_SIZE]) next_e = NULL;\n    }\n\n    return next_e;\n}\n\n\n/**\n * Try to do the real allocation with a given size\n * @param e try to allocate to this entry\n * @param size size of the new memory in bytes\n * @return pointer to the allocated memory or NULL if not enough memory in the entry\n */\nstatic void * ent_alloc(lv_mem_ent_t * e, uint32_t size)\n{\n    void * alloc = NULL;\n\n    /*If the memory is free and big enough then use it */\n    if(e->header.used == 0 && e->header.d_size >= size) {\n        /*Truncate the entry to the desired size */\n        ent_trunc(e, size),\n\n                  e->header.used = 1;\n\n        /*Save the allocated data*/\n        alloc = &e->first_data;\n    }\n\n    return alloc;\n}\n\n/**\n * Truncate the data of entry to the given size\n * @param e Pointer to an entry\n * @param size new size in bytes\n */\nstatic void ent_trunc(lv_mem_ent_t * e, uint32_t size)\n{\n    /*Don't let empty space only for a header without data*/\n    if(e->header.d_size == size + sizeof(lv_mem_header_t)) {\n        size = e->header.d_size;\n    }\n\n    /* Create the new entry after the current if there is space for it */\n    if(e->header.d_size != size) {\n        uint8_t * e_data = &e->first_data;\n        lv_mem_ent_t * after_new_e = (lv_mem_ent_t *)&e_data[size];\n        after_new_e->header.used = 0;\n        after_new_e->header.d_size = e->header.d_size - size - sizeof(lv_mem_header_t);\n    }\n\n    /* Set the new size for the original entry */\n    e->header.d_size = size;\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_mem.h",
    "content": "/**\n * @file lv_mem.h\n *\n */\n\n#ifndef LV_MEM_H\n#define LV_MEM_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#include <stdint.h>\n#include <stddef.h>\n#include \"lv_log.h\"\n\n/*********************\n *      DEFINES\n *********************/\n// Check windows\n#ifdef __WIN64\n//# define LV_MEM_ENV64\n#endif\n\n// Check GCC\n#ifdef __GNUC__\n# if defined(__x86_64__) || defined(__ppc64__)\n//#   define LV_MEM_ENV64\n# endif\n#endif\n\n/**********************\n *      TYPEDEFS\n **********************/\n\ntypedef struct\n{\n    uint32_t total_size;\n    uint32_t free_cnt;\n    uint32_t free_size;\n    uint32_t free_biggest_size;\n    uint32_t used_cnt;\n    uint8_t used_pct;\n    uint8_t frag_pct;\n} lv_mem_monitor_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n\n/**\n * Initiaize the dyn_mem module (work memory and other variables)\n */\nvoid lv_mem_init(void);\n\n/**\n * Allocate a memory dynamically\n * @param size size of the memory to allocate in bytes\n * @return pointer to the allocated memory\n */\nvoid * lv_mem_alloc(uint32_t size);\n\n/**\n * Free an allocated data\n * @param data pointer to an allocated memory\n */\nvoid lv_mem_free(const void * data);\n\n/**\n * Reallocate a memory with a new size. The old content will be kept.\n * @param data pointer to an allocated memory.\n * Its content will be copied to the new memory block and freed\n * @param new_size the desired new size in byte\n * @return pointer to the new memory\n */\nvoid * lv_mem_realloc(void * data_p, uint32_t new_size);\n\n/**\n * Join the adjacent free memory blocks\n */\nvoid lv_mem_defrag(void);\n\n/**\n * Give information about the work memory of dynamic allocation\n * @param mon_p pointer to a dm_mon_p variable,\n *              the result of the analysis will be stored here\n */\nvoid lv_mem_monitor(lv_mem_monitor_t * mon_p);\n\n/**\n * Give the size of an allocated memory\n * @param data pointer to an allocated memory\n * @return the size of data memory in bytes\n */\nuint32_t lv_mem_get_size(const void * data);\n\n\n/**********************\n *      MACROS\n **********************/\n\n/**\n * Halt on NULL pointer\n * p pointer to a memory\n */\n#if USE_LV_LOG == 0\n# define  lv_mem_assert(p) {if(p == NULL) while(1); }\n#else\n# define  lv_mem_assert(p) {if(p == NULL) {LV_LOG_ERROR(\"Out of memory!\"); while(1); }}\n#endif\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_MEM_H*/\n\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_misc.mk",
    "content": "CSRCS += lv_font.c\nCSRCS += lv_circ.c\nCSRCS += lv_area.c\nCSRCS += lv_task.c\nCSRCS += lv_fs.c\nCSRCS += lv_anim.c\nCSRCS += lv_mem.c\nCSRCS += lv_ll.c\nCSRCS += lv_color.c\nCSRCS += lv_txt.c\nCSRCS += lv_ufs.c\nCSRCS += lv_math.c\nCSRCS += lv_log.c\nCSRCS += lv_gc.c\n\nDEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_misc\nVPATH += :$(LVGL_DIR)/lvgl/lv_misc\n\nCFLAGS += \"-I$(LVGL_DIR)/lvgl/lv_misc\"\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_symbol_def.h",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef LV_SYMBOL_DEF_H\n#define LV_SYMBOL_DEF_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n/*\n * With no UTF-8 support (192- 255) (192..241 is used)\n *\n * With UTF-8 support (in Supplemental Private Use Area-A): 0xF800 .. 0xF831\n * - Basic symbols:     0xE000..0xE01F\n * - File symbols:      0xE020..0xE03F\n * - Feedback symbols:  0xE040..0xE05F\n * - Reserved:          0xE060..0xE07F\n */\n\n#if LV_TXT_UTF8 == 0\n#define LV_SYMBOL_GLYPH_FIRST  0xC0\n#define SYMBOL_DOT             _SYMBOL_VALUE1(C0)\n#define SYMBOL_CLOCK           _SYMBOL_VALUE1(C1)\n#define SYMBOL_LIST            _SYMBOL_VALUE1(C2)\n#define SYMBOL_OK              _SYMBOL_VALUE1(C3)\n#define SYMBOL_CLOSE           _SYMBOL_VALUE1(C4)\n#define SYMBOL_POWER           _SYMBOL_VALUE1(C5)\n#define SYMBOL_SETTINGS        _SYMBOL_VALUE1(C6)\n#define SYMBOL_TRASH           _SYMBOL_VALUE1(C7)\n#define SYMBOL_HOME            _SYMBOL_VALUE1(C8)\n#define SYMBOL_DOWNLOAD        _SYMBOL_VALUE1(C9)\n#define SYMBOL_DRIVE           _SYMBOL_VALUE1(CA)\n#define SYMBOL_REFRESH         _SYMBOL_VALUE1(CB)\n#define SYMBOL_REBOOT          _SYMBOL_VALUE1(CC)\n#define SYMBOL_CHIP            _SYMBOL_VALUE1(CD)\n#define SYMBOL_SD              _SYMBOL_VALUE1(CE)\n#define SYMBOL_CIRCUIT         _SYMBOL_VALUE1(CF)\n#define SYMBOL_EDIT            _SYMBOL_VALUE1(D0)\n#define SYMBOL_FILE_ALT        _SYMBOL_VALUE1(D1)\n#define SYMBOL_FILE_CODE       _SYMBOL_VALUE1(D2)\n#define SYMBOL_FILE_ARC        _SYMBOL_VALUE1(D3)\n#define SYMBOL_TEMPERATURE     _SYMBOL_VALUE1(D4)\n#define SYMBOL_MODULES         _SYMBOL_VALUE1(D5)\n#define SYMBOL_MODULES_ALT     _SYMBOL_VALUE1(D6)\n#define SYMBOL_LEFT            _SYMBOL_VALUE1(D7)\n#define SYMBOL_RIGHT           _SYMBOL_VALUE1(D8)\n#define SYMBOL_KEY             _SYMBOL_VALUE1(D9)\n#define SYMBOL_INFO            _SYMBOL_VALUE1(DA)\n#define SYMBOL_WARNING         _SYMBOL_VALUE1(DB)\n#define SYMBOL_SHUFFLE         _SYMBOL_VALUE1(DC)\n#define SYMBOL_UP              _SYMBOL_VALUE1(DD)\n#define SYMBOL_DOWN            _SYMBOL_VALUE1(DE)\n#define SYMBOL_BRIGHTNESS      _SYMBOL_VALUE1(DF)\n#define SYMBOL_DIRECTORY       _SYMBOL_VALUE1(E0)\n#define SYMBOL_UPLOAD          _SYMBOL_VALUE1(E1)\n#define SYMBOL_USB             _SYMBOL_VALUE1(E2)\n#define SYMBOL_TOOLS           _SYMBOL_VALUE1(E3)\n#define SYMBOL_COPY            _SYMBOL_VALUE1(E4)\n#define SYMBOL_SAVE            _SYMBOL_VALUE1(E5)\n#define SYMBOL_CHARGE          _SYMBOL_VALUE1(E6)\n#define SYMBOL_HINT            _SYMBOL_VALUE1(E7)\n#define SYMBOL_KEYBOARD        _SYMBOL_VALUE1(E8)\n#define SYMBOL_GPS             _SYMBOL_VALUE1(E9)\n#define SYMBOL_FILE            _SYMBOL_VALUE1(EA)\n#define SYMBOL_CAMERA          _SYMBOL_VALUE1(EB)\n#define SYMBOL_BATTERY_FULL    _SYMBOL_VALUE1(EC)\n#define SYMBOL_BATTERY_3       _SYMBOL_VALUE1(ED)\n#define SYMBOL_BATTERY_2       _SYMBOL_VALUE1(EE)\n#define SYMBOL_BATTERY_1       _SYMBOL_VALUE1(EF)\n#define SYMBOL_BATTERY_EMPTY   _SYMBOL_VALUE1(F0)\n#define SYMBOL_SHRK            _SYMBOL_VALUE1(F1)\n#define LV_SYMBOL_GLYPH_LAST   0xF1\n#define SYMBOL_DUMMY           _SYMBOL_VALUE1(FF)       /*Invalid symbol. If written before a string then `lv_img` will show it as a label*/\n\n#else\n#define LV_SYMBOL_GLYPH_FIRST  0xF800\n#define SYMBOL_DOT             _SYMBOL_VALUE3(EF,A0,80)\n#define SYMBOL_CLOCK           _SYMBOL_VALUE3(EF,A0,81)\n#define SYMBOL_LIST            _SYMBOL_VALUE3(EF,A0,82)\n#define SYMBOL_OK              _SYMBOL_VALUE3(EF,A0,83)\n#define SYMBOL_CLOSE           _SYMBOL_VALUE3(EF,A0,84)\n#define SYMBOL_POWER           _SYMBOL_VALUE3(EF,A0,85)\n#define SYMBOL_SETTINGS        _SYMBOL_VALUE3(EF,A0,86)\n#define SYMBOL_TRASH           _SYMBOL_VALUE3(EF,A0,87)\n#define SYMBOL_HOME            _SYMBOL_VALUE3(EF,A0,88)\n#define SYMBOL_DOWNLOAD        _SYMBOL_VALUE3(EF,A0,89)\n#define SYMBOL_DRIVE           _SYMBOL_VALUE3(EF,A0,8A)\n#define SYMBOL_REFRESH         _SYMBOL_VALUE3(EF,A0,8B)\n#define SYMBOL_REBOOT          _SYMBOL_VALUE3(EF,A0,8C)\n#define SYMBOL_CHIP            _SYMBOL_VALUE3(EF,A0,8D)\n#define SYMBOL_SD              _SYMBOL_VALUE3(EF,A0,8E)\n#define SYMBOL_CIRCUIT         _SYMBOL_VALUE3(EF,A0,8F)\n#define SYMBOL_EDIT            _SYMBOL_VALUE3(EF,A0,90)\n#define SYMBOL_FILE_ALT        _SYMBOL_VALUE3(EF,A0,91)\n#define SYMBOL_FILE_CODE       _SYMBOL_VALUE3(EF,A0,92)\n#define SYMBOL_FILE_ARC        _SYMBOL_VALUE3(EF,A0,93)\n#define SYMBOL_TEMPERATURE     _SYMBOL_VALUE3(EF,A0,94)\n#define SYMBOL_MODULES         _SYMBOL_VALUE3(EF,A0,95)\n#define SYMBOL_MODULES_ALT     _SYMBOL_VALUE3(EF,A0,96)\n#define SYMBOL_LEFT            _SYMBOL_VALUE3(EF,A0,97)\n#define SYMBOL_RIGHT           _SYMBOL_VALUE3(EF,A0,98)\n#define SYMBOL_KEY             _SYMBOL_VALUE3(EF,A0,99)\n#define SYMBOL_INFO            _SYMBOL_VALUE3(EF,A0,9A)\n#define SYMBOL_WARNING         _SYMBOL_VALUE3(EF,A0,9B)\n#define SYMBOL_SHUFFLE         _SYMBOL_VALUE3(EF,A0,9C)\n#define SYMBOL_UP              _SYMBOL_VALUE3(EF,A0,9D)\n#define SYMBOL_DOWN            _SYMBOL_VALUE3(EF,A0,9E)\n#define SYMBOL_BRIGHTNESS      _SYMBOL_VALUE3(EF,A0,9F)\n#define SYMBOL_DIRECTORY       _SYMBOL_VALUE3(EF,A0,A0)\n#define SYMBOL_UPLOAD          _SYMBOL_VALUE3(EF,A0,A1)\n#define SYMBOL_USB             _SYMBOL_VALUE3(EF,A0,A2)\n#define SYMBOL_TOOLS           _SYMBOL_VALUE3(EF,A0,A3)\n#define SYMBOL_COPY            _SYMBOL_VALUE3(EF,A0,A4)\n#define SYMBOL_SAVE            _SYMBOL_VALUE3(EF,A0,A5)\n#define SYMBOL_CHARGE          _SYMBOL_VALUE3(EF,A0,A6)\n#define SYMBOL_HINT            _SYMBOL_VALUE3(EF,A0,A7)\n#define SYMBOL_KEYBOARD        _SYMBOL_VALUE3(EF,A0,A8)\n#define SYMBOL_GPS             _SYMBOL_VALUE3(EF,A0,A9)\n#define SYMBOL_FILE            _SYMBOL_VALUE3(EF,A0,AA)\n#define SYMBOL_CAMERA          _SYMBOL_VALUE3(EF,A0,AB)\n#define SYMBOL_BATTERY_FULL    _SYMBOL_VALUE3(EF,A0,AC)\n#define SYMBOL_BATTERY_3       _SYMBOL_VALUE3(EF,A0,AD)\n#define SYMBOL_BATTERY_2       _SYMBOL_VALUE3(EF,A0,AE)\n#define SYMBOL_BATTERY_1       _SYMBOL_VALUE3(EF,A0,AF)\n#define SYMBOL_BATTERY_EMPTY   _SYMBOL_VALUE3(EF,A0,B0)\n#define SYMBOL_SHRK            _SYMBOL_VALUE3(EF,A0,B1)\n#define LV_SYMBOL_GLYPH_LAST   0xF831\n#define SYMBOL_DUMMY           _SYMBOL_VALUE3(EF,A3,BF)       /*Invalid symbol at (U+F831). If written before a string then `lv_img` will show it as a label*/\n#endif\n\n#define _SYMBOL_VALUE1(x) (0x ## x)\n#define _SYMBOL_VALUE3(x, y, z) (0x ## z ## y ## x)\n#define _SYMBOL_NUMSTR(sym) LV_ ## sym ## _NUMSTR = sym\n\nenum\n{\n    _SYMBOL_NUMSTR(SYMBOL_DOT),\n    _SYMBOL_NUMSTR(SYMBOL_CLOCK),\n    _SYMBOL_NUMSTR(SYMBOL_LIST),\n    _SYMBOL_NUMSTR(SYMBOL_OK),\n    _SYMBOL_NUMSTR(SYMBOL_CLOSE),\n    _SYMBOL_NUMSTR(SYMBOL_POWER),\n    _SYMBOL_NUMSTR(SYMBOL_SETTINGS),\n    _SYMBOL_NUMSTR(SYMBOL_TRASH),\n    _SYMBOL_NUMSTR(SYMBOL_HOME),\n    _SYMBOL_NUMSTR(SYMBOL_DOWNLOAD),\n    _SYMBOL_NUMSTR(SYMBOL_DRIVE),\n    _SYMBOL_NUMSTR(SYMBOL_REFRESH),\n    _SYMBOL_NUMSTR(SYMBOL_REBOOT),\n    _SYMBOL_NUMSTR(SYMBOL_CHIP),\n    _SYMBOL_NUMSTR(SYMBOL_SD),\n    _SYMBOL_NUMSTR(SYMBOL_CIRCUIT),\n    _SYMBOL_NUMSTR(SYMBOL_EDIT),\n    _SYMBOL_NUMSTR(SYMBOL_FILE_ALT),\n    _SYMBOL_NUMSTR(SYMBOL_FILE_CODE),\n    _SYMBOL_NUMSTR(SYMBOL_FILE_ARC),\n    _SYMBOL_NUMSTR(SYMBOL_TEMPERATURE),\n    _SYMBOL_NUMSTR(SYMBOL_MODULES),\n    _SYMBOL_NUMSTR(SYMBOL_MODULES_ALT),\n    _SYMBOL_NUMSTR(SYMBOL_LEFT),\n    _SYMBOL_NUMSTR(SYMBOL_RIGHT),\n    _SYMBOL_NUMSTR(SYMBOL_KEY),\n    _SYMBOL_NUMSTR(SYMBOL_INFO),\n    _SYMBOL_NUMSTR(SYMBOL_WARNING),\n    _SYMBOL_NUMSTR(SYMBOL_SHUFFLE),\n    _SYMBOL_NUMSTR(SYMBOL_UP),\n    _SYMBOL_NUMSTR(SYMBOL_DOWN),\n    _SYMBOL_NUMSTR(SYMBOL_BRIGHTNESS),\n    _SYMBOL_NUMSTR(SYMBOL_DIRECTORY),\n    _SYMBOL_NUMSTR(SYMBOL_UPLOAD),\n    _SYMBOL_NUMSTR(SYMBOL_USB),\n    _SYMBOL_NUMSTR(SYMBOL_TOOLS),\n    _SYMBOL_NUMSTR(SYMBOL_COPY),\n    _SYMBOL_NUMSTR(SYMBOL_SAVE),\n    _SYMBOL_NUMSTR(SYMBOL_CHARGE),\n    _SYMBOL_NUMSTR(SYMBOL_HINT),\n    _SYMBOL_NUMSTR(SYMBOL_KEYBOARD),\n    _SYMBOL_NUMSTR(SYMBOL_GPS),\n    _SYMBOL_NUMSTR(SYMBOL_FILE),\n    _SYMBOL_NUMSTR(SYMBOL_CAMERA),\n    _SYMBOL_NUMSTR(SYMBOL_BATTERY_FULL),\n    _SYMBOL_NUMSTR(SYMBOL_BATTERY_3),\n    _SYMBOL_NUMSTR(SYMBOL_BATTERY_2),\n    _SYMBOL_NUMSTR(SYMBOL_BATTERY_1),\n    _SYMBOL_NUMSTR(SYMBOL_BATTERY_EMPTY),\n    _SYMBOL_NUMSTR(SYMBOL_SHRK),\n    _SYMBOL_NUMSTR(SYMBOL_DUMMY),\n};\n\n#undef _SYMBOL_VALUE1\n#undef _SYMBOL_VALUE3\n\n#define _SYMBOL_STR_(x) #x\n#define _SYMBOL_STR(x) _SYMBOL_STR_(x)\n#define _SYMBOL_CHAR(c) \\x ## c\n#define _SYMBOL_VALUE1(x) _SYMBOL_STR(_SYMBOL_CHAR(x))\n#define _SYMBOL_VALUE3(x, y, z) _SYMBOL_STR(_SYMBOL_CHAR(x)_SYMBOL_CHAR(y)_SYMBOL_CHAR(z))\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n\n#endif /*LV_SYMBOL_DEF_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_task.c",
    "content": "/**\n * @file lv_task.c\n * An 'lv_task'  is a void (*fp) (void* param) type function which will be called periodically.\n * A priority (5 levels + disable) can be assigned to lv_tasks.\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include <stddef.h>\n#include \"lv_task.h\"\n#include \"../lv_hal/lv_hal_tick.h\"\n#include \"lv_gc.h\"\n\n#if defined(LV_GC_INCLUDE)\n#   include LV_GC_INCLUDE\n#endif /* LV_ENABLE_GC */\n\n/*********************\n *      DEFINES\n *********************/\n#define IDLE_MEAS_PERIOD    500     /*[ms]*/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool lv_task_exec(lv_task_t * lv_task_p);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic bool lv_task_run = false;\nstatic uint8_t idle_last = 0;\nstatic bool task_deleted;\nstatic bool task_created;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Init the lv_task module\n */\nvoid lv_task_init(void)\n{\n    lv_ll_init(&LV_GC_ROOT(_lv_task_ll), sizeof(lv_task_t));\n\n    /*Initially enable the lv_task handling*/\n    lv_task_enable(true);\n}\n\n/**\n * Call it  periodically to handle lv_tasks.\n */\nLV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void)\n{\n    LV_LOG_TRACE(\"lv_task_handler started\");\n\n    /*Avoid concurrent running of the task handler*/\n    static bool task_handler_mutex = false;\n    if(task_handler_mutex) return;\n    task_handler_mutex = true;\n\n    static uint32_t idle_period_start = 0;\n    static uint32_t handler_start = 0;\n    static uint32_t busy_time = 0;\n\n    if(lv_task_run == false) return;\n\n    handler_start = lv_tick_get();\n\n    /* Run all task from the highest to the lowest priority\n     * If a lower priority task is executed check task again from the highest priority\n     * but on the priority of executed tasks don't run tasks before the executed*/\n    lv_task_t * task_interrupter = NULL;\n    lv_task_t * next;\n    bool end_flag;\n    do {\n        end_flag = true;\n        task_deleted = false;\n        task_created = false;\n        LV_GC_ROOT(_lv_task_act) = lv_ll_get_head(&LV_GC_ROOT(_lv_task_ll));\n        while(LV_GC_ROOT(_lv_task_act)) {\n            /* The task might be deleted if it runs only once ('once = 1')\n             * So get next element until the current is surely valid*/\n            next = lv_ll_get_next(&LV_GC_ROOT(_lv_task_ll), LV_GC_ROOT(_lv_task_act));\n\n            /*We reach priority of the turned off task. There is nothing more to do.*/\n            if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio == LV_TASK_PRIO_OFF) {\n                break;\n            }\n\n            /*Here is the interrupter task. Don't execute it again.*/\n            if(LV_GC_ROOT(_lv_task_act) == task_interrupter) {\n                task_interrupter = NULL;     /*From this point only task after the interrupter comes, so the interrupter is not interesting anymore*/\n                LV_GC_ROOT(_lv_task_act) = next;\n                continue;                   /*Load the next task*/\n            }\n\n            /*Just try to run the tasks with highest priority.*/\n            if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio == LV_TASK_PRIO_HIGHEST) {\n                lv_task_exec(LV_GC_ROOT(_lv_task_act));\n            }\n            /*Tasks with higher priority then the interrupted shall be run in every case*/\n            else if(task_interrupter) {\n                if(((lv_task_t *)LV_GC_ROOT(_lv_task_act))->prio > task_interrupter->prio) {\n                    if(lv_task_exec(LV_GC_ROOT(_lv_task_act))) {\n                        task_interrupter = LV_GC_ROOT(_lv_task_act);  /*Check all tasks again from the highest priority */\n                        end_flag = false;\n                        break;\n                    }\n                }\n            }\n            /* It is no interrupter task or we already reached it earlier.\n             * Just run the remaining tasks*/\n            else {\n                if(lv_task_exec(LV_GC_ROOT(_lv_task_act))) {\n                    task_interrupter = LV_GC_ROOT(_lv_task_act);  /*Check all tasks again from the highest priority */\n                    end_flag = false;\n                    break;\n                }\n            }\n\n            if(task_deleted) break;     /*If a task was deleted then this or the next item might be corrupted*/\n            if(task_created) break;     /*If a task was deleted then this or the next item might be corrupted*/\n\n            LV_GC_ROOT(_lv_task_act) = next;         /*Load the next task*/\n        }\n    } while(!end_flag);\n\n    busy_time += lv_tick_elaps(handler_start);\n    uint32_t idle_period_time = lv_tick_elaps(idle_period_start);\n    if(idle_period_time >= IDLE_MEAS_PERIOD) {\n\n        idle_last = (uint32_t)((uint32_t)busy_time * 100) / IDLE_MEAS_PERIOD;   /*Calculate the busy percentage*/\n        idle_last = idle_last > 100 ? 0 : 100 - idle_last;                      /*But we need idle time*/\n        busy_time = 0;\n        idle_period_start = lv_tick_get();\n\n\n    }\n\n    task_handler_mutex = false;     /*Release the mutex*/\n\n    LV_LOG_TRACE(\"lv_task_handler ready\");\n}\n\n/**\n * Create a new lv_task\n * @param task a function which is the task itself\n * @param period call period in ms unit\n * @param prio priority of the task (LV_TASK_PRIO_OFF means the task is stopped)\n * @param param free parameter\n * @return pointer to the new task\n */\nlv_task_t * lv_task_create(void (*task)(void *), uint32_t period, lv_task_prio_t prio, void * param)\n{\n    lv_task_t * new_lv_task = NULL;\n    lv_task_t * tmp;\n\n    /*Create task lists in order of priority from high to low*/\n    tmp = lv_ll_get_head(&LV_GC_ROOT(_lv_task_ll));\n    if(NULL == tmp) {                               /*First task*/\n        new_lv_task = lv_ll_ins_head(&LV_GC_ROOT(_lv_task_ll));\n        lv_mem_assert(new_lv_task);\n        if(new_lv_task == NULL) return NULL;\n    } else {\n        do {\n            if(tmp->prio <= prio) {\n                new_lv_task = lv_ll_ins_prev(&LV_GC_ROOT(_lv_task_ll), tmp);\n                lv_mem_assert(new_lv_task);\n                if(new_lv_task == NULL) return NULL;\n                break;\n            }\n            tmp = lv_ll_get_next(&LV_GC_ROOT(_lv_task_ll), tmp);\n        } while(tmp != NULL);\n\n        if(tmp == NULL) {   /*Only too high priority tasks were found*/\n            new_lv_task = lv_ll_ins_tail(&LV_GC_ROOT(_lv_task_ll));\n            lv_mem_assert(new_lv_task);\n            if(new_lv_task == NULL) return NULL;\n        }\n    }\n\n    new_lv_task->period = period;\n    new_lv_task->task = task;\n    new_lv_task->prio = prio;\n    new_lv_task->param = param;\n    new_lv_task->once = 0;\n    new_lv_task->last_run = lv_tick_get();\n\n    task_created = true;\n\n    return new_lv_task;\n}\n\n/**\n * Delete a lv_task\n * @param lv_task_p pointer to task created by lv_task_p\n */\nvoid lv_task_del(lv_task_t * lv_task_p)\n{\n    lv_ll_rem(&LV_GC_ROOT(_lv_task_ll), lv_task_p);\n\n    lv_mem_free(lv_task_p);\n\n    if(LV_GC_ROOT(_lv_task_act) == lv_task_p) task_deleted = true;      /*The active task was deleted*/\n}\n\n/**\n * Set new priority for a lv_task\n * @param lv_task_p pointer to a lv_task\n * @param prio the new priority\n */\nvoid lv_task_set_prio(lv_task_t * lv_task_p, lv_task_prio_t prio)\n{\n    /*Find the tasks with new priority*/\n    lv_task_t * i;\n    LL_READ(LV_GC_ROOT(_lv_task_ll), i) {\n        if(i->prio <= prio) {\n            if(i != lv_task_p) lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), lv_task_p, i);\n            break;\n        }\n    }\n\n    /*There was no such a low priority so far then add the node to the tail*/\n    if(i == NULL) {\n        lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), lv_task_p, NULL);\n    }\n\n\n    lv_task_p->prio = prio;\n}\n\n/**\n * Set new period for a lv_task\n * @param lv_task_p pointer to a lv_task\n * @param period the new period\n */\nvoid lv_task_set_period(lv_task_t * lv_task_p, uint32_t period)\n{\n    lv_task_p->period = period;\n}\n\n/**\n * Make a lv_task ready. It will not wait its period.\n * @param lv_task_p pointer to a lv_task.\n */\nvoid lv_task_ready(lv_task_t * lv_task_p)\n{\n    lv_task_p->last_run = lv_tick_get() - lv_task_p->period - 1;\n}\n\n/**\n * Delete the lv_task after one call\n * @param lv_task_p pointer to a lv_task.\n */\nvoid lv_task_once(lv_task_t * lv_task_p)\n{\n    lv_task_p->once = 1;\n}\n\n/**\n * Reset a lv_task.\n * It will be called the previously set period milliseconds later.\n * @param lv_task_p pointer to a lv_task.\n */\nvoid lv_task_reset(lv_task_t * lv_task_p)\n{\n    lv_task_p->last_run = lv_tick_get();\n}\n\n/**\n * Enable or disable the whole lv_task handling\n * @param en: true: lv_task handling is running, false: lv_task handling is suspended\n */\nvoid lv_task_enable(bool en)\n{\n    lv_task_run = en;\n}\n\n/**\n * Get idle percentage\n * @return the lv_task idle in percentage\n */\nuint8_t lv_task_get_idle(void)\n{\n    return idle_last;\n}\n\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Execute task if its the priority is appropriate\n * @param lv_task_p pointer to lv_task\n * @return true: execute, false: not executed\n */\nstatic bool lv_task_exec(lv_task_t * lv_task_p)\n{\n    bool exec = false;\n\n    /*Execute if at least 'period' time elapsed*/\n    uint32_t elp = lv_tick_elaps(lv_task_p->last_run);\n    if(elp >= lv_task_p->period) {\n        lv_task_p->last_run = lv_tick_get();\n        task_deleted = false;\n        task_created = false;\n\t\tif (lv_task_p->task)\n\t\t\tlv_task_p->task(lv_task_p->param);\n\n        /*Delete if it was a one shot lv_task*/\n        if(task_deleted == false) {\t\t\t/*The task might be deleted by itself as well*/\n        \tif(lv_task_p->once != 0) {\n        \t    lv_task_del(lv_task_p);\n        \t}\n        }\n        exec = true;\n    }\n\n    return exec;\n}\n\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_task.h",
    "content": "/**\n * @file lv_task.c\n * An 'lv_task'  is a void (*fp) (void* param) type function which will be called periodically.\n * A priority (5 levels + disable) can be assigned to lv_tasks.\n */\n\n#ifndef LV_TASK_H\n#define LV_TASK_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#include <stdint.h>\n#include \"lv_mem.h\"\n#include \"lv_ll.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#ifndef LV_ATTRIBUTE_TASK_HANDLER\n#define LV_ATTRIBUTE_TASK_HANDLER\n#endif\n/**********************\n *      TYPEDEFS\n **********************/\n/**\n * Possible priorities for lv_tasks\n */\n#define LV_TASK_ONESHOT 0\nenum\n{\n    LV_TASK_PRIO_OFF = 0,\n    LV_TASK_PRIO_LOWEST,\n    LV_TASK_PRIO_LOW,\n    LV_TASK_PRIO_MID,\n    LV_TASK_PRIO_HIGH,\n    LV_TASK_PRIO_HIGHEST,\n    LV_TASK_PRIO_NUM,\n};\ntypedef uint8_t lv_task_prio_t;\n\n/**\n * Descriptor of a lv_task\n */\ntypedef struct\n{\n    uint32_t period;\n    uint32_t last_run;\n    void (*task) (void*);\n    void * param;\n    uint8_t prio:3;\n    uint8_t once:1;\n} lv_task_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Init the lv_task module\n */\nvoid lv_task_init(void);\n\n/**\n * Call it  periodically to handle lv_tasks.\n */\nLV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void);\n\n/**\n * Create a new lv_task\n * @param task a function which is the task itself\n * @param period call period in ms unit\n * @param prio priority of the task (LV_TASK_PRIO_OFF means the task is stopped)\n * @param param free parameter\n * @return pointer to the new task\n */\nlv_task_t* lv_task_create(void (*task) (void *), uint32_t period, lv_task_prio_t prio, void * param);\n\n/**\n * Delete a lv_task\n * @param lv_task_p pointer to task created by lv_task_p\n */\nvoid lv_task_del(lv_task_t* lv_task_p);\n\n/**\n * Set new priority for a lv_task\n * @param lv_task_p pointer to a lv_task\n * @param prio the new priority\n */\nvoid lv_task_set_prio(lv_task_t* lv_task_p, lv_task_prio_t prio);\n\n/**\n * Set new period for a lv_task\n * @param lv_task_p pointer to a lv_task\n * @param period the new period\n */\nvoid lv_task_set_period(lv_task_t* lv_task_p, uint32_t period);\n\n/**\n * Make a lv_task ready. It will not wait its period.\n * @param lv_task_p pointer to a lv_task.\n */\nvoid lv_task_ready(lv_task_t* lv_task_p);\n\n\n/**\n * Delete the lv_task after one call\n * @param lv_task_p pointer to a lv_task.\n */\nvoid lv_task_once(lv_task_t * lv_task_p);\n\n/**\n * Reset a lv_task.\n * It will be called the previously set period milliseconds later.\n * @param lv_task_p pointer to a lv_task.\n */\nvoid lv_task_reset(lv_task_t* lv_task_p);\n\n/**\n * Enable or disable the whole  lv_task handling\n * @param en: true: lv_task handling is running, false: lv_task handling is suspended\n */\nvoid lv_task_enable(bool en);\n\n/**\n * Get idle percentage\n * @return the lv_task idle in percentage\n */\nuint8_t lv_task_get_idle(void);\n\n/**********************\n *      MACROS\n **********************/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_templ.c",
    "content": "/**\n * @file lv_templ.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_templ.h",
    "content": "/**\n * @file lv_templ.h\n *\n */\n\n#ifndef LV_TEMPL_H\n#define LV_TEMPL_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**********************\n *      MACROS\n **********************/\n\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_TEMPL_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_txt.c",
    "content": "/**\n * @file lv_text.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_txt.h\"\n#include \"lv_math.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define NO_BREAK_FOUND  UINT32_MAX\n\n#ifndef LV_TXT_LINE_BREAK_LONG_LEN\n#define LV_TXT_LINE_BREAK_LONG_LEN 12 /* If a character is at least this long, will break wherever \"prettiest\" */\n#endif\n\n#ifndef LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN\n#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 /* Minimum number of characters of a word to put on a line before a break */\n#endif\n\n#ifndef LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN\n#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 1 /* Minimum number of characters of a word to put on a line after a break */\n#endif\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool is_break_char(uint32_t letter);\n\n#if LV_TXT_UTF8\nstatic uint8_t lv_txt_utf8_size(const char * str);\nstatic uint32_t lv_txt_unicode_to_utf8(uint32_t letter_uni);\nstatic uint32_t lv_txt_utf8_conv_wc(uint32_t c);\nstatic uint32_t lv_txt_utf8_next(const char * txt, uint32_t * i);\nstatic uint32_t lv_txt_utf8_prev(const char * txt, uint32_t * i_start);\nstatic uint32_t lv_txt_utf8_get_byte_id(const char * txt, uint32_t utf8_id);\nstatic uint32_t lv_txt_utf8_get_char_id(const char * txt, uint32_t byte_id);\nstatic uint32_t lv_txt_utf8_get_length(const char * txt);\n#else\nstatic uint8_t lv_txt_ascii_size(const char * str);\nstatic uint32_t lv_txt_unicode_to_ascii(uint32_t letter_uni);\nstatic uint32_t lv_txt_ascii_conv_wc(uint32_t c);\nstatic uint32_t lv_txt_ascii_next(const char * txt, uint32_t * i);\nstatic uint32_t lv_txt_ascii_prev(const char * txt, uint32_t * i_start);\nstatic uint32_t lv_txt_ascii_get_byte_id(const char * txt, uint32_t utf8_id);\nstatic uint32_t lv_txt_ascii_get_char_id(const char * txt, uint32_t byte_id);\nstatic uint32_t lv_txt_ascii_get_length(const char * txt);\n#endif\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\n\n/**********************\n *  GLOBAL VARIABLES\n **********************/\n#if LV_TXT_UTF8\nuint8_t (*lv_txt_encoded_size)(const char *) =                  lv_txt_utf8_size;\nuint32_t (*lv_txt_unicode_to_encoded)(uint32_t) =               lv_txt_unicode_to_utf8;\nuint32_t (*lv_txt_encoded_conv_wc)(uint32_t) =                  lv_txt_utf8_conv_wc;\nuint32_t (*lv_txt_encoded_next)(const char *, uint32_t *) =    lv_txt_utf8_next;\nuint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *) =   lv_txt_utf8_prev;\nuint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t) = lv_txt_utf8_get_byte_id;\nuint32_t (*lv_encoded_get_char_id)(const char *, uint32_t) =   lv_txt_utf8_get_char_id;\nuint32_t (*lv_txt_get_encoded_length)(const char *) =          lv_txt_utf8_get_length;\n#else\nuint8_t (*lv_txt_encoded_size)(const char *) =                  lv_txt_ascii_size;\nuint32_t (*lv_txt_unicode_to_encoded)(uint32_t) =               lv_txt_unicode_to_ascii;\nuint32_t (*lv_txt_encoded_conv_wc)(uint32_t) =                  lv_txt_ascii_conv_wc;\nuint32_t (*lv_txt_encoded_next)(const char *, uint32_t *) =    lv_txt_ascii_next;\nuint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *) =   lv_txt_ascii_prev;\nuint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t) = lv_txt_ascii_get_byte_id;\nuint32_t (*lv_encoded_get_char_id)(const char *, uint32_t) =   lv_txt_ascii_get_char_id;\nuint32_t (*lv_txt_get_encoded_length)(const char *) =          lv_txt_ascii_get_length;\n#endif\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Get size of a text\n * @param size_res pointer to a 'point_t' variable to store the result\n * @param text pointer to a text\n * @param font pinter to font of the text\n * @param letter_space letter space of the text\n * @param txt.line_space line space of the text\n * @param flags settings for the text from 'txt_flag_t' enum\n * @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks\n */\nvoid lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * font,\n                     lv_coord_t letter_space, lv_coord_t line_space, lv_coord_t max_width, lv_txt_flag_t flag)\n{\n    size_res->x = 0;\n    size_res->y = 0;\n\n    if(text == NULL) return;\n    if(font == NULL) return;\n\n    if(flag & LV_TXT_FLAG_EXPAND) max_width = LV_COORD_MAX;\n\n    uint32_t line_start = 0;\n    uint32_t new_line_start = 0;\n    lv_coord_t act_line_length;\n    uint8_t letter_height = lv_font_get_height(font);\n\n    /*Calc. the height and longest line*/\n    while(text[line_start] != '\\0') {\n        new_line_start += lv_txt_get_next_line(&text[line_start], font, letter_space, max_width, flag);\n        size_res->y += letter_height ;\n        size_res->y += line_space;\n\n        /*Calculate the the longest line*/\n        act_line_length = lv_txt_get_width(&text[line_start], new_line_start - line_start,\n                                           font, letter_space, flag);\n\n        size_res->x = LV_MATH_MAX(act_line_length, size_res->x);\n        line_start = new_line_start;\n    }\n\n    /*Make the text one line taller if the last character is '\\n' or '\\r'*/\n    if((line_start != 0) && (text[line_start - 1] == '\\n' || text[line_start - 1] == '\\r')) {\n        size_res->y += letter_height + line_space;\n    }\n\n    /*Correction with the last line space or set the height manually if the text is empty*/\n    if(size_res->y == 0) size_res->y = letter_height;\n    else size_res->y -= line_space;\n\n}\n\n/**\n * Get the next line of text. Check line length and break chars too.\n * @param txt a '\\0' terminated string\n * @param font pointer to a font\n * @param letter_space letter space\n * @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks\n * @param flags settings for the text from 'txt_flag_type' enum\n * @return the index of the first char of the new line (in byte index not letter index. With UTF-8 they are different)\n */\nuint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font,\n                              lv_coord_t letter_space, lv_coord_t max_width, lv_txt_flag_t flag)\n{\n    if(txt == NULL) return 0;\n    if(font == NULL) return 0;\n\n    if(flag & LV_TXT_FLAG_EXPAND) max_width = LV_COORD_MAX;\n\n    uint32_t i = 0;\n    lv_coord_t cur_w = 0;\n    lv_coord_t w_at_last_break = 0;\n    uint32_t n_char_since_last_break = 0; /* Used count word length of long words */\n    uint32_t last_break = NO_BREAK_FOUND;\n    lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT;\n    uint32_t letter = 0;\n\n    while(txt[i] != '\\0') {\n        lv_coord_t letter_width;\n        letter = lv_txt_encoded_next(txt, &i);\n\n        /*Handle the recolor command*/\n        if((flag & LV_TXT_FLAG_RECOLOR) != 0) {\n            if(lv_txt_is_cmd(&cmd_state, letter) != false) {\n                continue;   /*Skip the letter is it is part of a command*/\n            }\n        }\n\n\n        /*Check for new line chars*/\n        if(letter == '\\n' || letter == '\\r') {\n            uint32_t i_tmp = i;\n            uint32_t letter_next = lv_txt_encoded_next(txt, &i_tmp);\n            if(letter == '\\r' &&  letter_next == '\\n') i = i_tmp;\n\n            return i;    /*Return with the first letter of the next line*/\n\n        } else { /*Check the actual length*/\n            n_char_since_last_break++;\n            letter_width = lv_font_get_width(font, letter);\n            cur_w += letter_width;\n\n            /* Get the length of the current work and determine best place\n             * to break the line. */\n            if(cur_w > max_width) {\n                if( last_break != NO_BREAK_FOUND ) {\n                    /* Continue searching for next breakable character to see if the next word will fit */\n                    uint32_t n_char_fit = n_char_since_last_break - 1;\n                    if(  n_char_since_last_break <= LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN ) {\n                        i = last_break;\n                    }\n                    else {\n                        uint32_t i_tmp = i;\n                        cur_w -= w_at_last_break + letter_space; /*ignore the first letter_space after the break char */\n                        bool other = true;\n                        while(txt[i_tmp] != '\\0') {\n                            letter = lv_txt_encoded_next(txt, &i_tmp);\n\n                            /*Handle the recolor command*/\n                            if((flag & LV_TXT_FLAG_RECOLOR) != 0) {\n                                if(lv_txt_is_cmd(&cmd_state, letter) != false) {\n                                    continue;   /*Skip the letter is it is part of a command*/\n                                }\n                            }\n\n                            /*Check for new line chars*/\n                            if(letter == '\\n' || letter == '\\r' || is_break_char(letter)) {\n                                if(n_char_since_last_break >= LV_TXT_LINE_BREAK_LONG_LEN) {\n                                    /* Figure out the prettiest place to break */\n                                    uint32_t char_remain;\n                                    lv_txt_encoded_prev(txt, &i);\n                                    for(char_remain=n_char_since_last_break - n_char_fit;\n                                            char_remain < LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN;\n                                            char_remain++) {\n                                        lv_txt_encoded_prev(txt, &i);\n                                    }\n                                }\n                                else{\n                                    i = last_break;\n                                }\n                                other = false;\n                                break;\n                            }\n                            n_char_since_last_break++;\n                            lv_coord_t letter_width2 = lv_font_get_width(font, letter);\n                            cur_w += letter_width2;\n                            if(cur_w > max_width) {\n                                /* Current letter already exceeds, return previous */\n                                lv_txt_encoded_prev(txt, &i);\n                                other = false;\n                                break;\n                            }\n                            if(letter_width2 > 0){\n                                cur_w += letter_space;\n                            }\n                        }\n                        if( other ) {\n                            if(n_char_since_last_break >= LV_TXT_LINE_BREAK_LONG_LEN) {\n                                /* Figure out the prettiest place to break */\n                                uint32_t char_remain;\n                                lv_txt_encoded_prev(txt, &i);\n                                for(char_remain=n_char_since_last_break - n_char_fit;\n                                        char_remain < LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN;\n                                        char_remain++){\n                                    lv_txt_encoded_prev(txt, &i);\n                                }\n                            }\n                            else{\n                                i = last_break;\n                            }\n                        }\n                    }\n                } else {\n                    /* Now this character is out of the area so it will be first character of the next line*/\n                    /* But 'i' already points to the next character (because of lv_txt_utf8_next) step beck one*/\n                    lv_txt_encoded_prev(txt, &i);\n                }\n\n                /* Do not let to return without doing nothing.\n                 * Find at least one character (Avoid infinite loop )*/\n                if(i == 0) lv_txt_encoded_next(txt, &i);\n\n                return i;\n            }\n            /*If this char still can fit to this line then check if\n             * txt can be broken here later */\n            else if(is_break_char(letter)) {\n                last_break = i; /*Save the first char index  after break*/\n                w_at_last_break = cur_w;\n                if(letter_width > 0) {\n                    w_at_last_break += letter_space;\n                }\n                n_char_since_last_break = 0;\n            }\n        }\n\n        if(letter_width > 0) {\n            cur_w += letter_space;\n        }\n    }\n\n    return i;\n}\n\n/**\n * Give the length of a text with a given font\n * @param txt a '\\0' terminate string\n * @param length length of 'txt' in byte count and not characters (Á is 1 character but 2 bytes in UTF-8)\n * @param font pointer to a font\n * @param letter_space letter space\n * @param flags settings for the text from 'txt_flag_t' enum\n * @return length of a char_num long text\n */\nlv_coord_t lv_txt_get_width(const char * txt, uint16_t length,\n                            const lv_font_t * font, lv_coord_t letter_space, lv_txt_flag_t flag)\n{\n    if(txt == NULL) return 0;\n    if(font == NULL) return 0;\n\n    uint32_t i = 0;\n    lv_coord_t width = 0;\n    lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT;\n    uint32_t letter;\n\n    if(length != 0) {\n        while(i< length){\n            letter = lv_txt_encoded_next(txt, &i);\n            if((flag & LV_TXT_FLAG_RECOLOR) != 0) {\n                if(lv_txt_is_cmd(&cmd_state, letter) != false) {\n                    continue;\n                }\n            }\n\n            lv_coord_t char_width = lv_font_get_width(font, letter);\n            if(char_width > 0){\n                width += char_width;\n                width += letter_space;\n            }\n        }\n\n        if(width > 0) {\n            width -= letter_space;  /*Trim the last letter space. Important if the text is center aligned */\n        }\n    }\n\n    return width;\n}\n\n/**\n * Check next character in a string and decide if the character is part of the command or not\n * @param state pointer to a txt_cmd_state_t variable which stores the current state of command processing\n *             (Initied. to TXT_CMD_STATE_WAIT )\n * @param c the current character\n * @return true: the character is part of a command and should not be written,\n *         false: the character should be written\n */\nbool lv_txt_is_cmd(lv_txt_cmd_state_t * state, uint32_t c)\n{\n    bool ret = false;\n\n    if(c == (uint32_t)LV_TXT_COLOR_CMD[0]) {\n        if(*state == LV_TXT_CMD_STATE_WAIT) { /*Start char*/\n            *state = LV_TXT_CMD_STATE_PAR;\n            ret = true;\n        } else if(*state == LV_TXT_CMD_STATE_PAR) { /*Other start char in parameter is escaped cmd. char */\n            *state = LV_TXT_CMD_STATE_WAIT;\n        } else if(*state == LV_TXT_CMD_STATE_IN) { /*Command end */\n            *state = LV_TXT_CMD_STATE_WAIT;\n            ret = true;\n        }\n    }\n\n    /*Skip the color parameter and wait the space after it*/\n    if(*state == LV_TXT_CMD_STATE_PAR) {\n        if(c == ' ') {\n            *state = LV_TXT_CMD_STATE_IN; /*After the parameter the text is in the command*/\n        }\n        ret = true;\n    }\n\n    return ret;\n}\n\n/**\n * Insert a string into an other\n * @param txt_buf the original text (must be big enough for the result text)\n * @param pos position to insert. Expressed in character index and not byte index (Different in UTF-8)\n *            0: before the original text, 1: after the first char etc.\n * @param ins_txt text to insert\n */\nvoid lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt)\n{\n    uint32_t old_len = strlen(txt_buf);\n    uint32_t ins_len = strlen(ins_txt);\n    uint32_t new_len = ins_len + old_len;\n#if LV_TXT_UTF8 != 0\n    pos = lv_txt_encoded_get_byte_id(txt_buf, pos);   /*Convert to byte index instead of letter index*/\n#endif\n    /*Copy the second part into the end to make place to text to insert*/\n    uint32_t i;\n    for(i = new_len; i >= pos + ins_len; i--) {\n        txt_buf[i] = txt_buf[i - ins_len];\n    }\n\n    /* Copy the text into the new space*/\n    memcpy(txt_buf + pos, ins_txt, ins_len);\n}\n\n/**\n * Delete a part of a string\n * @param txt string to modify\n * @param pos position where to start the deleting (0: before the first char, 1: after the first char etc.)\n * @param len number of characters to delete\n */\nvoid lv_txt_cut(char * txt, uint32_t pos, uint32_t len)\n{\n\n    uint32_t old_len = strlen(txt);\n#if LV_TXT_UTF8 != 0\n    pos = lv_txt_encoded_get_byte_id(txt, pos);   /*Convert to byte index instead of letter index*/\n    len = lv_txt_encoded_get_byte_id(&txt[pos], len);\n#endif\n\n    /*Copy the second part into the end to make place to text to insert*/\n    uint32_t i;\n    for(i = pos; i <= old_len - len; i++) {\n        txt[i] = txt[i + len];\n    }\n}\n\n\n/*******************************\n *   UTF-8 ENCODER/DECOER\n ******************************/\n\n#if LV_TXT_UTF8\n\n/**\n * Give the size of an UTF-8 coded character\n * @param str pointer to a character in a string\n * @return length of the UTF-8 character (1,2,3 or 4). O on invalid code\n */\nstatic uint8_t lv_txt_utf8_size(const char * str)\n{\n    if((str[0] & 0x80) == 0) return 1;\n    else if((str[0] & 0xE0) == 0xC0) return 2;\n    else if((str[0] & 0xF0) == 0xE0) return 3;\n    else if((str[0] & 0xF8) == 0xF0) return 4;\n    return 0;\n}\n\n\n/**\n * Convert an Unicode letter to UTF-8.\n * @param letter_uni an Unicode letter\n * @return UTF-8 coded character in Little Endian to be compatible with C chars (e.g. 'Á', 'Ű')\n */\nstatic uint32_t lv_txt_unicode_to_utf8(uint32_t letter_uni)\n{\n    if(letter_uni < 128) return letter_uni;\n    uint8_t bytes[4];\n\n    if(letter_uni < 0x0800) {\n        bytes[0] = ((letter_uni >> 6)  & 0x1F) | 0xC0;\n        bytes[1] = ((letter_uni >> 0)  & 0x3F) | 0x80;\n        bytes[2] = 0;\n        bytes[3] = 0;\n    } else if(letter_uni < 0x010000) {\n        bytes[0] = ((letter_uni >> 12) & 0x0F) | 0xE0;\n        bytes[1] = ((letter_uni >> 6)  & 0x3F) | 0x80;\n        bytes[2] = ((letter_uni >> 0)  & 0x3F) | 0x80;\n        bytes[3] = 0;\n    } else if(letter_uni < 0x110000) {\n        bytes[0] = ((letter_uni >> 18) & 0x07) | 0xF0;\n        bytes[1] = ((letter_uni >> 12) & 0x3F) | 0x80;\n        bytes[2] = ((letter_uni >> 6)  & 0x3F) | 0x80;\n        bytes[3] = ((letter_uni >> 0)  & 0x3F) | 0x80;\n    }\n\n    uint32_t * res_p = (uint32_t *)bytes;\n    return *res_p;\n}\n\n/**\n * Convert a wide character, e.g. 'Á' little endian to be UTF-8 compatible\n * @param c a wide character or a  Little endian number\n * @return `c` in big endian\n */\nstatic uint32_t lv_txt_utf8_conv_wc(uint32_t c)\n{\n    /*Swap the bytes (UTF-8 is big endian, but the MCUs are little endian)*/\n    if((c & 0x80) != 0) {\n        uint32_t swapped;\n        uint8_t c8[4];\n        memcpy(c8, &c, 4);\n        swapped = (c8[0] << 24) + (c8[1] << 16) + (c8[2] << 8) + (c8[3]);\n        uint8_t i;\n        for(i = 0; i < 4; i++) {\n            if((swapped & 0xFF) == 0) swapped = (swapped >> 8); /*Ignore leading zeros (they were in the end originally)*/\n        }\n        c = swapped;\n    }\n\n    return c;\n}\n\n/**\n * Decode an UTF-8 character from a string.\n * @param txt pointer to '\\0' terminated string\n * @param i start byte index in 'txt' where to start.\n *          After call it will point to the next UTF-8 char in 'txt'.\n *          NULL to use txt[0] as index\n * @return the decoded Unicode character or 0 on invalid UTF-8 code\n */\nstatic uint32_t lv_txt_utf8_next(const char * txt, uint32_t * i)\n{\n    /* Unicode to UTF-8\n     * 00000000 00000000 00000000 0xxxxxxx -> 0xxxxxxx\n     * 00000000 00000000 00000yyy yyxxxxxx -> 110yyyyy 10xxxxxx\n     * 00000000 00000000 zzzzyyyy yyxxxxxx -> 1110zzzz 10yyyyyy 10xxxxxx\n     * 00000000 000wwwzz zzzzyyyy yyxxxxxx -> 11110www 10zzzzzz 10yyyyyy 10xxxxxx\n     * */\n\n    uint32_t result = 0;\n\n    /*Dummy 'i' pointer is required*/\n    uint32_t i_tmp = 0;\n    if(i == NULL) i = &i_tmp;\n\n    /*Normal ASCII*/\n    if((txt[*i] & 0x80) == 0) {\n        result = txt[*i];\n        (*i)++;\n    }\n    /*Real UTF-8 decode*/\n    else {\n        /*2 bytes UTF-8 code*/\n        if((txt[*i] & 0xE0) == 0xC0) {\n            result = (uint32_t)(txt[*i] & 0x1F) << 6;\n            (*i)++;\n            if((txt[*i] & 0xC0) != 0x80) return 0;  /*Invalid UTF-8 code*/\n            result += (txt[*i] & 0x3F);\n            (*i)++;\n        }\n        /*3 bytes UTF-8 code*/\n        else if((txt[*i] & 0xF0) == 0xE0) {\n            result = (uint32_t)(txt[*i] & 0x0F) << 12;\n            (*i)++;\n\n            if((txt[*i] & 0xC0) != 0x80) return 0;  /*Invalid UTF-8 code*/\n            result += (uint32_t)(txt[*i] & 0x3F) << 6;\n            (*i)++;\n\n            if((txt[*i] & 0xC0) != 0x80) return 0;  /*Invalid UTF-8 code*/\n            result += (txt[*i] & 0x3F);\n            (*i)++;\n        }\n        /*4 bytes UTF-8 code*/\n        else if((txt[*i] & 0xF8) == 0xF0) {\n            result = (uint32_t)(txt[*i] & 0x07) << 18;\n            (*i)++;\n\n            if((txt[*i] & 0xC0) != 0x80) return 0;  /*Invalid UTF-8 code*/\n            result += (uint32_t)(txt[*i] & 0x3F) << 12;\n            (*i)++;\n\n            if((txt[*i] & 0xC0) != 0x80) return 0;  /*Invalid UTF-8 code*/\n            result += (uint32_t)(txt[*i] & 0x3F) << 6;\n            (*i)++;\n\n            if((txt[*i] & 0xC0) != 0x80) return 0;  /*Invalid UTF-8 code*/\n            result += txt[*i] & 0x3F;\n            (*i)++;\n        } else {\n            (*i)++; /*Not UTF-8 char. Go the next.*/\n        }\n    }\n    return result;\n}\n\n/**\n * Get previous UTF-8 character form a string.\n * @param txt pointer to '\\0' terminated string\n * @param i start byte index in 'txt' where to start. After the call it will point to the previous UTF-8 char in 'txt'.\n * @return the decoded Unicode character or 0 on invalid UTF-8 code\n */\nstatic uint32_t lv_txt_utf8_prev(const char * txt, uint32_t * i)\n{\n    uint8_t c_size;\n    uint8_t cnt = 0;\n\n    /*Try to find a !0 long UTF-8 char by stepping one character back*/\n    (*i)--;\n    do {\n        if(cnt >= 4) return 0;      /*No UTF-8 char found before the initial*/\n\n        c_size = lv_txt_encoded_size(&txt[*i]);\n        if(c_size == 0) {\n            if(*i != 0)(*i)--;\n            else return 0;\n        }\n        cnt++;\n    } while(c_size == 0);\n\n    uint32_t i_tmp = *i;\n    uint32_t letter = lv_txt_encoded_next(txt, &i_tmp);   /*Character found, get it*/\n\n    return letter;\n\n}\n\n/**\n * Convert a character index (in an UTF-8 text) to byte index.\n * E.g. in \"AÁRT\" index of 'R' is 2th char but start at byte 3 because 'Á' is 2 bytes long\n * @param txt a '\\0' terminated UTF-8 string\n * @param utf8_id character index\n * @return byte index of the 'utf8_id'th letter\n */\nstatic uint32_t lv_txt_utf8_get_byte_id(const char * txt, uint32_t utf8_id)\n{\n    uint32_t i;\n    uint32_t byte_cnt = 0;\n    for(i = 0; i < utf8_id; i++) {\n        byte_cnt += lv_txt_encoded_size(&txt[byte_cnt]);\n    }\n\n    return byte_cnt;\n\n}\n\n\n/**\n * Convert a byte index (in an UTF-8 text) to character index.\n * E.g. in \"AÁRT\" index of 'R' is 2th char but start at byte 3 because 'Á' is 2 bytes long\n * @param txt a '\\0' terminated UTF-8 string\n * @param byte_id byte index\n * @return character index of the letter at 'byte_id'th position\n */\nstatic uint32_t lv_txt_utf8_get_char_id(const char * txt, uint32_t byte_id)\n{\n    uint32_t i = 0;\n    uint32_t char_cnt = 0;\n\n    while(i < byte_id) {\n        lv_txt_encoded_next(txt, &i); /*'i' points to the next letter so use the prev. value*/\n        char_cnt++;\n    }\n\n    return char_cnt;\n}\n\n/**\n * Get the number of characters (and NOT bytes) in a string. Decode it with UTF-8 if enabled.\n * E.g.: \"ÁBC\" is 3 characters (but 4 bytes)\n * @param txt a '\\0' terminated char string\n * @return number of characters\n */\nstatic uint32_t lv_txt_utf8_get_length(const char * txt)\n{\n#if LV_TXT_UTF8 == 0\n    return strlen(txt);\n#else\n    uint32_t len = 0;\n    uint32_t i = 0;\n\n    while(txt[i] != '\\0') {\n        lv_txt_encoded_next(txt, &i);\n        len++;\n    }\n\n    return len;\n#endif\n}\n\n#else\n/**\n * Give the size of an UTF-8 coded character\n * @param str pointer to a character in a string\n * @return length of the UTF-8 character (1,2,3 or 4). O on invalid code\n */\nstatic uint8_t lv_txt_ascii_size(const char * str)\n{\n    return 1;\n}\n\n\n/**\n * Convert an Unicode letter to UTF-8.\n * @param letter_uni an Unicode letter\n * @return UTF-8 coded character in Little Endian to be compatible with C chars (e.g. 'Á', 'Ű')\n */\nstatic uint32_t lv_txt_unicode_to_ascii(uint32_t letter_uni)\n{\n    if(letter_uni < 128) return letter_uni;\n    else return ' ';\n}\n\n/**\n * Convert wide characters to ASCII, however wide characters in ASCII range (e.g. 'A') are ASCII compatible by default.\n * So this function does nothing just returns with `c`.\n * @param c a character, e.g. 'A'\n * @return same as `c`\n */\nstatic uint32_t lv_txt_ascii_conv_wc(uint32_t c)\n{\n    return c;\n}\n\n/**\n * Decode an UTF-8 character from a string.\n * @param txt pointer to '\\0' terminated string\n * @param i start byte index in 'txt' where to start.\n *          After call it will point to the next UTF-8 char in 'txt'.\n *          NULL to use txt[0] as index\n * @return the decoded Unicode character or 0 on invalid UTF-8 code\n */\nstatic uint32_t lv_txt_ascii_next(const char * txt, uint32_t * i)\n{\n    if(i == NULL) return txt[1];    /*Get the next char */\n\n    uint8_t letter = txt[*i] ;\n    (*i)++;\n    return letter;\n}\n\n/**\n * Get previous UTF-8 character form a string.\n * @param txt pointer to '\\0' terminated string\n * @param i start byte index in 'txt' where to start. After the call it will point to the previous UTF-8 char in 'txt'.\n * @return the decoded Unicode character or 0 on invalid UTF-8 code\n */\nstatic uint32_t lv_txt_ascii_prev(const char * txt, uint32_t * i)\n{\n    if(i == NULL) return *(txt - 1);   /*Get the prev. char */\n\n    (*i)--;\n    uint8_t letter = txt[*i] ;\n\n    return letter;\n}\n\n/**\n * Convert a character index (in an UTF-8 text) to byte index.\n * E.g. in \"AÁRT\" index of 'R' is 2th char but start at byte 3 because 'Á' is 2 bytes long\n * @param txt a '\\0' terminated UTF-8 string\n * @param utf8_id character index\n * @return byte index of the 'utf8_id'th letter\n */\nstatic uint32_t lv_txt_ascii_get_byte_id(const char * txt, uint32_t utf8_id)\n{\n    return utf8_id;     /*In Non encoded no difference*/\n}\n\n\n/**\n * Convert a byte index (in an UTF-8 text) to character index.\n * E.g. in \"AÁRT\" index of 'R' is 2th char but start at byte 3 because 'Á' is 2 bytes long\n * @param txt a '\\0' terminated UTF-8 string\n * @param byte_id byte index\n * @return character index of the letter at 'byte_id'th position\n */\nstatic uint32_t lv_txt_ascii_get_char_id(const char * txt, uint32_t byte_id)\n{\n    return byte_id;     /*In Non encoded no difference*/\n}\n\n/**\n * Get the number of characters (and NOT bytes) in a string. Decode it with UTF-8 if enabled.\n * E.g.: \"ÁBC\" is 3 characters (but 4 bytes)\n * @param txt a '\\0' terminated char string\n * @return number of characters\n */\nstatic uint32_t lv_txt_ascii_get_length(const char * txt)\n{\n    return strlen(txt);\n}\n#endif\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Test if char is break char or not (a text can broken here or not)\n * @param letter a letter\n * @return false: 'letter' is not break char\n */\nstatic bool is_break_char(uint32_t letter)\n{\n    uint8_t i;\n    bool ret = false;\n\n    /*Compare the letter to TXT_BREAK_CHARS*/\n    for(i = 0; LV_TXT_BREAK_CHARS[i] != '\\0'; i++) {\n        if(letter == (uint32_t)LV_TXT_BREAK_CHARS[i]) {\n            ret = true; /*If match then it is break char*/\n            break;\n        }\n    }\n\n    return ret;\n}\n\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_txt.h",
    "content": "/**\n * @file lv_text.h\n *\n */\n\n#ifndef LV_TXT_H\n#define LV_TXT_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#include \"lv_area.h\"\n#include \"lv_font.h\"\n#include \"lv_area.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_TXT_COLOR_CMD  \"#\"\n\n/**********************\n *      TYPEDEFS\n **********************/\nenum\n{\n    LV_TXT_FLAG_NONE =     0x00,\n    LV_TXT_FLAG_RECOLOR =  0x01,   /*Enable parsing of recolor command*/\n    LV_TXT_FLAG_EXPAND =   0x02,   /*Ignore width to avoid automatic word wrapping*/\n    LV_TXT_FLAG_CENTER =   0x04,   /*Align the text to the middle*/\n    LV_TXT_FLAG_RIGHT  =   0x08,   /*Align the text to the right*/\n};\ntypedef uint8_t lv_txt_flag_t;\n\nenum\n{\n    LV_TXT_CMD_STATE_WAIT,      /*Waiting for command*/\n    LV_TXT_CMD_STATE_PAR,       /*Processing the parameter*/\n    LV_TXT_CMD_STATE_IN,        /*Processing the command*/\n};\ntypedef uint8_t lv_txt_cmd_state_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Get size of a text\n * @param size_res pointer to a 'point_t' variable to store the result\n * @param text pointer to a text\n * @param font pinter to font of the text\n * @param letter_space letter space of the text\n * @param line_space line space of the text\n * @param flags settings for the text from 'txt_flag_t' enum\n * @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks\n */\nvoid lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * font,\n                     lv_coord_t letter_space, lv_coord_t line_space, lv_coord_t max_width, lv_txt_flag_t flag);\n\n/**\n * Get the next line of text. Check line length and break chars too.\n * @param txt a '\\0' terminated string\n * @param font pointer to a font\n * @param letter_space letter space\n * @param max_width max with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks\n * @param flags settings for the text from 'txt_flag_type' enum\n * @return the index of the first char of the new line (in byte index not letter index. With UTF-8 they are different)\n */\nuint16_t lv_txt_get_next_line(const char * txt, const lv_font_t * font,\n                              lv_coord_t letter_space, lv_coord_t max_width, lv_txt_flag_t flag);\n\n/**\n * Give the length of a text with a given font\n * @param txt a '\\0' terminate string\n * @param length length of 'txt' in byte count and not characters (Á is 1 character but 2 bytes in UTF-8)\n * @param font pointer to a font\n * @param letter_space letter space\n * @param flags settings for the text from 'txt_flag_t' enum\n * @return length of a char_num long text\n */\nlv_coord_t lv_txt_get_width(const char * txt, uint16_t length,\n                            const lv_font_t * font, lv_coord_t letter_space, lv_txt_flag_t flag);\n\n\n/**\n * Check next character in a string and decide if te character is part of the command or not\n * @param state pointer to a txt_cmd_state_t variable which stores the current state of command processing\n * @param c the current character\n * @return true: the character is part of a command and should not be written,\n *         false: the character should be written\n */\nbool lv_txt_is_cmd(lv_txt_cmd_state_t * state, uint32_t c);\n\n/**\n * Insert a string into an other\n * @param txt_buf the original text (must be big enough for the result text)\n * @param pos position to insert (0: before the original text, 1: after the first char etc.)\n * @param ins_txt text to insert\n */\nvoid lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt);\n\n/**\n * Delete a part of a string\n * @param txt string to modify\n * @param pos position where to start the deleting (0: before the first char, 1: after the first char etc.)\n * @param len number of characters to delete\n */\nvoid lv_txt_cut(char * txt, uint32_t pos, uint32_t len);\n\n/***************************************************************\n *  GLOBAL FUNCTION POINTERS FOR CAHRACTER ENCODING INTERFACE\n ***************************************************************/\n\n/**\n * Give the size of an encoded character\n * @param str pointer to a character in a string\n * @return length of the encoded character (1,2,3 ...). O in invalid\n */\nextern uint8_t (*lv_txt_encoded_size)(const char *);\n\n\n/**\n * Convert an Unicode letter to encoded\n * @param letter_uni an Unicode letter\n * @return Encoded character in Little Endian to be compatible with C chars (e.g. 'Á', 'Ü')\n */\nextern uint32_t (*lv_txt_unicode_to_encoded)(uint32_t );\n\n/**\n * Convert a wide character, e.g. 'Á' little endian to be compatible with the encoded format.\n * @param c a wide character\n * @return `c` in the encoded format\n */\nextern uint32_t (*lv_txt_encoded_conv_wc) (uint32_t c);\n\n/**\n * Decode the next encoded character from a string.\n * @param txt pointer to '\\0' terminated string\n * @param i start index in 'txt' where to start.\n *                After the call it will point to the next encoded char in 'txt'.\n *                NULL to use txt[0] as index\n * @return the decoded Unicode character or 0 on invalid data code\n */\nextern uint32_t (*lv_txt_encoded_next)(const char *, uint32_t * );\n\n/**\n * Get the previous encoded character form a string.\n * @param txt pointer to '\\0' terminated string\n * @param i_start index in 'txt' where to start. After the call it will point to the previous encoded char in 'txt'.\n * @return the decoded Unicode character or 0 on invalid data\n */\nextern uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *);\n\n/**\n * Convert a letter index (in an the encoded text) to byte index.\n * E.g. in UTF-8 \"AÁRT\" index of 'R' is 2 but start at byte 3 because 'Á' is 2 bytes long\n * @param txt a '\\0' terminated UTF-8 string\n * @param enc_id letter index\n * @return byte index of the 'enc_id'th letter\n */\nextern uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t);\n\n/**\n * Convert a byte index (in an encoded text) to character index.\n * E.g. in UTF-8 \"AÁRT\" index of 'R' is 2 but start at byte 3 because 'Á' is 2 bytes long\n * @param txt a '\\0' terminated UTF-8 string\n * @param byte_id byte index\n * @return character index of the letter at 'byte_id'th position\n */\nextern uint32_t (*lv_encoded_get_char_id)(const char *, uint32_t);\n\n/**\n * Get the number of characters (and NOT bytes) in a string.\n * E.g. in UTF-8 \"ÁBC\" is 3 characters (but 4 bytes)\n * @param txt a '\\0' terminated char string\n * @return number of characters\n */\nextern uint32_t (*lv_txt_get_encoded_length)(const char *);\n\n/**********************\n *      MACROS\n **********************/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*USE_TXT*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_ufs.c",
    "content": "/**\n * @file lv_ufs.c\n * Implementation of RAM file system which do NOT support directories.\n * The API is compatible with the lv_fs_int module.\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_ufs.h\"\n#if USE_LV_FILESYSTEM\n\n#include \"lv_ll.h\"\n#include <string.h>\n#include <stdio.h>\n#include <errno.h>\n#include \"lv_gc.h\"\n\n#if defined(LV_GC_INCLUDE)\n#   include LV_GC_INCLUDE\n#endif /* LV_ENABLE_GC */\n\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic lv_ufs_ent_t * lv_ufs_ent_get(const char * fn);\nstatic lv_ufs_ent_t * lv_ufs_ent_new(const char * fn);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic bool inited = false;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a driver for ufs and initialize it.\n */\nvoid lv_ufs_init(void)\n{\n    lv_ll_init(&LV_GC_ROOT(_lv_file_ll), sizeof(lv_ufs_ent_t));\n\n    lv_fs_drv_t ufs_drv;\n    memset(&ufs_drv, 0, sizeof(lv_fs_drv_t));    /*Initialization*/\n\n    ufs_drv.file_size = sizeof(lv_ufs_file_t);\n    ufs_drv.rddir_size = sizeof(lv_ufs_dir_t);\n    ufs_drv.letter = UFS_LETTER;\n    ufs_drv.ready = lv_ufs_ready;\n\n    ufs_drv.open = lv_ufs_open;\n    ufs_drv.close = lv_ufs_close;\n    ufs_drv.remove = lv_ufs_remove;\n    ufs_drv.read = lv_ufs_read;\n    ufs_drv.write = lv_ufs_write;\n    ufs_drv.seek = lv_ufs_seek;\n    ufs_drv.tell = lv_ufs_tell;\n    ufs_drv.size = lv_ufs_size;\n    ufs_drv.trunc = lv_ufs_trunc;\n    ufs_drv.free = lv_ufs_free;\n\n    ufs_drv.dir_open = lv_ufs_dir_open;\n    ufs_drv.dir_read = lv_ufs_dir_read;\n    ufs_drv.dir_close = lv_ufs_dir_close;\n\n    lv_fs_add_drv(&ufs_drv);\n\n    inited = true;\n}\n\n/**\n * Give the state of the ufs\n * @return true if ufs is initialized and can be used else false\n */\nbool lv_ufs_ready(void)\n{\n    return inited;\n}\n\n/**\n * Open a file in ufs\n * @param file_p pointer to a lv_ufs_file_t variable\n * @param fn name of the file. There are no directories so e.g. \"myfile.txt\"\n * @param mode element of 'fs_mode_t' enum or its 'OR' connection (e.g. FS_MODE_WR | FS_MODE_RD)\n * @return LV_FS_RES_OK: no error, the file is opened\n *         any error from lv__fs_res_t enum\n */\nlv_fs_res_t lv_ufs_open(void * file_p, const char * fn, lv_fs_mode_t mode)\n{\n    lv_ufs_file_t * fp = file_p;    /*Convert type*/\n    lv_ufs_ent_t * ent = lv_ufs_ent_get(fn);\n\n    fp->ent = NULL;\n\n    /*If the file not exists ...*/\n    if(ent == NULL) {\n        if((mode & LV_FS_MODE_WR) != 0) {  /*Create the file if opened for write*/\n            ent = lv_ufs_ent_new(fn);\n            if(ent == NULL) return LV_FS_RES_FULL; /*No space for the new file*/\n        } else {\n            return LV_FS_RES_NOT_EX;       /*Can not read not existing file*/\n        }\n    }\n\n    /*Can not write already opened and const data files*/\n    if((mode & LV_FS_MODE_WR) != 0) {\n        if(ent->oc != 0) return LV_FS_RES_LOCKED;\n        if(ent->const_data != 0) return LV_FS_RES_DENIED;\n    }\n\n    /*No error, the file can be opened*/\n    fp->ent = ent;\n    fp->ar = mode & LV_FS_MODE_RD ? 1 : 0;\n    fp->aw = mode & LV_FS_MODE_WR ? 1 : 0;\n    fp->rwp = 0;\n    ent->oc ++;\n\n    return LV_FS_RES_OK;\n}\n\n\n/**\n * Create a file with a constant data\n * @param fn name of the file (directories are not supported)\n * @param const_p pointer to a constant data\n * @param len length of the data pointed by 'const_p' in bytes\n * @return LV_FS_RES_OK: no error, the file is read\n *         any error from lv__fs_res_t enum\n */\nlv_fs_res_t lv_ufs_create_const(const char * fn, const void * const_p, uint32_t len)\n{\n    lv_ufs_file_t file;\n    lv_fs_res_t res;\n\n    /*Error if the file already exists*/\n    res = lv_ufs_open(&file, fn, LV_FS_MODE_RD);\n    if(res == LV_FS_RES_OK) {\n        lv_ufs_close(&file);\n        return LV_FS_RES_DENIED;\n    }\n\n    lv_ufs_close(&file);\n\n    res = lv_ufs_open(&file, fn, LV_FS_MODE_WR);\n    if(res != LV_FS_RES_OK) return res;\n\n    lv_ufs_ent_t * ent = file.ent;\n\n    if(ent->data_d != NULL) return LV_FS_RES_DENIED;\n\n    ent->data_d = (void *) const_p;\n    ent->size = len;\n    ent->const_data = 1;\n\n    res = lv_ufs_close(&file);\n    if(res != LV_FS_RES_OK) return res;\n\n    return LV_FS_RES_OK;\n}\n\n/**\n * Close an opened file\n * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open)\n * @return LV_FS_RES_OK: no error, the file is read\n *         any error from lv__fs_res_t enum\n */\nlv_fs_res_t lv_ufs_close(void * file_p)\n{\n    lv_ufs_file_t * fp = file_p;    /*Convert type*/\n\n    if(fp->ent == NULL) return LV_FS_RES_OK;\n\n    /*Decrement the Open counter*/\n    if(fp->ent->oc > 0) {\n        fp->ent->oc--;\n    }\n\n    return LV_FS_RES_OK;\n}\n\n/**\n * Remove a file. The file can not be opened.\n * @param fn '\\0' terminated string\n * @return LV_FS_RES_OK: no error, the file is removed\n *         LV_FS_RES_DENIED: the file was opened, remove failed\n */\nlv_fs_res_t lv_ufs_remove(const char * fn)\n{\n    lv_ufs_ent_t * ent = lv_ufs_ent_get(fn);\n    if(ent == NULL) return LV_FS_RES_DENIED;    /*File not exists*/\n\n    /*Can not be deleted is opened*/\n    if(ent->oc != 0) return LV_FS_RES_DENIED;\n\n    lv_ll_rem(&LV_GC_ROOT(_lv_file_ll), ent);\n    lv_mem_free(ent->fn_d);\n    ent->fn_d = NULL;\n    if(ent->const_data == 0) {\n        lv_mem_free(ent->data_d);\n        ent->data_d = NULL;\n    }\n\n    lv_mem_free(ent);\n\n    return LV_FS_RES_OK;\n}\n\n/**\n * Read data from an opened file\n * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open )\n * @param buf pointer to a memory block where to store the read data\n * @param btr number of Bytes To Read\n * @param br the real number of read bytes (Byte Read)\n * @return LV_FS_RES_OK: no error, the file is read\n *         any error from lv__fs_res_t enum\n */\nlv_fs_res_t lv_ufs_read(void * file_p, void * buf, uint32_t btr, uint32_t * br)\n{\n    lv_ufs_file_t * fp = file_p;    /*Convert type*/\n\n    lv_ufs_ent_t * ent = fp->ent;\n    *br = 0;\n\n    if(ent->data_d == NULL || ent->size == 0) { /*Don't read empty files*/\n        return LV_FS_RES_OK;\n    } else if(fp->ar == 0) {    /*The file is not opened for read*/\n        return LV_FS_RES_DENIED;\n    }\n\n    /*No error, read the file*/\n    if(fp->rwp + btr > ent->size) {  /*Check too much bytes read*/\n        *br =  ent->size - fp->rwp;\n    } else {\n        *br = btr;\n    }\n\n    /*Read the data*/\n    uint8_t * data8_p;\n    if(ent->const_data == 0) {\n        data8_p = (uint8_t *) ent->data_d;\n    } else {\n        data8_p = ent->data_d;\n    }\n\n    data8_p += fp->rwp;\n    memcpy(buf, data8_p, *br);\n\n    fp->rwp += *br; /*Refresh the read write pointer*/\n\n    return LV_FS_RES_OK;\n}\n\n/**\n * Write data to an opened file\n * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open)\n * @param buf pointer to a memory block which content will be written\n * @param btw the number Bytes To Write\n * @param bw The real number of written bytes (Byte Written)\n * @return LV_FS_RES_OK: no error, the file is read\n *         any error from lv__fs_res_t enum\n */\nlv_fs_res_t lv_ufs_write(void * file_p, const void * buf, uint32_t btw, uint32_t * bw)\n{\n    lv_ufs_file_t * fp = file_p;    /*Convert type*/\n    *bw = 0;\n\n    if(fp->aw == 0) return LV_FS_RES_DENIED; /*Not opened for write*/\n\n    lv_ufs_ent_t * ent = fp->ent;\n\n    /*Reallocate data array if it necessary*/\n    uint32_t new_size = fp->rwp + btw;\n    if(new_size > ent->size) {\n        uint8_t * new_data = lv_mem_realloc(ent->data_d, new_size);\n        lv_mem_assert(new_data);\n        if(new_data == NULL) return LV_FS_RES_FULL; /*Cannot allocate the new memory*/\n\n        ent->data_d = new_data;\n        ent->size = new_size;\n    }\n\n    /*Write the file*/\n    uint8_t * data8_p = (uint8_t *) ent->data_d;\n    data8_p += fp->rwp;\n    memcpy(data8_p, buf, btw);\n    *bw = btw;\n    fp->rwp += *bw;\n\n    return LV_FS_RES_OK;\n}\n\n/**\n * Set the read write pointer. Also expand the file size if necessary.\n * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open )\n * @param pos the new position of read write pointer\n * @return LV_FS_RES_OK: no error, the file is read\n *         any error from lv__fs_res_t enum\n */\nlv_fs_res_t lv_ufs_seek(void * file_p, uint32_t pos)\n{\n    lv_ufs_file_t * fp = file_p;    /*Convert type*/\n    lv_ufs_ent_t * ent = fp->ent;\n\n    /*Simply move the rwp before EOF*/\n    if(pos < ent->size) {\n        fp->rwp = pos;\n    } else { /*Expand the file size*/\n        if(fp->aw == 0) return LV_FS_RES_DENIED;       /*Not opened for write*/\n\n        uint8_t * new_data = lv_mem_realloc(ent->data_d, pos);\n        lv_mem_assert(new_data);\n        if(new_data == NULL) return LV_FS_RES_FULL; /*Out of memory*/\n\n        ent->data_d = new_data;\n        ent->size = pos;\n        fp->rwp = pos;\n    }\n\n    return LV_FS_RES_OK;\n}\n\n/**\n * Give the position of the read write pointer\n * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open )\n * @param pos_p pointer to to store the result\n * @return LV_FS_RES_OK: no error, the file is read\n *         any error from lv__fs_res_t enum\n */\nlv_fs_res_t lv_ufs_tell(void * file_p, uint32_t * pos_p)\n{\n    lv_ufs_file_t * fp = file_p;    /*Convert type*/\n\n    *pos_p = fp->rwp;\n\n    return LV_FS_RES_OK;\n}\n\n/**\n * Truncate the file size to the current position of the read write pointer\n * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open )\n * @return LV_FS_RES_OK: no error, the file is read\n *         any error from lv__fs_res_t enum\n */\nlv_fs_res_t lv_ufs_trunc(void * file_p)\n{\n    lv_ufs_file_t * fp = file_p;    /*Convert type*/\n    lv_ufs_ent_t * ent = fp->ent;\n\n    if(fp->aw == 0) return LV_FS_RES_DENIED; /*Not opened for write*/\n\n    void * new_data = lv_mem_realloc(ent->data_d, fp->rwp);\n    lv_mem_assert(new_data);\n    if(new_data == NULL) return LV_FS_RES_FULL; /*Out of memory*/\n\n    ent->data_d = new_data;\n    ent->size = fp->rwp;\n\n    return LV_FS_RES_OK;\n}\n\n/**\n * Give the size of the file in bytes\n * @param file_p file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open )\n * @param size_p pointer to store the size\n * @return LV_FS_RES_OK: no error, the file is read\n *         any error from lv__fs_res_t enum\n */\nlv_fs_res_t lv_ufs_size(void * file_p, uint32_t * size_p)\n{\n    lv_ufs_file_t * fp = file_p;    /*Convert type*/\n    lv_ufs_ent_t * ent = fp->ent;\n\n    *size_p = ent->size;\n\n    return LV_FS_RES_OK;\n}\n\n/**\n * Initialize a lv_ufs_read_dir_t variable to directory reading\n * @param rddir_p pointer to a 'ufs_dir_t' variable\n * @param path uFS doesn't support folders so it has to be \"\"\n * @return LV_FS_RES_OK or any error from lv__fs_res_t enum\n */\nlv_fs_res_t lv_ufs_dir_open(void * rddir_p, const char * path)\n{\n    lv_ufs_dir_t * lv_ufs_rddir_p = rddir_p;\n\n    lv_ufs_rddir_p->last_ent = NULL;\n\n    if(path[0] != '\\0') return LV_FS_RES_NOT_EX;       /*Must be \"\" */\n    else return LV_FS_RES_OK;\n}\n\n/**\n * Read the next file name\n * @param dir_p pointer to an initialized 'ufs_dir_t' variable\n * @param fn pointer to buffer to sore the file name\n * @return LV_FS_RES_OK or any error from lv__fs_res_t enum\n */\nlv_fs_res_t lv_ufs_dir_read(void * dir_p, char * fn)\n{\n    lv_ufs_dir_t * ufs_dir_p = dir_p;\n\n    if(ufs_dir_p->last_ent == NULL) {\n        ufs_dir_p->last_ent = lv_ll_get_head(&LV_GC_ROOT(_lv_file_ll));\n    } else {\n        ufs_dir_p->last_ent = lv_ll_get_next(&LV_GC_ROOT(_lv_file_ll), ufs_dir_p->last_ent);\n    }\n\n    if(ufs_dir_p->last_ent != NULL) {\n        strcpy(fn, ufs_dir_p->last_ent->fn_d);\n    } else {\n        fn[0] = '\\0';\n    }\n\n    return LV_FS_RES_OK;\n}\n\n/**\n * Close the directory reading\n * @param rddir_p pointer to an initialized 'ufs_dir_t' variable\n * @return LV_FS_RES_OK or any error from lv__fs_res_t enum\n */\nlv_fs_res_t lv_ufs_dir_close(void * rddir_p)\n{\n    (void)rddir_p;\n    return LV_FS_RES_OK;\n}\n\n/**\n * Give the size of a drive\n * @param total_p pointer to store the total size [kB]\n * @param free_p pointer to store the free site [kB]\n * @return LV_FS_RES_OK or any error from 'lv_fs_res_t'\n */\nlv_fs_res_t lv_ufs_free(uint32_t * total_p, uint32_t * free_p)\n{\n\n#if LV_MEM_CUSTOM == 0\n    lv_mem_monitor_t mon;\n\n    lv_mem_monitor(&mon);\n    *total_p = LV_MEM_SIZE >> 10;    /*Convert bytes to kB*/\n    *free_p = mon.free_size >> 10;\n#else\n    *free_p = 0;\n#endif\n    return LV_FS_RES_OK;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Gives the lv_ufs_entry from a filename\n * @param fn filename ('\\0' terminated string)\n * @return pointer to the dynamically allocated entry with 'fn' filename.\n *         NULL if no entry found with that name.\n */\nstatic lv_ufs_ent_t * lv_ufs_ent_get(const char * fn)\n{\n    lv_ufs_ent_t * fp;\n\n    LL_READ(LV_GC_ROOT(_lv_file_ll), fp) {\n        if(strcmp(fp->fn_d, fn) == 0) {\n            return fp;\n        }\n    }\n\n    return NULL;\n}\n\n/**\n * Create a new entry with 'fn' filename\n * @param fn filename ('\\0' terminated string)\n * @return pointer to the dynamically allocated new entry.\n *         NULL if no space for the entry.\n */\nstatic lv_ufs_ent_t * lv_ufs_ent_new(const char * fn)\n{\n    lv_ufs_ent_t * new_ent = NULL;\n    new_ent = lv_ll_ins_head(&LV_GC_ROOT(_lv_file_ll));                 /*Create a new file*/\n    lv_mem_assert(new_ent);\n    if(new_ent == NULL) return NULL;\n\n    new_ent->fn_d = lv_mem_alloc(strlen(fn)  + 1); /*Save the name*/\n    lv_mem_assert(new_ent->fn_d);\n    if(new_ent->fn_d == NULL) return NULL;\n\n    strcpy(new_ent->fn_d, fn);\n    new_ent->data_d = NULL;\n    new_ent->size = 0;\n    new_ent->oc = 0;\n    new_ent->const_data = 0;\n\n    return new_ent;\n}\n\n#endif /*USE_LV_FILESYSTEM*/\n\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_misc/lv_ufs.h",
    "content": "/**\n * @file lv_ufs.h\n * Implementation of RAM file system which do NOT support directories.\n * The API is compatible with the lv_fs_int module.\n */\n\n#ifndef LV_UFS_H\n#define LV_UFS_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_FILESYSTEM\n\n#include \"lv_fs.h\"\n#include \"lv_mem.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define UFS_LETTER 'U'\n\n/**********************\n *      TYPEDEFS\n **********************/\n/*Description of a file entry */\ntypedef struct\n{\n    char * fn_d;\n    void * data_d;\n    uint32_t size;  /*Data length in bytes*/\n    uint16_t oc;    /*Open Count*/\n    uint8_t const_data :1;\n} lv_ufs_ent_t;\n\n/*File descriptor, used to handle opening an entry more times simultaneously\n Contains unique informations about the specific opening*/\ntypedef struct\n{\n    lv_ufs_ent_t* ent; /*Pointer to the entry*/\n    uint32_t rwp;   /*Read Write Pointer*/\n    uint8_t ar :1;  /*1: Access for read is enabled */\n    uint8_t aw :1;  /*1: Access for write is enabled */\n} lv_ufs_file_t;\n\n/* Read directory descriptor.\n * It is used to to iterate through the entries in a directory*/\ntypedef struct\n{\n    lv_ufs_ent_t * last_ent;\n} lv_ufs_dir_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a driver for ufs and initialize it.\n */\nvoid lv_ufs_init(void);\n\n/**\n * Give the state of the ufs\n * @return true if ufs is initialized and can be used else false\n */\nbool lv_ufs_ready(void);\n\n/**\n * Open a file in ufs\n * @param file_p pointer to a lv_ufs_file_t variable\n * @param fn name of the file. There are no directories so e.g. \"myfile.txt\"\n * @param mode element of 'fs_mode_t' enum or its 'OR' connection (e.g. FS_MODE_WR | FS_MODE_RD)\n * @return LV_FS_RES_OK: no error, the file is opened\n *         any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_ufs_open (void * file_p, const char * fn, lv_fs_mode_t mode);\n\n/**\n * Create a file with a constant data\n * @param fn name of the file (directories are not supported)\n * @param const_p pointer to a constant data\n * @param len length of the data pointed by 'const_p' in bytes\n * @return LV_FS_RES_OK: no error, the file is read\n *         any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_ufs_create_const(const char * fn, const void * const_p, uint32_t len);\n\n/**\n * Close an opened file\n * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open)\n * @return LV_FS_RES_OK: no error, the file is read\n *         any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_ufs_close (void * file_p);\n\n/**\n * Remove a file. The file can not be opened.\n * @param fn '\\0' terminated string\n * @return LV_FS_RES_OK: no error, the file is removed\n *         LV_FS_RES_DENIED: the file was opened, remove failed\n */\nlv_fs_res_t lv_ufs_remove(const char * fn);\n\n/**\n * Read data from an opened file\n * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open )\n * @param buf pointer to a memory block where to store the read data\n * @param btr number of Bytes To Read\n * @param br the real number of read bytes (Byte Read)\n * @return LV_FS_RES_OK: no error, the file is read\n *         any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_ufs_read (void * file_p, void * buf, uint32_t btr, uint32_t * br);\n\n/**\n * Write data to an opened file\n * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open)\n * @param buf pointer to a memory block which content will be written\n * @param btw the number Bytes To Write\n * @param bw The real number of written bytes (Byte Written)\n * @return LV_FS_RES_OK: no error, the file is read\n *         any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_ufs_write (void * file_p, const void * buf, uint32_t btw, uint32_t * bw);\n\n/**\n * Set the read write pointer. Also expand the file size if necessary.\n * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open )\n * @param pos the new position of read write pointer\n * @return LV_FS_RES_OK: no error, the file is read\n *         any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_ufs_seek (void * file_p, uint32_t pos);\n\n/**\n * Give the position of the read write pointer\n * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open )\n * @param pos_p pointer to to store the result\n * @return LV_FS_RES_OK: no error, the file is read\n *         any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_ufs_tell (void * file_p, uint32_t * pos_p);\n\n/**\n * Truncate the file size to the current position of the read write pointer\n * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open )\n * @return LV_FS_RES_OK: no error, the file is read\n *         any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_ufs_trunc (void * file_p);\n\n/**\n * Give the size of the file in bytes\n * @param file_p file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open )\n * @param size_p pointer to store the size\n * @return LV_FS_RES_OK: no error, the file is read\n *         any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_ufs_size (void * file_p, uint32_t * size_p);\n\n/**\n * Initialize a lv_ufs_read_dir_t variable to directory reading\n * @param rddir_p pointer to a 'ufs_read_dir_t' variable\n * @param path uFS doesn't support folders so it has to be \"\"\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_ufs_dir_open(void * rddir_p, const char * path);\n\n/**\n * Read the next file name\n * @param dir_p pointer to an initialized 'ufs_read_dir_t' variable\n * @param fn pointer to buffer to sore the file name\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_ufs_dir_read(void * dir_p, char * fn);\n\n/**\n * Close the directory reading\n * @param rddir_p pointer to an initialized 'ufs_read_dir_t' variable\n * @return LV_FS_RES_OK or any error from lv_fs_res_t enum\n */\nlv_fs_res_t lv_ufs_dir_close(void * rddir_p);\n\n/**\n * Give the size of a drive\n * @param total_p pointer to store the total size [kB]\n * @param free_p pointer to store the free site [kB]\n * @return LV_FS_RES_OK or any error from 'fs_res_t'\n */\nlv_fs_res_t lv_ufs_free (uint32_t * total_p, uint32_t * free_p);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif /*USE_LV_FILESYSTEM*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_arc.c",
    "content": "/**\n * @file lv_arc.c\n *\n */\n\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_arc.h\"\n#if USE_LV_ARC != 0\n\n#include \"../lv_misc/lv_math.h\"\n#include \"../lv_draw/lv_draw_arc.h\"\n#include \"../lv_themes/lv_theme.h\"\n\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool lv_arc_design(lv_obj_t * arc, const lv_area_t * mask, lv_design_mode_t mode);\nstatic lv_res_t lv_arc_signal(lv_obj_t * arc, lv_signal_t sign, void * param);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\nstatic lv_design_func_t ancestor_design;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a arc object\n * @param par pointer to an object, it will be the parent of the new arc\n * @param copy pointer to a arc object, if not NULL then the new object will be copied from it\n * @return pointer to the created arc\n */\nlv_obj_t * lv_arc_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n\n    LV_LOG_TRACE(\"arc create started\");\n\n    /*Create the ancestor of arc*/\n    lv_obj_t * new_arc = lv_obj_create(par, copy);\n    lv_mem_assert(new_arc);\n    if(new_arc == NULL) return NULL;\n\n    /*Allocate the arc type specific extended data*/\n    lv_arc_ext_t * ext = lv_obj_allocate_ext_attr(new_arc, sizeof(lv_arc_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_arc);\n    if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_arc);\n\n    /*Initialize the allocated 'ext' */\n    ext->angle_start = 45;\n    ext->angle_end = 315;\n\n    /*The signal and design functions are not copied so set them here*/\n    lv_obj_set_signal_func(new_arc, lv_arc_signal);\n    lv_obj_set_design_func(new_arc, lv_arc_design);\n\n    /*Init the new arc arc*/\n    if(copy == NULL) {\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_arc_set_style(new_arc, LV_ARC_STYLE_MAIN, th->arc);\n        } else {\n            lv_arc_set_style(new_arc, LV_ARC_STYLE_MAIN, &lv_style_plain_color);\n        }\n\n    }\n    /*Copy an existing arc*/\n    else {\n        lv_arc_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        ext->angle_start = copy_ext->angle_start;\n        ext->angle_end = copy_ext->angle_end;\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_arc);\n    }\n\n    LV_LOG_INFO(\"arc created\");\n\n    return new_arc;\n}\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n/*\n * New object specific \"add\" or \"remove\" functions come here\n */\n\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set the start and end angles of an arc. 0 deg: bottom, 90 deg: right etc.\n * @param arc pointer to an arc object\n * @param start the start angle [0..360]\n * @param end the end angle [0..360]\n */\nvoid lv_arc_set_angles(lv_obj_t * arc, uint16_t start, uint16_t end)\n{\n    lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);\n\n    if(start > 360) start = 360;\n    if(end > 360) end = 360;\n\n    ext->angle_start = start;\n    ext->angle_end = end;\n\n    lv_obj_invalidate(arc);\n}\n\n/**\n * Set a style of a arc.\n * @param arc pointer to arc object\n * @param type which style should be set\n * @param style pointer to a style\n *  */\nvoid lv_arc_set_style(lv_obj_t * arc, lv_arc_style_t type, lv_style_t * style)\n{\n    switch(type) {\n        case LV_ARC_STYLE_MAIN:\n            lv_obj_set_style(arc, style);\n            break;\n    }\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the start angle of an arc.\n * @param arc pointer to an arc object\n * @return the start angle [0..360]\n */\nuint16_t lv_arc_get_angle_start(lv_obj_t * arc)\n{\n    lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);\n\n    return ext->angle_start;\n}\n\n/**\n * Get the end angle of an arc.\n * @param arc pointer to an arc object\n * @return the end angle [0..360]\n */\nuint16_t lv_arc_get_angle_end(lv_obj_t * arc)\n{\n    lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);\n\n    return ext->angle_end;\n}\n\n/**\n * Get style of a arc.\n * @param arc pointer to arc object\n * @param type which style should be get\n * @return style pointer to the style\n *  */\nlv_style_t * lv_arc_get_style(const lv_obj_t * arc, lv_arc_style_t type)\n{\n    lv_style_t * style = NULL;\n\n    switch(type) {\n        case LV_ARC_STYLE_MAIN:\n            style = lv_obj_get_style(arc);\n            break;\n        default:\n            style = NULL;\n            break;\n    }\n\n    return style;\n}\n\n/*=====================\n * Other functions\n *====================*/\n\n/*\n * New object specific \"other\" functions come here\n */\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Handle the drawing related tasks of the arcs\n * @param arc pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_arc_design(lv_obj_t * arc, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    /*Return false if the object is not covers the mask_p area*/\n    if(mode == LV_DESIGN_COVER_CHK) {\n        return false;\n    }\n    /*Draw the object*/\n    else if(mode == LV_DESIGN_DRAW_MAIN) {\n        lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);\n        lv_style_t * style = lv_arc_get_style(arc, LV_ARC_STYLE_MAIN);\n\n        lv_coord_t r = (LV_MATH_MIN(lv_obj_get_width(arc), lv_obj_get_height(arc))) / 2;\n        lv_coord_t x = arc->coords.x1 + lv_obj_get_width(arc) / 2;\n        lv_coord_t y = arc->coords.y1 + lv_obj_get_height(arc) / 2;\n        lv_opa_t opa_scale = lv_obj_get_opa_scale(arc);\n        lv_draw_arc(x, y, r, mask, ext->angle_start, ext->angle_end, style, opa_scale);\n\n\n        /*Draw circle on the ends if enabled */\n        if(style->line.rounded) {\n            lv_coord_t thick_half = style->line.width / 2;\n            lv_coord_t cir_x = ((r - thick_half) * lv_trigo_sin(ext->angle_start) >> LV_TRIGO_SHIFT);\n            lv_coord_t cir_y = ((r - thick_half) * lv_trigo_sin(ext->angle_start + 90) >> LV_TRIGO_SHIFT);\n\n            lv_style_t cir_style;\n            lv_style_copy(&cir_style, &lv_style_plain);\n            cir_style.body.grad_color = style->line.color;\n            cir_style.body.main_color = cir_style.body.grad_color;\n            cir_style.body.radius = LV_RADIUS_CIRCLE;\n            lv_area_t cir_area;\n            cir_area.x1 = cir_x + x - thick_half;\n            cir_area.y1 = cir_y + y - thick_half;\n            cir_area.x2 = cir_x + x + thick_half;\n            cir_area.y2 = cir_y + y + thick_half;\n\n            lv_draw_rect(&cir_area, mask, &cir_style, opa_scale);\n\n            cir_x = ((r - thick_half) * lv_trigo_sin(ext->angle_end) >> LV_TRIGO_SHIFT);\n            cir_y = ((r - thick_half) * lv_trigo_sin(ext->angle_end + 90) >> LV_TRIGO_SHIFT);\n\n            cir_area.x1 = cir_x + x - thick_half;\n            cir_area.y1 = cir_y + y - thick_half;\n            cir_area.x2 = cir_x + x + thick_half;\n            cir_area.y2 = cir_y + y + thick_half;\n\n            lv_draw_rect(&cir_area, mask, &cir_style, opa_scale);\n        }\n\n    }\n    /*Post draw when the children are drawn*/\n    else if(mode == LV_DESIGN_DRAW_POST) {\n\n    }\n\n    return true;\n}\n\n/**\n * Signal function of the arc\n * @param arc pointer to a arc object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_arc_signal(lv_obj_t * arc, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(arc, sign, param);\n    if(res != LV_RES_OK) return res;\n\n\n    if(sign == LV_SIGNAL_CLEANUP) {\n        /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_arc\";\n    }\n\n    return res;\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_arc.h",
    "content": "/**\n * @file lv_arc.h\n *\n */\n\n\n#ifndef LV_ARC_H\n#define LV_ARC_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_ARC != 0\n\n#include \"../lv_core/lv_obj.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n/*Data of arc*/\ntypedef struct {\n    /*New data for this type */\n    lv_coord_t angle_start;\n    lv_coord_t angle_end;\n} lv_arc_ext_t;\n\n\n/*Styles*/\nenum {\n    LV_ARC_STYLE_MAIN,\n};\ntypedef uint8_t lv_arc_style_t;\n\n\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a arc objects\n * @param par pointer to an object, it will be the parent of the new arc\n * @param copy pointer to a arc object, if not NULL then the new object will be copied from it\n * @return pointer to the created arc\n */\nlv_obj_t * lv_arc_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set the start and end angles of an arc. 0 deg: bottom, 90 deg: right etc.\n * @param arc pointer to an arc object\n * @param start the start angle [0..360]\n * @param end the end angle [0..360]\n */\nvoid lv_arc_set_angles(lv_obj_t * arc, uint16_t start, uint16_t end);\n\n/**\n * Set a style of a arc.\n * @param arc pointer to arc object\n * @param type which style should be set\n * @param style pointer to a style\n *  */\nvoid lv_arc_set_style(lv_obj_t * arc, lv_arc_style_t type, lv_style_t *style);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the start angle of an arc.\n * @param arc pointer to an arc object\n * @return the start angle [0..360]\n */\nuint16_t lv_arc_get_angle_start(lv_obj_t * arc);\n\n/**\n * Get the end angle of an arc.\n * @param arc pointer to an arc object\n * @return the end angle [0..360]\n */\nuint16_t lv_arc_get_angle_end(lv_obj_t * arc);\n\n/**\n * Get style of a arc.\n * @param arc pointer to arc object\n * @param type which style should be get\n * @return style pointer to the style\n *  */\nlv_style_t * lv_arc_get_style(const lv_obj_t * arc, lv_arc_style_t type);\n\n/*=====================\n * Other functions\n *====================*/\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_ARC*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_ARC_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_bar.c",
    "content": "\n\n/**\n * @file lv_bar.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_bar.h\"\n#if USE_LV_BAR != 0\n\n#include \"../lv_draw/lv_draw.h\"\n#include \"../lv_themes/lv_theme.h\"\n#include \"../lv_misc/lv_anim.h\"\n#include <stdio.h>\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool lv_bar_design(lv_obj_t * bar, const lv_area_t * mask, lv_design_mode_t mode);\nstatic lv_res_t lv_bar_signal(lv_obj_t * bar, lv_signal_t sign, void * param);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_design_func_t ancestor_design_f;\nstatic lv_signal_func_t ancestor_signal;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a bar objects\n * @param par pointer to an object, it will be the parent of the new bar\n * @param copy pointer to a bar object, if not NULL then the new object will be copied from it\n * @return pointer to the created bar\n */\nlv_obj_t * lv_bar_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"lv_bar create started\");\n\n    /*Create the ancestor basic object*/\n    lv_obj_t * new_bar = lv_obj_create(par, copy);\n    lv_mem_assert(new_bar);\n    if(new_bar == NULL) return NULL;\n\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_bar);\n    if(ancestor_design_f == NULL) ancestor_design_f = lv_obj_get_design_func(new_bar);\n\n    /*Allocate the object type specific extended data*/\n    lv_bar_ext_t * ext = lv_obj_allocate_ext_attr(new_bar, sizeof(lv_bar_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    ext->min_value = 0;\n    ext->max_value = 100;\n    ext->cur_value = 0;\n    ext->sym = 0;\n    ext->style_indic = &lv_style_pretty_color;\n\n    lv_obj_set_signal_func(new_bar, lv_bar_signal);\n    lv_obj_set_design_func(new_bar, lv_bar_design);\n\n    /*Init the new  bar object*/\n    if(copy == NULL) {\n        lv_obj_set_click(new_bar, false);\n        lv_obj_set_size(new_bar, LV_DPI * 2, LV_DPI / 3);\n        lv_bar_set_value(new_bar, ext->cur_value);\n\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_bar_set_style(new_bar, LV_BAR_STYLE_BG, th->bar.bg);\n            lv_bar_set_style(new_bar, LV_BAR_STYLE_INDIC, th->bar.indic);\n        } else {\n            lv_obj_set_style(new_bar, &lv_style_pretty);\n        }\n    } else {\n        lv_bar_ext_t * ext_copy = lv_obj_get_ext_attr(copy);\n        ext->min_value = ext_copy->min_value;\n        ext->max_value = ext_copy->max_value;\n        ext->cur_value = ext_copy->cur_value;\n        ext->style_indic = ext_copy->style_indic;\n        ext->sym = ext_copy->sym;\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_bar);\n\n        lv_bar_set_value(new_bar, ext->cur_value);\n    }\n\n    LV_LOG_INFO(\"bar created\");\n\n    return new_bar;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a new value on the bar\n * @param bar pointer to a bar object\n * @param value new value\n */\nvoid lv_bar_set_value(lv_obj_t * bar, int16_t value)\n{\n    lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);\n    if(ext->cur_value == value) return;\n\n    ext->cur_value = value > ext->max_value ? ext->max_value : value;\n    ext->cur_value = ext->cur_value < ext->min_value ? ext->min_value : ext->cur_value;\n    lv_obj_invalidate(bar);\n}\n\n#if USE_LV_ANIMATION\n/**\n * Set a new value with animation on the bar\n * @param bar pointer to a bar object\n * @param value new value\n * @param anim_time animation time in milliseconds\n */\nvoid lv_bar_set_value_anim(lv_obj_t * bar, int16_t value, uint16_t anim_time)\n{\n    lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);\n    if(ext->cur_value == value) return;\n\n    int16_t new_value;\n    new_value = value > ext->max_value ? ext->max_value : value;\n    new_value = new_value < ext->min_value ? ext->min_value : new_value;\n\n    lv_anim_t a;\n    a.var = bar;\n    a.start = ext->cur_value;\n    a.end = new_value;\n    a.fp = (lv_anim_fp_t)lv_bar_set_value;\n    a.path = lv_anim_path_linear;\n    a.end_cb = NULL;\n    a.act_time = 0;\n    a.time = anim_time;\n    a.playback = 0;\n    a.playback_pause = 0;\n    a.repeat = 0;\n    a.repeat_pause = 0;\n\n    lv_anim_create(&a);\n}\n#endif\n\n\n/**\n * Set minimum and the maximum values of a bar\n * @param bar pointer to the bar object\n * @param min minimum value\n * @param max maximum value\n */\nvoid lv_bar_set_range(lv_obj_t * bar, int16_t min, int16_t max)\n{\n    lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);\n    if(ext->min_value == min && ext->max_value == max) return;\n\n    ext->max_value = max;\n    ext->min_value = min;\n    if(ext->cur_value > max) {\n        ext->cur_value = max;\n        lv_bar_set_value(bar, ext->cur_value);\n    }\n    if(ext->cur_value < min) {\n        ext->cur_value = min;\n        lv_bar_set_value(bar, ext->cur_value);\n    }\n    lv_obj_invalidate(bar);\n}\n\n/**\n * Make the bar symmetric to zero. The indicator will grow from zero instead of the minimum position.\n * @param bar pointer to a bar object\n * @param en true: enable disable symmetric behavior; false: disable\n */\nvoid lv_bar_set_sym(lv_obj_t * bar, bool en)\n{\n    lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);\n    ext->sym = en ? 1 : 0;\n}\n\n/**\n * Set a style of a bar\n * @param bar pointer to a bar object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_bar_set_style(lv_obj_t * bar, lv_bar_style_t type, lv_style_t * style)\n{\n    lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);\n\n    switch(type) {\n        case LV_BAR_STYLE_BG:\n            lv_obj_set_style(bar, style);\n            break;\n        case LV_BAR_STYLE_INDIC:\n            ext->style_indic = style;\n            lv_obj_refresh_ext_size(bar);\n            break;\n    }\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the value of a bar\n * @param bar pointer to a bar object\n * @return the value of the bar\n */\nint16_t lv_bar_get_value(const lv_obj_t * bar)\n{\n    lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);\n    return ext->cur_value;\n}\n\n/**\n * Get the minimum value of a bar\n * @param bar pointer to a bar object\n * @return the minimum value of the bar\n */\nint16_t lv_bar_get_min_value(const lv_obj_t * bar)\n{\n    lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);\n    return ext->min_value;\n}\n\n/**\n * Get the maximum value of a bar\n * @param bar pointer to a bar object\n * @return the maximum value of the bar\n */\nint16_t lv_bar_get_max_value(const lv_obj_t * bar)\n{\n    lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);\n    return ext->max_value;\n}\n\n/**\n * Get whether the bar is symmetric or not.\n * @param bar pointer to a bar object\n * @return true: symmetric is enabled; false: disable\n */\nbool lv_bar_get_sym(lv_obj_t * bar)\n{\n    lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);\n    return ext->sym ? true : false;\n}\n\n/**\n * Get a style of a bar\n * @param bar pointer to a bar object\n * @param type which style should be get\n * @return style pointer to a style\n */\nlv_style_t * lv_bar_get_style(const lv_obj_t * bar, lv_bar_style_t type)\n{\n    lv_style_t * style = NULL;\n    lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);\n\n    switch(type) {\n        case LV_BAR_STYLE_BG:\n            style = lv_obj_get_style(bar);\n            break;\n        case LV_BAR_STYLE_INDIC:\n            style = ext->style_indic;\n            break;\n        default:\n            style = NULL;\n            break;\n    }\n\n    return style;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Handle the drawing related tasks of the bars\n * @param bar pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_bar_design(lv_obj_t * bar, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    if(mode == LV_DESIGN_COVER_CHK) {\n        /*Return false if the object is not covers the mask area*/\n        return  ancestor_design_f(bar, mask, mode);\n    } else if(mode == LV_DESIGN_DRAW_MAIN) {\n        lv_opa_t opa_scale = lv_obj_get_opa_scale(bar);\n\n#if USE_LV_GROUP == 0\n        ancestor_design_f(bar, mask, mode);\n#else\n        /* Draw the borders later if the bar is focused.\n         * At value = 100% the indicator can cover to whole background and the focused style won't be visible*/\n        if(lv_obj_is_focused(bar)) {\n            lv_style_t * style_bg = lv_bar_get_style(bar, LV_BAR_STYLE_BG);\n            lv_style_t style_tmp;\n            lv_style_copy(&style_tmp, style_bg);\n            style_tmp.body.border.width = 0;\n            lv_draw_rect(&bar->coords, mask, &style_tmp, opa_scale);\n        } else {\n            ancestor_design_f(bar, mask, mode);\n        }\n#endif\n        lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);\n\n        if(ext->cur_value != ext->min_value || ext->sym) {\n            lv_style_t * style_indic = lv_bar_get_style(bar, LV_BAR_STYLE_INDIC);\n            lv_area_t indic_area;\n            lv_area_copy(&indic_area, &bar->coords);\n            indic_area.x1 += style_indic->body.padding.hor;\n            indic_area.x2 -= style_indic->body.padding.hor;\n            indic_area.y1 += style_indic->body.padding.ver;\n            indic_area.y2 -= style_indic->body.padding.ver;\n\n            lv_coord_t w = lv_area_get_width(&indic_area);\n            lv_coord_t h = lv_area_get_height(&indic_area);\n\n            if(w >= h) {\n                /*Horizontal*/\n                indic_area.x2 = (int32_t)((int32_t)w * (ext->cur_value - ext->min_value)) / (ext->max_value - ext->min_value);\n                indic_area.x2 = indic_area.x1 + indic_area.x2 - 1;\n\n                if(ext->sym && ext->min_value < 0 && ext->max_value > 0) {\n                    /*Calculate the coordinate of the zero point*/\n                    lv_coord_t zero;\n                    zero = indic_area.x1 + (-ext->min_value * w) / (ext->max_value - ext->min_value);\n                    if(indic_area.x2 > zero) indic_area.x1 = zero;\n                    else {\n                        indic_area.x1 = indic_area.x2;\n                        indic_area.x2 = zero;\n                    }\n                }\n            } else {\n                indic_area.y1 = (int32_t)((int32_t)h * (ext->cur_value - ext->min_value)) / (ext->max_value - ext->min_value);\n                indic_area.y1 = indic_area.y2 - indic_area.y1 + 1;\n\n                if(ext->sym && ext->min_value < 0 && ext->max_value > 0) {\n                    /*Calculate the coordinate of the zero point*/\n                    lv_coord_t zero;\n                    zero = indic_area.y2 - (-ext->min_value * h) / (ext->max_value - ext->min_value);\n                    if(indic_area.y1 < zero) indic_area.y2 = zero;\n                    else {\n                        indic_area.y2 = indic_area.y1;\n                        indic_area.y1 = zero;\n                    }\n                }\n            }\n\n\n            /*Draw the indicator*/\n            lv_draw_rect(&indic_area, mask, style_indic, opa_scale);\n        }\n    } else if(mode == LV_DESIGN_DRAW_POST) {\n#if USE_LV_GROUP\n        /*Draw the border*/\n        if(lv_obj_is_focused(bar)) {\n            lv_opa_t opa_scale = lv_obj_get_opa_scale(bar);\n            lv_style_t * style_bg = lv_bar_get_style(bar, LV_BAR_STYLE_BG);\n            lv_style_t style_tmp;\n            lv_style_copy(&style_tmp, style_bg);\n            style_tmp.body.empty = 1;\n            style_tmp.body.shadow.width = 0;\n            lv_draw_rect(&bar->coords, mask, &style_tmp, opa_scale);\n        }\n#endif\n\n    }\n    return true;\n}\n\n/**\n * Signal function of the bar\n * @param bar pointer to a bar object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_bar_signal(lv_obj_t * bar, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(bar, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    if(sign == LV_SIGNAL_REFR_EXT_SIZE) {\n        lv_style_t * style_indic = lv_bar_get_style(bar, LV_BAR_STYLE_INDIC);\n        if(style_indic->body.shadow.width > bar->ext_size) bar->ext_size = style_indic->body.shadow.width;\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_bar\";\n    }\n\n    return res;\n}\n\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_bar.h",
    "content": "/**\n * @file lv_bar.h\n *\n */\n\n#ifndef LV_BAR_H\n#define LV_BAR_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_BAR != 0\n\n#include \"../lv_core/lv_obj.h\"\n#include \"lv_cont.h\"\n#include \"lv_btn.h\"\n#include \"lv_label.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/*Data of bar*/\ntypedef struct\n{\n    /*No inherited ext*/            /*Ext. of ancestor*/\n    /*New data for this type */\n    int16_t cur_value;              /*Current value of the bar*/\n    int16_t min_value;              /*Minimum value of the bar*/\n    int16_t max_value;              /*Maximum value of the bar*/\n    uint8_t sym    :1;              /*Symmetric: means the center is around zero value*/\n    lv_style_t *style_indic;        /*Style of the indicator*/\n} lv_bar_ext_t;\n\nenum {\n    LV_BAR_STYLE_BG,\n    LV_BAR_STYLE_INDIC,\n};\ntypedef uint8_t lv_bar_style_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a bar objects\n * @param par pointer to an object, it will be the parent of the new bar\n * @param copy pointer to a bar object, if not NULL then the new object will be copied from it\n * @return pointer to the created bar\n */\nlv_obj_t * lv_bar_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a new value on the bar\n * @param bar pointer to a bar object\n * @param value new value\n */\nvoid lv_bar_set_value(lv_obj_t * bar, int16_t value);\n\n/**\n * Set a new value with animation on the bar\n * @param bar pointer to a bar object\n * @param value new value\n * @param anim_time animation time in milliseconds\n */\nvoid lv_bar_set_value_anim(lv_obj_t * bar, int16_t value, uint16_t anim_time);\n\n\n/**\n * Set minimum and the maximum values of a bar\n * @param bar pointer to the bar object\n * @param min minimum value\n * @param max maximum value\n */\nvoid lv_bar_set_range(lv_obj_t * bar, int16_t min, int16_t max);\n\n/**\n * Make the bar symmetric to zero. The indicator will grow from zero instead of the minimum position.\n * @param bar pointer to a bar object\n * @param en true: enable disable symmetric behavior; false: disable\n */\nvoid lv_bar_set_sym(lv_obj_t * bar, bool en);\n\n/**\n * Set a style of a bar\n * @param bar pointer to a bar object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_bar_set_style(lv_obj_t *bar, lv_bar_style_t type, lv_style_t *style);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the value of a bar\n * @param bar pointer to a bar object\n * @return the value of the bar\n */\nint16_t lv_bar_get_value(const lv_obj_t * bar);\n\n/**\n * Get the minimum value of a bar\n * @param bar pointer to a bar object\n * @return the minimum value of the bar\n */\nint16_t lv_bar_get_min_value(const lv_obj_t * bar);\n\n/**\n * Get the maximum value of a bar\n * @param bar pointer to a bar object\n * @return the maximum value of the bar\n */\nint16_t lv_bar_get_max_value(const lv_obj_t * bar);\n\n/**\n * Get whether the bar is symmetric or not.\n * @param bar pointer to a bar object\n * @return true: symmetric is enabled; false: disable\n */\nbool lv_bar_get_sym(lv_obj_t * bar);\n\n/**\n * Get a style of a bar\n * @param bar pointer to a bar object\n * @param type which style should be get\n * @return style pointer to a style\n */\nlv_style_t * lv_bar_get_style(const lv_obj_t *bar, lv_bar_style_t type);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_BAR*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_BAR_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_btn.c",
    "content": "/**\n * @file lv_btn.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n\n#include \"lv_btn.h\"\n#if USE_LV_BTN != 0\n\n#include <string.h>\n#include \"../lv_core/lv_group.h\"\n#include \"../lv_draw/lv_draw.h\"\n#include \"../lv_themes/lv_theme.h\"\n#include \"../lv_misc/lv_area.h\"\n#include \"../lv_misc/lv_color.h\"\n#include \"../lv_misc/lv_math.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_BTN_INK_VALUE_MAX            256\n#define LV_BTN_INK_VALUE_MAX_SHIFT      8\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool lv_btn_design(lv_obj_t * btn, const lv_area_t * mask, lv_design_mode_t mode);\nstatic lv_res_t lv_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param);\n\n#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT\nstatic void lv_btn_ink_effect_anim(lv_obj_t * btn, int32_t val);\nstatic void lv_btn_ink_effect_anim_ready(void * p);\n#endif\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\nstatic lv_design_func_t ancestor_design;\n\n#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT\nstatic lv_coord_t ink_act_value;\nstatic lv_obj_t * ink_obj;\nstatic lv_btn_state_t ink_bg_state;\nstatic lv_btn_state_t ink_top_state;\nstatic bool ink_ready;\nstatic bool ink_playback;\nstatic lv_point_t ink_point;\n#endif\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a button objects\n * @param par pointer to an object, it will be the parent of the new button\n * @param copy pointer to a button object, if not NULL then the new object will be copied from it\n * @return pointer to the created button\n */\nlv_obj_t * lv_btn_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"button create started\");\n\n    lv_obj_t * new_btn;\n\n    new_btn = lv_cont_create(par, copy);\n    lv_mem_assert(new_btn);\n    if(new_btn == NULL) return NULL;\n\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_btn);\n    if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_btn);\n\n    /*Allocate the extended data*/\n    lv_btn_ext_t * ext = lv_obj_allocate_ext_attr(new_btn, sizeof(lv_btn_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    ext->state = LV_BTN_STATE_REL;\n\n    ext->actions[LV_BTN_ACTION_PR] = NULL;\n    ext->actions[LV_BTN_ACTION_CLICK] = NULL;\n    ext->actions[LV_BTN_ACTION_LONG_PR] = NULL;\n    ext->actions[LV_BTN_ACTION_LONG_PR_REPEAT] = NULL;\n\n    ext->styles[LV_BTN_STATE_REL] = &lv_style_btn_rel;\n    ext->styles[LV_BTN_STATE_PR] = &lv_style_btn_pr;\n    ext->styles[LV_BTN_STATE_TGL_REL] = &lv_style_btn_tgl_rel;\n    ext->styles[LV_BTN_STATE_TGL_PR] = &lv_style_btn_tgl_pr;\n    ext->styles[LV_BTN_STATE_INA] = &lv_style_btn_ina;\n\n    ext->long_pr_action_executed = 0;\n    ext->toggle = 0;\n    ext->idx = 0;\n#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT\n    ext->ink_in_time = 0;\n    ext->ink_wait_time = 0;\n    ext->ink_out_time = 0;\n#endif\n\n    lv_obj_set_signal_func(new_btn, lv_btn_signal);\n    lv_obj_set_design_func(new_btn, lv_btn_design);\n\n    /*If no copy do the basic initialization*/\n    if(copy == NULL) {\n        /*Set layout if the button is not a screen*/\n        if(par != NULL) {\n            lv_btn_set_layout(new_btn, LV_LAYOUT_CENTER);\n        }\n\n        lv_obj_set_click(new_btn, true);        /*Be sure the button is clickable*/\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_btn_set_style(new_btn, LV_BTN_STYLE_REL, th->btn.rel);\n            lv_btn_set_style(new_btn, LV_BTN_STYLE_PR, th->btn.pr);\n            lv_btn_set_style(new_btn, LV_BTN_STYLE_TGL_REL, th->btn.tgl_rel);\n            lv_btn_set_style(new_btn, LV_BTN_STYLE_TGL_PR, th->btn.tgl_pr);\n            lv_btn_set_style(new_btn, LV_BTN_STYLE_INA, th->btn.ina);\n        } else {\n            lv_obj_set_style(new_btn, ext->styles[LV_BTN_STATE_REL]);\n        }\n    }\n    /*Copy 'copy'*/\n    else {\n        lv_btn_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        ext->state = copy_ext->state;\n        ext->toggle = copy_ext->toggle;\n#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT\n        ext->ink_in_time = copy_ext->ink_in_time;\n        ext->ink_wait_time = copy_ext->ink_wait_time;\n        ext->ink_out_time = copy_ext->ink_out_time;\n#endif\n        memcpy(ext->actions, copy_ext->actions, sizeof(ext->actions));\n        memcpy(ext->styles, copy_ext->styles, sizeof(ext->styles));\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_btn);\n    }\n\n    LV_LOG_INFO(\"button created\");\n\n    return new_btn;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Enable the toggled states\n * @param btn pointer to a button object\n * @param tgl true: enable toggled states, false: disable\n */\nvoid lv_btn_set_toggle(lv_obj_t * btn, bool tgl)\n{\n    lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);\n\n    ext->toggle = tgl != false ? 1 : 0;\n}\n\n/**\n * Set the state of the button\n * @param btn pointer to a button object\n * @param state the new state of the button (from lv_btn_state_t enum)\n */\nvoid lv_btn_set_state(lv_obj_t * btn, lv_btn_state_t state)\n{\n    lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);\n    if(ext->state != state) {\n        ext->state = state;\n        lv_obj_set_style(btn, ext->styles[state]);\n    }\n}\n\n/**\n * Toggle the state of the button (ON->OFF, OFF->ON)\n * @param btn pointer to a button object\n */\nvoid lv_btn_toggle(lv_obj_t * btn)\n{\n    lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);\n    switch(ext->state) {\n        case LV_BTN_STATE_REL:\n            lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);\n            break;\n        case LV_BTN_STATE_PR:\n            lv_btn_set_state(btn, LV_BTN_STATE_TGL_PR);\n            break;\n        case LV_BTN_STATE_TGL_REL:\n            lv_btn_set_state(btn, LV_BTN_STATE_REL);\n            break;\n        case LV_BTN_STATE_TGL_PR:\n            lv_btn_set_state(btn, LV_BTN_STATE_PR);\n            break;\n        default:\n            break;\n    }\n}\n\n/**\n * Set a function to call when a button event happens\n * @param btn pointer to a button object\n * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat)\n */\nvoid lv_btn_set_action(lv_obj_t * btn, lv_btn_action_t type, lv_action_t action)\n{\n    if(type >= LV_BTN_ACTION_NUM) return;\n\n    lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);\n    ext->actions[type] = action;\n}\n\n/**\n * Set time of the ink effect (draw a circle on click to animate in the new state)\n * @param btn pointer to a button object\n * @param time the time of the ink animation\n */\nvoid lv_btn_set_ink_in_time(lv_obj_t * btn, uint16_t time)\n{\n#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT\n    lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);\n    ext->ink_in_time = time;\n#else\n    (void)btn; /*Unused*/\n    (void)time; /*Unused*/\n    LV_LOG_WARN(\"`lv_btn_set_ink_ink_time` has no effect if LV_BTN_INK_EFEFCT or USE_LV_ANIMATION is disabled\")\n#endif\n}\n\n/**\n * Set the wait time before the ink disappears\n * @param btn pointer to a button object\n * @param time the time of the ink animation\n */\nvoid lv_btn_set_ink_wait_time(lv_obj_t * btn, uint16_t time)\n{\n\n#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT\n    lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);\n    ext->ink_wait_time = time;\n#else\n    (void)btn; /*Unused*/\n    (void)time; /*Unused*/\n    LV_LOG_WARN(\"`lv_btn_set_ink_wait_time` has no effect if LV_BTN_INK_EFEFCT or USE_LV_ANIMATION is disabled\")\n#endif\n}\n\n/**\n * Set time of the ink out effect (animate to the released state)\n * @param btn pointer to a button object\n * @param time the time of the ink animation\n */\nvoid lv_btn_set_ink_out_time(lv_obj_t * btn, uint16_t time)\n{\n#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT\n    lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);\n    ext->ink_out_time = time;\n#else\n    (void)btn; /*Unused*/\n    (void)time; /*Unused*/\n    LV_LOG_WARN(\"`lv_btn_set_ink_out_time` has no effect if LV_BTN_INK_EFEFCT or USE_LV_ANIMATION is disabled\")\n#endif\n}\n\n/**\n * Set a style of a button\n * @param btn pointer to a button object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_btn_set_style(lv_obj_t * btn, lv_btn_style_t type, lv_style_t * style)\n{\n    lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);\n\n    switch(type) {\n        case LV_BTN_STYLE_REL:\n            ext->styles[LV_BTN_STATE_REL] = style;\n            break;\n        case LV_BTN_STYLE_PR:\n            ext->styles[LV_BTN_STATE_PR] = style;\n            break;\n        case LV_BTN_STYLE_TGL_REL:\n            ext->styles[LV_BTN_STATE_TGL_REL] = style;\n            break;\n        case LV_BTN_STYLE_TGL_PR:\n            ext->styles[LV_BTN_STATE_TGL_PR] = style;\n            break;\n        case LV_BTN_STYLE_INA:\n            ext->styles[LV_BTN_STATE_INA] = style;\n            break;\n    }\n\n    /*Refresh the object with the new style*/\n    lv_obj_set_style(btn, ext->styles[ext->state]);\n}\n\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the current state of the button\n * @param btn pointer to a button object\n * @return the state of the button (from lv_btn_state_t enum)\n */\nlv_btn_state_t lv_btn_get_state(const lv_obj_t * btn)\n{\n    lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);\n    return ext->state;\n}\n\n/**\n * Get the toggle enable attribute of the button\n * @param btn pointer to a button object\n * @return ture: toggle enabled, false: disabled\n */\nbool lv_btn_get_toggle(const lv_obj_t * btn)\n{\n    lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);\n\n    return ext->toggle != 0 ? true : false;\n}\n\n/**\n * Get the release action of a button\n * @param btn pointer to a button object\n * @return pointer to the release action function\n */\nlv_action_t lv_btn_get_action(const lv_obj_t * btn, lv_btn_action_t type)\n{\n    if(type >= LV_BTN_ACTION_NUM) return NULL;\n\n    lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);\n    return ext->actions[type];\n}\n\n/**\n * Get time of the ink in effect (draw a circle on click to animate in the new state)\n * @param btn pointer to a button object\n * @return the time of the ink animation\n */\nuint16_t lv_btn_get_ink_in_time(const lv_obj_t * btn)\n{\n#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT\n    lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);\n    return ext->ink_in_time;\n#else\n    (void)btn; /*Unused*/\n    return 0;\n#endif\n}\n\n\n/**\n * Get the wait time before the ink disappears\n * @param btn pointer to a button object\n * @return the time of the ink animation\n */\nuint16_t lv_btn_get_ink_wait_time(const lv_obj_t * btn)\n{\n#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT\n    lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);\n    return ext->ink_wait_time;\n#else\n    (void)btn; /*Unused*/\n    return 0;\n#endif\n}\n/**\n * Get time of the ink out effect (animate to the releases state)\n * @param btn pointer to a button object\n * @return the time of the ink animation\n */\nuint16_t lv_btn_get_ink_out_time(const lv_obj_t * btn)\n{\n#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT\n    lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);\n    return ext->ink_in_time;\n#else\n    (void)btn; /*Unused*/\n    return 0;\n#endif\n}\n\n/**\n * Get a style of a button\n * @param btn pointer to a button object\n * @param type which style should be get\n * @return style pointer to a style\n */\nlv_style_t * lv_btn_get_style(const lv_obj_t * btn, lv_btn_style_t type)\n{\n    lv_style_t * style = NULL;\n    lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);\n\n    switch(type) {\n        case LV_BTN_STYLE_REL:\n            style = ext->styles[LV_BTN_STATE_REL];\n            break;\n        case LV_BTN_STYLE_PR:\n            style = ext->styles[LV_BTN_STATE_PR];\n            break;\n        case LV_BTN_STYLE_TGL_REL:\n            style = ext->styles[LV_BTN_STATE_TGL_REL];\n            break;\n        case LV_BTN_STYLE_TGL_PR:\n            style = ext->styles[LV_BTN_STATE_TGL_PR];\n            break;\n        case LV_BTN_STYLE_INA:\n            style = ext->styles[LV_BTN_STATE_INA];\n            break;\n        default:\n            style = NULL;\n            break;\n    }\n\n    return style;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n\n/**\n * Handle the drawing related tasks of the drop down lists\n * @param btn pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_btn_design(lv_obj_t * btn, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    if(mode == LV_DESIGN_COVER_CHK) {\n        return false;\n    } else if(mode == LV_DESIGN_DRAW_MAIN) {\n\n#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT\n        if(btn != ink_obj) {\n            ancestor_design(btn, mask, mode);\n        } else {\n            lv_opa_t opa_scale = lv_obj_get_opa_scale(btn);\n            lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);\n\n            /*Draw the normal button*/\n            if(ink_playback == false) {\n                lv_style_t style_tmp;\n                lv_style_copy(&style_tmp, ext->styles[ink_bg_state]);\n                style_tmp.body.shadow.width = ext->styles[ink_top_state]->body.shadow.width;\n                lv_draw_rect(&btn->coords, mask, &style_tmp, opa_scale);\n\n                lv_coord_t w = lv_obj_get_width(btn);\n                lv_coord_t h = lv_obj_get_height(btn);\n                lv_coord_t r_max = LV_MATH_MIN(w, h) / 2;\n\n                /*In the first part of the animation increase the size of the circle (ink effect) */\n                lv_area_t cir_area;\n\n                lv_coord_t coord_state = ink_act_value < LV_BTN_INK_VALUE_MAX / 2 ? ink_act_value : LV_BTN_INK_VALUE_MAX / 2;\n                lv_point_t p_act;\n                p_act.x = ink_point.x;\n                p_act.y = ink_point.y;\n                lv_coord_t x_err = (btn->coords.x1 + w / 2) - p_act.x;\n                lv_coord_t y_err = (btn->coords.y1 + h / 2) - p_act.y;\n\n                p_act.x += (x_err * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1);\n                p_act.y += (y_err * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1);\n\n                lv_coord_t half_side = LV_MATH_MAX(w, h) / 2;\n                cir_area.x1 = p_act.x - ((half_side * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1));\n                cir_area.y1 = p_act.y - ((half_side * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1));\n                cir_area.x2 = p_act.x + ((half_side * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1));\n                cir_area.y2 = p_act.y + ((half_side * coord_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1));\n\n                lv_area_intersect(&cir_area, &btn->coords, &cir_area);      /*Limit the area. (It might be too big on the smaller side)*/\n\n                /*In the second part animate the radius. Circle -> body.radius*/\n                lv_coord_t r_state = ink_act_value > LV_BTN_INK_VALUE_MAX / 2 ? ink_act_value - LV_BTN_INK_VALUE_MAX / 2 : 0;\n\n                lv_style_copy(&style_tmp, ext->styles[ink_top_state]);\n                style_tmp.body.radius = r_max + (((ext->styles[ink_bg_state]->body.radius - r_max) * r_state) >> (LV_BTN_INK_VALUE_MAX_SHIFT - 1));\n                style_tmp.body.border.width = 0;\n\n                /*Draw the circle*/\n                lv_draw_rect(&cir_area, mask, &style_tmp, opa_scale);\n            } else {\n                lv_style_t res;\n                lv_style_copy(&res, ext->styles[ink_bg_state]);\n                lv_style_mix(ext->styles[ink_bg_state], ext->styles[ink_top_state], &res, ink_act_value);\n                lv_draw_rect(&btn->coords, mask, &res, opa_scale);\n\n            }\n        }\n#else\n        ancestor_design(btn, mask, mode);\n#endif\n    } else if(mode == LV_DESIGN_DRAW_POST) {\n        ancestor_design(btn, mask, mode);\n    }\n\n    return true;\n}\n\n/**\n * Signal function of the button\n * @param btn pointer to a button object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(btn, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    lv_btn_ext_t * ext = lv_obj_get_ext_attr(btn);\n    lv_btn_state_t state = lv_btn_get_state(btn);\n    bool tgl = lv_btn_get_toggle(btn);\n\n    if(sign == LV_SIGNAL_PRESSED) {\n        /*Refresh the state*/\n        if(ext->state == LV_BTN_STATE_REL) {\n            lv_btn_set_state(btn, LV_BTN_STATE_PR);\n#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT\n            ink_bg_state = LV_BTN_STATE_REL;\n            ink_top_state = LV_BTN_STATE_PR;\n#endif\n        } else if(ext->state == LV_BTN_STATE_TGL_REL) {\n            lv_btn_set_state(btn, LV_BTN_STATE_TGL_PR);\n#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT\n            ink_bg_state = LV_BTN_STATE_TGL_REL;\n            ink_top_state = LV_BTN_STATE_TGL_PR;\n#endif\n        }\n\n        ext->long_pr_action_executed = 0;\n\n#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT\n        /*Forget the old inked button*/\n        if(ink_obj != NULL && ink_obj != btn) {\n            lv_anim_del(ink_obj, (lv_anim_fp_t)lv_btn_ink_effect_anim);\n            lv_obj_invalidate(ink_obj);\n            ink_obj = NULL;\n        }\n        /*Save the new data for inking and start it's animation if enabled*/\n        if(ext->ink_in_time > 0) {\n            ink_obj = btn;\n            ink_playback = false;\n            ink_ready = false;\n            lv_indev_get_point(lv_indev_get_act(), &ink_point);\n\n            lv_anim_t a;\n            a.var = btn;\n            a.start = 0;\n            a.end = LV_BTN_INK_VALUE_MAX;\n            a.fp = (lv_anim_fp_t)lv_btn_ink_effect_anim;\n            a.path = lv_anim_path_linear;\n            a.end_cb = lv_btn_ink_effect_anim_ready;\n            a.act_time = 0;\n            a.time = ext->ink_in_time;\n            a.playback = 0;\n            a.playback_pause = 0;\n            a.repeat = 0;\n            a.repeat_pause = 0;\n            lv_anim_create(&a);\n        }\n#endif\n        /*Call the press action, 'param' is the caller indev_proc*/\n        if(ext->actions[LV_BTN_ACTION_PR] && state != LV_BTN_STATE_INA) {\n            res = ext->actions[LV_BTN_ACTION_PR](btn);\n        }\n    } else if(sign == LV_SIGNAL_PRESS_LOST) {\n        /*Refresh the state*/\n        if(ext->state == LV_BTN_STATE_PR) lv_btn_set_state(btn, LV_BTN_STATE_REL);\n        else if(ext->state == LV_BTN_STATE_TGL_PR) lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);\n    } else if(sign == LV_SIGNAL_PRESSING) {\n        /*When the button begins to drag revert pressed states to released*/\n        if(lv_indev_is_dragging(param) != false) {\n            if(ext->state == LV_BTN_STATE_PR) lv_btn_set_state(btn, LV_BTN_STATE_REL);\n            else if(ext->state == LV_BTN_STATE_TGL_PR) lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);\n        }\n    } else if(sign == LV_SIGNAL_RELEASED) {\n        /*If not dragged and it was not long press action then\n         *change state and run the action*/\n        if(lv_indev_is_dragging(param) == false && ext->long_pr_action_executed == 0) {\n            if(ext->state == LV_BTN_STATE_PR && tgl == false) {\n                lv_btn_set_state(btn, LV_BTN_STATE_REL);\n            } else if(ext->state == LV_BTN_STATE_TGL_PR && tgl == false) {\n                lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);\n            } else if(ext->state == LV_BTN_STATE_PR && tgl == true) {\n                lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);\n            } else if(ext->state == LV_BTN_STATE_TGL_PR && tgl == true) {\n                lv_btn_set_state(btn, LV_BTN_STATE_REL);\n            }\n\n            if(ext->actions[LV_BTN_ACTION_CLICK] && state != LV_BTN_STATE_INA) {\n                res = ext->actions[LV_BTN_ACTION_CLICK](btn);\n            }\n        } else { /*If dragged change back the state*/\n            if(ext->state == LV_BTN_STATE_PR) {\n                lv_btn_set_state(btn, LV_BTN_STATE_REL);\n            } else if(ext->state == LV_BTN_STATE_TGL_PR) {\n                lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);\n            }\n        }\n\n#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT\n        /*Draw the toggled state in the inking instead*/\n        if(ext->toggle) {\n            ink_top_state = ext->state;\n        }\n        /*If not a toggle button and the \"IN\" inking is ready then start an \"OUT\" inking*/\n        else if(ink_ready && ext->ink_out_time > 0) {\n            ink_obj = btn;\n            ink_playback = true;    /*It is the playback. If not set `lv_btn_ink_effect_anim_ready` will start its own playback*/\n            lv_indev_get_point(lv_indev_get_act(), &ink_point);\n\n            lv_anim_t a;\n            a.var = ink_obj;\n            a.start = LV_BTN_INK_VALUE_MAX;\n            a.end = 0;\n            a.fp = (lv_anim_fp_t)lv_btn_ink_effect_anim;\n            a.path = lv_anim_path_linear;\n            a.end_cb = lv_btn_ink_effect_anim_ready;\n            a.act_time = 0;\n            a.time = ext->ink_out_time;\n            a.playback = 0;\n            a.playback_pause = 0;\n            a.repeat = 0;\n            a.repeat_pause = 0;\n            lv_anim_create(&a);\n        }\n#endif\n    } else if(sign == LV_SIGNAL_LONG_PRESS) {\n        if(ext->actions[LV_BTN_ACTION_LONG_PR] && state != LV_BTN_STATE_INA) {\n            ext->long_pr_action_executed = 1;\n            res = ext->actions[LV_BTN_ACTION_LONG_PR](btn);\n        }\n    } else if(sign == LV_SIGNAL_LONG_PRESS_REP) {\n        if(ext->actions[LV_BTN_ACTION_LONG_PR_REPEAT] && state != LV_BTN_STATE_INA) {\n            res = ext->actions[LV_BTN_ACTION_LONG_PR_REPEAT](btn);\n        }\n    } else if(sign == LV_SIGNAL_CONTROLL) {\n        char c = *((char *)param);\n        if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_UP) {\n            if(lv_btn_get_toggle(btn) != false) lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);\n            if(ext->actions[LV_BTN_ACTION_CLICK] && lv_btn_get_state(btn) != LV_BTN_STATE_INA) {\n                res = ext->actions[LV_BTN_ACTION_CLICK](btn);\n            }\n        } else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_DOWN) {\n            if(lv_btn_get_toggle(btn) != false) lv_btn_set_state(btn, LV_BTN_STATE_REL);\n            if(ext->actions[LV_BTN_ACTION_CLICK] && lv_btn_get_state(btn) != LV_BTN_STATE_INA) {\n                res = ext->actions[LV_BTN_ACTION_CLICK](btn);\n            }\n        } else if(c == LV_GROUP_KEY_ENTER) {\n            if(!ext->long_pr_action_executed) {\n                if(lv_btn_get_toggle(btn)) {\n                    if(state == LV_BTN_STATE_REL || state == LV_BTN_STATE_PR) lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);\n                    else if(state == LV_BTN_STATE_TGL_REL || state == LV_BTN_STATE_TGL_PR) lv_btn_set_state(btn, LV_BTN_STATE_REL);\n                } else {\n                    if(state == LV_BTN_STATE_REL || state == LV_BTN_STATE_PR) lv_btn_set_state(btn, LV_BTN_STATE_REL);\n                    else if(state == LV_BTN_STATE_TGL_REL || state == LV_BTN_STATE_TGL_PR) lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);\n                }\n                if(ext->actions[LV_BTN_ACTION_CLICK] && state != LV_BTN_STATE_INA) {\n                    res = ext->actions[LV_BTN_ACTION_CLICK](btn);\n                }\n            }\n            if(res != LV_RES_INV) {\n                ext->long_pr_action_executed  = 0;\n            }\n        }\n    } else if(sign == LV_SIGNAL_CLEANUP) {\n#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT\n        if(btn == ink_obj) {\n            lv_anim_del(ink_obj, (lv_anim_fp_t)lv_btn_ink_effect_anim);\n            ink_obj = NULL;\n        }\n#endif\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_btn\";\n    }\n\n    return res;\n}\n\n#if USE_LV_ANIMATION && LV_BTN_INK_EFFECT\n\n/**\n * The animator function of inking. CAlled to increase the radius of ink\n * @param btn pointer to the animated button\n * @param val the new radius\n */\nstatic void lv_btn_ink_effect_anim(lv_obj_t * btn, int32_t val)\n{\n    if(btn) {\n        ink_act_value = val;\n        lv_obj_invalidate(btn);\n    }\n}\n\n/**\n * Called to clean up when the ink animation is ready\n * @param p unused\n */\nstatic void lv_btn_ink_effect_anim_ready(void * p)\n{\n    (void) p;    /*Unused*/\n\n    lv_btn_ext_t * ext = lv_obj_get_ext_attr(ink_obj);\n    lv_btn_state_t state = lv_btn_get_state(ink_obj);\n\n    lv_obj_invalidate(ink_obj);\n    ink_ready = true;\n\n    if((state == LV_BTN_STATE_REL || state == LV_BTN_STATE_TGL_REL) && ext->toggle == 0 && ink_playback == false) {\n        lv_anim_t a;\n        a.var = ink_obj;\n        a.start = LV_BTN_INK_VALUE_MAX;\n        a.end = 0;\n        a.fp = (lv_anim_fp_t)lv_btn_ink_effect_anim;\n        a.path = lv_anim_path_linear;\n        a.end_cb = lv_btn_ink_effect_anim_ready;\n        a.act_time = -ext->ink_wait_time;\n        a.time = ext->ink_out_time;\n        a.playback = 0;\n        a.playback_pause = 0;\n        a.repeat = 0;\n        a.repeat_pause = 0;\n        lv_anim_create(&a);\n\n        ink_playback = true;\n    } else {\n        ink_obj = NULL;\n    }\n}\n#endif /*USE_LV_ANIMATION*/\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_btn.h",
    "content": "/**\n * @file lv_btn.h\n *\n */\n\n#ifndef LV_BTN_H\n#define LV_BTN_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_BTN != 0\n\n/*Testing of dependencies*/\n#if USE_LV_CONT == 0\n#error \"lv_btn: lv_cont is required. Enable it in lv_conf.h (USE_LV_CONT  1) \"\n#endif\n\n#include \"lv_cont.h\"\n#include \"../lv_core/lv_indev.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/* Button states\n * It can be used not only by buttons but other button-like objects too*/\nenum\n{\n    LV_BTN_STATE_REL,\n    LV_BTN_STATE_PR,\n    LV_BTN_STATE_TGL_REL,\n    LV_BTN_STATE_TGL_PR,\n    LV_BTN_STATE_INA,\n    LV_BTN_STATE_NUM,\n};\ntypedef uint8_t lv_btn_state_t;\n\nenum\n{\n    LV_BTN_ACTION_CLICK,\n    LV_BTN_ACTION_PR,\n    LV_BTN_ACTION_LONG_PR,\n    LV_BTN_ACTION_LONG_PR_REPEAT,\n    LV_BTN_ACTION_NUM,\n};\ntypedef uint8_t lv_btn_action_t;\n\n\n/*Data of button*/\ntypedef struct\n{\n    lv_cont_ext_t cont; /*Ext. of ancestor*/\n    /*New data for this type */\n    lv_action_t actions[LV_BTN_ACTION_NUM];\n    lv_style_t * styles[LV_BTN_STATE_NUM];        /*Styles in each state*/\n    lv_btn_state_t state;                         /*Current state of the button from 'lv_btn_state_t' enum*/\n    int idx;\n#if LV_BTN_INK_EFFECT\n    uint16_t ink_in_time;                         /*[ms] Time of ink fill effect (0: disable ink effect)*/\n    uint16_t ink_wait_time;                       /*[ms] Wait before the ink disappears */\n    uint16_t ink_out_time;                        /*[ms] Time of ink disappearing*/\n#endif\n    uint8_t toggle :1;                            /*1: Toggle enabled*/\n    uint8_t long_pr_action_executed :1;           /*1: Long press action executed (Handled by the library)*/\n} lv_btn_ext_t;\n\n/*Styles*/\nenum {\n    LV_BTN_STYLE_REL,\n    LV_BTN_STYLE_PR,\n    LV_BTN_STYLE_TGL_REL,\n    LV_BTN_STYLE_TGL_PR,\n    LV_BTN_STYLE_INA,\n};\ntypedef uint8_t lv_btn_style_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a button objects\n * @param par pointer to an object, it will be the parent of the new button\n * @param copy pointer to a button object, if not NULL then the new object will be copied from it\n * @return pointer to the created button\n */\nlv_obj_t * lv_btn_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Enable the toggled states. On release the button will change from/to toggled state.\n * @param btn pointer to a button object\n * @param tgl true: enable toggled states, false: disable\n */\nvoid lv_btn_set_toggle(lv_obj_t * btn, bool tgl);\n\n/**\n * Set the state of the button\n * @param btn pointer to a button object\n * @param state the new state of the button (from lv_btn_state_t enum)\n */\nvoid lv_btn_set_state(lv_obj_t * btn, lv_btn_state_t state);\n\n/**\n * Toggle the state of the button (ON->OFF, OFF->ON)\n * @param btn pointer to a button object\n */\nvoid lv_btn_toggle(lv_obj_t * btn);\n\n/**\n * Set a function to call when a button event happens\n * @param btn pointer to a button object\n * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat)\n */\nvoid lv_btn_set_action(lv_obj_t * btn, lv_btn_action_t type, lv_action_t action);\n\n/**\n * Set the layout on a button\n * @param btn pointer to a button object\n * @param layout a layout from 'lv_cont_layout_t'\n */\nstatic inline void lv_btn_set_layout(lv_obj_t * btn, lv_layout_t layout)\n{\n    lv_cont_set_layout(btn, layout);\n}\n\n/**\n * Enable the horizontal or vertical fit.\n * The button size will be set to involve the children horizontally or vertically.\n * @param btn pointer to a button object\n * @param hor_en true: enable the horizontal fit\n * @param ver_en true: enable the vertical fit\n */\nstatic inline void lv_btn_set_fit(lv_obj_t * btn, bool hor_en, bool ver_en)\n{\n    lv_cont_set_fit(btn, hor_en, ver_en);\n}\n\n/**\n * Set time of the ink effect (draw a circle on click to animate in the new state)\n * @param btn pointer to a button object\n * @param time the time of the ink animation\n */\nvoid lv_btn_set_ink_in_time(lv_obj_t * btn, uint16_t time);\n\n/**\n * Set the wait time before the ink disappears\n * @param btn pointer to a button object\n * @param time the time of the ink animation\n */\nvoid lv_btn_set_ink_wait_time(lv_obj_t * btn, uint16_t time);\n\n/**\n * Set time of the ink out effect (animate to the released state)\n * @param btn pointer to a button object\n * @param time the time of the ink animation\n */\nvoid lv_btn_set_ink_out_time(lv_obj_t * btn, uint16_t time);\n\n/**\n * Set a style of a button.\n * @param btn pointer to button object\n * @param type which style should be set\n * @param style pointer to a style\n *  */\nvoid lv_btn_set_style(lv_obj_t * btn, lv_btn_style_t type, lv_style_t *style);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the current state of the button\n * @param btn pointer to a button object\n * @return the state of the button (from lv_btn_state_t enum)\n */\nlv_btn_state_t lv_btn_get_state(const lv_obj_t * btn);\n\n/**\n * Get the toggle enable attribute of the button\n * @param btn pointer to a button object\n * @return ture: toggle enabled, false: disabled\n */\nbool lv_btn_get_toggle(const lv_obj_t * btn);\n\n/**\n * Get the release action of a button\n * @param btn pointer to a button object\n * @return pointer to the release action function\n */\nlv_action_t lv_btn_get_action(const lv_obj_t * btn, lv_btn_action_t type);\n\n/**\n * Get the layout of a button\n * @param btn pointer to button object\n * @return the layout from 'lv_cont_layout_t'\n */\nstatic inline lv_layout_t lv_btn_get_layout(const lv_obj_t * btn)\n{\n    return lv_cont_get_layout(btn);\n}\n\n/**\n * Get horizontal fit enable attribute of a button\n * @param btn pointer to a button object\n * @return true: horizontal fit is enabled; false: disabled\n */\nstatic inline bool lv_btn_get_hor_fit(const lv_obj_t * btn)\n{\n    return lv_cont_get_hor_fit(btn);\n}\n\n/**\n * Get vertical fit enable attribute of a container\n * @param btn pointer to a button object\n * @return true: vertical fit is enabled; false: disabled\n */\nstatic inline bool lv_btn_get_ver_fit(const lv_obj_t * btn)\n{\n    return lv_cont_get_ver_fit(btn);\n}\n\n/**\n * Get time of the ink in effect (draw a circle on click to animate in the new state)\n * @param btn pointer to a button object\n * @return the time of the ink animation\n */\nuint16_t lv_btn_get_ink_in_time(const lv_obj_t * btn);\n\n/**\n * Get the wait time before the ink disappears\n * @param btn pointer to a button object\n * @return the time of the ink animation\n */\nuint16_t lv_btn_get_ink_wait_time(const lv_obj_t * btn);\n\n/**\n * Get time of the ink out effect (animate to the releases state)\n * @param btn pointer to a button object\n * @return the time of the ink animation\n */\nuint16_t lv_btn_get_ink_out_time(const lv_obj_t * btn);\n\n/**\n * Get style of a button.\n * @param btn pointer to button object\n * @param type which style should be get\n * @return style pointer to the style\n *  */\nlv_style_t * lv_btn_get_style(const lv_obj_t * btn, lv_btn_style_t type);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_BUTTON*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_BTN_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_btnm.c",
    "content": "/**\n * @file lv_btnm.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_btnm.h\"\n#if USE_LV_BTNM != 0\n\n#include \"../lv_core/lv_group.h\"\n#include \"../lv_draw/lv_draw.h\"\n#include \"../lv_core/lv_refr.h\"\n#include \"../lv_themes/lv_theme.h\"\n#include \"../lv_misc/lv_txt.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic lv_res_t lv_btnm_signal(lv_obj_t * btnm, lv_signal_t sign, void * param);\nstatic bool lv_btnm_design(lv_obj_t * btnm, const lv_area_t * mask, lv_design_mode_t mode);\nstatic uint8_t get_button_width(const char * btn_str);\nstatic bool button_is_hidden(const char * btn_str);\nstatic bool button_is_repeat_disabled(const char * btn_str);\nstatic bool button_is_inactive(const char * btn_str);\nconst char * cut_ctrl_byte(const char * btn_str);\nstatic uint16_t get_button_from_point(lv_obj_t * btnm, lv_point_t * p);\nstatic uint16_t get_button_text(lv_obj_t * btnm, uint16_t btn_id);\nstatic void allocate_btn_areas(lv_obj_t * btnm, const char ** map);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic const char * lv_btnm_def_map[] = {\"Btn1\", \"Btn2\", \"Btn3\", \"\\n\",\n                                         \"\\002Btn4\", \"Btn5\", \"\"\n                                        };\n\nstatic lv_design_func_t ancestor_design_f;\nstatic lv_signal_func_t ancestor_signal;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a button matrix objects\n * @param par pointer to an object, it will be the parent of the new button matrix\n * @param copy pointer to a button matrix object, if not NULL then the new object will be copied from it\n * @return pointer to the created button matrix\n */\nlv_obj_t * lv_btnm_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"button matrix create started\");\n\n    /*Create the ancestor object*/\n    lv_obj_t * new_btnm = lv_obj_create(par, copy);\n    lv_mem_assert(new_btnm);\n    if(new_btnm == NULL) return NULL;\n\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_btnm);\n\n    /*Allocate the object type specific extended data*/\n    lv_btnm_ext_t * ext = lv_obj_allocate_ext_attr(new_btnm, sizeof(lv_btnm_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    ext->btn_cnt = 0;\n    ext->btn_id_pr = LV_BTNM_PR_NONE;\n    ext->btn_id_tgl = LV_BTNM_PR_NONE;\n    ext->button_areas = NULL;\n    ext->action = NULL;\n    ext->map_p = NULL;\n    ext->toggle = 0;\n    ext->recolor = 0;\n    ext->styles_btn[LV_BTN_STATE_REL] = &lv_style_btn_rel;\n    ext->styles_btn[LV_BTN_STATE_PR] = &lv_style_btn_pr;\n    ext->styles_btn[LV_BTN_STATE_TGL_REL] = &lv_style_btn_tgl_rel;\n    ext->styles_btn[LV_BTN_STATE_TGL_PR] = &lv_style_btn_tgl_pr;\n    ext->styles_btn[LV_BTN_STATE_INA] = &lv_style_btn_ina;\n\n    if(ancestor_design_f == NULL) ancestor_design_f = lv_obj_get_design_func(new_btnm);\n\n    lv_obj_set_signal_func(new_btnm, lv_btnm_signal);\n    lv_obj_set_design_func(new_btnm, lv_btnm_design);\n\n    /*Init the new button matrix object*/\n    if(copy == NULL) {\n        lv_obj_set_size(new_btnm, LV_HOR_RES / 2, LV_VER_RES / 4);\n        lv_btnm_set_map(new_btnm, lv_btnm_def_map);\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_btnm_set_style(new_btnm, LV_BTNM_STYLE_BG, th->btnm.bg);\n            lv_btnm_set_style(new_btnm, LV_BTNM_STYLE_BTN_REL, th->btnm.btn.rel);\n            lv_btnm_set_style(new_btnm, LV_BTNM_STYLE_BTN_PR, th->btnm.btn.pr);\n            lv_btnm_set_style(new_btnm, LV_BTNM_STYLE_BTN_TGL_REL, th->btnm.btn.tgl_rel);\n            lv_btnm_set_style(new_btnm, LV_BTNM_STYLE_BTN_TGL_PR, th->btnm.btn.tgl_pr);\n            lv_btnm_set_style(new_btnm, LV_BTNM_STYLE_BTN_INA, th->btnm.btn.ina);\n        } else {\n            lv_obj_set_style(new_btnm, &lv_style_pretty);\n        }\n    }\n    /*Copy an existing object*/\n    else {\n        lv_btnm_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        memcpy(ext->styles_btn, copy_ext->styles_btn, sizeof(ext->styles_btn));\n        ext->action = copy_ext->action;\n        ext->toggle = copy_ext->toggle;\n        ext->btn_id_tgl = copy_ext->btn_id_tgl;\n        lv_btnm_set_map(new_btnm, lv_btnm_get_map(copy));\n    }\n\n    LV_LOG_INFO(\"button matrix created\");\n\n    return new_btnm;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a new map. Buttons will be created/deleted according to the map.\n * @param btnm pointer to a button matrix object\n * @param map pointer a string array. The last string has to be: \"\".\n *            Use \"\\n\" to begin a new line.\n *            The first byte can be a control data:\n *             - bit 7: always 1\n *             - bit 6: always 0\n *             - bit 5: inactive (disabled) (\\24x)\n *             - bit 4: no repeat (on long press) (\\22x)\n *             - bit 3: hidden (\\21x)\n *             - bit 2..0: button relative width\n *             Example (practically use octal numbers): \"\\224abc\": \"abc\" text with 4 width and no long press\n */\nvoid lv_btnm_set_map(lv_obj_t * btnm, const char ** map)\n{\n    if(map == NULL) return;\n\n    lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);\n    ext->map_p = map;\n\n    /*Analyze the map and create the required number of buttons*/\n    allocate_btn_areas(btnm, map);\n\n    /*Set size and positions of the buttons*/\n    lv_style_t * style_bg = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BG);\n    lv_coord_t max_w = lv_obj_get_width(btnm) - 2 * style_bg->body.padding.hor;\n    lv_coord_t max_h = lv_obj_get_height(btnm) - 2 * style_bg->body.padding.ver;\n    lv_coord_t act_y = style_bg->body.padding.ver;\n\n    /*Count the lines to calculate button height*/\n    uint8_t line_cnt = 1;\n    uint8_t li;\n    for(li = 0; strlen(map[li]) != 0; li++) {\n        if(strcmp(map[li], \"\\n\") == 0) line_cnt ++;\n    }\n\n    lv_coord_t btn_h = max_h - ((line_cnt - 1) * style_bg->body.padding.inner);\n    btn_h = btn_h / line_cnt;\n    btn_h --;                              /*-1 because e.g. height = 100 means 101 pixels (0..100)*/\n\n    /* Count the units and the buttons in a line\n     * (A button can be 1,2,3... unit wide)*/\n    uint16_t unit_cnt;      /*Number of units in a row*/\n    uint16_t unit_act_cnt;  /*Number of units currently put in a row*/\n    uint16_t btn_cnt;       /*Number of buttons in a row*/\n    uint16_t i_tot = 0;     /*Act. index in the str map*/\n    uint16_t btn_i = 0;     /*Act. index of button areas*/\n    const char  ** map_p_tmp = map;\n\n    /*Count the units and the buttons in a line*/\n    while(1) {\n        unit_cnt = 0;\n        btn_cnt = 0;\n        /*Count the buttons in a line*/\n        while(strcmp(map_p_tmp[btn_cnt], \"\\n\") != 0 &&\n                strlen(map_p_tmp[btn_cnt]) != 0) { /*Check a line*/\n            unit_cnt += get_button_width(map_p_tmp[btn_cnt]);\n            btn_cnt ++;\n        }\n\n        /*Make sure the last row is at the bottom of 'btnm'*/\n        if(map_p_tmp[btn_cnt][0] == '\\0') {         /*Last row?*/\n            btn_h = max_h - act_y + style_bg->body.padding.ver - 1;\n        }\n\n        /*Only deal with the non empty lines*/\n        if(btn_cnt != 0) {\n            /*Calculate the width of all units*/\n            lv_coord_t all_unit_w = max_w - ((btn_cnt - 1) * style_bg->body.padding.inner);\n\n            /*Set the button size and positions and set the texts*/\n            uint16_t i;\n            lv_coord_t act_x = style_bg->body.padding.hor;\n            lv_coord_t act_unit_w;\n            unit_act_cnt = 0;\n            for(i = 0; i < btn_cnt; i++) {\n                /* one_unit_w = all_unit_w / unit_cnt\n                 * act_unit_w = one_unit_w * button_width\n                 * do this two operations but the multiply first to divide a greater number */\n                act_unit_w = (all_unit_w * get_button_width(map_p_tmp[i])) / unit_cnt;\n                act_unit_w --;                              /*-1 because e.g. width = 100 means 101 pixels (0..100)*/\n\n                /*Always recalculate act_x because of rounding errors */\n                act_x = (unit_act_cnt * all_unit_w) / unit_cnt + i * style_bg->body.padding.inner + style_bg->body.padding.hor;\n\n                /* Set the button's area.\n                 * If inner padding is zero then use the prev. button x2 as x1 to avoid rounding errors*/\n                if(style_bg->body.padding.inner == 0 && act_x != style_bg->body.padding.hor) {\n                    lv_area_set(&ext->button_areas[btn_i],  ext->button_areas[btn_i - 1].x2, act_y,\n                                act_x + act_unit_w, act_y + btn_h);\n                } else {\n                    lv_area_set(&ext->button_areas[btn_i],  act_x, act_y,\n                                act_x + act_unit_w, act_y + btn_h);\n                }\n\n                unit_act_cnt += get_button_width(map_p_tmp[i]);\n\n                i_tot ++;\n                btn_i ++;\n            }\n        }\n        act_y += btn_h + style_bg->body.padding.inner;\n\n\n        if(strlen(map_p_tmp[btn_cnt]) == 0) break; /*Break on end of map*/\n        map_p_tmp = &map_p_tmp[btn_cnt + 1]; /*Set the map to the next line*/\n        i_tot ++;   /*Skip the '\\n'*/\n    }\n\n    lv_obj_invalidate(btnm);\n}\n\n/**\n * Set a new callback function for the buttons (It will be called when a button is released)\n * @param btnm: pointer to button matrix object\n * @param cb pointer to a callback function\n */\nvoid lv_btnm_set_action(lv_obj_t * btnm, lv_btnm_action_t action)\n{\n    lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);\n    ext->action = action;\n}\n\n/**\n * Enable or disable button toggling\n * @param btnm pointer to button matrix object\n * @param en true: enable toggling; false: disable toggling\n * @param id index of the currently toggled button (ignored if 'en' == false)\n */\nvoid lv_btnm_set_toggle(lv_obj_t * btnm, bool en, uint16_t id)\n{\n    lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);\n\n    ext->toggle = en == false ? 0 : 1;\n    if(ext->toggle != 0) {\n        if(id >= ext->btn_cnt) id = ext->btn_cnt - 1;\n        ext->btn_id_tgl = id;\n    } else {\n        ext->btn_id_tgl = LV_BTNM_PR_NONE;\n    }\n\n    lv_obj_invalidate(btnm);\n}\n\n/**\n * Set a style of a button matrix\n * @param btnm pointer to a button matrix object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_btnm_set_style(lv_obj_t * btnm, lv_btnm_style_t type, lv_style_t * style)\n{\n    lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);\n\n    switch(type) {\n        case LV_BTNM_STYLE_BG:\n            lv_obj_set_style(btnm, style);\n            break;\n        case LV_BTNM_STYLE_BTN_REL:\n            ext->styles_btn[LV_BTN_STATE_REL] = style;\n            lv_obj_invalidate(btnm);\n            break;\n        case LV_BTNM_STYLE_BTN_PR:\n            ext->styles_btn[LV_BTN_STATE_PR] = style;\n            lv_obj_invalidate(btnm);\n            break;\n        case LV_BTNM_STYLE_BTN_TGL_REL:\n            ext->styles_btn[LV_BTN_STATE_TGL_REL] = style;\n            lv_obj_invalidate(btnm);\n            break;\n        case LV_BTNM_STYLE_BTN_TGL_PR:\n            ext->styles_btn[LV_BTN_STATE_TGL_PR] = style;\n            lv_obj_invalidate(btnm);\n            break;\n        case LV_BTNM_STYLE_BTN_INA:\n            ext->styles_btn[LV_BTN_STATE_INA] = style;\n            lv_obj_invalidate(btnm);\n            break;\n    }\n}\n\nvoid lv_btnm_set_recolor(const lv_obj_t * btnm, bool en)\n{\n    lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);\n\n    ext->recolor = en;\n    lv_obj_invalidate(btnm);\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the current map of a button matrix\n * @param btnm pointer to a button matrix object\n * @return the current map\n */\nconst char ** lv_btnm_get_map(const lv_obj_t * btnm)\n{\n    lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);\n    return ext->map_p;\n}\n\n/**\n * Get a the callback function of the buttons on a button matrix\n * @param btnm: pointer to button matrix object\n * @return pointer to the callback function\n */\nlv_btnm_action_t lv_btnm_get_action(const lv_obj_t * btnm)\n{\n    lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);\n    return ext->action;\n}\n\n/**\n * Get the pressed button\n * @param btnm pointer to button matrix object\n * @return  index of the currently pressed button (LV_BTNM_PR_NONE: if unset)\n */\nuint16_t lv_btnm_get_pressed(const lv_obj_t * btnm)\n{\n    lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);\n    return ext->btn_id_pr;\n}\n\n/**\n * Get the toggled button\n * @param btnm pointer to button matrix object\n * @return  index of the currently toggled button (LV_BTNM_PR_NONE: if unset)\n */\nuint16_t lv_btnm_get_toggled(const lv_obj_t * btnm)\n{\n    lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);\n\n    if(ext->toggle == 0) return LV_BTNM_PR_NONE;\n    else return ext->btn_id_tgl;\n}\n\n/**\n * Get a style of a button matrix\n * @param btnm pointer to a button matrix object\n * @param type which style should be get\n * @return style pointer to a style\n */\nlv_style_t * lv_btnm_get_style(const lv_obj_t * btnm, lv_btnm_style_t type)\n{\n    lv_style_t * style = NULL;\n    lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);\n\n    switch(type) {\n        case LV_BTNM_STYLE_BG:\n            style = lv_obj_get_style(btnm);\n            break;\n        case LV_BTNM_STYLE_BTN_REL:\n            style = ext->styles_btn[LV_BTN_STATE_REL];\n            break;\n        case LV_BTNM_STYLE_BTN_PR:\n            style = ext->styles_btn[LV_BTN_STATE_PR];\n            break;\n        case LV_BTNM_STYLE_BTN_TGL_REL:\n            style = ext->styles_btn[LV_BTN_STATE_TGL_REL];\n            break;\n        case LV_BTNM_STYLE_BTN_TGL_PR:\n            style = ext->styles_btn[LV_BTN_STATE_TGL_PR];\n            break;\n        case LV_BTNM_STYLE_BTN_INA:\n            style = ext->styles_btn[LV_BTN_STATE_INA];\n            break;\n        default:\n            style = NULL;\n            break;\n    }\n\n    return style;\n}\n\nbool lv_btnm_get_recolor(const lv_obj_t * btnm)\n{\n    lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);\n\n    return ext->recolor;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Handle the drawing related tasks of the button matrixs\n * @param btnm pointer to a button matrix object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_btnm_design(lv_obj_t * btnm, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    if(mode == LV_DESIGN_COVER_CHK) {\n        return ancestor_design_f(btnm, mask, mode);\n        /*Return false if the object is not covers the mask_p area*/\n    }\n    /*Draw the object*/\n    else if(mode == LV_DESIGN_DRAW_MAIN) {\n\n        ancestor_design_f(btnm, mask, mode);\n\n        lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);\n        lv_style_t * bg_style = lv_obj_get_style(btnm);\n        lv_style_t * btn_style;\n        lv_opa_t opa_scale = lv_obj_get_opa_scale(btnm);\n\n        lv_area_t area_btnm;\n        lv_obj_get_coords(btnm, &area_btnm);\n\n        lv_area_t area_tmp;\n        lv_coord_t btn_w;\n        lv_coord_t btn_h;\n\n        uint16_t btn_i = 0;\n        uint16_t txt_i = 0;\n        lv_style_t style_tmp;\n        lv_txt_flag_t txt_flag = LV_TXT_FLAG_NONE;\n\n        if(ext->recolor) txt_flag = LV_TXT_FLAG_RECOLOR;\n\n        for(btn_i = 0; btn_i < ext->btn_cnt; btn_i ++, txt_i ++) {\n            /*Search the next valid text in the map*/\n            while(strcmp(ext->map_p[txt_i], \"\\n\") == 0) {\n                txt_i ++;\n            }\n\n            /*Skip hidden buttons*/\n            if(button_is_hidden(ext->map_p[txt_i])) continue;\n\n            lv_area_copy(&area_tmp, &ext->button_areas[btn_i]);\n            area_tmp.x1 += area_btnm.x1;\n            area_tmp.y1 += area_btnm.y1;\n            area_tmp.x2 += area_btnm.x1;\n            area_tmp.y2 += area_btnm.y1;\n\n            btn_w = lv_area_get_width(&area_tmp);\n            btn_h = lv_area_get_height(&area_tmp);\n\n            /*Load the style*/\n            if(button_is_inactive(ext->map_p[txt_i])) btn_style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BTN_INA);\n            else if(btn_i != ext->btn_id_pr && btn_i != ext->btn_id_tgl) btn_style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BTN_REL);\n            else if(btn_i == ext->btn_id_pr && btn_i != ext->btn_id_tgl) btn_style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BTN_PR);\n            else if(btn_i != ext->btn_id_pr && btn_i == ext->btn_id_tgl) btn_style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BTN_TGL_REL);\n            else if(btn_i == ext->btn_id_pr && btn_i == ext->btn_id_tgl) btn_style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BTN_TGL_PR);\n            else btn_style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BTN_REL);    /*Not possible option, just to be sure*/\n\n            lv_style_copy(&style_tmp, btn_style);\n\n            /*Remove borders on the edges if `LV_BORDER_INTERNAL`*/\n            if(style_tmp.body.border.part & LV_BORDER_INTERNAL) {\n                if(area_tmp.y1 == btnm->coords.y1 + bg_style->body.padding.ver) {\n                    style_tmp.body.border.part &= ~LV_BORDER_TOP;\n                }\n                if(area_tmp.y2 == btnm->coords.y2 - bg_style->body.padding.ver) {\n                    style_tmp.body.border.part &= ~LV_BORDER_BOTTOM;\n                }\n\n                if(txt_i == 0) {\n                    style_tmp.body.border.part &= ~LV_BORDER_LEFT;\n                }\n                else if(strcmp(ext->map_p[txt_i - 1],\"\\n\") == 0) {\n                    style_tmp.body.border.part &= ~LV_BORDER_LEFT;\n                }\n\n                if(ext->map_p[txt_i + 1][0] == '\\0' || strcmp(ext->map_p[txt_i + 1], \"\\n\") == 0) {\n                        style_tmp.body.border.part &= ~LV_BORDER_RIGHT;\n                }\n            }\n            lv_draw_rect(&area_tmp, mask, &style_tmp, opa_scale);\n\n            /*Calculate the size of the text*/\n            if(btn_style->glass) btn_style = bg_style;\n            const lv_font_t * font = btn_style->text.font;\n            lv_point_t txt_size;\n            lv_txt_get_size(&txt_size, ext->map_p[txt_i], font,\n                            btn_style->text.letter_space, btn_style->text.line_space,\n                            lv_area_get_width(&area_btnm), txt_flag);\n\n            area_tmp.x1 += (btn_w - txt_size.x) / 2;\n            area_tmp.y1 += (btn_h - txt_size.y) / 2;\n            area_tmp.x2 = area_tmp.x1 + txt_size.x;\n            area_tmp.y2 = area_tmp.y1 + txt_size.y;\n\n            lv_draw_label(&area_tmp, mask, btn_style, opa_scale,  ext->map_p[txt_i], txt_flag, NULL);\n        }\n    }\n    return true;\n}\n\n/**\n * Signal function of the button matrix\n * @param btnm pointer to a button matrix object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_btnm_signal(lv_obj_t * btnm, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(btnm, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);\n    lv_area_t btnm_area;\n    lv_area_t btn_area;\n    lv_point_t p;\n    if(sign == LV_SIGNAL_CLEANUP) {\n        lv_mem_free(ext->button_areas);\n    } else if(sign == LV_SIGNAL_STYLE_CHG || sign == LV_SIGNAL_CORD_CHG) {\n        lv_btnm_set_map(btnm, ext->map_p);\n    } else if(sign == LV_SIGNAL_PRESSING) {\n        uint16_t btn_pr;\n        /*Search the pressed area*/\n        lv_indev_get_point(param, &p);\n        btn_pr = get_button_from_point(btnm, &p);\n        /*Invalidate to old and the new areas*/;\n        lv_obj_get_coords(btnm, &btnm_area);\n        if(btn_pr != ext->btn_id_pr) {\n            lv_indev_reset_lpr(param);\n            if(ext->btn_id_pr != LV_BTNM_PR_NONE) {\n                lv_area_copy(&btn_area, &ext->button_areas[ext->btn_id_pr]);\n                btn_area.x1 += btnm_area.x1;\n                btn_area.y1 += btnm_area.y1;\n                btn_area.x2 += btnm_area.x1;\n                btn_area.y2 += btnm_area.y1;\n                lv_inv_area(&btn_area);\n            }\n            if(btn_pr != LV_BTNM_PR_NONE) {\n                lv_area_copy(&btn_area, &ext->button_areas[btn_pr]);\n                btn_area.x1 += btnm_area.x1;\n                btn_area.y1 += btnm_area.y1;\n                btn_area.x2 += btnm_area.x1;\n                btn_area.y2 += btnm_area.y1;\n                lv_inv_area(&btn_area);\n            }\n        }\n\n        ext->btn_id_pr = btn_pr;\n    }\n\n    else if(sign == LV_SIGNAL_LONG_PRESS_REP) {\n        if(ext->action && ext->btn_id_pr != LV_BTNM_PR_NONE) {\n            uint16_t txt_i = get_button_text(btnm, ext->btn_id_pr);\n            if(txt_i != LV_BTNM_PR_NONE) {\n                if(button_is_repeat_disabled(ext->map_p[txt_i]) == false &&\n                        button_is_inactive(ext->map_p[txt_i]) == false) {\n                    res = ext->action(btnm, cut_ctrl_byte(ext->map_p[txt_i]));\n                }\n            }\n        }\n    } else if(sign == LV_SIGNAL_RELEASED) {\n        if(ext->btn_id_pr != LV_BTNM_PR_NONE) {\n            uint16_t txt_i = get_button_text(btnm, ext->btn_id_pr);\n            if(button_is_inactive(ext->map_p[txt_i]) == false && txt_i != LV_BTNM_PR_NONE) {        /*Ignore the inactive buttons anf click between the buttons*/\n                if(ext->action) res = ext->action(btnm, cut_ctrl_byte(ext->map_p[txt_i]));\n                if(res == LV_RES_OK) {\n\n                    /*Invalidate to old pressed area*/;\n                    lv_obj_get_coords(btnm, &btnm_area);\n                    lv_area_copy(&btn_area, &ext->button_areas[ext->btn_id_pr]);\n                    btn_area.x1 += btnm_area.x1;\n                    btn_area.y1 += btnm_area.y1;\n                    btn_area.x2 += btnm_area.x1;\n                    btn_area.y2 += btnm_area.y1;\n                    lv_inv_area(&btn_area);\n\n                    if(ext->toggle != 0) {\n                        /*Invalidate to old toggled area*/;\n                        lv_area_copy(&btn_area, &ext->button_areas[ext->btn_id_tgl]);\n                        btn_area.x1 += btnm_area.x1;\n                        btn_area.y1 += btnm_area.y1;\n                        btn_area.x2 += btnm_area.x1;\n                        btn_area.y2 += btnm_area.y1;\n                        lv_inv_area(&btn_area);\n                        ext->btn_id_tgl = ext->btn_id_pr;\n\n                    }\n\n        #if USE_LV_GROUP\n                    /*Leave the clicked button when releases if this not the focused object in a group*/\n                    lv_group_t * g = lv_obj_get_group(btnm);\n                    if(lv_group_get_focused(g) != btnm) {\n                        ext->btn_id_pr = LV_BTNM_PR_NONE;\n                    }\n        #else\n                    ext->btn_id_pr = LV_BTNM_PR_NONE;\n        #endif\n\n                }\n            }\n        }\n    } else if(sign == LV_SIGNAL_PRESS_LOST || sign == LV_SIGNAL_DEFOCUS) {\n        ext->btn_id_pr = LV_BTNM_PR_NONE;\n        lv_obj_invalidate(btnm);\n    } else if(sign == LV_SIGNAL_FOCUS) {\n#if USE_LV_GROUP\n        lv_indev_t * indev = lv_indev_get_act();\n        lv_hal_indev_type_t indev_type = lv_indev_get_type(indev);\n        if(indev_type == LV_INDEV_TYPE_POINTER) {\n            /*Select the clicked button*/\n            lv_point_t p1;\n            lv_indev_get_point(indev, &p1);\n            uint16_t btn_i = get_button_from_point(btnm, &p1);\n            ext->btn_id_pr = btn_i;\n        } else  if(indev_type == LV_INDEV_TYPE_ENCODER) {\n            /*In navigation mode don't select any button but in edit mode select the fist*/\n            if(lv_group_get_editing(lv_obj_get_group(btnm))) ext->btn_id_pr = 0;\n            else ext->btn_id_pr = LV_BTNM_PR_NONE;\n        } else {\n            ext->btn_id_pr = 0;\n        }\n#else\n        ext->btn_id_pr = 0;\n#endif\n        lv_obj_invalidate(btnm);\n    } else if(sign == LV_SIGNAL_CONTROLL) {\n        char c = *((char *)param);\n        if(c == LV_GROUP_KEY_RIGHT) {\n            if(ext->btn_id_pr  == LV_BTNM_PR_NONE) ext->btn_id_pr = 0;\n            else ext->btn_id_pr++;\n            if(ext->btn_id_pr >= ext->btn_cnt - 1) ext->btn_id_pr = ext->btn_cnt - 1;\n            lv_obj_invalidate(btnm);\n        } else if(c == LV_GROUP_KEY_LEFT) {\n            if(ext->btn_id_pr  == LV_BTNM_PR_NONE) ext->btn_id_pr = 0;\n            if(ext->btn_id_pr > 0) ext->btn_id_pr--;\n            lv_obj_invalidate(btnm);\n        } else if(c == LV_GROUP_KEY_DOWN) {\n            lv_style_t * style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BG);\n            /*Find the area below the the current*/\n            if(ext->btn_id_pr  == LV_BTNM_PR_NONE) {\n                ext->btn_id_pr = 0;\n            } else {\n                uint16_t area_below;\n                lv_coord_t pr_center = ext->button_areas[ext->btn_id_pr].x1 + (lv_area_get_width(&ext->button_areas[ext->btn_id_pr]) >> 1);\n\n                for(area_below = ext->btn_id_pr; area_below < ext->btn_cnt; area_below ++) {\n                    if(ext->button_areas[area_below].y1 >  ext->button_areas[ext->btn_id_pr].y1 &&\n                            pr_center >=  ext->button_areas[area_below].x1 &&\n                            pr_center <=  ext->button_areas[area_below].x2 + style->body.padding.hor) {\n                        break;\n                    }\n                }\n\n                if(area_below < ext->btn_cnt) ext->btn_id_pr = area_below;\n            }\n            lv_obj_invalidate(btnm);\n        } else if(c == LV_GROUP_KEY_UP) {\n            lv_style_t * style = lv_btnm_get_style(btnm, LV_BTNM_STYLE_BG);\n            /*Find the area below the the current*/\n            if(ext->btn_id_pr  == LV_BTNM_PR_NONE) {\n                ext->btn_id_pr = 0;\n            } else {\n                int16_t area_above;\n                lv_coord_t pr_center = ext->button_areas[ext->btn_id_pr].x1 + (lv_area_get_width(&ext->button_areas[ext->btn_id_pr]) >> 1);\n\n                for(area_above = ext->btn_id_pr; area_above >= 0; area_above --) {\n                    if(ext->button_areas[area_above].y1 < ext->button_areas[ext->btn_id_pr].y1 &&\n                            pr_center >=  ext->button_areas[area_above].x1 - style->body.padding.hor &&\n                            pr_center <=  ext->button_areas[area_above].x2) {\n                        break;\n                    }\n                }\n                if(area_above >= 0) ext->btn_id_pr = area_above;\n\n            }\n            lv_obj_invalidate(btnm);\n        } else if(c == LV_GROUP_KEY_ENTER) {\n            if(ext->action != NULL) {\n                uint16_t txt_i = get_button_text(btnm, ext->btn_id_pr);\n                if(txt_i != LV_BTNM_PR_NONE) {\n                    res = ext->action(btnm, cut_ctrl_byte(ext->map_p[txt_i]));\n                }\n            }\n        }\n    } else if(sign == LV_SIGNAL_GET_EDITABLE) {\n        bool * editable = (bool *)param;\n        *editable = true;\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_btnm\";\n    }\n\n\n    return res;\n}\n\n/**\n * Create the required number of buttons according to a map\n * @param btnm pointer to button matrix object\n * @param map_p pointer to a string array\n */\nstatic void allocate_btn_areas(lv_obj_t * btnm, const char ** map)\n{\n    /*Count the buttons in the map*/\n    uint16_t btn_cnt = 0;\n    uint16_t i = 0;\n    while(strlen(map[i]) != 0) {\n        if(strcmp(map[i], \"\\n\") != 0) { /*Do not count line breaks*/\n            btn_cnt ++;\n        }\n        i++;\n    }\n\n    lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);\n\n    if(ext->button_areas != NULL) {\n        lv_mem_free(ext->button_areas);\n        ext->button_areas = NULL;\n    }\n\n    ext->button_areas = lv_mem_alloc(sizeof(lv_area_t) * btn_cnt);\n    lv_mem_assert(ext->button_areas);\n    if(ext->button_areas == NULL) btn_cnt = 0;\n\n    ext->btn_cnt = btn_cnt;\n}\n\n/**\n * Get the width of a button in units. It comes from the first \"letter\".\n * @param btn_str The descriptor string of a button. E.g. \"apple\" or \"\\004banana\"\n * @return the width of the button in units\n */\nstatic uint8_t get_button_width(const char * btn_str)\n{\n    if((btn_str[0] & LV_BTNM_CTRL_MASK) == LV_BTNM_CTRL_CODE) {\n        return btn_str[0] & LV_BTNM_WIDTH_MASK;\n    }\n\n    return 1;   /*Default width is 1*/\n}\n\nstatic bool button_is_hidden(const char * btn_str)\n{\n    /*If control byte presents and hidden bit is '1' then the button is hidden*/\n    if(((btn_str[0] & LV_BTNM_CTRL_MASK) == LV_BTNM_CTRL_CODE) &&\n            (btn_str[0] & LV_BTNM_HIDE_MASK)) {\n        return true;\n    }\n\n    return false;\n}\n\nstatic bool button_is_repeat_disabled(const char * btn_str)\n{\n    /*If control byte presents and hidden bit is '1' then the button is hidden*/\n    if(((btn_str[0] & LV_BTNM_CTRL_MASK) == LV_BTNM_CTRL_CODE) &&\n            (btn_str[0] & LV_BTNM_REPEAT_DISABLE_MASK)) {\n        return true;\n    }\n\n    return false;\n}\n\nstatic bool button_is_inactive(const char * btn_str)\n{\n    /*If control byte presents and hidden bit is '1' then the button is hidden*/\n    if(((btn_str[0] & LV_BTNM_CTRL_MASK) == LV_BTNM_CTRL_CODE) &&\n            (btn_str[0] & LV_BTNM_INACTIVE_MASK)) {\n        return true;\n    }\n\n    return false;\n}\n\n\nconst char * cut_ctrl_byte(const char * btn_str)\n{\n    /*Cut the control byte if present*/\n    if((btn_str[0] & LV_BTNM_CTRL_MASK) == LV_BTNM_CTRL_CODE) return &btn_str[1];\n    else return btn_str;\n}\n\n/**\n * Gives the button id of a button under a given point\n * @param btnm pointer to a button matrix object\n * @param p a point with absolute coordinates\n * @return the id of the button or LV_BTNM_PR_NONE.\n */\nstatic uint16_t get_button_from_point(lv_obj_t * btnm, lv_point_t * p)\n{\n    lv_area_t btnm_cords;\n    lv_area_t btn_area;\n    lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);\n    uint16_t i;\n    lv_obj_get_coords(btnm, &btnm_cords);\n\n    for(i = 0; i < ext->btn_cnt; i++) {\n        lv_area_copy(&btn_area, &ext->button_areas[i]);\n        btn_area.x1 += btnm_cords.x1;\n        btn_area.y1 += btnm_cords.y1;\n        btn_area.x2 += btnm_cords.x1;\n        btn_area.y2 += btnm_cords.y1;\n        if(lv_area_is_point_on(&btn_area, p) != false) {\n            break;\n        }\n    }\n\n    if(i == ext->btn_cnt) i = LV_BTNM_PR_NONE;\n\n    return i;\n}\n\n/**\n * Get the text of a button\n * @param btnm pointer to a button matrix object\n * @param btn_id button id\n * @return text id in ext->map_p or LV_BTNM_PR_NONE if 'btn_id' was invalid\n */\nstatic uint16_t get_button_text(lv_obj_t * btnm, uint16_t btn_id)\n{\n    lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);\n    if(btn_id > ext->btn_cnt) return LV_BTNM_PR_NONE;\n\n    uint16_t txt_i = 0;\n    uint16_t btn_i = 0;\n\n    /* Search the text of ext->btn_pr the buttons text in the map\n     * Skip \"\\n\"-s*/\n    while(btn_i != btn_id) {\n        btn_i ++;\n        txt_i ++;\n        if(strcmp(ext->map_p[txt_i], \"\\n\") == 0) txt_i ++;\n    }\n\n    if(btn_i == ext->btn_cnt) return  LV_BTNM_PR_NONE;\n\n    return txt_i;\n}\n\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_btnm.h",
    "content": "/**\n * @file lv_btnm.h\n *\n */\n\n\n#ifndef LV_BTNM_H\n#define LV_BTNM_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_BTNM != 0\n\n#include \"../lv_core/lv_obj.h\"\n#include \"lv_label.h\"\n#include \"lv_btn.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/*Control byte*/\n#define LV_BTNM_CTRL_CODE       0x80    /*The control byte has to begin (if present) with 0b10xxxxxx*/\n#define LV_BTNM_CTRL_MASK       0xC0\n#define LV_BTNM_WIDTH_MASK      0x07\n#define LV_BTNM_HIDE_MASK       0x08\n#define LV_BTNM_REPEAT_DISABLE_MASK     0x10\n#define LV_BTNM_INACTIVE_MASK   0x20\n\n\n#define LV_BTNM_PR_NONE         0xFFFF\n/**********************\n *      TYPEDEFS\n **********************/\n\n/* Type of callback function which is called when a button is released or long pressed on the button matrix\n * Parameters: button matrix, text of the released button\n * return LV_ACTION_RES_INV if  the button matrix is deleted else LV_ACTION_RES_OK*/\ntypedef lv_res_t (*lv_btnm_action_t) (lv_obj_t *, const char *txt);\n\n/*Data of button matrix*/\ntypedef struct\n{\n    /*No inherited ext.*/ /*Ext. of ancestor*/\n    /*New data for this type */\n    const char ** map_p;                        /*Pointer to the current map*/\n    lv_area_t *button_areas;                    /*Array of areas of buttons*/\n    lv_btnm_action_t action;                    /*A function to call when a button is releases*/\n    lv_style_t *styles_btn[LV_BTN_STATE_NUM];   /*Styles of buttons in each state*/\n    uint16_t btn_cnt;                           /*Number of button in 'map_p'(Handled by the library)*/\n    uint16_t btn_id_pr;                         /*Index of the currently pressed button (in `button_areas`) or LV_BTNM_PR_NONE*/\n    uint16_t btn_id_tgl;                        /*Index of the currently toggled button (in `button_areas`) or LV_BTNM_PR_NONE */\n    uint8_t toggle     :1;                      /*Enable toggling*/\n    uint8_t\trecolor    :1;                      /*Enable button recoloring*/\n} lv_btnm_ext_t;\n\nenum {\n    LV_BTNM_STYLE_BG,\n    LV_BTNM_STYLE_BTN_REL,\n    LV_BTNM_STYLE_BTN_PR,\n    LV_BTNM_STYLE_BTN_TGL_REL,\n    LV_BTNM_STYLE_BTN_TGL_PR,\n    LV_BTNM_STYLE_BTN_INA,\n};\ntypedef uint8_t lv_btnm_style_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a button matrix objects\n * @param par pointer to an object, it will be the parent of the new button matrix\n * @param copy pointer to a button matrix object, if not NULL then the new object will be copied from it\n * @return pointer to the created button matrix\n */\nlv_obj_t * lv_btnm_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a new map. Buttons will be created/deleted according to the map.\n * @param btnm pointer to a button matrix object\n * @param map pointer a string array. The last string has to be: \"\".\n *            Use \"\\n\" to begin a new line.\n *            The first byte can be a control data:\n *             - bit 7: always 1\n *             - bit 6: always 0\n *             - bit 5: inactive (disabled)\n *             - bit 4: no repeat (on long press)\n *             - bit 3: hidden\n *             - bit 2..0: button relative width\n *             Example (practically use octal numbers): \"\\224abc\": \"abc\" text with 4 width and no long press\n */\nvoid lv_btnm_set_map(lv_obj_t * btnm, const char ** map);\n\n/**\n * Set a new callback function for the buttons (It will be called when a button is released)\n * @param btnm: pointer to button matrix object\n * @param action pointer to a callback function\n */\nvoid lv_btnm_set_action(lv_obj_t * btnm, lv_btnm_action_t action);\n\n/**\n * Enable or disable button toggling\n * @param btnm pointer to button matrix object\n * @param en true: enable toggling; false: disable toggling\n * @param id index of the currently toggled button (ignored if 'en' == false)\n */\nvoid lv_btnm_set_toggle(lv_obj_t * btnm, bool en, uint16_t id);\n\n/**\n * Set a style of a button matrix\n * @param btnm pointer to a button matrix object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_btnm_set_style(lv_obj_t *btnm, lv_btnm_style_t type, lv_style_t *style);\n\n/**\n * Set whether recoloring is enabled\n * @param btnm pointer to button matrix object\n * @param en whether recoloring is enabled\n */\nvoid lv_btnm_set_recolor(const lv_obj_t * btnm, bool en);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the current map of a button matrix\n * @param btnm pointer to a button matrix object\n * @return the current map\n */\nconst char ** lv_btnm_get_map(const lv_obj_t * btnm);\n\n/**\n * Get a the callback function of the buttons on a button matrix\n * @param btnm: pointer to button matrix object\n * @return pointer to the callback function\n */\nlv_btnm_action_t lv_btnm_get_action(const lv_obj_t * btnm);\n\n/**\n * Get the pressed button\n * @param btnm pointer to button matrix object\n * @return  index of the currently pressed button (LV_BTNM_PR_NONE: if unset)\n */\nuint16_t lv_btnm_get_pressed(const lv_obj_t * btnm);\n\n/**\n * Get the toggled button\n * @param btnm pointer to button matrix object\n * @return  index of the currently toggled button (LV_BTNM_PR_NONE: if unset)\n */\nuint16_t lv_btnm_get_toggled(const lv_obj_t * btnm);\n\n/**\n * Get a style of a button matrix\n * @param btnm pointer to a button matrix object\n * @param type which style should be get\n * @return style pointer to a style\n */\nlv_style_t * lv_btnm_get_style(const lv_obj_t *btnm, lv_btnm_style_t type);\n\n/**\n * Find whether recoloring is enabled\n * @param btnm pointer to button matrix object\n * @return whether recoloring is enabled\n */\nbool lv_btnm_get_recolor(const lv_obj_t * btnm);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif /*USE_LV_BTNM*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_BTNM_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_calendar.c",
    "content": "/**\n * @file lv_calendar.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_calendar.h\"\n#if USE_LV_CALENDAR != 0\n\n#include \"../lv_draw/lv_draw.h\"\n#include \"../lv_hal/lv_hal_indev.h\"\n#include \"../lv_misc/lv_math.h\"\n#include \"../lv_core/lv_indev.h\"\n#include \"../lv_themes/lv_theme.h\"\n//#include <strings.h>\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\nenum {\n    DAY_DRAW_PREV_MONTH,\n    DAY_DRAW_ACT_MONTH,\n    DAY_DRAW_NEXT_MONTH,\n};\ntypedef uint8_t day_draw_state_t;\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool lv_calendar_design(lv_obj_t * calendar, const lv_area_t * mask, lv_design_mode_t mode);\nstatic lv_res_t lv_calendar_signal(lv_obj_t * calendar, lv_signal_t sign, void * param);\nstatic bool calculate_touched_day(lv_obj_t * calendar, const lv_point_t * touched_point);\nstatic lv_coord_t get_header_height(lv_obj_t * calendar);\nstatic lv_coord_t get_day_names_height(lv_obj_t * calendar);\nstatic void draw_header(lv_obj_t * calendar, const lv_area_t * mask);\nstatic void draw_day_names(lv_obj_t * calendar, const lv_area_t * mask);\nstatic void draw_days(lv_obj_t * calendar, const lv_area_t * mask);\nstatic uint8_t get_day_of_week(uint32_t year, uint32_t month, uint32_t day);\nstatic bool is_highlighted(lv_obj_t * calendar, int32_t year, int32_t month, int32_t day);\nstatic const char * get_day_name(lv_obj_t * calendar, uint8_t day);\nstatic const char * get_month_name(lv_obj_t * calendar, int32_t month);\nstatic uint8_t get_month_length(int32_t year, int32_t month);\nstatic uint8_t is_leap_year(uint32_t year);\n\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\nstatic lv_design_func_t ancestor_design;\nstatic const char * day_name[7] = {\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"};\nstatic const char * month_name[12] = {\"January\",   \"February\",   \"March\",    \"April\",\n        \"May\",       \"June\",       \"July\",     \"August\",\n        \"September\", \"October\",    \"November\", \"December\"\n};\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a calendar object\n * @param par pointer to an object, it will be the parent of the new calendar\n * @param copy pointer to a calendar object, if not NULL then the new object will be copied from it\n * @return pointer to the created calendar\n */\nlv_obj_t * lv_calendar_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"calendar create started\");\n\n    /*Create the ancestor of calendar*/\n    lv_obj_t * new_calendar = lv_obj_create(par, copy);\n    lv_mem_assert(new_calendar);\n    if(new_calendar == NULL) return NULL;\n\n    /*Allocate the calendar type specific extended data*/\n    lv_calendar_ext_t * ext = lv_obj_allocate_ext_attr(new_calendar, sizeof(lv_calendar_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_calendar);\n    if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_calendar);\n\n    /*Initialize the allocated 'ext' */\n    ext->today.year = 2018;\n    ext->today.month = 1;\n    ext->today.day = 1;\n\n    ext->showed_date.year = 2018;\n    ext->showed_date.month = 1;\n    ext->showed_date.day = 1;\n\n    ext->pressed_date.year = 0;\n    ext->pressed_date.month = 0;\n    ext->pressed_date.day = 0;\n\n    ext->highlighted_dates  = NULL;\n    ext->highlighted_dates_num = 0;\n    ext->day_names = NULL;\n    ext->month_names = NULL;\n    ext->actions[LV_CALENDAR_ACTION_PR] = NULL;\n    ext->actions[LV_CALENDAR_ACTION_CLICK] = NULL;\n    ext->actions[LV_CALENDAR_ACTION_LONG_PR] = NULL;\n    ext->actions[LV_CALENDAR_ACTION_LONG_PR_REPEAT] = NULL;\n    ext->style_header = &lv_style_plain_color;\n    ext->style_header_pr = &lv_style_pretty_color;\n    ext->style_highlighted_days = &lv_style_plain_color;\n    ext->style_inactive_days = &lv_style_btn_ina;\n    ext->style_week_box = &lv_style_plain_color;\n    ext->style_today_box = &lv_style_pretty_color;\n    ext->style_day_names = &lv_style_pretty;\n\n    /*The signal and design functions are not copied so set them here*/\n    lv_obj_set_signal_func(new_calendar, lv_calendar_signal);\n    lv_obj_set_design_func(new_calendar, lv_calendar_design);\n\n    /*Init the new calendar calendar*/\n    if(copy == NULL) {\n        lv_obj_set_size(new_calendar, LV_DPI * 2, LV_DPI * 2);\n        lv_obj_set_style(new_calendar, &lv_style_pretty);\n\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_BG, th->calendar.bg);\n            lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HEADER, th->calendar.header);\n            lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HEADER_PR, th->calendar.header_pr);\n            lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_DAY_NAMES, th->calendar.day_names);\n            lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_WEEK_BOX, th->calendar.week_box);\n            lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_TODAY_BOX, th->calendar.today_box);\n            lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS, th->calendar.highlighted_days);\n            lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_INACTIVE_DAYS, th->calendar.inactive_days);\n        } else {\n            lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_BG, &lv_style_pretty);\n            lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HEADER, ext->style_header);\n            lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HEADER_PR, ext->style_header_pr);\n            lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_DAY_NAMES, ext->style_day_names);\n            lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_WEEK_BOX, ext->style_week_box);\n            lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_TODAY_BOX, ext->style_today_box);\n            lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS, ext->style_highlighted_days);\n            lv_calendar_set_style(new_calendar, LV_CALENDAR_STYLE_INACTIVE_DAYS, ext->style_inactive_days);\n\n        }\n\n    }\n    /*Copy an existing calendar*/\n    else {\n        lv_calendar_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        ext->today.year = copy_ext->today.year;\n        ext->today.month = copy_ext->today.month;\n        ext->today.day = copy_ext->today.day;\n\n        ext->showed_date.year = copy_ext->showed_date.year;\n        ext->showed_date.month = copy_ext->showed_date.month;\n        ext->showed_date.day = copy_ext->showed_date.day;\n\n        ext->highlighted_dates  = copy_ext->highlighted_dates;\n        ext->highlighted_dates_num = copy_ext->highlighted_dates_num;\n        ext->day_names = copy_ext->day_names;\n\n        memcpy(ext->actions, copy_ext->actions, sizeof(ext->actions));\n\n        ext->month_names = copy_ext->month_names;\n        ext->style_header = copy_ext->style_header;\n        ext->style_header_pr = copy_ext->style_header_pr;\n        ext->style_highlighted_days = copy_ext->style_highlighted_days;\n        ext->style_inactive_days = copy_ext->style_inactive_days;\n        ext->style_week_box = copy_ext->style_week_box;\n        ext->style_today_box = copy_ext->style_today_box;\n        ext->style_day_names = copy_ext->style_day_names;\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_calendar);\n    }\n\n    LV_LOG_INFO(\"calendar created\");\n\n    return new_calendar;\n}\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n/*\n * New object specific \"add\" or \"remove\" functions come here\n */\n\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a function to call when a calendar event happens\n * @param calendar pointer to a calendar object\n * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat)\n */\nvoid lv_calendar_set_action(lv_obj_t * calendar, lv_calendar_action_t type, lv_action_t action)\n{\n    if(type >= LV_CALENDAR_ACTION_NUM) return;\n\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n    ext->actions[type] = action;\n}\n\n/**\n * Set the today's date\n * @param calendar pointer to a calendar object\n * @param today pointer to an `lv_calendar_date_t` variable containing the date of today. The value will be saved it can be local variable too.\n */\nvoid lv_calendar_set_today_date(lv_obj_t * calendar, lv_calendar_date_t * today)\n{\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n    ext->today.year = today->year;\n    ext->today.month = today->month;\n    ext->today.day = today->day;\n\n    lv_obj_invalidate(calendar);\n}\n\n/**\n * Set the currently showed\n * @param calendar pointer to a calendar object\n * @param showed pointer to an `lv_calendar_date_t` variable containing the date to show. The value will be saved it can be local variable too.\n */\nvoid lv_calendar_set_showed_date(lv_obj_t * calendar, lv_calendar_date_t * showed)\n{\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n    ext->showed_date.year = showed->year;\n    ext->showed_date.month = showed->month;\n    ext->showed_date.day = showed->day;\n\n    lv_obj_invalidate(calendar);\n}\n\n/**\n * Set the the highlighted dates\n * @param calendar pointer to a calendar object\n * @param highlighted pointer to an `lv_calendar_date_t` array containing the dates. ONLY A POINTER WILL BE SAVED! CAN'T BE LOCAL ARRAY.\n * @param date_num number of dates in the array\n */\nvoid lv_calendar_set_highlighted_dates(lv_obj_t * calendar, lv_calendar_date_t * highlighted, uint16_t date_num)\n{\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n    ext->highlighted_dates = highlighted;\n    ext->highlighted_dates_num = date_num;\n\n    lv_obj_invalidate(calendar);\n}\n\n\n/**\n * Set the name of the days\n * @param calendar pointer to a calendar object\n * @param day_names pointer to an array with the names. E.g. `const char * days[7] = {\"Sun\", \"Mon\", ...}`\n *                  Only the pointer will be saved so this variable can't be local which will be destroyed later.\n */\nvoid lv_calendar_set_day_names(lv_obj_t * calendar, const char ** day_names)\n{\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n    ext->day_names = day_names;\n    lv_obj_invalidate(calendar);\n}\n\n/**\n * Set the name of the month\n * @param calendar pointer to a calendar object\n * @param day_names pointer to an array with the names. E.g. `const char * days[12] = {\"Jan\", \"Feb\", ...}`\n *                  Only the pointer will be saved so this variable can't be local which will be destroyed later.\n */\nvoid lv_calendar_set_month_names(lv_obj_t * calendar, const char ** day_names)\n{\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n    ext->month_names = day_names;\n    lv_obj_invalidate(calendar);\n}\n\n/**\n * Set a style of a calendar.\n * @param calendar pointer to calendar object\n * @param type which style should be set\n * @param style pointer to a style\n *  */\nvoid lv_calendar_set_style(lv_obj_t * calendar, lv_calendar_style_t type, lv_style_t * style)\n{\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n\n    switch(type) {\n    case LV_CALENDAR_STYLE_BG:\n        lv_obj_set_style(calendar, style);\n        break;\n    case LV_CALENDAR_STYLE_DAY_NAMES:\n        ext->style_day_names = style;\n        break;\n    case LV_CALENDAR_STYLE_HEADER:\n        ext->style_header = style;\n        break;\n    case LV_CALENDAR_STYLE_HEADER_PR:\n        ext->style_header_pr = style;\n        break;\n    case LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS:\n        ext->style_highlighted_days = style;\n        break;\n    case LV_CALENDAR_STYLE_INACTIVE_DAYS:\n        ext->style_inactive_days = style;\n        break;\n    case LV_CALENDAR_STYLE_TODAY_BOX:\n        ext->style_today_box = style;\n        break;\n    case LV_CALENDAR_STYLE_WEEK_BOX:\n        ext->style_week_box = style;\n        break;\n    }\n\n    lv_obj_invalidate(calendar);\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the action of a calendar\n * @param calendar pointer to a calendar object\n * @return pointer to the action function\n */\nlv_action_t lv_calendar_get_action(const lv_obj_t * calendar, lv_calendar_action_t type)\n{\n    if(type >= LV_CALENDAR_ACTION_NUM) return NULL;\n\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n    return ext->actions[type];\n}\n\n/**\n * Get the today's date\n * @param calendar pointer to a calendar object\n * @return return pointer to an `lv_calendar_date_t` variable containing the date of today.\n */\nlv_calendar_date_t * lv_calendar_get_today_date(const lv_obj_t * calendar)\n{\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n    return &ext->today;\n}\n\n/**\n * Get the currently showed\n * @param calendar pointer to a calendar object\n * @return pointer to an `lv_calendar_date_t` variable containing the date is being shown.\n */\nlv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * calendar)\n{\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n    return &ext->showed_date;\n}\n\n/**\n * Get the the pressed date.\n * @param calendar pointer to a calendar object\n * @return pointer to an `lv_calendar_date_t` variable containing the pressed date.\n */\nlv_calendar_date_t * lv_calendar_get_pressed_date(const lv_obj_t * calendar)\n{\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n    return &ext->pressed_date;\n}\n\n/**\n * Get the the highlighted dates\n * @param calendar pointer to a calendar object\n * @return pointer to an `lv_calendar_date_t` array containing the dates.\n */\nlv_calendar_date_t * lv_calendar_get_highlighted_dates(const lv_obj_t * calendar)\n{\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n    return ext->highlighted_dates;\n}\n\n/**\n * Get the number of the highlighted dates\n * @param calendar pointer to a calendar object\n * @return number of highlighted days\n */\nuint16_t lv_calendar_get_highlighted_dates_num(const lv_obj_t * calendar)\n{\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n    return ext->highlighted_dates_num;\n}\n\n/**\n * Get the name of the days\n * @param calendar pointer to a calendar object\n * @return pointer to the array of day names\n */\nconst char ** lv_calendar_get_day_names(const lv_obj_t * calendar)\n{\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n    return ext->day_names;\n}\n\n/**\n * Get the name of the month\n * @param calendar pointer to a calendar object\n * @return pointer to the array of month names\n */\nconst char ** lv_calendar_get_month_names(const lv_obj_t * calendar)\n{\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n    return ext->month_names;\n}\n\n/**\n * Get style of a calendar.\n * @param calendar pointer to calendar object\n * @param type which style should be get\n * @return style pointer to the style\n *  */\nlv_style_t * lv_calendar_get_style(const lv_obj_t * calendar, lv_calendar_style_t type)\n{\n    lv_style_t * style = NULL;\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n\n    switch(type) {\n        case LV_CALENDAR_STYLE_BG:\n            style = lv_obj_get_style(calendar);\n            break;\n        case LV_CALENDAR_STYLE_HEADER:\n            style = ext->style_header;\n            break;\n        case LV_CALENDAR_STYLE_HEADER_PR:\n            style = ext->style_header_pr;\n            break;\n        case LV_CALENDAR_STYLE_DAY_NAMES:\n            style = ext->style_day_names;\n            break;\n        case LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS:\n            style = ext->style_highlighted_days;\n            break;\n        case LV_CALENDAR_STYLE_INACTIVE_DAYS:\n            style = ext->style_inactive_days;\n            break;\n        case LV_CALENDAR_STYLE_WEEK_BOX:\n            style = ext->style_week_box;\n            break;\n        case LV_CALENDAR_STYLE_TODAY_BOX:\n            style = ext->style_today_box;\n            break;\n        default:\n            style = NULL;\n            break;\n    }\n\n    return style;\n}\n\n/*=====================\n * Other functions\n *====================*/\n\n/*\n * New object specific \"other\" functions come here\n */\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Handle the drawing related tasks of the calendars\n * @param calendar pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_calendar_design(lv_obj_t * calendar, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    /*Return false if the object is not covers the mask_p area*/\n    if(mode == LV_DESIGN_COVER_CHK) {\n        return false;\n    }\n    /*Draw the object*/\n    else if(mode == LV_DESIGN_DRAW_MAIN) {\n        lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar);\n        lv_draw_rect(&calendar->coords, mask, lv_calendar_get_style(calendar, LV_CALENDAR_STYLE_BG), opa_scale);\n\n        draw_header(calendar, mask);\n        draw_day_names(calendar, mask);\n        draw_days(calendar, mask);\n\n    }\n    /*Post draw when the children are drawn*/\n    else if(mode == LV_DESIGN_DRAW_POST) {\n\n    }\n\n    return true;\n}\n\n/**\n * Signal function of the calendar\n * @param calendar pointer to a calendar object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_calendar_signal(lv_obj_t * calendar, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(calendar, sign, param);\n    if(res != LV_RES_OK) return res;\n\n\n    if(sign == LV_SIGNAL_CLEANUP) {\n        /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/\n    } else if(sign == LV_SIGNAL_PRESSED) {\n        lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n        /*Call the press action, 'param' is the caller indev_proc*/\n        if(ext->actions[LV_CALENDAR_ACTION_PR]) {\n            lv_indev_t * indev = lv_indev_get_act();\n            lv_point_t p;\n            lv_indev_get_point(indev, &p);\n\n            if(calculate_touched_day(calendar, &p)){\n                if(ext->btn_pressing != 0) lv_obj_invalidate(calendar);\n                ext->btn_pressing = 0;\n                res = ext->actions[LV_CALENDAR_ACTION_PR](calendar);\n            }\n        }\n    } else if(sign == LV_SIGNAL_PRESSING) {\n        lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n        lv_area_t header_area;\n        lv_area_copy(&header_area, &calendar->coords);\n        header_area.y2 = header_area.y1 + get_header_height(calendar);\n\n        lv_indev_t * indev = lv_indev_get_act();\n        lv_point_t p;\n        lv_indev_get_point(indev, &p);\n\n        if(lv_area_is_point_on(&header_area, &p)) {\n            if(p.x < header_area.x1 + lv_area_get_width(&header_area) / 2) {\n                if(ext->btn_pressing != -1) lv_obj_invalidate(calendar);\n                ext->btn_pressing = -1;\n            } else {\n                if(ext->btn_pressing != 1) lv_obj_invalidate(calendar);\n                ext->btn_pressing = 1;\n            }\n\n            ext->pressed_date.year = 0;\n        } else if(calculate_touched_day(calendar, &p)) {\n            if(ext->btn_pressing != 0) lv_obj_invalidate(calendar);\n            ext->btn_pressing = 0;\n        } else {\n            if(ext->btn_pressing != 0) lv_obj_invalidate(calendar);\n            ext->btn_pressing = 0;\n            ext->pressed_date.year = 0;\n        }\n    } else if(sign == LV_SIGNAL_PRESS_LOST) {\n        lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n        ext->pressed_date.year = 0;\n        ext->btn_pressing = 0;\n        lv_obj_invalidate(calendar);\n\n    } else if(sign == LV_SIGNAL_RELEASED) {\n        lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n        if(ext->btn_pressing < 0) {\n            if(ext->showed_date.month <= 1) {\n                ext->showed_date.month = 12;\n                ext->showed_date.year --;\n            } else {\n                ext->showed_date.month --;\n            }\n        } else if(ext->btn_pressing >  0) {\n            if(ext->showed_date.month >= 12) {\n                ext->showed_date.month = 1;\n                ext->showed_date.year ++;\n            } else {\n                ext->showed_date.month ++;\n            }\n        }\n        else if(ext->pressed_date.year != 0)\n        {\n            if(ext->actions[LV_CALENDAR_ACTION_CLICK]) {\n                res = ext->actions[LV_CALENDAR_ACTION_CLICK](calendar);\n            }\n        }\n\n        ext->pressed_date.year = 0;\n        ext->btn_pressing = 0;\n        lv_obj_invalidate(calendar);\n\n\n    } else if(sign == LV_SIGNAL_LONG_PRESS) {\n        lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n        if(ext->actions[LV_CALENDAR_ACTION_LONG_PR] && (ext->pressed_date.year != 0)) {\n            res = ext->actions[LV_CALENDAR_ACTION_LONG_PR](calendar);\n        }\n    } else if(sign == LV_SIGNAL_LONG_PRESS_REP) {\n        lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n        if(ext->actions[LV_CALENDAR_ACTION_LONG_PR_REPEAT] && (ext->pressed_date.year != 0)) {\n            res = ext->actions[LV_CALENDAR_ACTION_LONG_PR_REPEAT](calendar);\n        }\n    } else if(sign == LV_SIGNAL_CONTROLL) {\n        uint8_t c = *((uint8_t *) param);\n        lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n        if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_UP) {\n            if(ext->showed_date.month >= 12) {\n                ext->showed_date.month = 1;\n                ext->showed_date.year ++;\n            } else {\n                ext->showed_date.month ++;\n            }\n            lv_obj_invalidate(calendar);\n        } else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_DOWN) {\n            if(ext->showed_date.month <= 1) {\n                ext->showed_date.month = 12;\n                ext->showed_date.year --;\n            } else {\n                ext->showed_date.month --;\n            }\n            lv_obj_invalidate(calendar);\n        }\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set date*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_calendar\";\n    }\n\n    return res;\n}\n\n/**\n * It will check if the days part of calendar is touched\n * and if it is, it will calculate the day and put it in pressed_date of calendar object.\n * @param calendar pointer to a calendar object\n * @param pointer to a point\n * @return true: days part of calendar is touched and its related date is put in pressed date\n * false: the point is out of days part area.\n */\nstatic bool calculate_touched_day(lv_obj_t * calendar, const lv_point_t * touched_point)\n{\n    lv_area_t days_area;\n    lv_area_copy(&days_area, &calendar->coords);\n    lv_style_t * style_bg = lv_calendar_get_style(calendar, LV_CALENDAR_STYLE_BG);\n    days_area.x1 += style_bg->body.padding.hor;\n    days_area.x2 -= style_bg->body.padding.hor;\n    days_area.y1 = calendar->coords.y1 + get_header_height(calendar) + get_day_names_height(calendar) - style_bg->body.padding.ver;\n\n    if(lv_area_is_point_on(&days_area, touched_point)) {\n        lv_coord_t w = (days_area.x2 - days_area.x1 + 1) / 7;\n        lv_coord_t h = (days_area.y2 - days_area.y1 + 1) / 6;\n        uint8_t x_pos = 0;\n        x_pos = (touched_point->x - days_area.x1) / w;\n        if(x_pos > 6) x_pos = 6;\n        uint8_t y_pos = 0;\n        y_pos = (touched_point->y - days_area.y1) / h;\n        if(y_pos > 5) y_pos = 5;\n\n        uint8_t i_pos = 0;\n        i_pos = (y_pos * 7) + x_pos;\n        lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n        if(i_pos < get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1) ) {\n            ext->pressed_date.year = ext->showed_date.year - (ext->showed_date.month == 1 ? 1 : 0);\n            ext->pressed_date.month = ext->showed_date.month == 1 ? 12 : (ext->showed_date.month - 1);\n            ext->pressed_date.day = get_month_length(ext->pressed_date.year, ext->pressed_date.month) -\n                    get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1) + 1 + i_pos;\n        }\n        else if(i_pos < (get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1) +\n                get_month_length(ext->showed_date.year, ext->showed_date.month))) {\n            ext->pressed_date.year = ext->showed_date.year;\n            ext->pressed_date.month = ext->showed_date.month;\n            ext->pressed_date.day = i_pos + 1 - get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1);\n        }\n        else if(i_pos < 42) {\n            ext->pressed_date.year = ext->showed_date.year + (ext->showed_date.month == 12 ? 1 : 0);\n            ext->pressed_date.month = ext->showed_date.month == 12 ? 1 : (ext->showed_date.month + 1);\n            ext->pressed_date.day = i_pos + 1 - get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1)\n                                                                                                                                                                                                                                                                                           - get_month_length(ext->showed_date.year, ext->showed_date.month);\n        }\n        return true;\n    }else {\n        return false;\n    }\n}\n\n/**\n * Get the height of a calendar's header based on it's style\n * @param calendar point to a calendar\n * @return the header's height\n */\nstatic lv_coord_t get_header_height(lv_obj_t * calendar)\n{\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n\n    return lv_font_get_height(ext->style_header->text.font) + ext->style_header->body.padding.ver * 2;\n}\n\n/**\n * Get the height of a calendar's day_names based on it's style\n * @param calendar point to a calendar\n * @return the day_names's height\n */\nstatic lv_coord_t get_day_names_height(lv_obj_t * calendar)\n{\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n\n    return lv_font_get_height(ext->style_day_names->text.font) + ext->style_day_names->body.padding.ver * 2;\n}\n\n/**\n * Draw the calendar header with month name and arrows\n * @param calendar point to a calendar\n * @param mask a mask for drawing\n */\nstatic void draw_header(lv_obj_t * calendar, const lv_area_t * mask)\n{\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n    lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar);\n\n    lv_area_t header_area;\n    header_area.x1 = calendar->coords.x1;\n    header_area.x2 = calendar->coords.x2;\n    header_area.y1 = calendar->coords.y1;\n    header_area.y2 = calendar->coords.y1 + get_header_height(calendar);\n\n    lv_draw_rect(&header_area, mask, ext->style_header, opa_scale);\n\n    /*Add the year + month name*/\n    char txt_buf[64];\n    lv_math_num_to_str(ext->showed_date.year, txt_buf);\n    txt_buf[4] =  ' ';\n    txt_buf[5] =  '\\0';\n    strcpy(&txt_buf[5], get_month_name(calendar, ext->showed_date.month));\n    header_area.y1 += ext->style_header->body.padding.ver;\n    lv_draw_label(&header_area, mask, ext->style_header, opa_scale, txt_buf, LV_TXT_FLAG_CENTER, NULL);\n\n    /*Add the left arrow*/\n    lv_style_t * arrow_style = ext->btn_pressing < 0 ? ext->style_header_pr : ext->style_header;\n    header_area.x1 += ext->style_header->body.padding.hor;\n    lv_draw_label(&header_area, mask, arrow_style, opa_scale, SYMBOL_LEFT, LV_TXT_FLAG_NONE, NULL);\n\n    /*Add the right arrow*/\n    arrow_style = ext->btn_pressing > 0 ? ext->style_header_pr : ext->style_header;\n    header_area.x1 = header_area.x2 - ext->style_header->body.padding.hor -\n            lv_txt_get_width(SYMBOL_RIGHT, strlen(SYMBOL_RIGHT), arrow_style->text.font,\n                    arrow_style->text.line_space, LV_TXT_FLAG_NONE);\n    lv_draw_label(&header_area, mask, arrow_style, opa_scale, SYMBOL_RIGHT, LV_TXT_FLAG_NONE, NULL);\n\n}\n\n/**\n * Draw the day's name below the header\n * @param calendar point to a calendar\n * @param mask a mask for drawing\n */\nstatic void draw_day_names(lv_obj_t * calendar, const lv_area_t * mask)\n{\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n    lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar);\n\n    lv_coord_t hpad = ext->style_day_names->body.padding.hor;\n    lv_coord_t w = lv_obj_get_width(calendar) - 2 * hpad;\n    lv_coord_t box_w = w / 7;\n    lv_area_t label_area;\n    label_area.y1 = calendar->coords.y1 + get_header_height(calendar) + ext->style_day_names->body.padding.ver;\n    label_area.y2 = label_area.y1 + lv_font_get_height(ext->style_day_names->text.font);\n    uint32_t i;\n    for(i = 0; i < 7; i++) {\n        label_area.x1 = calendar->coords.x1 + (w * i) / 7 + hpad;\n        label_area.x2 = label_area.x1 + box_w;\n        lv_draw_label(&label_area, mask, ext->style_day_names, opa_scale, get_day_name(calendar, i), LV_TXT_FLAG_CENTER, NULL);\n    }\n\n}\n\n/**\n * Draw the date numbers in a matrix\n * @param calendar point to a calendar\n * @param mask a mask for drawing\n */\nstatic void draw_days(lv_obj_t * calendar, const lv_area_t * mask)\n{\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n    lv_style_t * style_bg = lv_calendar_get_style(calendar, LV_CALENDAR_STYLE_BG);\n    lv_coord_t hpad = style_bg->body.padding.hor;\n    lv_area_t label_area;\n    lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar);\n    label_area.y1 = calendar->coords.y1 + get_header_height(calendar) +\n            ext->style_day_names->body.padding.ver + lv_font_get_height(ext->style_day_names->text.font) +\n            ext->style_day_names->body.padding.ver;\n    label_area.y2 = label_area.y1 + lv_font_get_height(style_bg->text.font);\n\n    lv_coord_t w = lv_obj_get_width(calendar) - 2 * hpad;\n    lv_coord_t h = calendar->coords.y2 - label_area.y1 - style_bg->body.padding.ver;\n    lv_coord_t box_w = w / 7;\n    lv_coord_t vert_space = (h - (6 * lv_font_get_height(style_bg->text.font))) / 5;\n\n    uint32_t week;\n    uint8_t day_cnt;\n    uint8_t month_start_day = get_day_of_week(ext->showed_date.year, ext->showed_date.month, 1);\n    day_draw_state_t draw_state;    /*true: Not the prev. or next month is drawn*/\n    lv_style_t * act_style;\n\n    /*If starting with the first day of the week then the previous month is not visible*/\n    if(month_start_day == 0) {\n        day_cnt = 1;\n        draw_state = DAY_DRAW_ACT_MONTH;\n        act_style = style_bg;\n    } else {\n        draw_state = DAY_DRAW_PREV_MONTH;\n        day_cnt = get_month_length(ext->showed_date.year, ext->showed_date.month - 1); /*Length of the previous month*/\n        day_cnt -= month_start_day - 1;             /*First visible number of the previous month*/\n        act_style = ext->style_inactive_days;\n    }\n\n\n    bool month_of_today_shown = false;\n    if(ext->showed_date.year ==  ext->today.year &&\n            ext->showed_date.month ==  ext->today.month) {\n        month_of_today_shown = true;\n    }\n\n    char buf[3];\n    bool in_week_box = false;\n\n    /*Draw 6 weeks*/\n    for(week = 0; week < 6; week++) {\n\n        /*Draw the \"week box\"*/\n        if(month_of_today_shown &&\n                ((draw_state == DAY_DRAW_ACT_MONTH  && ext->today.day >= day_cnt && ext->today.day < day_cnt + 7) ||\n                        (draw_state == DAY_DRAW_PREV_MONTH && ext->today.day <= 7 - month_start_day && week == 0))) {\n            lv_area_t week_box_area;\n            lv_area_copy(&week_box_area, &label_area);      /*'label_area' is already set for this row*/\n            week_box_area.x1 = calendar->coords.x1 + style_bg->body.padding.hor - ext->style_week_box->body.padding.hor;\n            week_box_area.x2 = calendar->coords.x2 - style_bg->body.padding.hor + ext->style_week_box->body.padding.hor;\n\n            week_box_area.y1 -= ext->style_week_box->body.padding.ver;\n            week_box_area.y2 += ext->style_week_box->body.padding.ver;\n            lv_draw_rect(&week_box_area, mask, ext->style_week_box, opa_scale);\n\n            in_week_box = true;\n        } else {\n            in_week_box = false;\n        }\n\n        /*Draw the 7 days of a week*/\n        uint32_t day;\n        for(day = 0; day < 7; day++) {\n            /*The previous month is over*/\n            if(draw_state == DAY_DRAW_PREV_MONTH && day == month_start_day) {\n                draw_state = DAY_DRAW_ACT_MONTH;\n                day_cnt = 1;\n                act_style = style_bg;\n            }\n            /*The current month is over*/\n            if(draw_state == DAY_DRAW_ACT_MONTH &&\n                    day_cnt > get_month_length(ext->showed_date.year, ext->showed_date.month)) {\n                draw_state = DAY_DRAW_NEXT_MONTH;\n                day_cnt = 1;\n                act_style = ext->style_inactive_days;\n            }\n\n            label_area.x1 = calendar->coords.x1 + (w * day) / 7 + hpad;\n            label_area.x2 = label_area.x1 + box_w;\n\n            /*Draw the \"today box\"*/\n            if(draw_state == DAY_DRAW_ACT_MONTH && month_of_today_shown && ext->today.day == day_cnt) {\n                lv_area_t today_box_area;\n                lv_area_copy(&today_box_area, &label_area);\n                today_box_area.x1 = label_area.x1;\n                today_box_area.x2 = label_area.x2;\n\n                today_box_area.y1 = label_area.y1 - ext->style_today_box->body.padding.ver;\n                today_box_area.y2 = label_area.y2 + ext->style_today_box->body.padding.ver;\n                lv_draw_rect(&today_box_area, mask, ext->style_today_box, opa_scale);\n            }\n\n            /*Get the final style : highlighted/week box/today box/normal*/\n            lv_style_t * final_style;\n            if(draw_state == DAY_DRAW_PREV_MONTH &&\n                    is_highlighted(calendar, ext->showed_date.year - (ext->showed_date.month == 1 ? 1 : 0),\n                            ext->showed_date.month == 1 ? 12 : ext->showed_date.month - 1,\n                                    day_cnt)) {\n                final_style = ext->style_highlighted_days;\n            } else if(draw_state == DAY_DRAW_ACT_MONTH &&\n                    is_highlighted(calendar, ext->showed_date.year,\n                            ext->showed_date.month,\n                            day_cnt)) {\n                final_style = ext->style_highlighted_days;\n            } else if(draw_state == DAY_DRAW_NEXT_MONTH &&\n                    is_highlighted(calendar, ext->showed_date.year + (ext->showed_date.month == 12 ? 1 : 0),\n                            ext->showed_date.month == 12 ? 1 : ext->showed_date.month + 1,\n                                    day_cnt)) {\n                final_style = ext->style_highlighted_days;\n            } else if(month_of_today_shown && day_cnt == ext->today.day && draw_state == DAY_DRAW_ACT_MONTH) final_style = ext->style_today_box;\n            else if(in_week_box && draw_state == DAY_DRAW_ACT_MONTH) final_style = ext->style_week_box;\n            else final_style = act_style;\n\n            /*Write the day's number*/\n            lv_math_num_to_str(day_cnt, buf);\n            lv_draw_label(&label_area, mask, final_style, opa_scale, buf, LV_TXT_FLAG_CENTER, NULL);\n\n            /*Go to the next day*/\n            day_cnt ++;\n\n        }\n\n        /*Got to the next weeks row*/\n        label_area.y1 += vert_space + lv_font_get_height(style_bg->text.font);\n        label_area.y2 += vert_space + lv_font_get_height(style_bg->text.font);\n    }\n}\n\n/**\n * Check weather a date is highlighted or not\n * @param calendar pointer to a calendar object\n * @param year a year\n * @param month a  month [1..12]\n * @param day a day [1..31]\n * @return true: highlighted\n */\nstatic bool is_highlighted(lv_obj_t * calendar, int32_t year, int32_t month, int32_t day)\n{\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n\n    if(ext->highlighted_dates == NULL || ext->highlighted_dates_num == 0) return false;\n\n    uint32_t i;\n    for(i = 0; i < ext->highlighted_dates_num; i++) {\n        if(ext->highlighted_dates[i].year == year &&\n                ext->highlighted_dates[i].month == month &&\n                ext->highlighted_dates[i].day == day) {\n            return true;\n        }\n    }\n\n    return false;\n}\n\n/**\n * Get the day name\n * @param calendar pointer to a calendar object\n * @param day a day in [0..6]\n * @return\n */\nstatic const char * get_day_name(lv_obj_t * calendar, uint8_t day)\n{\n\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n    if(ext->day_names) return ext->day_names[day];\n    else return day_name[day];\n}\n\n/**\n * Get the month name\n * @param calendar pointer to a calendar object\n * @param month a month. The range is basically [1..12] but [-11..1] is also supported to handle previous year\n * @return\n */\nstatic const char * get_month_name(lv_obj_t * calendar, int32_t month)\n{\n    month --;   /*Range of months id [1..12] but range of indexes is [0..11]*/\n    if(month < 0) month = 12 + month;\n\n    lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);\n    if(ext->month_names) return ext->month_names[month];\n    else return month_name[month];\n}\n\n/**\n * Get the number of days in a month\n * @param year a year\n * @param month a month. The range is basically [1..12] but [-11..1] is also supported to handle previous year\n * @return [28..31]\n */\nstatic uint8_t get_month_length(int32_t year, int32_t month)\n{\n    month --;   /*Range of months id [1..12] but range of indexes is [0..11]*/\n    if(month < 0) {\n        year--;   /*Already in the previous year (won't be less then -12 to skip a whole year)*/\n        month = 12 + month; /*`month` is negative, the result will be < 12*/\n    }\n    if(month >= 12) {\n        year ++;\n        month -= 12;\n    }\n\n    /*month == 1 is february*/\n    return (month == 1) ? (28 + is_leap_year(year)) : 31 - month % 7 % 2;\n\n\n}\n\n/**\n * Tells whether a year is leap year or not\n * @param year a year\n * @return 0: not leap year; 1: leap year\n */\nstatic uint8_t is_leap_year(uint32_t year)\n{\n    return (year % 4) || ((year % 100 == 0) && (year % 400)) ? 0 : 1;\n}\n\n/**\n * Get the day of the week\n * @param year a year\n * @param month a  month\n * @param day a day\n * @return [0..6] which means [Sun..Sat]\n */\nstatic uint8_t get_day_of_week(uint32_t year, uint32_t month, uint32_t day)\n{\n    uint32_t a = month < 3 ? 1 : 0;\n    uint32_t b = year - a;\n\n    uint32_t day_of_week = (day + (31 * (month - 2 + 12 * a) / 12) +\n            b + (b / 4) - (b / 100) + (b / 400)) % 7;\n\n    return day_of_week;\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_calendar.h",
    "content": "/**\n * @file lv_calendar.h\n *\n */\n\n#ifndef LV_CALENDAR_H\n#define LV_CALENDAR_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_CALENDAR != 0\n\n#include \"../lv_core/lv_obj.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\ntypedef struct {\n    uint16_t year;\n    int8_t month;\n    int8_t day;\n} lv_calendar_date_t;\n\nenum\n{\n    LV_CALENDAR_ACTION_CLICK,\n    LV_CALENDAR_ACTION_PR,\n    LV_CALENDAR_ACTION_LONG_PR,\n    LV_CALENDAR_ACTION_LONG_PR_REPEAT,\n    LV_CALENDAR_ACTION_NUM,\n};\ntypedef uint8_t lv_calendar_action_t;\n\n/*Data of calendar*/\ntypedef struct {\n    /*None*/ /*Ext. of ancestor*/\n    /*New data for this type */\n    lv_calendar_date_t today;          /*Date of today*/\n    lv_calendar_date_t showed_date;   /*Currently visible month (day is ignored)*/\n    lv_calendar_date_t * highlighted_dates;  /*Apply different style on these days (pointer to an array defined by the user)*/\n    uint8_t highlighted_dates_num;           /*Number of elements in `highlighted_days`*/\n    int8_t btn_pressing;                    /*-1: prev month pressing, +1 next month pressing on the header*/\n    lv_calendar_date_t pressed_date;\n    const char ** day_names;            /*Pointer to an array with the name of the days (NULL: use default names)*/\n    const char ** month_names;          /*Pointer to an array with the name of the month (NULL. use default names)*/\n    lv_action_t actions[LV_CALENDAR_ACTION_NUM];\n\n    /*Styles*/\n    lv_style_t * style_header;\n    lv_style_t * style_header_pr;\n    lv_style_t * style_day_names;\n    lv_style_t * style_highlighted_days;\n    lv_style_t * style_inactive_days;\n    lv_style_t * style_week_box;\n    lv_style_t * style_today_box;\n} lv_calendar_ext_t;\n\n/*Styles*/\nenum {\n    LV_CALENDAR_STYLE_BG,       /*Also the style of the \"normal\" date numbers*/\n    LV_CALENDAR_STYLE_HEADER,\n    LV_CALENDAR_STYLE_HEADER_PR,\n    LV_CALENDAR_STYLE_DAY_NAMES,\n    LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS,\n    LV_CALENDAR_STYLE_INACTIVE_DAYS,\n    LV_CALENDAR_STYLE_WEEK_BOX,\n    LV_CALENDAR_STYLE_TODAY_BOX,\n};\ntypedef uint8_t lv_calendar_style_t;\n\n\n\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a calendar objects\n * @param par pointer to an object, it will be the parent of the new calendar\n * @param copy pointer to a calendar object, if not NULL then the new object will be copied from it\n * @return pointer to the created calendar\n */\nlv_obj_t * lv_calendar_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n\n/*=====================\n * Setter functions\n *====================*/\n/**\n * Set a function to call when a calendar event happens\n * @param calendar pointer to a calendar object\n * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat)\n */\nvoid lv_calendar_set_action(lv_obj_t * calendar, lv_calendar_action_t type, lv_action_t action);\n\n/**\n * Set the today's date\n * @param calendar pointer to a calendar object\n * @param today pointer to an `lv_calendar_date_t` variable containing the date of today. The value will be saved it can be local variable too.\n */\nvoid lv_calendar_set_today_date(lv_obj_t * calendar, lv_calendar_date_t * today);\n\n/**\n * Set the currently showed\n * @param calendar pointer to a calendar object\n * @param showed pointer to an `lv_calendar_date_t` variable containing the date to show. The value will be saved it can be local variable too.\n */\nvoid lv_calendar_set_showed_date(lv_obj_t * calendar, lv_calendar_date_t * showed);\n\n/**\n * Set the the highlighted dates\n * @param calendar pointer to a calendar object\n * @param highlighted pointer to an `lv_calendar_date_t` array containing the dates. ONLY A POINTER WILL BE SAVED! CAN'T BE LOCAL ARRAY.\n * @param date_num number of dates in the array\n */\nvoid lv_calendar_set_highlighted_dates(lv_obj_t * calendar, lv_calendar_date_t * highlighted, uint16_t date_num);\n\n\n/**\n * Set the name of the days\n * @param calendar pointer to a calendar object\n * @param day_names pointer to an array with the names. E.g. `const char * days[7] = {\"Sun\", \"Mon\", ...}`\n *                  Only the pointer will be saved so this variable can't be local which will be destroyed later.\n */\nvoid lv_calendar_set_day_names(lv_obj_t * calendar, const char ** day_names);\n\n/**\n * Set the name of the month\n * @param calendar pointer to a calendar object\n * @param day_names pointer to an array with the names. E.g. `const char * days[12] = {\"Jan\", \"Feb\", ...}`\n *                  Only the pointer will be saved so this variable can't be local which will be destroyed later.\n */\nvoid lv_calendar_set_month_names(lv_obj_t * calendar, const char ** day_names);\n\n/**\n * Set a style of a calendar.\n * @param calendar pointer to calendar object\n * @param type which style should be set\n * @param style pointer to a style\n *  */\nvoid lv_calendar_set_style(lv_obj_t * calendar, lv_calendar_style_t type, lv_style_t *style);\n\n/*=====================\n * Getter functions\n *====================*/\n/**\n * Get the action of a calendar\n * @param calendar pointer to a calendar object\n * @return pointer to the action function\n */\nlv_action_t lv_calendar_get_action(const lv_obj_t * calendar, lv_calendar_action_t type);\n\n/**\n * Get the today's date\n * @param calendar pointer to a calendar object\n * @return return pointer to an `lv_calendar_date_t` variable containing the date of today.\n */\nlv_calendar_date_t * lv_calendar_get_today_date(const lv_obj_t * calendar);\n\n/**\n * Get the currently showed\n * @param calendar pointer to a calendar object\n * @return pointer to an `lv_calendar_date_t` variable containing the date is being shown.\n */\nlv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * calendar);\n\n/**\n * Get the the pressed date.\n * @param calendar pointer to a calendar object\n * @return pointer to an `lv_calendar_date_t` variable containing the pressed date.\n */\nlv_calendar_date_t * lv_calendar_get_pressed_date(const lv_obj_t * calendar);\n\n/**\n * Get the the highlighted dates\n * @param calendar pointer to a calendar object\n * @return pointer to an `lv_calendar_date_t` array containing the dates.\n */\nlv_calendar_date_t * lv_calendar_get_highlighted_dates(const lv_obj_t * calendar);\n\n/**\n * Get the number of the highlighted dates\n * @param calendar pointer to a calendar object\n * @return number of highlighted days\n */\nuint16_t lv_calendar_get_highlighted_dates_num(const lv_obj_t * calendar);\n\n\n/**\n * Get the name of the days\n * @param calendar pointer to a calendar object\n * @return pointer to the array of day names\n */\nconst char ** lv_calendar_get_day_names(const lv_obj_t * calendar);\n\n/**\n * Get the name of the month\n * @param calendar pointer to a calendar object\n * @return pointer to the array of month names\n */\nconst char ** lv_calendar_get_month_names(const lv_obj_t * calendar);\n\n/**\n * Get style of a calendar.\n * @param calendar pointer to calendar object\n * @param type which style should be get\n * @return style pointer to the style\n *  */\nlv_style_t * lv_calendar_get_style(const lv_obj_t * calendar, lv_calendar_style_t type);\n\n/*=====================\n * Other functions\n *====================*/\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_CALENDAR*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_CALENDAR_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_canvas.c",
    "content": "/**\n * @file lv_canvas.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_canvas.h\"\n#if USE_LV_CANVAS != 0\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic lv_res_t lv_canvas_signal(lv_obj_t * canvas, lv_signal_t sign, void * param);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\nstatic lv_design_func_t ancestor_design;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a canvas object\n * @param par pointer to an object, it will be the parent of the new canvas\n * @param copy pointer to a canvas object, if not NULL then the new object will be copied from it\n * @return pointer to the created canvas\n */\nlv_obj_t * lv_canvas_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"canvas create started\");\n\n    /*Create the ancestor of canvas*/\n    lv_obj_t * new_canvas = lv_img_create(par, copy);\n    lv_mem_assert(new_canvas);\n    if(new_canvas == NULL) return NULL;\n\n    /*Allocate the canvas type specific extended data*/\n    lv_canvas_ext_t * ext = lv_obj_allocate_ext_attr(new_canvas, sizeof(lv_canvas_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_canvas);\n    if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_canvas);\n\n    /*Initialize the allocated 'ext' */\n    ext->dsc.header.always_zero = 0;\n    ext->dsc.header.cf = LV_IMG_CF_TRUE_COLOR;\n    ext->dsc.header.h = 0;\n    ext->dsc.header.w = 0;\n    ext->dsc.data_size = 0;\n    ext->dsc.data = NULL;\n\n    lv_img_set_src(new_canvas, &ext->dsc);\n\n    /*The signal and design functions are not copied so set them here*/\n    lv_obj_set_signal_func(new_canvas, lv_canvas_signal);\n\n    /*Init the new canvas canvas*/\n    if(copy == NULL) {\n\n    }\n    /*Copy an existing canvas*/\n    else {\n        //lv_canvas_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_canvas);\n    }\n\n    LV_LOG_INFO(\"canvas created\");\n\n    return new_canvas;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a buffer for the canvas.\n * @param buf a buffer where the content of the canvas will be.\n * The required size is (lv_img_color_format_get_px_size(cf) * w * h) / 8)\n * It can be allocated with `lv_mem_alloc()` or\n * it can be statically allocated array (e.g. static lv_color_t buf[100*50]) or\n * it can be an address in RAM or external SRAM\n * @param canvas pointer to a canvas object\n * @param w width of the canvas\n * @param h height of the canvas\n * @param cf color format. The following formats are supported:\n *      LV_IMG_CF_TRUE_COLOR, LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, LV_IMG_CF_INDEXES_1/2/4/8BIT\n *\n */\nvoid lv_canvas_set_buffer(lv_obj_t * canvas, void * buf, lv_coord_t w, lv_coord_t h, lv_img_cf_t cf)\n{\n    lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas);\n\n    ext->dsc.header.cf = cf;\n    ext->dsc.header.w = w;\n    ext->dsc.header.h = h;\n    ext->dsc.data = buf;\n    ext->dsc.data_size = (lv_img_color_format_get_px_size(cf) * w * h) / 8;\n\n    lv_img_set_src(canvas, &ext->dsc);\n}\n/**\n * Set the color of a pixel on the canvas\n * @param canvas\n * @param x x coordinate of the point to set\n * @param y x coordinate of the point to set\n * @param c color of the point\n */\nvoid lv_canvas_set_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t c)\n{\n\n    lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas);\n    if(x >= ext->dsc.header.w || y >= ext->dsc.header.h) {\n        LV_LOG_WARN(\"lv_canvas_set_px: x or y out of the canvas\");\n        return;\n    }\n\n    uint8_t * buf_u8 = (uint8_t *) ext->dsc.data;\n\n    if(ext->dsc.header.cf == LV_IMG_CF_TRUE_COLOR ||\n            ext->dsc.header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED)\n    {\n        uint32_t px = ext->dsc.header.w * y * sizeof(lv_color_t) + x * sizeof(lv_color_t);\n\n        memcpy(&buf_u8[px], &c, sizeof(lv_color_t));\n    }\n    else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_1BIT) {\n        buf_u8 += 4 * 2;\n        uint8_t bit = x & 0x7;\n        x = x >> 3;\n\n        uint32_t px = (ext->dsc.header.w >> 3) * y + x;\n        buf_u8[px] = buf_u8[px] & ~(1 << (7 - bit));\n        buf_u8[px] = buf_u8[px] | ((c.full & 0x1) << (7 - bit));\n    }\n    else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_2BIT) {\n        buf_u8 += 4 * 4;\n        uint8_t bit = (x & 0x3) * 2;\n        x = x >> 2;\n\n        uint32_t px = (ext->dsc.header.w >> 2) * y + x;\n\n        buf_u8[px] = buf_u8[px] & ~(3 << (6 - bit));\n        buf_u8[px] = buf_u8[px] | ((c.full & 0x3) << (6 - bit));\n    }\n    else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_4BIT) {\n        buf_u8 += 4 * 16;\n        uint8_t bit = (x & 0x1) * 4;\n        x = x >> 1;\n\n        uint32_t px = (ext->dsc.header.w >> 1) * y + x;\n\n        buf_u8[px] = buf_u8[px] & ~(0xF << (4 - bit));\n        buf_u8[px] = buf_u8[px] | ((c.full & 0xF) << (4 - bit));\n    }\n    else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_8BIT) {\n        buf_u8 += 4 * 256;\n        uint32_t px = ext->dsc.header.w * y + x;\n        buf_u8[px] = c.full;\n    }\n}\n\n/**\n * Set a style of a canvas.\n * @param canvas pointer to canvas object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_canvas_set_style(lv_obj_t * canvas, lv_canvas_style_t type, lv_style_t * style)\n{\n    switch(type) {\n    case LV_CANVAS_STYLE_MAIN:\n        lv_img_set_style(canvas, style);\n        break;\n    }\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the color of a pixel on the canvas\n * @param canvas\n * @param x x coordinate of the point to set\n * @param y x coordinate of the point to set\n * @return color of the point\n */\nlv_color_t lv_canvas_get_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y)\n{\n    lv_color_t p_color = LV_COLOR_BLACK;\n    lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas);\n    if(x >= ext->dsc.header.w || y >= ext->dsc.header.h) {\n        LV_LOG_WARN(\"lv_canvas_get_px: x or y out of the canvas\");\n        return p_color;\n    }\n\n    uint8_t * buf_u8 = (uint8_t *) ext->dsc.data;\n\n    if(ext->dsc.header.cf == LV_IMG_CF_TRUE_COLOR ||\n            ext->dsc.header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED)\n    {\n        uint32_t px = ext->dsc.header.w * y * sizeof(lv_color_t) + x * sizeof(lv_color_t);\n        memcpy(&p_color, &buf_u8[px], sizeof(lv_color_t));\n    }\n    else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_1BIT) {\n        buf_u8 += 4 * 2;\n        uint8_t bit = x & 0x7;\n        x = x >> 3;\n\n        uint32_t px = (ext->dsc.header.w >> 3) * y + x;\n        p_color.full = (buf_u8[px] & (1 << (7 - bit))) >> (7 - bit);\n    }\n    else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_2BIT) {\n        buf_u8 += 4 * 4;\n        uint8_t bit = (x & 0x3) * 2;\n        x = x >> 2;\n\n        uint32_t px = (ext->dsc.header.w >> 2) * y + x;\n        p_color.full = (buf_u8[px] & (3 << (6 - bit))) >> (6 - bit);\n    }\n    else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_4BIT) {\n        buf_u8 += 4 * 16;\n        uint8_t bit = (x & 0x1) * 4;\n        x = x >> 1;\n\n        uint32_t px = (ext->dsc.header.w >> 1) * y + x;\n        p_color.full = (buf_u8[px] & (0xF << (4 - bit))) >> (4 - bit);\n    }\n    else if(ext->dsc.header.cf == LV_IMG_CF_INDEXED_8BIT) {\n        buf_u8 += 4 * 256;\n        uint32_t px = ext->dsc.header.w * y + x;\n        p_color.full = buf_u8[px];\n    }\n    return p_color;\n}\n\n/**\n * Get style of a canvas.\n * @param canvas pointer to canvas object\n * @param type which style should be get\n * @return style pointer to the style\n */\nlv_style_t * lv_canvas_get_style(const lv_obj_t * canvas, lv_canvas_style_t type)\n{\n    // lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas);\n    lv_style_t * style = NULL;\n\n    switch(type) {\n    case LV_CANVAS_STYLE_MAIN:\n        style = lv_img_get_style(canvas);\n        break;\n    default:\n        style =  NULL;\n    }\n\n    return style;\n}\n\n/*=====================\n * Other functions\n *====================*/\n\n/**\n * Copy a buffer to the canvas\n * @param canvas pointer to a canvas object\n * @param to_copy buffer to copy. The color format has to match with the canvas's buffer color format\n * @param w width of the buffer to copy\n * @param h height of the buffer to copy\n * @param x left side of the destination position\n * @param y top side of the destination position\n */\nvoid lv_canvas_copy_buf(lv_obj_t * canvas, const void * to_copy, lv_coord_t w, lv_coord_t h, lv_coord_t x, lv_coord_t y)\n{\n    lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas);\n    if(x + w >= ext->dsc.header.w || y + h >= ext->dsc.header.h) {\n        LV_LOG_WARN(\"lv_canvas_copy_buf: x or y out of the canvas\");\n        return;\n    }\n\n    uint32_t px_size = lv_img_color_format_get_px_size(ext->dsc.header.cf) >> 3;\n    uint32_t px = ext->dsc.header.w * y * px_size + x * px_size;\n    uint8_t * to_copy8 = (uint8_t *) to_copy;\n    lv_coord_t i;\n    for(i = 0; i < h; i++) {\n        memcpy((void*)&ext->dsc.data[px], to_copy8, w * px_size);\n        px += ext->dsc.header.w * px_size;\n        to_copy8 += w * px_size;\n    }\n}\n\n/**\n * Multiply a buffer with the canvas\n * @param canvas pointer to a canvas object\n * @param to_copy buffer to copy (multiply). LV_IMG_CF_TRUE_COLOR_ALPHA is not supported\n * @param w width of the buffer to copy\n * @param h height of the buffer to copy\n * @param x left side of the destination position\n * @param y top side of the destination position\n */\nvoid lv_canvas_mult_buf(lv_obj_t * canvas, void * to_copy, lv_coord_t w, lv_coord_t h, lv_coord_t x, lv_coord_t y)\n{\n    lv_canvas_ext_t * ext = lv_obj_get_ext_attr(canvas);\n    if(x + w >= ext->dsc.header.w || y + h >= ext->dsc.header.h) {\n        LV_LOG_WARN(\"lv_canvas_mult_buf: x or y out of the canvas\");\n        return;\n    }\n\n    if(ext->dsc.header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {\n        LV_LOG_WARN(\"lv_canvas_mult_buf: LV_IMG_CF_TRUE_COLOR_ALPHA is not supported\");\n        return;\n    }\n\n    uint32_t px_size = lv_img_color_format_get_px_size(ext->dsc.header.cf) >> 3;\n    uint32_t px = ext->dsc.header.w * y * px_size + x * px_size;\n    lv_color_t * copy_buf_color = (lv_color_t *) to_copy;\n    lv_color_t * canvas_buf_color = (lv_color_t *) &ext->dsc.data[px];\n\n    lv_coord_t i;\n    lv_coord_t j;\n    for(i = 0; i < h; i++) {\n        for(j = 0; j < w; j++) {\n#if LV_COLOR_DEPTH == 32\n            canvas_buf_color[j].red = (uint16_t) ((uint16_t) canvas_buf_color[j].red * copy_buf_color[j].red) >> 8;\n            canvas_buf_color[j].green = (uint16_t) ((uint16_t) canvas_buf_color[j].green * copy_buf_color[j].green) >> 8;\n            canvas_buf_color[j].blue = (uint16_t) ((uint16_t) canvas_buf_color[j].blue * copy_buf_color[j].blue) >> 8;\n#elif LV_COLOR_DEPTH == 16\n\n            canvas_buf_color[j].red = (uint16_t) ((uint16_t) canvas_buf_color[j].red * copy_buf_color[j].red) >> 5;\n            canvas_buf_color[j].blue = (uint16_t) ((uint16_t) canvas_buf_color[j].blue * copy_buf_color[j].blue) >> 5;\n#  if LV_COLOR_16_SWAP == 0\n            canvas_buf_color[j].green = (uint16_t) ((uint16_t) canvas_buf_color[j].green * copy_buf_color[j].green) >> 6;\n#  else\n            uint8_t green_canvas = (canvas_buf_color[j].green_h << 3) + (canvas_buf_color[j].green_l);\n            uint8_t green_buf = (copy_buf_color[j].green_h << 3) + (copy_buf_color[j].green_l);\n            uint8_t green_res = (uint16_t)((uint16_t)green_canvas * green_buf) >> 6;\n            canvas_buf_color[j].green_h = (green_res >> 3) & 0x07;\n            canvas_buf_color[j].green_l = green_res & 0x07;\n#  endif    /*LV_COLOR_16_SWAP*/\n\n#elif LV_COLOR_DEPTH == 8\n            canvas_buf_color[j].red = (uint16_t) ((uint16_t) canvas_buf_color[j].red * copy_buf_color[j].red) >> 3;\n            canvas_buf_color[j].green = (uint16_t) ((uint16_t) canvas_buf_color[j].green * copy_buf_color[j].green) >> 3;\n            canvas_buf_color[j].blue = (uint16_t) ((uint16_t) canvas_buf_color[j].blue * copy_buf_color[j].blue) >> 2;\n#endif\n        }\n        copy_buf_color += w;\n        canvas_buf_color += ext->dsc.header.w;\n    }\n}\n\n/**\n * Draw circle function of the canvas\n * @param canvas pointer to a canvas object\n * @param x0 x coordinate of the circle\n * @param y0 y coordinate of the circle\n * @param radius radius of the circle\n * @param color border color of the circle\n */\nvoid lv_canvas_draw_circle(lv_obj_t * canvas, lv_coord_t x0, lv_coord_t y0, lv_coord_t radius, lv_color_t color)\n{\n    int x = radius;\n    int y = 0;\n    int err = 0;\n\n    while (x >= y)\n    {\n        lv_canvas_set_px(canvas, x0 + x, y0 + y, color);\n        lv_canvas_set_px(canvas, x0 + y, y0 + x, color);\n        lv_canvas_set_px(canvas, x0 - y, y0 + x, color);\n        lv_canvas_set_px(canvas, x0 - x, y0 + y, color);\n        lv_canvas_set_px(canvas, x0 - x, y0 - y, color);\n        lv_canvas_set_px(canvas, x0 - y, y0 - x, color);\n        lv_canvas_set_px(canvas, x0 + y, y0 - x, color);\n        lv_canvas_set_px(canvas, x0 + x, y0 - y, color);\n\n        if (err <= 0)\n        {\n            y += 1;\n            err += 2*y + 1;\n        }\n\n        if (err > 0)\n        {\n            x -= 1;\n            err -= 2*x + 1;\n        }\n    }\n}\n\n/**\n * Draw line function of the canvas\n * @param canvas pointer to a canvas object\n * @param point1 start point of the line\n * @param point2 end point of the line\n * @param color color of the line\n *\n * NOTE: The lv_canvas_draw_line function originates from https://github.com/jb55/bresenham-line.c.\n */\n/*\n * NOTE: The lv_canvas_draw_line function originates from https://github.com/jb55/bresenham-line.c.\n */\nvoid lv_canvas_draw_line(lv_obj_t * canvas, lv_point_t point1, lv_point_t point2, lv_color_t color)\n{\n  lv_coord_t x0, y0, x1, y1;\n\n  x0 = point1.x;\n  y0 = point1.y;\n  x1 = point2.x;\n  y1 = point2.y;\n\n  int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;\n  int dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;\n  int err = (dx>dy ? dx : -dy)/2, e2;\n\n  for(;;){\n    lv_canvas_set_px(canvas, x0, y0, color);\n\n    if (x0==x1 && y0==y1) break;\n    e2 = err;\n    if (e2 >-dx) { err -= dy; x0 += sx; }\n    if (e2 < dy) { err += dx; y0 += sy; }\n  }\n}\n\n/**\n * Draw triangle function of the canvas\n * @param canvas pointer to a canvas object\n * @param points edge points of the triangle\n * @param color line color of the triangle\n */\nvoid lv_canvas_draw_triangle(lv_obj_t * canvas, lv_point_t * points, lv_color_t color)\n{\n  lv_canvas_draw_polygon(canvas, points, 3, color);\n}\n\n/**\n * Draw rectangle function of the canvas\n * @param canvas pointer to a canvas object\n * @param points edge points of the rectangle\n * @param color line color of the rectangle\n */\nvoid lv_canvas_draw_rect(lv_obj_t * canvas, lv_point_t * points, lv_color_t color)\n{\n  lv_canvas_draw_polygon(canvas, points, 4, color);\n}\n\n/**\n * Draw polygon function of the canvas\n * @param canvas pointer to a canvas object\n * @param points edge points of the polygon\n * @param size edge count of the polygon\n * @param color line color of the polygon\n */\nvoid lv_canvas_draw_polygon(lv_obj_t * canvas, lv_point_t * points, size_t size, lv_color_t color)\n{\n  uint8_t i;\n\n  for(i=0; i < (size - 1); i++) {\n    lv_canvas_draw_line(canvas, points[i], points[i + 1], color);\n  }\n\n  lv_canvas_draw_line(canvas, points[size - 1], points[0], color);\n}\n\n/**\n * Fill polygon function of the canvas\n * @param canvas pointer to a canvas object\n * @param points edge points of the polygon\n * @param size edge count of the polygon\n * @param boundary_color line color of the polygon\n * @param fill_color fill color of the polygon\n */\nvoid lv_canvas_fill_polygon(lv_obj_t * canvas, lv_point_t * points, size_t size, lv_color_t boundary_color, lv_color_t fill_color)\n{\n  uint32_t x = 0, y = 0;\n  uint8_t i;\n\n  for(i=0; i<size; i++) {\n    x += points[i].x;\n    y += points[i].y;\n  }\n\n  x = x / size;\n  y = y / size;\n\n  lv_canvas_boundary_fill4(canvas, (lv_coord_t) x, (lv_coord_t) y, boundary_color, fill_color);\n}\n\n/**\n * Boundary fill function of the canvas\n * @param canvas pointer to a canvas object\n * @param x x coordinate of the start position (seed)\n * @param y y coordinate of the start position (seed)\n * @param boundary_color edge/boundary color of the area\n * @param fill_color fill color of the area\n */\nvoid lv_canvas_boundary_fill4(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t boundary_color, lv_color_t fill_color)\n{\n    lv_color_t c;\n\n    c = lv_canvas_get_px(canvas, x, y);\n\n    if(c.full != boundary_color.full &&\n       c.full != fill_color.full)\n    {\n      lv_canvas_set_px(canvas, x, y, fill_color);\n\n      lv_canvas_boundary_fill4(canvas, x + 1,     y, boundary_color, fill_color);\n      lv_canvas_boundary_fill4(canvas,     x, y + 1, boundary_color, fill_color);\n      lv_canvas_boundary_fill4(canvas, x - 1,     y, boundary_color, fill_color);\n      lv_canvas_boundary_fill4(canvas,     x, y - 1, boundary_color, fill_color);\n    }\n}\n\n/**\n * Flood fill function of the canvas\n * @param canvas pointer to a canvas object\n * @param x x coordinate of the start position (seed)\n * @param y y coordinate of the start position (seed)\n * @param fill_color fill color of the area\n * @param bg_color background color of the area\n */\nvoid lv_canvas_flood_fill(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t fill_color, lv_color_t bg_color)\n{\n  lv_color_t c;\n\n  c = lv_canvas_get_px(canvas, x, y);\n\n  if(c.full == bg_color.full)\n  {\n    lv_canvas_set_px(canvas, x, y, fill_color);\n\n    lv_canvas_flood_fill(canvas, x+1,   y, fill_color, bg_color);\n    lv_canvas_flood_fill(canvas,   x, y+1, fill_color, bg_color);\n    lv_canvas_flood_fill(canvas, x-1,   y, fill_color, bg_color);\n    lv_canvas_flood_fill(canvas,   x, y-1, fill_color, bg_color);\n  }\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Signal function of the canvas\n * @param canvas pointer to a canvas object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_canvas_signal(lv_obj_t * canvas, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(canvas, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    if(sign == LV_SIGNAL_CLEANUP) {\n        /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_canvas\";\n    }\n\n    return res;\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_canvas.h",
    "content": "/**\n * @file lv_canvas.h\n *\n */\n\n#ifndef LV_CANVAS_H\n#define LV_CANVAS_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_CANVAS != 0\n\n#include \"../lv_core/lv_obj.h\"\n#include \"../lv_objx/lv_img.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n/*Data of canvas*/\ntypedef struct {\n    lv_img_ext_t img; /*Ext. of ancestor*/\n    /*New data for this type */\n    lv_img_dsc_t dsc;\n} lv_canvas_ext_t;\n\n\n/*Styles*/\nenum {\n    LV_CANVAS_STYLE_MAIN,\n};\ntypedef uint8_t lv_canvas_style_t;\n\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a canvas object\n * @param par pointer to an object, it will be the parent of the new canvas\n * @param copy pointer to a canvas object, if not NULL then the new object will be copied from it\n * @return pointer to the created canvas\n */\nlv_obj_t * lv_canvas_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a buffer for the canvas.\n * @param buf a buffer where the content of the canvas will be.\n * The required size is (lv_img_color_format_get_px_size(cf) * w * h) / 8)\n * It can be allocated with `lv_mem_alloc()` or\n * it can be statically allocated array (e.g. static lv_color_t buf[100*50]) or\n * it can be an address in RAM or external SRAM\n * @param canvas pointer to a canvas object\n * @param w width of the canvas\n * @param h height of the canvas\n * @param cf color format. The following formats are supported:\n *      LV_IMG_CF_TRUE_COLOR, LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, LV_IMG_CF_INDEXES_1/2/4/8BIT\n */\nvoid lv_canvas_set_buffer(lv_obj_t * canvas, void * buf, lv_coord_t w, lv_coord_t h, lv_img_cf_t cf);\n\n/**\n * Set the color of a pixel on the canvas\n * @param canvas\n * @param x x coordinate of the point to set\n * @param y x coordinate of the point to set\n * @param c color of the point\n */\nvoid lv_canvas_set_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t c);\n\n/**\n * Set a style of a canvas.\n * @param canvas pointer to canvas object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_canvas_set_style(lv_obj_t * canvas, lv_canvas_style_t type, lv_style_t * style);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the color of a pixel on the canvas\n * @param canvas\n * @param x x coordinate of the point to set\n * @param y x coordinate of the point to set\n * @return color of the point\n */\nlv_color_t lv_canvas_get_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y);\n\n/**\n * Get style of a canvas.\n * @param canvas pointer to canvas object\n * @param type which style should be get\n * @return style pointer to the style\n */\nlv_style_t * lv_canvas_get_style(const lv_obj_t * canvas, lv_canvas_style_t type);\n\n/*=====================\n * Other functions\n *====================*/\n\n/**\n * Copy a buffer to the canvas\n * @param canvas pointer to a canvas object\n * @param to_copy buffer to copy. The color format has to match with the canvas's buffer color format\n * @param w width of the buffer to copy\n * @param h height of the buffer to copy\n * @param x left side of the destination position\n * @param y top side of the destination position\n */\nvoid lv_canvas_copy_buf(lv_obj_t * canvas, const void * to_copy, lv_coord_t w, lv_coord_t h, lv_coord_t x, lv_coord_t y);\n\n/**\n * Multiply a buffer with the canvas\n * @param canvas pointer to a canvas object\n * @param to_copy buffer to copy (multiply). LV_IMG_CF_TRUE_COLOR_ALPHA is not supported\n * @param w width of the buffer to copy\n * @param h height of the buffer to copy\n * @param x left side of the destination position\n * @param y top side of the destination position\n */\nvoid lv_canvas_mult_buf(lv_obj_t * canvas, void * to_copy, lv_coord_t w, lv_coord_t h, lv_coord_t x, lv_coord_t y);\n\n/**\n * Draw circle function of the canvas\n * @param canvas pointer to a canvas object\n * @param x0 x coordinate of the circle\n * @param y0 y coordinate of the circle\n * @param radius radius of the circle\n * @param color border color of the circle\n */\nvoid lv_canvas_draw_circle(lv_obj_t * canvas, lv_coord_t x0, lv_coord_t y0, lv_coord_t radius, lv_color_t color);\n\n/**\n * Draw line function of the canvas\n * @param canvas pointer to a canvas object\n * @param point1 start point of the line\n * @param point2 end point of the line\n * @param color color of the line\n *\n * NOTE: The lv_canvas_draw_line function originates from https://github.com/jb55/bresenham-line.c.\n */\nvoid lv_canvas_draw_line(lv_obj_t * canvas, lv_point_t point1, lv_point_t point2, lv_color_t color);\n\n/**\n * Draw triangle function of the canvas\n * @param canvas pointer to a canvas object\n * @param points edge points of the triangle\n * @param color line color of the triangle\n */\nvoid lv_canvas_draw_triangle(lv_obj_t * canvas, lv_point_t * points, lv_color_t color);\n\n/**\n * Draw rectangle function of the canvas\n * @param canvas pointer to a canvas object\n * @param points edge points of the rectangle\n * @param color line color of the rectangle\n */\nvoid lv_canvas_draw_rect(lv_obj_t * canvas, lv_point_t * points, lv_color_t color);\n\n/**\n * Draw polygon function of the canvas\n * @param canvas pointer to a canvas object\n * @param points edge points of the polygon\n * @param size edge count of the polygon\n * @param color line color of the polygon\n */\nvoid lv_canvas_draw_polygon(lv_obj_t * canvas, lv_point_t * points, size_t size, lv_color_t color);\n\n/**\n * Fill polygon function of the canvas\n * @param canvas pointer to a canvas object\n * @param points edge points of the polygon\n * @param size edge count of the polygon\n * @param boundary_color line color of the polygon\n * @param fill_color fill color of the polygon\n */\nvoid lv_canvas_fill_polygon(lv_obj_t * canvas, lv_point_t * points, size_t size, lv_color_t boundary_color, lv_color_t fill_color);\n/**\n * Boundary fill function of the canvas\n * @param canvas pointer to a canvas object\n * @param x x coordinate of the start position (seed)\n * @param y y coordinate of the start position (seed)\n * @param boundary_color edge/boundary color of the area\n * @param fill_color fill color of the area\n */\nvoid lv_canvas_boundary_fill4(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t boundary_color, lv_color_t fill_color);\n\n/**\n * Flood fill function of the canvas\n * @param canvas pointer to a canvas object\n * @param x x coordinate of the start position (seed)\n * @param y y coordinate of the start position (seed)\n * @param fill_color fill color of the area\n * @param bg_color background color of the area\n */\nvoid lv_canvas_flood_fill(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t fill_color, lv_color_t bg_color);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_CANVAS*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_CANVAS_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_cb.c",
    "content": "/**\n * @file lv_cb.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_cb.h\"\n#if USE_LV_CB != 0\n\n#include \"../lv_core/lv_group.h\"\n#include \"../lv_themes/lv_theme.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool lv_cb_design(lv_obj_t * cb, const lv_area_t * mask, lv_design_mode_t mode);\nstatic bool lv_bullet_design(lv_obj_t * bullet, const lv_area_t * mask, lv_design_mode_t mode);\nstatic lv_res_t lv_cb_signal(lv_obj_t * cb, lv_signal_t sign, void * param);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_design_func_t ancestor_bg_design;\nstatic lv_design_func_t ancestor_bullet_design;\nstatic lv_signal_func_t ancestor_signal;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a check box objects\n * @param par pointer to an object, it will be the parent of the new check box\n * @param copy pointer to a check box object, if not NULL then the new object will be copied from it\n * @return pointer to the created check box\n */\nlv_obj_t * lv_cb_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n\n    LV_LOG_TRACE(\"check box create started\");\n\n    /*Create the ancestor basic object*/\n    lv_obj_t * new_cb = lv_btn_create(par, copy);\n    lv_mem_assert(new_cb);\n    if(new_cb == NULL) return NULL;\n\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_cb);\n    if(ancestor_bg_design == NULL) ancestor_bg_design = lv_obj_get_design_func(new_cb);\n\n    lv_cb_ext_t * ext = lv_obj_allocate_ext_attr(new_cb, sizeof(lv_cb_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    ext->bullet = NULL;\n    ext->label = NULL;\n\n    lv_obj_set_signal_func(new_cb, lv_cb_signal);\n    lv_obj_set_design_func(new_cb, lv_cb_design);\n\n    /*Init the new checkbox object*/\n    if(copy == NULL) {\n        ext->bullet = lv_btn_create(new_cb, NULL);\n        if(ancestor_bullet_design == NULL) ancestor_bullet_design = lv_obj_get_design_func(ext->bullet);\n        lv_obj_set_click(ext->bullet, false);\n\n        ext->label = lv_label_create(new_cb, NULL);\n\n        lv_cb_set_text(new_cb, \"Check box\");\n        lv_btn_set_layout(new_cb, LV_LAYOUT_ROW_M);\n        lv_btn_set_fit(new_cb, true, true);\n        lv_btn_set_toggle(new_cb, true);\n        lv_obj_set_protect(new_cb, LV_PROTECT_PRESS_LOST);\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_cb_set_style(new_cb, LV_CB_STYLE_BG, th->cb.bg);\n            lv_cb_set_style(new_cb, LV_CB_STYLE_BOX_REL, th->cb.box.rel);\n            lv_cb_set_style(new_cb, LV_CB_STYLE_BOX_PR, th->cb.box.pr);\n            lv_cb_set_style(new_cb, LV_CB_STYLE_BOX_TGL_REL, th->cb.box.tgl_rel);\n            lv_cb_set_style(new_cb, LV_CB_STYLE_BOX_TGL_PR, th->cb.box.tgl_pr);\n            lv_cb_set_style(new_cb, LV_CB_STYLE_BOX_INA, th->cb.box.ina);\n        } else {\n            lv_cb_set_style(new_cb, LV_CB_STYLE_BG, &lv_style_transp);\n            lv_cb_set_style(new_cb, LV_CB_STYLE_BOX_REL, &lv_style_pretty);\n        }\n    } else {\n        lv_cb_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        ext->bullet = lv_btn_create(new_cb, copy_ext->bullet);\n        ext->label = lv_label_create(new_cb, copy_ext->label);\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_cb);\n    }\n\n    lv_obj_set_design_func(ext->bullet, lv_bullet_design);\n\n\n    LV_LOG_INFO(\"check box created\");\n\n    return new_cb;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set the text of a check box\n * @param cb pointer to a check box\n * @param txt the text of the check box\n */\nvoid lv_cb_set_text(lv_obj_t * cb, const char * txt)\n{\n    lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb);\n    lv_label_set_text(ext->label, txt);\n}\n\n/**\n * Set a style of a check box\n * @param cb pointer to check box object\n * @param type which style should be set\n * @param style pointer to a style\n *  */\nvoid lv_cb_set_style(lv_obj_t * cb, lv_cb_style_t type, lv_style_t * style)\n{\n    lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb);\n\n    switch(type) {\n        case LV_CB_STYLE_BG:\n            lv_btn_set_style(cb, LV_BTN_STYLE_REL, style);\n            lv_btn_set_style(cb, LV_BTN_STYLE_PR, style);\n            lv_btn_set_style(cb, LV_BTN_STYLE_TGL_REL, style);\n            lv_btn_set_style(cb, LV_BTN_STYLE_TGL_PR, style);\n            lv_btn_set_style(cb, LV_BTN_STYLE_INA, style);\n            break;\n        case LV_CB_STYLE_BOX_REL:\n            lv_btn_set_style(ext->bullet, LV_BTN_STYLE_REL, style);\n            break;\n        case LV_CB_STYLE_BOX_PR:\n            lv_btn_set_style(ext->bullet, LV_BTN_STYLE_PR, style);\n            break;\n        case LV_CB_STYLE_BOX_TGL_REL:\n            lv_btn_set_style(ext->bullet, LV_BTN_STYLE_TGL_REL, style);\n            break;\n        case LV_CB_STYLE_BOX_TGL_PR:\n            lv_btn_set_style(ext->bullet, LV_BTN_STYLE_TGL_PR, style);\n            break;\n        case LV_CB_STYLE_BOX_INA:\n            lv_btn_set_style(ext->bullet, LV_BTN_STYLE_INA, style);\n            break;\n    }\n}\n\n\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the text of a check box\n * @param cb pointer to check box object\n * @return pointer to the text of the check box\n */\nconst char * lv_cb_get_text(const lv_obj_t * cb)\n{\n    lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb);\n    return lv_label_get_text(ext->label);\n}\n\n\n/**\n * Get a style of a button\n * @param cb pointer to check box object\n * @param type which style should be get\n * @return style pointer to the style\n *  */\nlv_style_t * lv_cb_get_style(const lv_obj_t * cb, lv_cb_style_t type)\n{\n    lv_style_t * style = NULL;\n    lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb);\n\n    switch(type) {\n        case LV_CB_STYLE_BOX_REL:\n            style = lv_btn_get_style(ext->bullet, LV_BTN_STYLE_REL);\n            break;\n        case LV_CB_STYLE_BOX_PR:\n            style = lv_btn_get_style(ext->bullet, LV_BTN_STYLE_PR);\n            break;\n        case LV_CB_STYLE_BOX_TGL_REL:\n            style = lv_btn_get_style(ext->bullet, LV_BTN_STYLE_TGL_REL);\n            break;\n        case LV_CB_STYLE_BOX_TGL_PR:\n            style = lv_btn_get_style(ext->bullet, LV_BTN_STYLE_TGL_PR);\n            break;\n        case LV_CB_STYLE_BOX_INA:\n            style = lv_btn_get_style(ext->bullet, LV_BTN_STYLE_INA);\n            break;\n        default:\n            style = NULL;\n            break;\n    }\n\n    return style;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Handle the drawing related tasks of the check boxes\n * @param cb pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_cb_design(lv_obj_t * cb, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    bool result = true;\n\n    if(mode == LV_DESIGN_COVER_CHK) {\n        /*Return false if the object is not covers the mask_p area*/\n        result = ancestor_bg_design(cb, mask, mode);\n    } else if(mode == LV_DESIGN_DRAW_MAIN || mode == LV_DESIGN_DRAW_POST) {\n        lv_cb_ext_t * cb_ext = lv_obj_get_ext_attr(cb);\n        lv_btn_ext_t * bullet_ext = lv_obj_get_ext_attr(cb_ext->bullet);\n\n        /*Be sure the state of the bullet is the same as the parent button*/\n        bullet_ext->state = cb_ext->bg_btn.state;\n\n        result = ancestor_bg_design(cb, mask, mode);\n\n    } else {\n        result = ancestor_bg_design(cb, mask, mode);\n    }\n\n    return result;\n}\n\n/**\n * Handle the drawing related tasks of the check boxes\n * @param bullet pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_bullet_design(lv_obj_t * bullet, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    if(mode == LV_DESIGN_COVER_CHK) {\n        return ancestor_bullet_design(bullet, mask, mode);\n    } else if(mode == LV_DESIGN_DRAW_MAIN) {\n#if USE_LV_GROUP\n        /* If the check box is the active in a group and\n         * the background is not visible (transparent or empty)\n         * then activate the style of the bullet*/\n        lv_style_t * style_ori = lv_obj_get_style(bullet);\n        lv_obj_t * bg = lv_obj_get_parent(bullet);\n        lv_style_t * style_page = lv_obj_get_style(bg);\n        lv_group_t * g = lv_obj_get_group(bg);\n        if(style_page->body.empty != 0 || style_page->body.opa == LV_OPA_TRANSP) { /*Background is visible?*/\n            if(lv_group_get_focused(g) == bg) {\n                lv_style_t * style_mod;\n                style_mod = lv_group_mod_style(g, style_ori);\n                bullet->style_p = style_mod;  /*Temporally change the style to the activated */\n            }\n        }\n#endif\n        ancestor_bullet_design(bullet, mask, mode);\n\n#if USE_LV_GROUP\n        bullet->style_p = style_ori;  /*Revert the style*/\n#endif\n    } else if(mode == LV_DESIGN_DRAW_POST) {\n        ancestor_bullet_design(bullet, mask, mode);\n    }\n\n    return true;\n}\n\n\n/**\n * Signal function of the check box\n * @param cb pointer to a check box object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_cb_signal(lv_obj_t * cb, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(cb, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    lv_cb_ext_t * ext = lv_obj_get_ext_attr(cb);\n\n    if(sign == LV_SIGNAL_STYLE_CHG) {\n        lv_style_t * label_style = lv_label_get_style(ext->label);\n        lv_obj_set_size(ext->bullet, lv_font_get_height(label_style->text.font), lv_font_get_height(label_style->text.font));\n        lv_btn_set_state(ext->bullet, lv_btn_get_state(cb));\n    } else if(sign == LV_SIGNAL_PRESSED ||\n              sign == LV_SIGNAL_RELEASED ||\n              sign == LV_SIGNAL_PRESS_LOST) {\n        lv_btn_set_state(ext->bullet, lv_btn_get_state(cb));\n    } else if(sign == LV_SIGNAL_CONTROLL) {\n        char c = *((char *)param);\n        if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_DOWN ||\n                c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_UP ||\n                c == LV_GROUP_KEY_ENTER) {\n            lv_btn_set_state(ext->bullet, lv_btn_get_state(cb));\n        }\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_cb\";\n    }\n\n    return res;\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_cb.h",
    "content": "/**\n * @file lv_cb.h\n *\n */\n\n#ifndef LV_CB_H\n#define LV_CB_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_CB != 0\n\n/*Testing of dependencies*/\n#if USE_LV_BTN == 0\n#error \"lv_cb: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN  1) \"\n#endif\n\n#if USE_LV_LABEL == 0\n#error \"lv_cb: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL  1) \"\n#endif\n\n#include \"../lv_core/lv_obj.h\"\n#include \"lv_btn.h\"\n#include \"lv_label.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/*Data of check box*/\ntypedef struct\n{\n    lv_btn_ext_t bg_btn; /*Ext. of ancestor*/\n    /*New data for this type */\n    lv_obj_t * bullet;  /*Pointer to button*/\n    lv_obj_t * label;   /*Pointer to label*/\n} lv_cb_ext_t;\n\nenum {\n    LV_CB_STYLE_BG,\n    LV_CB_STYLE_BOX_REL,\n    LV_CB_STYLE_BOX_PR,\n    LV_CB_STYLE_BOX_TGL_REL,\n    LV_CB_STYLE_BOX_TGL_PR,\n    LV_CB_STYLE_BOX_INA,\n};\ntypedef uint8_t lv_cb_style_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a check box objects\n * @param par pointer to an object, it will be the parent of the new check box\n * @param copy pointer to a check box object, if not NULL then the new object will be copied from it\n * @return pointer to the created check box\n */\nlv_obj_t * lv_cb_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set the text of a check box\n * @param cb pointer to a check box\n * @param txt the text of the check box\n */\nvoid lv_cb_set_text(lv_obj_t * cb, const char * txt);\n\n/**\n * Set the state of the check box\n * @param cb pointer to a check box object\n * @param checked true: make the check box checked; false: make it unchecked\n */\nstatic inline void lv_cb_set_checked(lv_obj_t * cb, bool checked)\n{\n    lv_btn_set_state(cb, checked ? LV_BTN_STATE_TGL_REL : LV_BTN_STATE_REL);\n}\n\n/**\n * Make the check box inactive (disabled)\n * @param cb pointer to a check box object\n */\nstatic inline void lv_cb_set_inactive(lv_obj_t * cb)\n{\n    lv_btn_set_state(cb, LV_BTN_STATE_INA);\n}\n\n/**\n * Set a function to call when the check box is clicked\n * @param cb pointer to a check box object\n */\nstatic inline void lv_cb_set_action(lv_obj_t * cb, lv_action_t action)\n{\n    lv_btn_set_action(cb, LV_BTN_ACTION_CLICK, action);\n}\n\n\n/**\n * Set a style of a check box\n * @param cb pointer to check box object\n * @param type which style should be set\n * @param style pointer to a style\n *  */\nvoid lv_cb_set_style(lv_obj_t * cb, lv_cb_style_t type, lv_style_t *style);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the text of a check box\n * @param cb pointer to check box object\n * @return pointer to the text of the check box\n */\nconst char * lv_cb_get_text(const lv_obj_t * cb);\n\n/**\n * Get the current state of the check box\n * @param cb pointer to a check box object\n * @return true: checked; false: not checked\n */\nstatic inline bool lv_cb_is_checked(const lv_obj_t * cb)\n{\n    return lv_btn_get_state(cb) == LV_BTN_STATE_REL ? false : true;\n}\n\n/**\n * Get the action of a check box\n * @param cb pointer to a button object\n * @return pointer to the action function\n */\nstatic inline lv_action_t lv_cb_get_action(const lv_obj_t * cb)\n{\n    return lv_btn_get_action(cb, LV_BTN_ACTION_CLICK);\n}\n\n\n/**\n * Get a style of a button\n * @param cb pointer to check box object\n * @param type which style should be get\n * @return style pointer to the style\n *  */\nlv_style_t * lv_cb_get_style(const lv_obj_t * cb, lv_cb_style_t type);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_CB*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_CB_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_chart.c",
    "content": "/**\n * @file lv_chart.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_chart.h\"\n#if USE_LV_CHART != 0\n\n#include \"../lv_draw/lv_draw.h\"\n#include \"../lv_themes/lv_theme.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_CHART_YMIN_DEF   0\n#define LV_CHART_YMAX_DEF   100\n#define LV_CHART_HDIV_DEF   3\n#define LV_CHART_VDIV_DEF   5\n#define LV_CHART_PNUM_DEF   10\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool lv_chart_design(lv_obj_t * chart, const lv_area_t * mask, lv_design_mode_t mode);\nstatic lv_res_t lv_chart_signal(lv_obj_t * chart, lv_signal_t sign, void * param);\nstatic void lv_chart_draw_div(lv_obj_t * chart, const lv_area_t * mask);\nstatic void lv_chart_draw_lines(lv_obj_t * chart, const lv_area_t * mask);\nstatic void lv_chart_draw_points(lv_obj_t * chart, const lv_area_t * mask);\nstatic void lv_chart_draw_cols(lv_obj_t * chart, const lv_area_t * mask);\nstatic void lv_chart_draw_vertical_lines(lv_obj_t * chart, const lv_area_t * mask);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_design_func_t ancestor_design_f;\nstatic lv_signal_func_t ancestor_signal;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a chart background objects\n * @param par pointer to an object, it will be the parent of the new chart background\n * @param copy pointer to a chart background object, if not NULL then the new object will be copied from it\n * @return pointer to the created chart background\n */\nlv_obj_t * lv_chart_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"chart create started\");\n\n    /*Create the ancestor basic object*/\n    lv_obj_t * new_chart = lv_obj_create(par, copy);\n    lv_mem_assert(new_chart);\n    if(new_chart == NULL) return NULL;\n\n    /*Allocate the object type specific extended data*/\n    lv_chart_ext_t * ext = lv_obj_allocate_ext_attr(new_chart, sizeof(lv_chart_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    lv_ll_init(&ext->series_ll, sizeof(lv_chart_series_t));\n    ext->series.num = 0;\n    ext->ymin = LV_CHART_YMIN_DEF;\n    ext->ymax = LV_CHART_YMAX_DEF;\n    ext->hdiv_cnt = LV_CHART_HDIV_DEF;\n    ext->vdiv_cnt = LV_CHART_VDIV_DEF;\n    ext->point_cnt = LV_CHART_PNUM_DEF;\n    ext->type = LV_CHART_TYPE_LINE;\n    ext->series.opa = LV_OPA_COVER;\n    ext->series.dark = LV_OPA_50;\n    ext->series.width = 2;\n\n    if(ancestor_design_f == NULL) ancestor_design_f = lv_obj_get_design_func(new_chart);\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_chart);\n\n    lv_obj_set_signal_func(new_chart, lv_chart_signal);\n    lv_obj_set_design_func(new_chart, lv_chart_design);\n\n    /*Init the new chart background object*/\n    if(copy == NULL) {\n        lv_obj_set_size(new_chart, LV_HOR_RES / 3, LV_VER_RES / 3);\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_chart_set_style(new_chart, th->chart);\n        } else {\n            lv_chart_set_style(new_chart, &lv_style_pretty);\n        }\n\n    } else {\n        lv_chart_ext_t * ext_copy = lv_obj_get_ext_attr(copy);\n        ext->type = ext_copy->type;\n        ext->ymin = ext_copy->ymin;\n        ext->ymax = ext_copy->ymax;\n        ext->hdiv_cnt = ext_copy->hdiv_cnt;\n        ext->vdiv_cnt = ext_copy->vdiv_cnt;\n        ext->point_cnt = ext_copy->point_cnt;\n        ext->series.opa =  ext_copy->series.opa;\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_chart);\n    }\n\n    LV_LOG_INFO(\"chart created\");\n\n\n    return new_chart;\n}\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n/**\n * Allocate and add a data series to the chart\n * @param chart pointer to a chart object\n * @param color color of the data series\n * @return pointer to the allocated data series\n */\nlv_chart_series_t * lv_chart_add_series(lv_obj_t * chart, lv_color_t color)\n{\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n    lv_chart_series_t * ser = lv_ll_ins_head(&ext->series_ll);\n    lv_mem_assert(ser);\n    if(ser == NULL) return NULL;\n\n    lv_coord_t def = LV_CHART_POINT_DEF;\n\n    if(ser == NULL) return NULL;\n\n    ser->color = color;\n\n    ser->points = lv_mem_alloc(sizeof(lv_coord_t) * ext->point_cnt);\n    lv_mem_assert(ser->points);\n    if(ser->points == NULL) {\n        lv_ll_rem(&ext->series_ll, ser);\n        lv_mem_free(ser);\n        return NULL;\n    }\n\n    ser->start_point = 0;\n\n    uint16_t i;\n    lv_coord_t * p_tmp = ser->points;\n    for(i = 0; i < ext->point_cnt; i++) {\n        *p_tmp = def;\n        p_tmp++;\n    }\n\n    ext->series.num++;\n\n    return ser;\n}\n\n/**\n * Clear the point of a serie\n * @param chart pointer to a chart object\n * @param serie pointer to the chart's serie to clear\n */\nvoid lv_chart_clear_serie(lv_obj_t * chart, lv_chart_series_t * serie)\n{\n    if(chart == NULL || serie == NULL)\n        return;\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n    if(ext == NULL) return;\n\n    uint32_t i;\n    for(i = 0; i < ext->point_cnt; i++)\n    {\n        serie->points[i] = LV_CHART_POINT_DEF;\n    }\n\n    serie->start_point = 0;\n\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set the number of horizontal and vertical division lines\n * @param chart pointer to a graph background object\n * @param hdiv number of horizontal division lines\n * @param vdiv number of vertical division lines\n */\nvoid lv_chart_set_div_line_count(lv_obj_t * chart, uint8_t hdiv, uint8_t vdiv)\n{\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n    if(ext->hdiv_cnt == hdiv && ext->vdiv_cnt == vdiv) return;\n\n    ext->hdiv_cnt = hdiv;\n    ext->vdiv_cnt = vdiv;\n\n    lv_obj_invalidate(chart);\n}\n\n/**\n * Set the minimal and maximal y values\n * @param chart pointer to a graph background object\n * @param ymin y minimum value\n * @param ymax y maximum value\n */\nvoid lv_chart_set_range(lv_obj_t * chart, lv_coord_t ymin, lv_coord_t ymax)\n{\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n    if(ext->ymin == ymin && ext->ymax == ymax) return;\n\n    ext->ymin = ymin;\n    ext->ymax = ymax;\n\n    lv_chart_refresh(chart);\n}\n\n/**\n * Set a new type for a chart\n * @param chart pointer to a chart object\n * @param type new type of the chart (from 'lv_chart_type_t' enum)\n */\nvoid lv_chart_set_type(lv_obj_t * chart, lv_chart_type_t type)\n{\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n    if(ext->type == type) return;\n\n    ext->type = type;\n\n    lv_chart_refresh(chart);\n}\n\n/**\n * Set the number of points on a data line on a chart\n * @param chart pointer r to chart object\n * @param point_cnt new number of points on the data lines\n */\nvoid lv_chart_set_point_count(lv_obj_t * chart, uint16_t point_cnt)\n{\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n    if(ext->point_cnt == point_cnt) return;\n\n    lv_chart_series_t * ser;\n    uint16_t point_cnt_old = ext->point_cnt;\n    uint16_t i;\n    lv_coord_t def = LV_CHART_POINT_DEF;\n\n    if(point_cnt < 1) point_cnt = 1;\n\n    LL_READ_BACK(ext->series_ll, ser) {\n        if(ser->start_point != 0) {\n            lv_coord_t * new_points = lv_mem_alloc(sizeof(lv_coord_t) * point_cnt);\n            lv_mem_assert(new_points);\n            if(new_points == NULL) return;\n\n            if(point_cnt >= point_cnt_old) {\n                for(i = 0; i < point_cnt_old; i++) {\n                    new_points[i] = ser->points[(i + ser->start_point) % point_cnt_old];    /*Copy old contents to new array*/\n                }\n                for(i = point_cnt_old; i < point_cnt; i++) {\n                    new_points[i] = def;                                                    /*Fill up the rest with default value*/\n                }\n            } else {\n                for(i = 0; i < point_cnt; i++) {\n                    new_points[i] = ser->points[(i + ser->start_point) % point_cnt_old];    /*Copy old contents to new array*/\n                }\n            }\n\n            /*Switch over pointer from old to new*/\n            lv_mem_free(ser->points);\n            ser->points = new_points;\n        } else {\n            ser->points = lv_mem_realloc(ser->points, sizeof(lv_coord_t) * point_cnt);\n            lv_mem_assert(ser->points);\n            if(ser->points == NULL) return;\n            /*Initialize the new points*/\n            if(point_cnt > point_cnt_old) {\n                for(i = point_cnt_old - 1; i < point_cnt; i++) {\n                    ser->points[i] = def;\n                }\n            }\n        }\n\n        ser->start_point = 0;\n    }\n\n    ext->point_cnt = point_cnt;\n\n    lv_chart_refresh(chart);\n}\n\n/**\n * Set the opacity of the data series\n * @param chart pointer to a chart object\n * @param opa opacity of the data series\n */\nvoid lv_chart_set_series_opa(lv_obj_t * chart, lv_opa_t opa)\n{\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n    if(ext->series.opa == opa) return;\n\n    ext->series.opa = opa;\n    lv_obj_invalidate(chart);\n}\n\n/**\n * Set the line width or point radius of the data series\n * @param chart pointer to a chart object\n * @param width the new width\n */\nvoid lv_chart_set_series_width(lv_obj_t * chart, lv_coord_t width)\n{\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n    if(ext->series.width == width) return;\n\n    ext->series.width = width;\n    lv_obj_invalidate(chart);\n}\n/**\n * Set the dark effect on the bottom of the points or columns\n * @param chart pointer to a chart object\n * @param dark_eff dark effect level (LV_OPA_TRANSP to turn off)\n */\nvoid lv_chart_set_series_darking(lv_obj_t * chart, lv_opa_t dark_eff)\n{\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n    if(ext->series.dark == dark_eff) return;\n\n    ext->series.dark = dark_eff;\n    lv_obj_invalidate(chart);\n}\n\n/**\n * Initialize all data points with a value\n * @param chart pointer to chart object\n * @param ser pointer to a data series on 'chart'\n * @param y the new value  for all points\n */\nvoid lv_chart_init_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y)\n{\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n    uint16_t i;\n    for(i = 0; i < ext->point_cnt; i++) {\n        ser->points[i] = y;\n    }\n    ser->start_point = 0;\n    lv_chart_refresh(chart);\n}\n\n/**\n * Set the value s of points from an array\n * @param chart pointer to chart object\n * @param ser pointer to a data series on 'chart'\n * @param y_array array of 'lv_coord_t' points (with 'points count' elements )\n */\nvoid lv_chart_set_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t * y_array)\n{\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n    memcpy(ser->points, y_array, ext->point_cnt * (sizeof(lv_coord_t)));\n    ser->start_point = 0;\n    lv_chart_refresh(chart);\n}\n\n/**\n * Shift all data left and set the rightmost data on a data line\n * @param chart pointer to chart object\n * @param ser pointer to a data series on 'chart'\n * @param y the new value of the rightmost data\n */\nvoid lv_chart_set_next(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y)\n{\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n\n    ser->points[ser->start_point] = y;  /*This was the place of the former left most value, after shifting it is the rightmost*/\n    ser->start_point = (ser->start_point + 1) % ext->point_cnt;\n\n    lv_chart_refresh(chart);\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the type of a chart\n * @param chart pointer to chart object\n * @return type of the chart (from 'lv_chart_t' enum)\n */\nlv_chart_type_t lv_chart_get_type(const lv_obj_t * chart)\n{\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n    return ext->type;\n}\n\n/**\n * Get the data point number per data line on chart\n * @param chart pointer to chart object\n * @return point number on each data line\n */\nuint16_t lv_chart_get_point_cnt(const lv_obj_t * chart)\n{\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n    return ext->point_cnt;\n}\n\n/**\n * Get the opacity of the data series\n * @param chart pointer to chart object\n * @return the opacity of the data series\n */\nlv_opa_t lv_chart_get_series_opa(const lv_obj_t * chart)\n{\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n    return ext->series.opa;\n}\n\n/**\n * Get the data series width\n * @param chart pointer to chart object\n * @return the width the data series (lines or points)\n */\nlv_coord_t lv_chart_get_series_width(const lv_obj_t * chart)\n{\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n    return ext->series.width;\n}\n\n/**\n * Get the dark effect level on the bottom of the points or columns\n * @param chart pointer to chart object\n * @return dark effect level (LV_OPA_TRANSP to turn off)\n */\nlv_opa_t lv_chart_get_series_darking(const lv_obj_t * chart)\n{\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n    return ext->series.dark;\n}\n\n/*=====================\n * Other functions\n *====================*/\n\n/**\n * Refresh a chart if its data line has changed\n * @param chart pointer to chart object\n */\nvoid lv_chart_refresh(lv_obj_t * chart)\n{\n    lv_obj_invalidate(chart);\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Handle the drawing related tasks of the chart backgrounds\n * @param chart pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_chart_design(lv_obj_t * chart, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    if(mode == LV_DESIGN_COVER_CHK) {\n        /*Return false if the object is not covers the mask_p area*/\n        return ancestor_design_f(chart, mask, mode);\n    } else if(mode == LV_DESIGN_DRAW_MAIN) {\n        /*Draw the background*/\n        lv_draw_rect(&chart->coords, mask, lv_obj_get_style(chart), lv_obj_get_opa_scale(chart));\n\n        lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n\n        lv_chart_draw_div(chart, mask);\n\n        if(ext->type & LV_CHART_TYPE_LINE) lv_chart_draw_lines(chart, mask);\n        if(ext->type & LV_CHART_TYPE_COLUMN) lv_chart_draw_cols(chart, mask);\n        if(ext->type & LV_CHART_TYPE_POINT) lv_chart_draw_points(chart, mask);\n        if(ext->type & LV_CHART_TYPE_VERTICAL_LINE) lv_chart_draw_vertical_lines(chart, mask);\n    }\n    return true;\n}\n\n/**\n * Signal function of the chart background\n * @param chart pointer to a chart background object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n */\nstatic lv_res_t lv_chart_signal(lv_obj_t * chart, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(chart, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    if(sign == LV_SIGNAL_CLEANUP) {\n        lv_coord_t ** datal;\n        lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n        LL_READ(ext->series_ll, datal) {\n            lv_mem_free(*datal);\n        }\n        lv_ll_clear(&ext->series_ll);\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_chart\";\n    }\n\n    return res;\n}\n\n/**\n * Draw the division lines on chart background\n * @param chart pointer to chart object\n * @param mask mask, inherited from the design function\n */\nstatic void lv_chart_draw_div(lv_obj_t * chart, const lv_area_t * mask)\n{\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n    lv_style_t * style = lv_obj_get_style(chart);\n    lv_opa_t opa_scale = lv_obj_get_opa_scale(chart);\n\n    uint8_t div_i;\n    uint8_t div_i_end;\n    uint8_t div_i_start;\n    lv_point_t p1;\n    lv_point_t p2;\n    lv_coord_t w = lv_obj_get_width(chart);\n    lv_coord_t h = lv_obj_get_height(chart);\n    lv_coord_t x_ofs = chart->coords.x1;\n    lv_coord_t y_ofs = chart->coords.y1;\n\n    if(ext->hdiv_cnt != 0) {\n        /*Draw slide lines if no border*/\n        if(style->body.border.width != 0) {\n            div_i_start = 1;\n            div_i_end = ext->hdiv_cnt;\n        } else {\n            div_i_start = 0;\n            div_i_end = ext->hdiv_cnt + 1;\n        }\n\n        p1.x = 0 + x_ofs;\n        p2.x = w + x_ofs;\n        for(div_i = div_i_start; div_i <= div_i_end; div_i++) {\n            p1.y = (int32_t)((int32_t)h * div_i) / (ext->hdiv_cnt + 1);\n            p1.y +=  y_ofs;\n            if(div_i == div_i_start) p1.y += (style->line.width >> 1) + 1;  /*The first line might not be visible*/\n            if(div_i == div_i_end) p1.y -= (style->line.width >> 1) + 1;  /*The last line might not be visible*/\n\n            p2.y = p1.y;\n            lv_draw_line(&p1, &p2, mask, style, opa_scale);\n        }\n    }\n\n    if(ext->vdiv_cnt != 0) {\n        /*Draw slide lines if no border*/\n        if(style->body.border.width != 0) {\n            div_i_start = 1;\n            div_i_end = ext->vdiv_cnt;\n        } else {\n            div_i_start = 0;\n            div_i_end = ext->vdiv_cnt + 1;\n        }\n\n        p1.y = 0 + y_ofs;\n        p2.y = h + y_ofs;\n        for(div_i = div_i_start; div_i <= div_i_end; div_i ++) {\n            p1.x = (int32_t)((int32_t)w * div_i) / (ext->vdiv_cnt + 1);\n            p1.x +=  x_ofs;\n            if(div_i == div_i_start) p1.x += (style->line.width >> 1) + 1;  /*The first line might not be visible*/\n            if(div_i == div_i_end) p1.x -= (style->line.width >> 1) + 1;  /*The last line might not be visible*/\n            p2.x = p1.x;\n            lv_draw_line(&p1, &p2, mask, style, opa_scale);\n        }\n    }\n}\n\n/**\n * Draw the data lines as lines on a chart\n * @param obj pointer to chart object\n */\nstatic void lv_chart_draw_lines(lv_obj_t * chart, const lv_area_t * mask)\n{\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n\n    uint16_t i;\n    lv_point_t p1;\n    lv_point_t p2;\n    lv_coord_t w = lv_obj_get_width(chart);\n    lv_coord_t h = lv_obj_get_height(chart);\n    lv_coord_t x_ofs = chart->coords.x1;\n    lv_coord_t y_ofs = chart->coords.y1;\n    int32_t y_tmp;\n    lv_coord_t p_prev;\n    lv_coord_t p_act;\n    lv_chart_series_t * ser;\n    lv_opa_t opa_scale = lv_obj_get_opa_scale(chart);\n    lv_style_t style;\n    lv_style_copy(&style, &lv_style_plain);\n    style.line.opa = ext->series.opa;\n    style.line.width = ext->series.width;\n\n    /*Go through all data lines*/\n    LL_READ_BACK(ext->series_ll, ser) {\n        style.line.color = ser->color;\n\n        p1.x = 0 + x_ofs;\n        p2.x = 0 + x_ofs;\n\n        p_prev = ser->start_point;\n        y_tmp = (int32_t)((int32_t) ser->points[p_prev] - ext->ymin) * h;\n        y_tmp = y_tmp / (ext->ymax - ext->ymin);\n        p2.y = h - y_tmp + y_ofs;\n\n        for(i = 1; i < ext->point_cnt; i ++) {\n            p1.x = p2.x;\n            p1.y = p2.y;\n\n            p2.x = ((w * i) / (ext->point_cnt - 1)) + x_ofs;\n\n            p_act = (ser->start_point + i) % ext->point_cnt;\n\n            y_tmp = (int32_t)((int32_t) ser->points[p_act] - ext->ymin) * h;\n            y_tmp = y_tmp / (ext->ymax - ext->ymin);\n            p2.y = h - y_tmp + y_ofs;\n\n            if(ser->points[p_prev] != LV_CHART_POINT_DEF && ser->points[p_act] != LV_CHART_POINT_DEF)\n                lv_draw_line(&p1, &p2, mask, &style, opa_scale);\n\n            p_prev = p_act;\n        }\n    }\n}\n\n/**\n * Draw the data lines as points on a chart\n * @param chart pointer to chart object\n * @param mask mask, inherited from the design function\n */\nstatic void lv_chart_draw_points(lv_obj_t * chart, const lv_area_t * mask)\n{\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n\n    uint16_t i;\n    lv_area_t cir_a;\n    lv_coord_t w = lv_obj_get_width(chart);\n    lv_coord_t h = lv_obj_get_height(chart);\n    lv_coord_t x_ofs = chart->coords.x1;\n    lv_coord_t y_ofs = chart->coords.y1;\n    int32_t y_tmp;\n    lv_coord_t p_act;\n    lv_chart_series_t * ser;\n    uint8_t series_cnt = 0;\n    lv_style_t style_point;\n    lv_style_copy(&style_point, &lv_style_plain);\n\n    style_point.body.border.width = 0;\n    style_point.body.empty = 0;\n    style_point.body.radius = LV_RADIUS_CIRCLE;\n    style_point.body.opa = ext->series.opa;\n    style_point.body.radius = ext->series.width;\n\n    /*Go through all data lines*/\n    LL_READ_BACK(ext->series_ll, ser) {\n        style_point.body.main_color = ser->color;\n        style_point.body.grad_color = lv_color_mix(LV_COLOR_BLACK, ser->color, ext->series.dark);\n\n        for(i = 0; i < ext->point_cnt; i ++) {\n            cir_a.x1 = ((w * i) / (ext->point_cnt - 1)) + x_ofs;\n            cir_a.x2 = cir_a.x1 + style_point.body.radius;\n            cir_a.x1 -= style_point.body.radius;\n            p_act = (ser->start_point + i) % ext->point_cnt;\n            y_tmp = (int32_t)((int32_t) ser->points[p_act] - ext->ymin) * h;\n            y_tmp = y_tmp / (ext->ymax - ext->ymin);\n            cir_a.y1 = h - y_tmp + y_ofs;\n            cir_a.y2 = cir_a.y1 + style_point.body.radius;\n            cir_a.y1 -= style_point.body.radius;\n\n            if(ser->points[p_act] != LV_CHART_POINT_DEF)\n                lv_draw_rect(&cir_a, mask, &style_point, lv_obj_get_opa_scale(chart));\n        }\n        series_cnt++;\n    }\n}\n\n/**\n * Draw the data lines as columns on a chart\n * @param chart pointer to chart object\n * @param mask mask, inherited from the design function\n */\nstatic void lv_chart_draw_cols(lv_obj_t * chart, const lv_area_t * mask)\n{\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n\n    uint16_t i;\n    lv_area_t col_a;\n    lv_area_t col_mask;\n    bool mask_ret;\n    lv_coord_t w = lv_obj_get_width(chart);\n    lv_coord_t h = lv_obj_get_height(chart);\n    int32_t y_tmp;\n    lv_chart_series_t * ser;\n    lv_style_t rects;\n    lv_coord_t col_w = w / ((ext->series.num + 1) * ext->point_cnt); /* Suppose + 1 series as separator*/\n    lv_coord_t x_ofs = col_w / 2; /*Shift with a half col.*/\n\n    lv_style_copy(&rects, &lv_style_plain);\n    rects.body.border.width = 0;\n    rects.body.empty = 0;\n    rects.body.radius = 0;\n    rects.body.opa = ext->series.opa;\n\n    col_a.y2 = chart->coords.y2;\n\n    lv_coord_t x_act;\n\n    /*Go through all points*/\n    for(i = 0; i < ext->point_cnt; i ++) {\n        x_act = (int32_t)((int32_t) w * i) / ext->point_cnt;\n        x_act += chart->coords.x1 + x_ofs;\n\n        /*Draw the current point of all data line*/\n        LL_READ_BACK(ext->series_ll, ser) {\n            rects.body.main_color = ser->color;\n            rects.body.grad_color = lv_color_mix(LV_COLOR_BLACK, ser->color, ext->series.dark);\n            col_a.x1 = x_act;\n            col_a.x2 = col_a.x1 + col_w;\n            x_act += col_w;\n\n            lv_coord_t p_act = (ser->start_point + i) % ext->point_cnt;\n            y_tmp = (int32_t)((int32_t) ser->points[p_act] - ext->ymin) * h;\n            y_tmp = y_tmp / (ext->ymax - ext->ymin);\n            col_a.y1 = h - y_tmp + chart->coords.y1;\n\n            mask_ret = lv_area_intersect(&col_mask, mask, &col_a);\n            if(mask_ret != false && ser->points[p_act] != LV_CHART_POINT_DEF) {\n                lv_draw_rect(&chart->coords, &col_mask, &rects, lv_obj_get_opa_scale(chart));\n            }\n        }\n    }\n}\n\n/**\n * Draw the data lines as vertical lines on a chart if there is only 1px between point\n * @param obj pointer to chart object\n */\nstatic void lv_chart_draw_vertical_lines(lv_obj_t * chart, const lv_area_t * mask)\n{\n\n    lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);\n    lv_coord_t w = lv_obj_get_width(chart);\n    /*Vertical lines works only if the width == point count. Else use the normal line type*/\n    if(ext->point_cnt != w) {\n        lv_chart_draw_lines(chart, mask);\n        return;\n    }\n\n    uint16_t i;\n    lv_point_t p1;\n    lv_point_t p2;\n    lv_coord_t h = lv_obj_get_height(chart);\n    lv_coord_t x_ofs = chart->coords.x1;\n    lv_coord_t y_ofs = chart->coords.y1;\n    int32_t y_tmp;\n    lv_chart_series_t * ser;\n    lv_opa_t opa_scale = lv_obj_get_opa_scale(chart);\n    lv_style_t style;\n    lv_style_copy(&style, &lv_style_plain);\n    style.line.opa = ext->series.opa;\n    style.line.width = ext->series.width;\n\n    /*Go through all data lines*/\n    LL_READ_BACK(ext->series_ll, ser) {\n        style.line.color = ser->color;\n\n        p1.x = 0 + x_ofs;\n        p2.x = 0 + x_ofs;\n        y_tmp = (int32_t)((int32_t) ser->points[0] - ext->ymin) * h;\n        y_tmp = y_tmp / (ext->ymax - ext->ymin);\n        p2.y = h - y_tmp + y_ofs;\n        p1.y = p2.y;\n\n        for(i = 0; i < ext->point_cnt; i++)\n        {\n\n            y_tmp = (int32_t)((int32_t) ser->points[i] - ext->ymin) * h;\n            y_tmp = y_tmp / (ext->ymax - ext->ymin);\n            p2.y = h - y_tmp + y_ofs;\n\n            if(p1.y == p2.y)\n            {\n                p2.x++;\n            }\n\n            if(ser->points[i] != LV_CHART_POINT_DEF) {\n                lv_draw_line(&p1, &p2, mask, &style, opa_scale);\n            }\n\n            p2.x = ((w * i) / (ext->point_cnt - 1)) + x_ofs;\n            p1.x = p2.x;\n            p1.y = p2.y;\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_chart.h",
    "content": "/**\n * @file lv_chart.h\n *\n */\n\n#ifndef LV_CHART_H\n#define LV_CHART_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_CHART != 0\n\n#include \"../lv_core/lv_obj.h\"\n#include \"lv_line.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_CHART_POINT_DEF  (LV_COORD_MIN)\n\n/**********************\n *      TYPEDEFS\n **********************/\ntypedef struct\n{\n    lv_coord_t * points;\n    lv_color_t color;\n    uint16_t start_point;\n} lv_chart_series_t;\n\n/*Data of chart */\ntypedef struct\n{\n    /*No inherited ext*/ /*Ext. of ancestor*/\n    /*New data for this type */\n    lv_ll_t series_ll;       /*Linked list for the data line pointers (stores lv_chart_dl_t)*/\n    lv_coord_t ymin;          /*y min value (used to scale the data)*/\n    lv_coord_t ymax;          /*y max value (used to scale the data)*/\n    uint8_t hdiv_cnt;     /*Number of horizontal division lines*/\n    uint8_t vdiv_cnt;     /*Number of vertical division lines*/\n    uint16_t point_cnt;   /*Point number in a data line*/\n    uint8_t type    :4;   /*Line, column or point chart (from 'lv_chart_type_t')*/\n    struct {\n        lv_coord_t width;  /*Line width or point radius*/\n        uint8_t num;       /*Number of data lines in dl_ll*/\n        lv_opa_t opa;      /*Opacity of data lines*/\n        lv_opa_t dark;     /*Dark level of the point/column bottoms*/\n    } series;\n} lv_chart_ext_t;\n\n/*Chart types*/\nenum\n{\n    LV_CHART_TYPE_LINE = 0x01,              /*Connect the points with lines*/\n    LV_CHART_TYPE_COLUMN = 0x02,            /*Draw columns*/\n    LV_CHART_TYPE_POINT = 0x04,             /*Draw circles on the points*/\n    LV_CHART_TYPE_VERTICAL_LINE = 0x08,     /*Draw vertical lines on points (useful when chart width == point count)*/\n};\ntypedef uint8_t lv_chart_type_t;\n\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a chart background objects\n * @param par pointer to an object, it will be the parent of the new chart background\n * @param copy pointer to a chart background object, if not NULL then the new object will be copied from it\n * @return pointer to the created chart background\n */\nlv_obj_t * lv_chart_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n/**\n * Allocate and add a data series to the chart\n * @param chart pointer to a chart object\n * @param color color of the data series\n * @return pointer to the allocated data series\n */\nlv_chart_series_t * lv_chart_add_series(lv_obj_t * chart, lv_color_t color);\n\n/**\n * Clear the point of a serie\n * @param chart pointer to a chart object\n * @param serie pointer to the chart's serie to clear\n */\nvoid lv_chart_clear_serie(lv_obj_t * chart, lv_chart_series_t * serie);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set the number of horizontal and vertical division lines\n * @param chart pointer to a graph background object\n * @param hdiv number of horizontal division lines\n * @param vdiv number of vertical division lines\n */\nvoid lv_chart_set_div_line_count(lv_obj_t * chart, uint8_t hdiv, uint8_t vdiv);\n\n/**\n * Set the minimal and maximal y values\n * @param chart pointer to a graph background object\n * @param ymin y minimum value\n * @param ymax y maximum value\n */\nvoid lv_chart_set_range(lv_obj_t * chart, lv_coord_t ymin, lv_coord_t ymax);\n\n/**\n * Set a new type for a chart\n * @param chart pointer to a chart object\n * @param type new type of the chart (from 'lv_chart_type_t' enum)\n */\nvoid lv_chart_set_type(lv_obj_t * chart, lv_chart_type_t type);\n\n/**\n * Set the number of points on a data line on a chart\n * @param chart pointer r to chart object\n * @param point_cnt new number of points on the data lines\n */\nvoid lv_chart_set_point_count(lv_obj_t * chart, uint16_t point_cnt);\n\n/**\n * Set the opacity of the data series\n * @param chart pointer to a chart object\n * @param opa opacity of the data series\n */\nvoid lv_chart_set_series_opa(lv_obj_t * chart, lv_opa_t opa);\n\n/**\n * Set the line width or point radius of the data series\n * @param chart pointer to a chart object\n * @param width the new width\n */\nvoid lv_chart_set_series_width(lv_obj_t * chart, lv_coord_t width);\n\n/**\n * Set the dark effect on the bottom of the points or columns\n * @param chart pointer to a chart object\n * @param dark_eff dark effect level (LV_OPA_TRANSP to turn off)\n */\nvoid lv_chart_set_series_darking(lv_obj_t * chart, lv_opa_t dark_eff);\n\n/**\n * Initialize all data points with a value\n * @param chart pointer to chart object\n * @param ser pointer to a data series on 'chart'\n * @param y the new value  for all points\n */\nvoid lv_chart_init_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y);\n\n/**\n * Set the value s of points from an array\n * @param chart pointer to chart object\n * @param ser pointer to a data series on 'chart'\n * @param y_array array of 'lv_coord_t' points (with 'points count' elements )\n */\nvoid lv_chart_set_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t * y_array);\n\n/**\n * Shift all data right and set the most right data on a data line\n * @param chart pointer to chart object\n * @param ser pointer to a data series on 'chart'\n * @param y the new value of the most right data\n */\nvoid lv_chart_set_next(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y);\n\n/**\n * Set the style of a chart\n * @param chart pointer to a chart object\n * @param style pointer to a style\n */\nstatic inline void lv_chart_set_style(lv_obj_t *chart, lv_style_t *style)\n{\n    lv_obj_set_style(chart, style);\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the type of a chart\n * @param chart pointer to chart object\n * @return type of the chart (from 'lv_chart_t' enum)\n */\nlv_chart_type_t lv_chart_get_type(const lv_obj_t * chart);\n\n/**\n * Get the data point number per data line on chart\n * @param chart pointer to chart object\n * @return point number on each data line\n */\nuint16_t lv_chart_get_point_cnt(const lv_obj_t * chart);\n\n/**\n * Get the opacity of the data series\n * @param chart pointer to chart object\n * @return the opacity of the data series\n */\nlv_opa_t lv_chart_get_series_opa(const lv_obj_t * chart);\n\n/**\n * Get the data series width\n * @param chart pointer to chart object\n * @return the width the data series (lines or points)\n */\nlv_coord_t lv_chart_get_series_width(const lv_obj_t * chart);\n\n/**\n * Get the dark effect level on the bottom of the points or columns\n * @param chart pointer to chart object\n * @return dark effect level (LV_OPA_TRANSP to turn off)\n */\nlv_opa_t lv_chart_get_series_darking(const lv_obj_t * chart);\n\n/**\n * Get the style of an chart object\n * @param chart pointer to an chart object\n * @return pointer to the chart's style\n */\nstatic inline lv_style_t* lv_chart_get_style(const lv_obj_t *chart)\n{\n    return lv_obj_get_style(chart);\n}\n\n/*=====================\n * Other functions\n *====================*/\n\n/**\n * Refresh a chart if its data line has changed\n * @param chart pointer to chart object\n */\nvoid lv_chart_refresh(lv_obj_t * chart);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_CHART*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_CHART_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_cont.c",
    "content": "/**\n * @file lv_cont.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n\n#include \"lv_cont.h\"\n#if USE_LV_CONT != 0\n\n#include <stdint.h>\n#include <string.h>\n\n#include \"../lv_draw/lv_draw.h\"\n#include \"../lv_draw/lv_draw_vbasic.h\"\n#include \"../lv_themes/lv_theme.h\"\n#include \"../lv_misc/lv_area.h\"\n#include \"../lv_misc/lv_color.h\"\n#include \"../lv_misc/lv_math.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic lv_res_t lv_cont_signal(lv_obj_t * cont, lv_signal_t sign, void * param);\nstatic void lv_cont_refr_layout(lv_obj_t * cont);\nstatic void lv_cont_layout_col(lv_obj_t * cont);\nstatic void lv_cont_layout_row(lv_obj_t * cont);\nstatic void lv_cont_layout_center(lv_obj_t * cont);\nstatic void lv_cont_layout_pretty(lv_obj_t * cont);\nstatic void lv_cont_layout_grid(lv_obj_t * cont);\nstatic void lv_cont_refr_autofit(lv_obj_t * cont);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a container objects\n * @param par pointer to an object, it will be the parent of the new container\n * @param copy pointer to a container object, if not NULL then the new object will be copied from it\n * @return pointer to the created container\n */\nlv_obj_t * lv_cont_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n\n\n    LV_LOG_TRACE(\"container create started\");\n\n    /*Create a basic object*/\n    lv_obj_t * new_cont = lv_obj_create(par, copy);\n    lv_mem_assert(new_cont);\n    if(new_cont == NULL) return NULL;\n\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_cont);\n\n    lv_obj_allocate_ext_attr(new_cont, sizeof(lv_cont_ext_t));\n    lv_cont_ext_t * ext = lv_obj_get_ext_attr(new_cont);\n    if(ext == NULL) return NULL;\n\n    lv_mem_assert(ext);\n    ext->hor_fit = 0;\n    ext->ver_fit = 0;\n    ext->layout = LV_LAYOUT_OFF;\n\n    lv_obj_set_signal_func(new_cont, lv_cont_signal);\n\n    /*Init the new container*/\n    if(copy == NULL) {\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_cont_set_style(new_cont, th->cont);\n        } else {\n            lv_cont_set_style(new_cont, &lv_style_pretty);\n        }\n    }\n    /*Copy an existing object*/\n    else {\n        lv_cont_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        ext->hor_fit = copy_ext->hor_fit;\n        ext->ver_fit = copy_ext->ver_fit;\n        ext->layout = copy_ext->layout;\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_cont);\n    }\n\n    LV_LOG_INFO(\"container created\");\n\n\n    return new_cont;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a layout on a container\n * @param cont pointer to a container object\n * @param layout a layout from 'lv_cont_layout_t'\n */\nvoid lv_cont_set_layout(lv_obj_t * cont, lv_layout_t layout)\n{\n    lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont);\n    if(ext->layout == layout) return;\n\n    ext->layout = layout;\n\n    /*Send a signal to refresh the layout*/\n    cont->signal_func(cont, LV_SIGNAL_CHILD_CHG, NULL);\n}\n\n\n/**\n * Enable the horizontal or vertical fit.\n * The container size will be set to involve the children horizontally or vertically.\n * @param cont pointer to a container object\n * @param hor_en true: enable the horizontal fit\n * @param ver_en true: enable the vertical fit\n */\nvoid lv_cont_set_fit(lv_obj_t * cont, bool hor_en, bool ver_en)\n{\n    lv_obj_invalidate(cont);\n    lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont);\n    if(ext->hor_fit == hor_en && ext->ver_fit == ver_en) return;\n\n    ext->hor_fit = hor_en == false ? 0 : 1;\n    ext->ver_fit = ver_en == false ? 0 : 1;\n\n    /*Send a signal to refresh the layout*/\n    cont->signal_func(cont, LV_SIGNAL_CHILD_CHG, NULL);\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the layout of a container\n * @param cont pointer to container object\n * @return the layout from 'lv_cont_layout_t'\n */\nlv_layout_t lv_cont_get_layout(const lv_obj_t * cont)\n{\n    lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont);\n    return ext->layout;\n}\n\n/**\n * Get horizontal fit enable attribute of a container\n * @param cont pointer to a container object\n * @return true: horizontal fit is enabled; false: disabled\n */\nbool lv_cont_get_hor_fit(const lv_obj_t * cont)\n{\n    lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont);\n    return ext->hor_fit == 0 ? false : true;\n}\n\n/**\n * Get vertical fit enable attribute of a container\n * @param cont pointer to a container object\n * @return true: vertical fit is enabled; false: disabled\n */\nbool lv_cont_get_ver_fit(const lv_obj_t * cont)\n{\n    lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont);\n    return ext->ver_fit == 0 ? false : true;\n}\n\n/**\n * Get that width reduced by the horizontal padding. Useful if a layout is used.\n * @param cont pointer to a container object\n * @return the width which still fits into the container\n */\nlv_coord_t lv_cont_get_fit_width(lv_obj_t * cont)\n{\n    lv_style_t * style = lv_cont_get_style(cont);\n\n    return lv_obj_get_width(cont) - 2 * style->body.padding.hor;\n}\n\n/**\n * Get that height reduced by the vertical padding. Useful if a layout is used.\n * @param cont pointer to a container object\n * @return the height which still fits into the container\n */\nlv_coord_t lv_cont_get_fit_height(lv_obj_t * cont)\n{\n    lv_style_t * style = lv_cont_get_style(cont);\n\n    return lv_obj_get_height(cont) - 2 * style->body.padding.ver;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Signal function of the container\n * @param cont pointer to a container object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_cont_signal(lv_obj_t * cont, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(cont, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    if(sign == LV_SIGNAL_STYLE_CHG) { /*Recalculate the padding if the style changed*/\n        lv_cont_refr_layout(cont);\n        lv_cont_refr_autofit(cont);\n    } else if(sign == LV_SIGNAL_CHILD_CHG) {\n        lv_cont_refr_layout(cont);\n        lv_cont_refr_autofit(cont);\n    } else if(sign == LV_SIGNAL_CORD_CHG) {\n        if(lv_obj_get_width(cont) != lv_area_get_width(param) ||\n                lv_obj_get_height(cont) != lv_area_get_height(param)) {\n            lv_cont_refr_layout(cont);\n            lv_cont_refr_autofit(cont);\n        }\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_cont\";\n    }\n\n    return res;\n}\n\n\n/**\n * Refresh the layout of a container\n * @param cont pointer to an object which layout should be refreshed\n */\nstatic void lv_cont_refr_layout(lv_obj_t * cont)\n{\n    lv_layout_t type = lv_cont_get_layout(cont);\n\n    /*'cont' has to be at least 1 child*/\n    if(lv_obj_get_child(cont, NULL) == NULL) return;\n\n    if(type == LV_LAYOUT_OFF) return;\n\n    if(type == LV_LAYOUT_CENTER) {\n        lv_cont_layout_center(cont);\n    } else if(type == LV_LAYOUT_COL_L || type == LV_LAYOUT_COL_M || type == LV_LAYOUT_COL_R) {\n        lv_cont_layout_col(cont);\n    } else if(type == LV_LAYOUT_ROW_T || type == LV_LAYOUT_ROW_M || type == LV_LAYOUT_ROW_B) {\n        lv_cont_layout_row(cont);\n    } else if(type == LV_LAYOUT_PRETTY) {\n        lv_cont_layout_pretty(cont);\n    }  else if(type == LV_LAYOUT_GRID) {\n        lv_cont_layout_grid(cont);\n    }\n}\n\n/**\n * Handle column type layouts\n * @param cont pointer to an object which layout should be handled\n */\nstatic void lv_cont_layout_col(lv_obj_t * cont)\n{\n    lv_layout_t type = lv_cont_get_layout(cont);\n    lv_obj_t * child;\n\n    /*Adjust margin and get the alignment type*/\n    lv_align_t align;\n    lv_style_t * style = lv_obj_get_style(cont);\n    lv_coord_t hpad_corr;\n\n    switch(type) {\n        case LV_LAYOUT_COL_L:\n            hpad_corr = style->body.padding.hor;\n            align = LV_ALIGN_IN_TOP_LEFT;\n            break;\n        case LV_LAYOUT_COL_M:\n            hpad_corr = 0;\n            align = LV_ALIGN_IN_TOP_MID;\n            break;\n        case LV_LAYOUT_COL_R:\n            hpad_corr = -style->body.padding.hor;\n            align = LV_ALIGN_IN_TOP_RIGHT;\n            break;\n        default:\n            hpad_corr = 0;\n            align = LV_ALIGN_IN_TOP_LEFT;\n            break;\n    }\n\n    /* Disable child change action because the children will be moved a lot\n     * an unnecessary child change signals could be sent*/\n    lv_obj_set_protect(cont, LV_PROTECT_CHILD_CHG);\n    /* Align the children */\n    lv_coord_t last_cord = style->body.padding.ver;\n    LL_READ_BACK(cont->child_ll, child) {\n        if(lv_obj_get_hidden(child) != false ||\n                lv_obj_is_protected(child, LV_PROTECT_POS) != false) continue;\n\n        lv_obj_align(child, cont, align, hpad_corr, last_cord);\n        last_cord += lv_obj_get_height(child) + style->body.padding.inner;\n    }\n\n    lv_obj_clear_protect(cont, LV_PROTECT_CHILD_CHG);\n}\n\n/**\n * Handle row type layouts\n * @param cont pointer to an object which layout should be handled\n */\nstatic void lv_cont_layout_row(lv_obj_t * cont)\n{\n    lv_layout_t type = lv_cont_get_layout(cont);\n    lv_obj_t * child;\n\n    /*Adjust margin and get the alignment type*/\n    lv_align_t align;\n    lv_style_t * style = lv_obj_get_style(cont);\n    lv_coord_t vpad_corr = style->body.padding.ver;\n\n    switch(type) {\n        case LV_LAYOUT_ROW_T:\n            vpad_corr = style->body.padding.ver;\n            align = LV_ALIGN_IN_TOP_LEFT;\n            break;\n        case LV_LAYOUT_ROW_M:\n            vpad_corr = 0;\n            align = LV_ALIGN_IN_LEFT_MID;\n            break;\n        case LV_LAYOUT_ROW_B:\n            vpad_corr = -style->body.padding.ver;\n            align = LV_ALIGN_IN_BOTTOM_LEFT;\n            break;\n        default:\n            vpad_corr = 0;\n            align = LV_ALIGN_IN_TOP_LEFT;\n            break;\n    }\n\n    /* Disable child change action because the children will be moved a lot\n     * an unnecessary child change signals could be sent*/\n    lv_obj_set_protect(cont, LV_PROTECT_CHILD_CHG);\n\n    /* Align the children */\n    lv_coord_t last_cord = style->body.padding.hor;\n    LL_READ_BACK(cont->child_ll, child) {\n        if(lv_obj_get_hidden(child) != false ||\n                lv_obj_is_protected(child, LV_PROTECT_POS) != false) continue;\n\n        lv_obj_align(child, cont, align, last_cord, vpad_corr);\n        last_cord += lv_obj_get_width(child) + style->body.padding.inner;\n    }\n\n    lv_obj_clear_protect(cont, LV_PROTECT_CHILD_CHG);\n}\n\n/**\n * Handle the center layout\n * @param cont pointer to an object which layout should be handled\n */\nstatic void lv_cont_layout_center(lv_obj_t * cont)\n{\n    lv_obj_t * child;\n    lv_style_t * style = lv_obj_get_style(cont);\n    uint32_t obj_num = 0;\n    lv_coord_t h_tot = 0;\n\n    LL_READ(cont->child_ll, child) {\n        if(lv_obj_get_hidden(child) != false ||\n                lv_obj_is_protected(child, LV_PROTECT_POS) != false) continue;\n        h_tot += lv_obj_get_height(child) + style->body.padding.inner;\n        obj_num ++;\n    }\n\n    if(obj_num == 0) return;\n\n    h_tot -= style->body.padding.inner;\n\n    /* Disable child change action because the children will be moved a lot\n     * an unnecessary child change signals could be sent*/\n    lv_obj_set_protect(cont, LV_PROTECT_CHILD_CHG);\n\n    /* Align the children */\n    lv_coord_t last_cord = - (h_tot / 2);\n    LL_READ_BACK(cont->child_ll, child) {\n        if(lv_obj_get_hidden(child) != false ||\n                lv_obj_is_protected(child, LV_PROTECT_POS) != false) continue;\n\n        lv_obj_align(child, cont, LV_ALIGN_CENTER, 0, last_cord + lv_obj_get_height(child) / 2);\n        last_cord += lv_obj_get_height(child) + style->body.padding.inner;\n    }\n\n    lv_obj_clear_protect(cont, LV_PROTECT_CHILD_CHG);\n}\n\n/**\n * Handle the pretty layout. Put as many object as possible in row\n * then begin a new row\n * @param cont pointer to an object which layout should be handled\n */\nstatic void lv_cont_layout_pretty(lv_obj_t * cont)\n{\n    lv_obj_t * child_rs;    /* Row starter child */\n    lv_obj_t * child_rc;    /* Row closer child */\n    lv_obj_t * child_tmp;   /* Temporary child */\n    lv_style_t * style = lv_obj_get_style(cont);\n    lv_coord_t w_obj = lv_obj_get_width(cont);\n    lv_coord_t act_y = style->body.padding.ver;\n    /* Disable child change action because the children will be moved a lot\n     * an unnecessary child change signals could be sent*/\n\n    child_rs = lv_ll_get_tail(&cont->child_ll); /*Set the row starter child*/\n    if(child_rs == NULL) return;    /*Return if no child*/\n\n    lv_obj_set_protect(cont, LV_PROTECT_CHILD_CHG);\n\n    child_rc = child_rs; /*Initially the the row starter and closer is the same*/\n    while(child_rs != NULL) {\n        lv_coord_t h_row = 0;\n        lv_coord_t w_row = style->body.padding.hor * 2; /*The width is at least the left+right hpad*/\n        uint32_t obj_num = 0;\n\n        /*Find the row closer object and collect some data*/\n        do {\n            if(lv_obj_get_hidden(child_rc) == false &&\n                    lv_obj_is_protected(child_rc, LV_PROTECT_POS) == false) {\n                /*If this object is already not fit then break*/\n                if(w_row + lv_obj_get_width(child_rc) > w_obj) {\n                    /*Step back one child because the last already not fit, so the previous is the closer*/\n                    if(child_rc != NULL  && obj_num != 0) {\n                        child_rc = lv_ll_get_next(&cont->child_ll, child_rc);\n                    }\n                    break;\n                }\n                w_row += lv_obj_get_width(child_rc) + style->body.padding.inner; /*Add the object width + opad*/\n                h_row = LV_MATH_MAX(h_row, lv_obj_get_height(child_rc)); /*Search the highest object*/\n                obj_num ++;\n                if(lv_obj_is_protected(child_rc, LV_PROTECT_FOLLOW)) break; /*If can not be followed by an other object then break here*/\n\n            }\n            child_rc = lv_ll_get_prev(&cont->child_ll, child_rc); /*Load the next object*/\n            if(obj_num == 0) child_rs = child_rc; /*If the first object was hidden (or too long) then set the next as first */\n        } while(child_rc != NULL);\n\n        /*If the object is too long  then align it to the middle*/\n        if(obj_num == 0) {\n            if(child_rc != NULL) {\n                lv_obj_align(child_rc, cont, LV_ALIGN_IN_TOP_MID, 0, act_y);\n                h_row = lv_obj_get_height(child_rc);    /*Not set previously because of the early break*/\n            }\n        }\n        /*If there is only one object in the row then align it to the middle*/\n        else if(obj_num == 1) {\n            lv_obj_align(child_rs, cont, LV_ALIGN_IN_TOP_MID, 0, act_y);\n        }\n        /*If there are two object in the row then align them proportionally*/\n        else if(obj_num == 2) {\n            lv_obj_t * obj1 = child_rs;\n            lv_obj_t * obj2 = lv_ll_get_prev(&cont->child_ll, child_rs);\n            w_row = lv_obj_get_width(obj1) + lv_obj_get_width(obj2);\n            lv_coord_t pad = (w_obj - w_row) / 3;\n            lv_obj_align(obj1, cont, LV_ALIGN_IN_TOP_LEFT, pad, act_y + (h_row - lv_obj_get_height(obj1)) / 2);\n            lv_obj_align(obj2, cont, LV_ALIGN_IN_TOP_RIGHT, -pad, act_y + (h_row - lv_obj_get_height(obj2)) / 2);\n        }\n        /* Align the children (from child_rs to child_rc)*/\n        else {\n            w_row -= style->body.padding.inner * obj_num;\n            lv_coord_t new_opad = (w_obj -  w_row) / (obj_num  - 1);\n            lv_coord_t act_x = style->body.padding.hor; /*x init*/\n            child_tmp = child_rs;\n            while(child_tmp != NULL) {\n                if(lv_obj_get_hidden(child_tmp) == false &&\n                        lv_obj_is_protected(child_tmp, LV_PROTECT_POS) == false) {\n                    lv_obj_align(child_tmp, cont, LV_ALIGN_IN_TOP_LEFT, act_x, act_y + (h_row - lv_obj_get_height(child_tmp)) / 2);\n                    act_x += lv_obj_get_width(child_tmp) + new_opad;\n                }\n                if(child_tmp == child_rc) break;\n                child_tmp = lv_ll_get_prev(&cont->child_ll, child_tmp);\n            }\n\n        }\n\n        if(child_rc == NULL) break;\n        act_y += style->body.padding.inner + h_row; /*y increment*/\n        child_rs = lv_ll_get_prev(&cont->child_ll, child_rc); /*Go to the next object*/\n        child_rc = child_rs;\n    }\n    lv_obj_clear_protect(cont, LV_PROTECT_CHILD_CHG);\n}\n\n/**\n * Handle the grid layout. Align same-sized objects in a grid\n * @param cont pointer to an object which layout should be handled\n */\nstatic void lv_cont_layout_grid(lv_obj_t * cont)\n{\n    lv_obj_t * child;\n    lv_style_t * style = lv_obj_get_style(cont);\n    lv_coord_t w_tot = lv_obj_get_width(cont);\n    lv_coord_t w_obj = lv_obj_get_width(lv_obj_get_child(cont, NULL));\n    lv_coord_t h_obj = lv_obj_get_height(lv_obj_get_child(cont, NULL));\n    uint16_t obj_row = (w_tot - (2 * style->body.padding.hor)) / (w_obj + style->body.padding.inner); /*Obj. num. in a row*/\n    lv_coord_t x_ofs;\n    if(obj_row > 1) {\n        x_ofs = w_obj + (w_tot - (2 * style->body.padding.hor) - (obj_row * w_obj)) / (obj_row - 1);\n    } else {\n        x_ofs = w_tot / 2 - w_obj / 2;\n    }\n    lv_coord_t y_ofs = h_obj + style->body.padding.inner;\n\n    /* Disable child change action because the children will be moved a lot\n     * an unnecessary child change signals could be sent*/\n    lv_obj_set_protect(cont, LV_PROTECT_CHILD_CHG);\n\n    /* Align the children */\n    lv_coord_t act_x = style->body.padding.hor;\n    lv_coord_t act_y = style->body.padding.ver;\n    uint16_t obj_cnt = 0;\n    LL_READ_BACK(cont->child_ll, child) {\n        if(lv_obj_get_hidden(child) != false ||\n                lv_obj_is_protected(child, LV_PROTECT_POS) != false) continue;\n\n        if(obj_row > 1) {\n            lv_obj_set_pos(child, act_x, act_y);\n            act_x += x_ofs;\n        } else {\n            lv_obj_set_pos(child, x_ofs, act_y);\n        }\n        obj_cnt ++;\n\n        if(obj_cnt >= obj_row) {\n            obj_cnt = 0;\n            act_x = style->body.padding.hor;\n            act_y += y_ofs;\n        }\n    }\n\n    lv_obj_clear_protect(cont, LV_PROTECT_CHILD_CHG);\n}\n\n/**\n * Handle auto fit. Set the size of the object to involve all children.\n * @param cont pointer to an object which size will be modified\n */\nstatic void lv_cont_refr_autofit(lv_obj_t * cont)\n{\n    lv_cont_ext_t * ext = lv_obj_get_ext_attr(cont);\n\n    if(ext->hor_fit == 0 &&\n            ext->ver_fit == 0) {\n        return;\n    }\n\n    lv_area_t new_cords;\n    lv_area_t ori;\n    lv_style_t * style = lv_obj_get_style(cont);\n    lv_obj_t * i;\n    lv_coord_t hpad = style->body.padding.hor;\n    lv_coord_t vpad = style->body.padding.ver;\n\n    /*Search the side coordinates of the children*/\n    lv_obj_get_coords(cont, &ori);\n    lv_obj_get_coords(cont, &new_cords);\n\n    new_cords.x1 = LV_COORD_MAX;\n    new_cords.y1 = LV_COORD_MAX;\n    new_cords.x2 = LV_COORD_MIN;\n    new_cords.y2 = LV_COORD_MIN;\n\n    LL_READ(cont->child_ll, i) {\n        if(lv_obj_get_hidden(i) != false) continue;\n        new_cords.x1 = LV_MATH_MIN(new_cords.x1, i->coords.x1);\n        new_cords.y1 = LV_MATH_MIN(new_cords.y1, i->coords.y1);\n        new_cords.x2 = LV_MATH_MAX(new_cords.x2, i->coords.x2);\n        new_cords.y2 = LV_MATH_MAX(new_cords.y2, i->coords.y2);\n    }\n\n    /*If the value is not the init value then the page has >=1 child.*/\n    if(new_cords.x1 != LV_COORD_MAX) {\n        if(ext->hor_fit != 0) {\n            new_cords.x1 -= hpad;\n            new_cords.x2 += hpad;\n        } else {\n            new_cords.x1 = cont->coords.x1;\n            new_cords.x2 = cont->coords.x2;\n        }\n        if(ext->ver_fit != 0) {\n            new_cords.y1 -= vpad;\n            new_cords.y2 += vpad;\n        } else {\n            new_cords.y1 = cont->coords.y1;\n            new_cords.y2 = cont->coords.y2;\n        }\n\n        /*Do nothing if the coordinates are not changed*/\n        if(cont->coords.x1 != new_cords.x1 ||\n                cont->coords.y1 != new_cords.y1 ||\n                cont->coords.x2 != new_cords.x2 ||\n                cont->coords.y2 != new_cords.y2) {\n\n            lv_obj_invalidate(cont);\n            lv_area_copy(&cont->coords, &new_cords);\n            lv_obj_invalidate(cont);\n\n            /*Notify the object about its new coordinates*/\n            cont->signal_func(cont, LV_SIGNAL_CORD_CHG, &ori);\n\n            /*Inform the parent about the new coordinates*/\n            lv_obj_t * par = lv_obj_get_parent(cont);\n            par->signal_func(par, LV_SIGNAL_CHILD_CHG, cont);\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_cont.h",
    "content": "/**\n * @file lv_cont.h\n *\n */\n\n#ifndef LV_CONT_H\n#define LV_CONT_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_CONT != 0\n\n#include \"../lv_core/lv_obj.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/*Layout options*/\nenum\n{\n    LV_LAYOUT_OFF = 0,\n    LV_LAYOUT_CENTER,\n    LV_LAYOUT_COL_L,    /*Column left align*/\n    LV_LAYOUT_COL_M,    /*Column middle align*/\n    LV_LAYOUT_COL_R,    /*Column right align*/\n    LV_LAYOUT_ROW_T,    /*Row top align*/\n    LV_LAYOUT_ROW_M,    /*Row middle align*/\n    LV_LAYOUT_ROW_B,    /*Row bottom align*/\n    LV_LAYOUT_PRETTY,   /*Put as many object as possible in row and begin a new row*/\n    LV_LAYOUT_GRID,     /*Align same-sized object into a grid*/\n};\ntypedef uint8_t lv_layout_t;\n\ntypedef struct\n{\n    /*Inherited from 'base_obj' so no inherited ext. */ /*Ext. of ancestor*/\n    /*New data for this type */\n    uint8_t layout  :4;     /*A layout from 'lv_cont_layout_t' enum*/\n    uint8_t hor_fit :1;     /*1: Enable horizontal fit to involve all children*/\n    uint8_t ver_fit :1;     /*1: Enable horizontal fit to involve all children*/\n} lv_cont_ext_t;\n\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a container objects\n * @param par pointer to an object, it will be the parent of the new container\n * @param copy pointer to a container object, if not NULL then the new object will be copied from it\n * @return pointer to the created container\n */\nlv_obj_t * lv_cont_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a layout on a container\n * @param cont pointer to a container object\n * @param layout a layout from 'lv_cont_layout_t'\n */\nvoid lv_cont_set_layout(lv_obj_t * cont, lv_layout_t layout);\n\n\n/**\n * Enable the horizontal or vertical fit.\n * The container size will be set to involve the children horizontally or vertically.\n * @param cont pointer to a container object\n * @param hor_en true: enable the horizontal fit\n * @param ver_en true: enable the vertical fit\n */\nvoid lv_cont_set_fit(lv_obj_t * cont, bool hor_en, bool ver_en);\n\n/**\n * Set the style of a container\n * @param cont pointer to a container object\n * @param style pointer to the new style\n */\nstatic inline void lv_cont_set_style(lv_obj_t *cont, lv_style_t * style)\n{\n    lv_obj_set_style(cont, style);\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the layout of a container\n * @param cont pointer to container object\n * @return the layout from 'lv_cont_layout_t'\n */\nlv_layout_t lv_cont_get_layout(const lv_obj_t * cont);\n\n/**\n * Get horizontal fit enable attribute of a container\n * @param cont pointer to a container object\n * @return true: horizontal fit is enabled; false: disabled\n */\nbool lv_cont_get_hor_fit(const lv_obj_t * cont);\n\n/**\n * Get vertical fit enable attribute of a container\n * @param cont pointer to a container object\n * @return true: vertical fit is enabled; false: disabled\n */\nbool lv_cont_get_ver_fit(const lv_obj_t * cont);\n\n\n/**\n * Get that width reduced by the horizontal padding. Useful if a layout is used.\n * @param cont pointer to a container object\n * @return the width which still fits into the container\n */\nlv_coord_t lv_cont_get_fit_width(lv_obj_t * cont);\n\n/**\n * Get that height reduced by the vertical padding. Useful if a layout is used.\n * @param cont pointer to a container object\n * @return the height which still fits into the container\n */\nlv_coord_t lv_cont_get_fit_height(lv_obj_t * cont);\n\n/**\n * Get the style of a container\n * @param cont pointer to a container object\n * @return pointer to the container's style\n */\nstatic inline lv_style_t * lv_cont_get_style(const lv_obj_t *cont)\n{\n    return lv_obj_get_style(cont);\n}\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_CONT*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_CONT_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_ddlist.c",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * @file lv_ddlist.c\n *\n */\n\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_ddlist.h\"\n#if USE_LV_DDLIST != 0\n\n#include \"../lv_draw/lv_draw.h\"\n#include \"../lv_core/lv_group.h\"\n#include \"../lv_core/lv_indev.h\"\n#include \"../lv_themes/lv_theme.h\"\n#include \"../lv_misc/lv_symbol_def.h\"\n#include \"../lv_misc/lv_anim.h\"\n//#include <strings.h>\n\n/*********************\n *      DEFINES\n *********************/\n#if USE_LV_ANIMATION\n#  ifndef LV_DDLIST_ANIM_TIME\n#    define LV_DDLIST_ANIM_TIME     200         /*ms*/\n#  endif\n#else\n#  undef  LV_DDLIST_ANIM_TIME\n#  define LV_DDLIST_ANIM_TIME     0             /*No animation*/\n#endif\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool lv_ddlist_design(lv_obj_t * ddlist, const lv_area_t * mask, lv_design_mode_t mode);\nstatic lv_res_t lv_ddlist_signal(lv_obj_t * ddlist, lv_signal_t sign, void * param);\nstatic lv_res_t lv_ddlist_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void * param);\nstatic lv_res_t lv_ddlist_release_action(lv_obj_t * ddlist);\nstatic lv_res_t lv_ddlist_press_action(lv_obj_t * ddlist);\nstatic void lv_ddlist_refr_size(lv_obj_t * ddlist, bool anim_en);\nstatic void lv_ddlist_pos_current_option(lv_obj_t * ddlist);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t  ancestor_signal;\nstatic lv_signal_func_t  ancestor_scrl_signal;\nstatic lv_design_func_t  ancestor_design;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a drop down list objects\n * @param par pointer to an object, it will be the parent of the new drop down list\n * @param copy pointer to a drop down list object, if not NULL then the new object will be copied from it\n * @return pointer to the created drop down list\n */\nlv_obj_t * lv_ddlist_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"drop down list create started\");\n\n    /*Create the ancestor drop down list*/\n    lv_obj_t * new_ddlist = lv_page_create(par, copy);\n    lv_mem_assert(new_ddlist);\n    if(new_ddlist == NULL) return NULL;\n\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_ddlist);\n    if(ancestor_scrl_signal == NULL) ancestor_scrl_signal = lv_obj_get_signal_func(lv_page_get_scrl(new_ddlist));\n    if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_ddlist);\n\n    /*Allocate the drop down list type specific extended data*/\n    lv_ddlist_ext_t * ext = lv_obj_allocate_ext_attr(new_ddlist, sizeof(lv_ddlist_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    /*Initialize the allocated 'ext' */\n    ext->label = NULL;\n    ext->action = NULL;\n    ext->opened = 0;\n    ext->fix_height = 0;\n    ext->sel_opt_id = 0;\n    ext->sel_opt_id_ori = 0;\n    ext->option_cnt = 0;\n    ext->anim_time = LV_DDLIST_ANIM_TIME;\n    ext->sel_style = &lv_style_plain_color;\n    ext->draw_arrow = 0;  /*Do not draw arrow by default*/\n\text->direction_up = 0;\n\n    /*The signal and design functions are not copied so set them here*/\n    lv_obj_set_signal_func(new_ddlist, lv_ddlist_signal);\n    lv_obj_set_signal_func(lv_page_get_scrl(new_ddlist), lv_ddlist_scrl_signal);\n    lv_obj_set_design_func(new_ddlist, lv_ddlist_design);\n\n    /*Init the new drop down list drop down list*/\n    if(copy == NULL) {\n        lv_obj_t * scrl = lv_page_get_scrl(new_ddlist);\n        lv_obj_set_drag(scrl, false);\n        lv_page_set_scrl_fit(new_ddlist, true, true);\n\n        ext->label = lv_label_create(new_ddlist, NULL);\n        lv_cont_set_fit(new_ddlist, true, false);\n        lv_page_set_rel_action(new_ddlist, lv_ddlist_release_action);\n\t\tlv_page_set_pr_action(new_ddlist, lv_ddlist_press_action);\n        lv_page_set_sb_mode(new_ddlist, LV_SB_MODE_DRAG);\n        lv_page_set_sb_mode(new_ddlist, LV_SB_MODE_HIDE);\n        lv_page_set_style(new_ddlist, LV_PAGE_STYLE_SCRL, &lv_style_transp_tight);\n\n        lv_ddlist_set_options(new_ddlist, \"Option 1\\nOption 2\\nOption 3\");\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_BG, th->ddlist.bg);\n\t\t\tlv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_BGO, th->ddlist.bgo);\n\t\t\tlv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_PR, th->ddlist.pr);\n            lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SEL, th->ddlist.sel);\n            lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SB, th->ddlist.sb);\n        } else {\n            lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_BG, &lv_style_pretty);\n\t\t\tlv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_BGO, &lv_style_pretty);\n\t\t\tlv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_PR, &lv_style_pretty);\n            lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SEL, &lv_style_plain_color);\n            lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SB, &lv_style_pretty_color);\n        }\n    }\n    /*Copy an existing drop down list*/\n    else {\n        lv_ddlist_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        ext->label = lv_label_create(new_ddlist, copy_ext->label);\n        lv_label_set_text(ext->label, lv_label_get_text(copy_ext->label));\n        ext->sel_opt_id = copy_ext->sel_opt_id;\n        ext->fix_height = copy_ext->fix_height;\n        ext->action = copy_ext->action;\n        ext->option_cnt = copy_ext->option_cnt;\n        ext->sel_style = copy_ext->sel_style;\n        ext->anim_time = copy_ext->anim_time;\n        ext->draw_arrow = copy_ext->draw_arrow;\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_ddlist);\n    }\n\n    LV_LOG_INFO(\"drop down list created\");\n\n\n    return new_ddlist;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set arrow draw in a drop down list\n * @param ddlist pointer to drop down list object\n * @param en enable/disable a arrow draw. E.g. \"true\" for draw.\n */\nvoid lv_ddlist_set_draw_arrow(lv_obj_t * ddlist, bool en)\n{\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n\n    /*Set the flag*/\n    ext->draw_arrow = en;\n}\n\n/**\n * Set the options in a drop down list from a string\n * @param ddlist pointer to drop down list object\n * @param options a string with '\\n' separated options. E.g. \"One\\nTwo\\nThree\"\n */\nvoid lv_ddlist_set_options(lv_obj_t * ddlist, const char * options)\n{\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n\n    /*Count the '\\n'-s to determine the number of options*/\n    ext->option_cnt = 0;\n    uint16_t i;\n    for(i = 0; options[i] != '\\0'; i++) {\n        if(options[i] == '\\n') ext->option_cnt++;\n    }\n    ext->option_cnt++;     /*Last option in the at row*/\n\n    lv_label_set_text(ext->label, options);\n    lv_ddlist_refr_size(ddlist, false);\n}\n\n/**\n * Set the selected option\n * @param ddlist pointer to drop down list object\n * @param sel_opt id of the selected option (0 ... number of option - 1);\n */\nvoid lv_ddlist_set_selected(lv_obj_t * ddlist, uint16_t sel_opt)\n{\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n    if(ext->sel_opt_id == sel_opt) return;\n\n    ext->sel_opt_id = sel_opt < ext->option_cnt ? sel_opt : ext->option_cnt - 1;\n    ext->sel_opt_id_ori = ext->sel_opt_id;\n    /*Move the list to show the current option*/\n    if(ext->opened == 0) {\n        lv_ddlist_pos_current_option(ddlist);\n    } else {\n        lv_obj_invalidate(ddlist);\n    }\n}\n\n/**\n * Set a function to call when a new option is chosen\n * @param ddlist pointer to a drop down list\n * @param action pointer to a call back function\n */\nvoid lv_ddlist_set_action(lv_obj_t * ddlist, lv_action_t action)\n{\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n    ext->action = action;\n}\n\n/**\n * Set the fix height for the drop down list\n * If 0 then the opened ddlist will be auto. sized else the set height will be applied.\n * @param ddlist pointer to a drop down list\n * @param h the height when the list is opened (0: auto size)\n */\nvoid lv_ddlist_set_fix_height(lv_obj_t * ddlist, lv_coord_t h)\n{\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n    if(ext->fix_height == h) return;\n\n    ext->fix_height = h;\n\n    lv_ddlist_refr_size(ddlist, false);\n}\n\n/**\n * Enable or disable the horizontal fit to the content\n * @param ddlist pointer to a drop down list\n * @param en true: enable auto fit; false: disable auto fit\n */\nvoid lv_ddlist_set_hor_fit(lv_obj_t * ddlist, bool en)\n{\n    lv_cont_set_fit(ddlist, en, lv_cont_get_ver_fit(ddlist));\n    lv_page_set_scrl_fit(ddlist, en, lv_page_get_scrl_fit_ver(ddlist));\n\n    lv_ddlist_refr_size(ddlist, false);\n}\n\n/**\n * Set the open/close animation time.\n * @param ddlist pointer to a drop down list\n * @param anim_time: open/close animation time [ms]\n */\nvoid lv_ddlist_set_anim_time(lv_obj_t * ddlist, uint16_t anim_time)\n{\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n#if USE_LV_ANIMATION == 0\n    anim_time = 0;\n#endif\n\n    ext->anim_time = anim_time;\n}\n\n/**\n * Set a style of a drop down list\n * @param ddlist pointer to a drop down list object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_ddlist_set_style(lv_obj_t * ddlist, lv_ddlist_style_t type, lv_style_t * style)\n{\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n\n    switch(type) {\n        case LV_DDLIST_STYLE_BG:\n            lv_page_set_style(ddlist, LV_PAGE_STYLE_BG, style);\n            break;\n\t\tcase LV_DDLIST_STYLE_BGO:\n\t\t\tlv_page_set_style(ddlist, LV_PAGE_STYLE_BGO, style);\n\t\t\tbreak;\n\t\tcase LV_DDLIST_STYLE_PR:\n\t\t\tlv_page_set_style(ddlist, LV_PAGE_STYLE_PR, style);\n\t\t\tbreak;\n        case LV_DDLIST_STYLE_SB:\n            lv_page_set_style(ddlist, LV_PAGE_STYLE_SB, style);\n            break;\n        case LV_DDLIST_STYLE_SEL:\n            ext->sel_style = style;\n            lv_obj_t * scrl = lv_page_get_scrl(ddlist);\n            lv_obj_refresh_ext_size(scrl);  /*Because of the wider selected rectangle*/\n            break;\n    }\n}\n\nvoid lv_ddlist_set_align(lv_obj_t *ddlist, lv_label_align_t align)\n{\n\tlv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n\n\tlv_label_set_align(ext->label, align);\n}\n\nvoid lv_ddlist_set_direction_up(lv_obj_t *ddlist, bool enable)\n{\n\tlv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n\n\text->direction_up = enable;\n}\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get arrow draw in a drop down list\n * @param ddlist pointer to drop down list object\n */\nbool lv_ddlist_get_draw_arrow(lv_obj_t * ddlist)\n{\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n\n    return ext->draw_arrow;\n}\n\n/**\n * Get the options of a drop down list\n * @param ddlist pointer to drop down list object\n * @return the options separated by '\\n'-s (E.g. \"Option1\\nOption2\\nOption3\")\n */\nconst char * lv_ddlist_get_options(const lv_obj_t * ddlist)\n{\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n    return lv_label_get_text(ext->label);\n}\n\n/**\n * Get the selected option\n * @param ddlist pointer to drop down list object\n * @return id of the selected option (0 ... number of option - 1);\n */\nuint16_t lv_ddlist_get_selected(const lv_obj_t * ddlist)\n{\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n\n    return ext->sel_opt_id;\n}\n\n/**\n * Get the current selected option as a string\n * @param ddlist pointer to ddlist object\n * @param buf pointer to an array to store the string\n */\nvoid lv_ddlist_get_selected_str(const lv_obj_t * ddlist, char * buf)\n{\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n\n    uint16_t i;\n    uint16_t line = 0;\n    const char * opt_txt = lv_label_get_text(ext->label);\n    uint16_t txt_len = strlen(opt_txt);\n\n\n    for(i = 0; i < txt_len && line != ext->sel_opt_id; i++) {\n        if(opt_txt[i] == '\\n') line ++;\n    }\n\n    uint16_t c;\n    for(c = 0; opt_txt[i] != '\\n' && i < txt_len; c++, i++) buf[c] = opt_txt[i];\n\n    buf[c] = '\\0';\n}\n\n/**\n * Get the \"option selected\" callback function\n * @param ddlist pointer to a drop down list\n * @return  pointer to the call back function\n */\nlv_action_t lv_ddlist_get_action(const lv_obj_t * ddlist)\n{\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n    return ext->action;\n}\n\n/**\n * Get the fix height value.\n * @param ddlist pointer to a drop down list object\n * @return the height if the ddlist is opened (0: auto size)\n */\nlv_coord_t lv_ddlist_get_fix_height(const lv_obj_t * ddlist)\n{\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n    return ext->fix_height;\n}\n\n/**\n * Get the open/close animation time.\n * @param ddlist pointer to a drop down list\n * @return open/close animation time [ms]\n */\nuint16_t lv_ddlist_get_anim_time(const lv_obj_t * ddlist)\n{\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n    return ext->anim_time;\n}\n\n/**\n * Get a style of a drop down list\n * @param ddlist pointer to a drop down list object\n * @param type which style should be get\n * @return style pointer to a style\n */\nlv_style_t * lv_ddlist_get_style(const lv_obj_t * ddlist, lv_ddlist_style_t type)\n{\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n\n    switch(type) {\n        case LV_DDLIST_STYLE_BG:\n            return lv_page_get_style(ddlist, LV_PAGE_STYLE_BG);\n\t\tcase LV_DDLIST_STYLE_BGO:\n\t\t\treturn lv_page_get_style(ddlist, LV_PAGE_STYLE_BGO);\n\t\tcase LV_DDLIST_STYLE_PR:\n\t\t\treturn lv_page_get_style(ddlist, LV_PAGE_STYLE_PR);\n        case LV_DDLIST_STYLE_SB:\n            return lv_page_get_style(ddlist, LV_PAGE_STYLE_SB);\n        case LV_DDLIST_STYLE_SEL:\n            return ext->sel_style;\n        default:\n            return NULL;\n    }\n\n    /*To avoid warning*/\n    return NULL;\n}\n\nlv_label_align_t lv_ddlist_get_align(const lv_obj_t *ddlist)\n{\n\tlv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n\n\treturn lv_label_get_align(ext->label);\n}\n\n/*=====================\n * Other functions\n *====================*/\n\n/**\n * Open the drop down list with or without animation\n * @param ddlist pointer to drop down list object\n * @param anim_en true: use animation; false: not use animations\n */\nvoid lv_ddlist_open(lv_obj_t * ddlist, bool anim_en)\n{\n#if USE_LV_ANIMATION == 0\n    anim_en = false;\n#endif\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n    ext->opened = 1;\n    lv_obj_set_drag(lv_page_get_scrl(ddlist), true);\n    lv_ddlist_refr_size(ddlist, anim_en);\n}\n\n/**\n * Close (Collapse) the drop down list\n * @param ddlist pointer to drop down list object\n * @param anim_en true: use animation; false: not use animations\n */\nvoid lv_ddlist_close(lv_obj_t * ddlist, bool anim_en)\n{\n#if USE_LV_ANIMATION == 0\n    anim_en = false;\n#endif\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n    ext->opened = 0;\n    lv_obj_set_drag(lv_page_get_scrl(ddlist), false);\n    lv_ddlist_refr_size(ddlist, anim_en);\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Get the text alignment flag for a drop down list.\n * @param ddlist drop down list\n * @return text alignment flag\n */\nstatic lv_txt_flag_t lv_ddlist_get_txt_flag(const lv_obj_t *ddlist)\n{\n\tlv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n\n\t/*The label might be already deleted so just return with some value*/\n\tif(!ext->label) return LV_TXT_FLAG_CENTER;\n\n\tlv_label_align_t align = lv_label_get_align(ext->label);\n\n\tswitch(align)\n\t{\n\tdefault:\n\tcase LV_LABEL_ALIGN_LEFT:\n\t\treturn LV_TXT_FLAG_NONE;\n\tcase LV_LABEL_ALIGN_CENTER:\n\t\treturn LV_TXT_FLAG_CENTER;\n\tcase LV_LABEL_ALIGN_RIGHT:\n\t\treturn LV_TXT_FLAG_RIGHT;\n\t}\n}\n\n/**\n * Handle the drawing related tasks of the drop down lists\n * @param ddlist pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_ddlist_design(lv_obj_t * ddlist, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    /*Return false if the object is not covers the mask_p area*/\n    if(mode == LV_DESIGN_COVER_CHK) {\n        return ancestor_design(ddlist, mask, mode);\n    }\n    /*Draw the object*/\n    else if(mode == LV_DESIGN_DRAW_MAIN) {\n        ancestor_design(ddlist, mask, mode);\n\n        lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n        lv_opa_t opa_scale = lv_obj_get_opa_scale(ddlist);\n        /*If the list is opened draw a rectangle under the selected item*/\n        if(ext->opened != 0) {\n            lv_style_t * style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BG);\n            const lv_font_t * font = style->text.font;\n            lv_coord_t font_h = lv_font_get_height(font);\n\n            /*Draw the selected*/\n            lv_area_t rect_area;\n            rect_area.y1 = ext->label->coords.y1;\n            rect_area.y1 += ext->sel_opt_id * (font_h + style->text.line_space);\n            rect_area.y1 -= style->text.line_space / 2;\n\n            rect_area.y2 = rect_area.y1 + font_h + style->text.line_space - 1;\n            rect_area.x1 = ddlist->coords.x1;\n            rect_area.x2 = ddlist->coords.x2;\n\n            lv_draw_rect(&rect_area, mask, ext->sel_style, opa_scale);\n        }\n    }\n    /*Post draw when the children are drawn*/\n    else if(mode == LV_DESIGN_DRAW_POST) {\n        /*Redraw the text on the selected area with a different color*/\n        lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n        lv_opa_t opa_scale = lv_obj_get_opa_scale(ddlist);\n\n        /*Redraw only in opened state*/\n        if(ext->opened) {\n            lv_style_t * style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BG);\n            const lv_font_t * font = style->text.font;\n            lv_coord_t font_h = lv_font_get_height(font);\n\n            lv_area_t area_sel;\n            area_sel.y1 = ext->label->coords.y1;\n            area_sel.y1 += ext->sel_opt_id * (font_h + style->text.line_space);\n            area_sel.y1 -= style->text.line_space / 2;\n\n            area_sel.y2 = area_sel.y1 + font_h + style->text.line_space - 1;\n            area_sel.x1 = ddlist->coords.x1;\n            area_sel.x2 = ddlist->coords.x2;\n            lv_area_t mask_sel;\n            bool area_ok;\n            area_ok = lv_area_intersect(&mask_sel, mask, &area_sel);\n            if(area_ok) {\n                lv_style_t * sel_style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_SEL);\n                lv_style_t new_style;\n                lv_style_copy(&new_style, style);\n                new_style.text.color = sel_style->text.color;\n                new_style.text.opa = sel_style->text.opa;\n                lv_txt_flag_t flag = lv_ddlist_get_txt_flag(ddlist);\n                lv_draw_label(&ext->label->coords, &mask_sel, &new_style, opa_scale,\n                              lv_label_get_text(ext->label), flag, NULL);\n            }\n        }\n\n\t\t/*Add a down symbol in ddlist when closed*/\n\t\telse\n\t\t{\n\t\t\t/*Draw a arrow in ddlist if enabled*/\n\t\t\tif(ext->draw_arrow)\n\t\t\t{\n\t\t\t\tlv_style_t * style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BG);\n\t\t\t\tconst lv_font_t * font = style->text.font;\n\t\t\t\tlv_style_t * sel_style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BG);\n\t\t\t\tlv_coord_t font_h = lv_font_get_height(font);\n\t\t\t\tlv_style_t new_style;\n\t\t\t\tlv_style_copy(&new_style, style);\n\t\t\t\tnew_style.text.color = sel_style->text.color;\n\t\t\t\tnew_style.text.opa = sel_style->text.opa;\n\t\t\t\tlv_area_t area_arrow;\n\t\t\t\tarea_arrow.x2 = ddlist->coords.x2 - style->body.padding.hor;\n\t\t\t\tif (!ext->direction_up)\n\t\t\t\t\tarea_arrow.x1 = area_arrow.x2 - lv_txt_get_width(SYMBOL_DOWN, strlen(SYMBOL_DOWN), sel_style->text.font, 0, 0);\n\t\t\t\telse\n\t\t\t\t\tarea_arrow.x1 = area_arrow.x2 - lv_txt_get_width(SYMBOL_UP, strlen(SYMBOL_UP), sel_style->text.font, 0, 0);\n\n\t\t\t\tarea_arrow.y1 = ddlist->coords.y1 + style->text.line_space;\n\t\t\t\tarea_arrow.y2 = area_arrow.y1 + font_h;\n\n\n\t\t\t\tlv_area_t mask_arrow;\n\t\t\t\tbool area_ok;\n\t\t\t\tarea_ok = lv_area_intersect(&mask_arrow, mask, &area_arrow);\n\t\t\t\tif (area_ok)\n\t\t\t\t{\n\t\t\t\t\tif (!ext->direction_up)\n\t\t\t\t\t\tlv_draw_label(&area_arrow, &mask_arrow, &new_style, opa_scale,\n\t\t\t\t\t\t\tSYMBOL_DOWN, LV_TXT_FLAG_NONE, NULL);\t\t/*Use a down arrow in ddlist, you can replace it with your custom symbol*/\n\t\t\t\t\telse\n\t\t\t\t\t\tlv_draw_label(&area_arrow, &mask_arrow, &new_style, opa_scale,\n\t\t\t\t\t\t\tSYMBOL_UP, LV_TXT_FLAG_NONE, NULL);\t\t/*Use a down arrow in ddlist, you can replace it with your custom symbol*/\n\t\t\t\t}\n\t\t\t}\n\t\t}\n        /*Draw the scrollbar in the ancestor page design function*/\n        ancestor_design(ddlist, mask, mode);\n    }\n\n    return true;\n}\n\n/**\n * Signal function of the drop down list\n * @param ddlist pointer to a drop down list object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_ddlist_signal(lv_obj_t * ddlist, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n    /* Include the ancient signal function */\n    res = ancestor_signal(ddlist, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n\n    if(sign == LV_SIGNAL_STYLE_CHG) {\n        //! lv_ddlist_refr_size(ddlist, 0); // uncommented in OG\n    } else if(sign == LV_SIGNAL_CLEANUP) {\n        ext->label = NULL;\n    } else if(sign == LV_SIGNAL_FOCUS) {\n#if USE_LV_GROUP\n        lv_group_t * g = lv_obj_get_group(ddlist);\n        bool editing = lv_group_get_editing(g);\n        lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act());\n\n        /*Encoders need special handling*/\n        if(indev_type == LV_INDEV_TYPE_ENCODER) {\n            /*Open the list if editing*/\n            if(editing) {\n                ext->opened = true;\n                ext->sel_opt_id_ori = ext->sel_opt_id;\n                lv_ddlist_refr_size(ddlist, true);\n            }\n            /*Close the lift if navigating*/\n            else {\n                ext->opened = false;\n                ext->sel_opt_id = ext->sel_opt_id_ori;\n                lv_ddlist_refr_size(ddlist, true);\n\n            }\n        } else {\n            /*Open the list if closed*/\n            if(!ext->opened) {\n                ext->opened = true;\n                ext->sel_opt_id_ori = ext->sel_opt_id;      /*Save the current value. Used to revert this state if ENER wont't be pressed*/\n                lv_ddlist_refr_size(ddlist, true);\n            }\n        }\n#endif\n    } else if(sign == LV_SIGNAL_DEFOCUS) {\n        if(ext->opened) {\n            ext->opened = false;\n            ext->sel_opt_id = ext->sel_opt_id_ori;\n            lv_ddlist_refr_size(ddlist, true);\n        }\n    } else if(sign == LV_SIGNAL_CONTROLL) {\n        char c = *((char *)param);\n        if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_DOWN) {\n            if(!ext->opened) {\n                ext->opened = 1;\n                lv_ddlist_refr_size(ddlist, true);\n            }\n\n            if(ext->sel_opt_id + 1 < ext->option_cnt) {\n                ext->sel_opt_id ++;\n                lv_ddlist_pos_current_option(ddlist);\n                lv_obj_invalidate(ddlist);\n            }\n        } else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_UP) {\n            if(!ext->opened) {\n                ext->opened = 1;\n                lv_ddlist_refr_size(ddlist, true);\n            }\n            if(ext->sel_opt_id > 0) {\n                ext->sel_opt_id --;\n                lv_ddlist_pos_current_option(ddlist);\n                lv_obj_invalidate(ddlist);\n            }\n        } else if(c == LV_GROUP_KEY_ENTER) {\n            if(ext->opened) {\n                ext->sel_opt_id_ori = ext->sel_opt_id;\n                ext->opened = 0;\n                if(ext->action) ext->action(ddlist);\n\n#if USE_LV_GROUP\n                lv_group_t * g = lv_obj_get_group(ddlist);\n                bool editing = lv_group_get_editing(g);\n                if(editing) lv_group_set_editing(g, false);     /*In edit mode go to navigate mode if an option is selected*/\n#endif\n            } else {\n                ext->opened = 1;\n            }\n\n            lv_ddlist_refr_size(ddlist, true);\n        } else if(c == LV_GROUP_KEY_ESC) {\n            if(ext->opened) {\n                ext->opened = 0;\n                ext->sel_opt_id = ext->sel_opt_id_ori;\n                lv_ddlist_refr_size(ddlist, true);\n            }\n        }\n    } else if(sign == LV_SIGNAL_GET_EDITABLE) {\n        bool * editable = (bool *)param;\n        *editable = true;\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_ddlist\";\n    }\n\n    return res;\n}\n\n/**\n * Signal function of the drop down list's scrollable part\n * @param scrl pointer to a drop down list's scrollable part\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_ddlist_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_scrl_signal(scrl, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    lv_obj_t * ddlist = lv_obj_get_parent(scrl);\n\n    if(sign == LV_SIGNAL_REFR_EXT_SIZE) {\n        /* Because of the wider selected rectangle ext. size\n         * In this way by dragging the scrollable part the wider rectangle area can be redrawn too*/\n        lv_style_t * style = lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BG);\n        if(scrl->ext_size < style->body.padding.hor) scrl->ext_size = style->body.padding.hor;\n    } else if(sign == LV_SIGNAL_CLEANUP) {\n        lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n        ext->label = NULL;      /*The label is already deleted*/\n    }\n\n    return res;\n}\n\n/**\n * Called when a drop down list is released to open it or set new option\n * @param ddlist pointer to a drop down list object\n * @return LV_ACTION_RES_INV if the ddlist it deleted in the user callback else LV_ACTION_RES_OK\n */\nstatic lv_res_t lv_ddlist_release_action(lv_obj_t * ddlist)\n{\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n\n\tif (!lv_obj_get_click(ddlist)) return LV_RES_OK;\n\n    if(ext->opened == 0) { /*Open the list*/\n        ext->opened = 1;\n\t\tlv_ddlist_set_style(ddlist, LV_DDLIST_STYLE_BG, lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BGO));\n        lv_obj_set_drag(lv_page_get_scrl(ddlist), true);\n    } else {\n        ext->opened = 0;\n\t\t//lv_ddlist_set_style(ddlist, LV_DDLIST_STYLE_BG, lv_ddlist_get_style(ddlist, lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_PR)));\n        lv_obj_set_drag(lv_page_get_scrl(ddlist), false);\n\n        /*Search the clicked option*/\n        lv_indev_t * indev = lv_indev_get_act();\n        lv_point_t p;\n        lv_indev_get_point(indev, &p);\n        p.x -= ext->label->coords.x1;\n        p.y -= ext->label->coords.y1;\n        uint16_t letter_i;\n        letter_i = lv_label_get_letter_on(ext->label, &p);\n\n        uint16_t new_opt = 0;\n        const char * txt = lv_label_get_text(ext->label);\n        uint32_t i = 0;\n        uint32_t line_cnt = 0;\n        uint32_t letter;\n        for(line_cnt = 0; line_cnt < letter_i; line_cnt++) {\n            letter = lv_txt_encoded_next(txt, &i);\n            if(letter == '\\n') new_opt ++;\n        }\n\n        ext->sel_opt_id = new_opt;\n\n        if(ext->action != NULL) {\n            ext->action(ddlist);\n        }\n    }\n    lv_ddlist_refr_size(ddlist, true);\n\n    return LV_RES_OK;\n}\n\nstatic lv_res_t lv_ddlist_press_action(lv_obj_t * ddlist)\n{\n\tlv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n\n\tif (!lv_obj_get_click(ddlist)) return LV_RES_OK;\n\n\tif (ext->opened == 0)\n\t{ /*Open the list*/\n\t\tlv_ddlist_set_style(ddlist, LV_DDLIST_STYLE_BG, lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_PR));\n\t}\n\telse\n\t{\n\t\t//lv_ddlist_set_style(ddlist, LV_DDLIST_STYLE_BG, lv_ddlist_get_style(ddlist, LV_DDLIST_STYLE_BGO));\n\t\t//lv_obj_set_drag(lv_page_get_scrl(ddlist), false);\n\n\t\t///*Search the clicked option*/\n\t\t//lv_indev_t * indev = lv_indev_get_act();\n\t\t//lv_point_t p;\n\t\t//lv_indev_get_point(indev, &p);\n\t\t//p.x -= ext->label->coords.x1;\n\t\t//p.y -= ext->label->coords.y1;\n\t\t//uint16_t letter_i;\n\t\t//letter_i = lv_label_get_letter_on(ext->label, &p);\n\n\t\t//uint16_t new_opt = 0;\n\t\t//const char * txt = lv_label_get_text(ext->label);\n\t\t//uint32_t i = 0;\n\t\t//uint32_t line_cnt = 0;\n\t\t//uint32_t letter;\n\t\t//for (line_cnt = 0; line_cnt < letter_i; line_cnt++)\n\t\t//{\n\t\t//\tletter = lv_txt_encoded_next(txt, &i);\n\t\t//\tif (letter == '\\n') new_opt++;\n\t\t//}\n\n\t\t//ext->sel_opt_id = new_opt;\n\n\t\t//if (ext->action != NULL)\n\t\t//{\n\t\t//\text->action(ddlist);\n\t\t//}\n\t}\n\n\treturn LV_RES_OK;\n}\n\n/**\n * Refresh the size of drop down list according to its status (open or closed)\n * @param ddlist pointer to a drop down list object\n * @param anim_en Change the size (open/close) with or without animation (true/false)\n */\nstatic void lv_ddlist_refr_size(lv_obj_t * ddlist, bool anim_en)\n{\n#if USE_LV_ANIMATION == 0\n    anim_en = false;\n#endif\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n    lv_style_t * style = lv_obj_get_style(ddlist);\n    lv_coord_t new_height, full_height;\n\tbool current_state = 0;\n\n    if(ext->opened) { /*Open the list*/\n        if(ext->fix_height == 0) new_height = lv_obj_get_height(lv_page_get_scrl(ddlist)) + 2 * style->body.padding.ver;\n        else new_height = ext->fix_height;\n\t\tcurrent_state = 1;\n\n        lv_page_set_sb_mode(ddlist, LV_SB_MODE_UNHIDE);\n    } else { /*Close the list*/\n        const lv_font_t * font = style->text.font;\n        lv_style_t * label_style = lv_obj_get_style(ext->label);\n        lv_coord_t font_h = lv_font_get_height(font);\n        new_height = font_h + 2 * label_style->text.line_space;\n\t\t//full_height = lv_obj_get_height(lv_page_get_scrl(ddlist)) + 2 * style->body.padding.ver;\n\t\tcurrent_state = 0;\n\n        lv_page_set_sb_mode(ddlist, LV_SB_MODE_HIDE);\n    }\n\n    if(anim_en == 0 || ext->direction_up) {\n        lv_obj_set_height(ddlist, new_height);\n\t\tif (ext->direction_up)\n\t\t{\n\t\t\tfull_height = lv_obj_get_height(lv_page_get_scrl(ddlist)) - lv_font_get_height(style->text.font);\n\t\t\tif (current_state)\n\t\t\t\tlv_obj_set_y(ddlist, lv_obj_get_y(ddlist) - full_height);\n\t\t\telse\n\t\t\t\tlv_obj_set_y(ddlist, lv_obj_get_y(ddlist) + full_height);\n\t\t}\n\n        lv_ddlist_pos_current_option(ddlist);\n#if USE_LV_ANIMATION\n        lv_anim_del(ddlist, (lv_anim_fp_t)lv_obj_set_height);  /*If an animation is in progress then it will overwrite this changes*/\n    } else {\n        lv_anim_t a;\n        a.var = ddlist;\n        a.start = lv_obj_get_height(ddlist);\n        a.end = new_height;\n        a.fp = (lv_anim_fp_t)lv_obj_set_height;\n        a.path = lv_anim_path_linear;\n        a.end_cb = (lv_anim_cb_t)lv_ddlist_pos_current_option;\n        a.act_time = 0;\n        a.time = ext->anim_time;\n        a.playback = 0;\n        a.playback_pause = 0;\n        a.repeat = 0;\n        a.repeat_pause = 0;\n\n        lv_anim_create(&a);\n#endif\n    }\n}\n\n/**\n * Set the position of list when it is closed to show the selected item\n * @param ddlist pointer to a drop down list\n */\nstatic void lv_ddlist_pos_current_option(lv_obj_t * ddlist)\n{\n    lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);\n    lv_style_t * style = lv_obj_get_style(ddlist);\n    const lv_font_t * font = style->text.font;\n    lv_coord_t font_h = lv_font_get_height(font);\n    lv_style_t * label_style = lv_obj_get_style(ext->label);\n    lv_obj_t * scrl = lv_page_get_scrl(ddlist);\n\n    lv_coord_t h = lv_obj_get_height(ddlist);\n    lv_coord_t line_y1 = ext->sel_opt_id * (font_h + label_style->text.line_space) + ext->label->coords.y1 - scrl->coords.y1;\n\n    lv_obj_set_y(scrl, - line_y1 + (h - font_h) / 2);\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_ddlist.h",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * @file lv_ddlist.h\n *\n */\n\n#ifndef LV_DDLIST_H\n#define LV_DDLIST_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_DDLIST != 0\n\n/*Testing of dependencies*/\n#if USE_LV_PAGE == 0\n#error \"lv_ddlist: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE  1) \"\n#endif\n\n#if USE_LV_LABEL == 0\n#error \"lv_ddlist: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL  1) \"\n#endif\n\n#include \"../lv_core/lv_obj.h\"\n#include \"../lv_objx/lv_page.h\"\n#include \"../lv_objx/lv_label.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n/*Data of drop down list*/\ntypedef struct\n{\n    lv_page_ext_t page; /*Ext. of ancestor*/\n    /*New data for this type */\n    lv_obj_t *label;                     /*Label for the options*/\n    lv_style_t * sel_style;              /*Style of the selected option*/\n    lv_action_t action;                  /*Pointer to function to call when an option is selected*/\n    uint16_t option_cnt;                 /*Number of options*/\n    uint16_t sel_opt_id;                 /*Index of the current option*/\n    uint16_t sel_opt_id_ori;             /*Store the original index on focus*/\n    uint16_t anim_time;                  /*Open/Close animation time [ms]*/\n    uint8_t opened :1;                   /*1: The list is opened (handled by the library)*/\n    uint8_t draw_arrow :1;               /*1: Draw arrow*/\n\tuint8_t direction_up : 1;            /*1: Open direction*/\n\n    lv_coord_t fix_height;               /*Height of the ddlist when opened. (0: auto-size)*/\n} lv_ddlist_ext_t;\n\nenum {\n    LV_DDLIST_STYLE_BG,\n\tLV_DDLIST_STYLE_BGO,\n\tLV_DDLIST_STYLE_PR,\n    LV_DDLIST_STYLE_SEL,\n    LV_DDLIST_STYLE_SB,\n};\ntypedef uint8_t lv_ddlist_style_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n/**\n * Create a drop down list objects\n * @param par pointer to an object, it will be the parent of the new drop down list\n * @param copy pointer to a drop down list object, if not NULL then the new object will be copied from it\n * @return pointer to the created drop down list\n */\nlv_obj_t * lv_ddlist_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set arrow draw in a drop down list\n * @param ddlist pointer to drop down list object\n * @param en enable/disable a arrow draw. E.g. \"true\" for draw.\n */\nvoid lv_ddlist_set_draw_arrow(lv_obj_t * ddlist, bool en);\n\n/**\n * Set the options in a drop down list from a string\n * @param ddlist pointer to drop down list object\n * @param options a string with '\\n' separated options. E.g. \"One\\nTwo\\nThree\"\n */\nvoid lv_ddlist_set_options(lv_obj_t * ddlist, const char * options);\n\n/**\n * Set the selected option\n * @param ddlist pointer to drop down list object\n * @param sel_opt id of the selected option (0 ... number of option - 1);\n */\nvoid lv_ddlist_set_selected(lv_obj_t * ddlist, uint16_t sel_opt);\n\n/**\n * Set a function to call when a new option is chosen\n * @param ddlist pointer to a drop down list\n * @param action pointer to a call back function\n */\nvoid lv_ddlist_set_action(lv_obj_t * ddlist, lv_action_t action);\n\n/**\n * Set the fix height for the drop down list\n * If 0 then the opened ddlist will be auto. sized else the set height will be applied.\n * @param ddlist pointer to a drop down list\n * @param h the height when the list is opened (0: auto size)\n */\nvoid lv_ddlist_set_fix_height(lv_obj_t * ddlist, lv_coord_t h);\n\n/**\n * Enable or disable the horizontal fit to the content\n * @param ddlist pointer to a drop down list\n * @param en true: enable auto fit; false: disable auto fit\n */\nvoid lv_ddlist_set_hor_fit(lv_obj_t * ddlist, bool en);\n\n/**\n * Set the scroll bar mode of a drop down list\n * @param ddlist pointer to a drop down list object\n * @param sb_mode the new mode from 'lv_page_sb_mode_t' enum\n */\nstatic inline void lv_ddlist_set_sb_mode(lv_obj_t * ddlist, lv_sb_mode_t mode)\n{\n    lv_page_set_sb_mode(ddlist, mode);\n}\n\n/**\n * Set the open/close animation time.\n * @param ddlist pointer to a drop down list\n * @param anim_time: open/close animation time [ms]\n */\nvoid lv_ddlist_set_anim_time(lv_obj_t * ddlist, uint16_t anim_time);\n\n\n/**\n * Set a style of a drop down list\n * @param ddlist pointer to a drop down list object\n * @param type which style should be set\n * @param style pointer to a style\n *  */\nvoid lv_ddlist_set_style(lv_obj_t *ddlist, lv_ddlist_style_t type, lv_style_t *style);\n\n/**\n * Set the alignment of the labels in a drop down list\n * @param ddlist pointer to a drop down list object\n * @param align alignment of labels\n */\nvoid lv_ddlist_set_align(lv_obj_t *ddlist, lv_label_align_t align);\n\nvoid lv_ddlist_set_direction_up(lv_obj_t *ddlist, bool enable);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get arrow draw in a drop down list\n * @param ddlist pointer to drop down list object\n */\nbool lv_ddlist_get_draw_arrow(lv_obj_t * ddlist);\n\n/**\n * Get the options of a drop down list\n * @param ddlist pointer to drop down list object\n * @return the options separated by '\\n'-s (E.g. \"Option1\\nOption2\\nOption3\")\n */\nconst char * lv_ddlist_get_options(const lv_obj_t * ddlist);\n\n/**\n * Get the selected option\n * @param ddlist pointer to drop down list object\n * @return id of the selected option (0 ... number of option - 1);\n */\nuint16_t lv_ddlist_get_selected(const lv_obj_t * ddlist);\n\n/**\n * Get the current selected option as a string\n * @param ddlist pointer to ddlist object\n * @param buf pointer to an array to store the string\n */\nvoid lv_ddlist_get_selected_str(const lv_obj_t * ddlist, char * buf);\n\n/**\n * Get the \"option selected\" callback function\n * @param ddlist pointer to a drop down list\n * @return  pointer to the call back function\n */\nlv_action_t lv_ddlist_get_action(const lv_obj_t * ddlist);\n\n/**\n * Get the fix height value.\n * @param ddlist pointer to a drop down list object\n * @return the height if the ddlist is opened (0: auto size)\n */\nlv_coord_t lv_ddlist_get_fix_height(const lv_obj_t * ddlist);\n\n/**\n * Get the scroll bar mode of a drop down list\n * @param ddlist pointer to a  drop down list object\n * @return scrollbar mode from 'lv_page_sb_mode_t' enum\n */\nstatic inline lv_sb_mode_t lv_ddlist_get_sb_mode(const lv_obj_t * ddlist)\n{\n    return lv_page_get_sb_mode(ddlist);\n}\n\n/**\n * Get the open/close animation time.\n * @param ddlist pointer to a drop down list\n * @return open/close animation time [ms]\n */\nuint16_t lv_ddlist_get_anim_time(const lv_obj_t * ddlist);\n\n/**\n * Get a style of a drop down list\n * @param ddlist pointer to a drop down list object\n * @param type which style should be get\n * @return style pointer to a style\n */\nlv_style_t * lv_ddlist_get_style(const lv_obj_t *ddlist, lv_ddlist_style_t type);\n\n/**\n * Get the alignment of the labels in a drop down list\n * @param ddlist pointer to a drop down list object\n * @return alignment of labels\n */\nlv_label_align_t lv_ddlist_get_align(const lv_obj_t *ddlist);\n\n/*=====================\n * Other functions\n *====================*/\n\n/**\n * Open the drop down list with or without animation\n * @param ddlist pointer to drop down list object\n * @param anim_en true: use animation; false: not use animations\n */\nvoid lv_ddlist_open(lv_obj_t * ddlist, bool anim_en);\n\n/**\n * Close (Collapse) the drop down list\n * @param ddlist pointer to drop down list object\n * @param anim_en true: use animation; false: not use animations\n */\nvoid lv_ddlist_close(lv_obj_t * ddlist, bool anim_en);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_DDLIST*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_DDLIST_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_gauge.c",
    "content": "/**\n * @file lv_gauge.c\n *\n */\n\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_gauge.h\"\n#if USE_LV_GAUGE != 0\n\n#include \"../lv_draw/lv_draw.h\"\n#include \"../lv_themes/lv_theme.h\"\n#include \"../lv_misc/lv_txt.h\"\n#include \"../lv_misc/lv_math.h\"\n#include <stdio.h>\n#include <string.h>\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_GAUGE_DEF_NEEDLE_COLOR       LV_COLOR_RED\n#define LV_GAUGE_DEF_LABEL_COUNT        6\n#define LV_GAUGE_DEF_LINE_COUNT         21      /*Should be: ((label_cnt - 1) * internal_lines) + 1*/\n#define LV_GAUGE_DEF_ANGLE              220\n#define LV_GAUGE_INTERPOLATE_SHIFT\t\t5\t\t/*Interpolate the needle drawing between to degrees*/\n#define LV_GAUGE_INTERPOLATE_MASK\t\t0x1F\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool lv_gauge_design(lv_obj_t * gauge, const lv_area_t * mask, lv_design_mode_t mode);\nstatic lv_res_t lv_gauge_signal(lv_obj_t * gauge, lv_signal_t sign, void * param);\nstatic void lv_gauge_draw_scale(lv_obj_t * gauge, const lv_area_t * mask);\nstatic void lv_gauge_draw_needle(lv_obj_t * gauge, const lv_area_t * mask);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_design_func_t ancestor_design;\nstatic lv_signal_func_t ancestor_signal;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a gauge objects\n * @param par pointer to an object, it will be the parent of the new gauge\n * @param copy pointer to a gauge object, if not NULL then the new object will be copied from it\n * @return pointer to the created gauge\n */\nlv_obj_t * lv_gauge_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"gauge create started\");\n\n    /*Create the ancestor gauge*/\n    lv_obj_t * new_gauge = lv_lmeter_create(par, copy);\n    lv_mem_assert(new_gauge);\n    if(new_gauge == NULL) return NULL;\n\n    /*Allocate the gauge type specific extended data*/\n    lv_gauge_ext_t * ext = lv_obj_allocate_ext_attr(new_gauge, sizeof(lv_gauge_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    /*Initialize the allocated 'ext' */\n    ext->needle_count = 0;\n    ext->values = NULL;\n    ext->needle_colors = NULL;\n    ext->label_count = LV_GAUGE_DEF_LABEL_COUNT;\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_gauge);\n    if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_gauge);\n\n    /*The signal and design functions are not copied so set them here*/\n    lv_obj_set_signal_func(new_gauge, lv_gauge_signal);\n    lv_obj_set_design_func(new_gauge, lv_gauge_design);\n\n    /*Init the new gauge gauge*/\n    if(copy == NULL) {\n        lv_gauge_set_scale(new_gauge, LV_GAUGE_DEF_ANGLE, LV_GAUGE_DEF_LINE_COUNT, LV_GAUGE_DEF_LABEL_COUNT);\n        lv_gauge_set_needle_count(new_gauge, 1, NULL);\n        lv_gauge_set_critical_value(new_gauge, 80);\n        lv_obj_set_size(new_gauge, 2 * LV_DPI, 2 * LV_DPI);\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_gauge_set_style(new_gauge, th->gauge);\n        } else {\n            lv_gauge_set_style(new_gauge, &lv_style_pretty_color);\n        }\n    }\n    /*Copy an existing gauge*/\n    else {\n        lv_gauge_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        lv_gauge_set_needle_count(new_gauge, copy_ext->needle_count, copy_ext->needle_colors);\n\n        uint8_t i;\n        for(i = 0; i < ext->needle_count; i++) {\n            ext->values[i] = copy_ext->values[i];\n        }\n        ext->label_count = copy_ext->label_count;\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_gauge);\n    }\n\n    LV_LOG_INFO(\"gauge created\");\n\n    return new_gauge;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set the number of needles\n * @param gauge pointer to gauge object\n * @param needle_cnt new count of needles\n * @param colors an array of colors for needles (with 'num' elements)\n */\nvoid lv_gauge_set_needle_count(lv_obj_t * gauge, uint8_t needle_cnt, const lv_color_t * colors)\n{\n    lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);\n\n    if(ext->needle_count != needle_cnt) {\n        if(ext->values != NULL) {\n            lv_mem_free(ext->values);\n            ext->values = NULL;\n        }\n\n        ext->values = lv_mem_realloc(ext->values, needle_cnt * sizeof(int16_t));\n        lv_mem_assert(ext->values);\n        if(ext->values == NULL) return;\n\n        int16_t min = lv_gauge_get_min_value(gauge);\n        uint8_t n;\n        for(n = ext->needle_count; n < needle_cnt; n++) {\n            ext->values[n] = min;\n        }\n\n        ext->needle_count = needle_cnt;\n    }\n\n    ext->needle_colors = colors;\n    lv_obj_invalidate(gauge);\n}\n\n/**\n * Set the value of a needle\n * @param gauge pointer to a gauge\n * @param needle_id the id of the needle\n * @param value the new value\n */\nvoid lv_gauge_set_value(lv_obj_t * gauge, uint8_t needle_id, int16_t value)\n{\n    lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);\n\n    if(needle_id >= ext->needle_count) return;\n    if(ext->values[needle_id] == value) return;\n\n\n    int16_t min = lv_gauge_get_min_value(gauge);\n    int16_t max = lv_gauge_get_max_value(gauge);\n\n    if(value > max) value = max;\n    else if(value < min) value = min;\n\n    ext->values[needle_id] = value;\n\n\n    lv_obj_invalidate(gauge);\n}\n\n\n/**\n * Set the scale settings of a gauge\n * @param gauge pointer to a gauge object\n * @param angle angle of the scale (0..360)\n * @param line_cnt count of scale lines.\n * The get a given \"subdivision\" lines between label, `line_cnt` = (sub_div + 1) * (label_cnt - 1) + 1\n * @param label_cnt count of scale labels.\n */\nvoid lv_gauge_set_scale(lv_obj_t * gauge, uint16_t angle, uint8_t line_cnt, uint8_t label_cnt)\n{\n    /*TODO v6.0: change `line_cnt` to `subdiv_cnt`*/\n\n    lv_lmeter_set_scale(gauge, angle, line_cnt);\n\n    lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);\n    ext->label_count = label_cnt;\n    lv_obj_invalidate(gauge);\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the value of a needle\n * @param gauge pointer to gauge object\n * @param needle the id of the needle\n * @return the value of the needle [min,max]\n */\nint16_t lv_gauge_get_value(const lv_obj_t * gauge,  uint8_t needle)\n{\n    lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);\n    int16_t min = lv_gauge_get_min_value(gauge);\n\n    if(needle >= ext->needle_count) return min;\n\n    return ext->values[needle];\n}\n\n/**\n * Get the count of needles on a gauge\n * @param gauge pointer to gauge\n * @return count of needles\n */\nuint8_t lv_gauge_get_needle_count(const lv_obj_t * gauge)\n{\n    lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);\n    return ext->needle_count;\n}\n\n/**\n * Set the number of labels (and the thicker lines too)\n * @param gauge pointer to a gauge object\n * @return count of labels\n */\nuint8_t lv_gauge_get_label_count(const lv_obj_t * gauge)\n{\n    lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);\n    return ext->label_count;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Handle the drawing related tasks of the gauges\n * @param gauge pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_gauge_design(lv_obj_t * gauge, const lv_area_t * mask, lv_design_mode_t mode)\n{\n\n    /*Return false if the object is not covers the mask_p area*/\n    if(mode == LV_DESIGN_COVER_CHK) {\n        return false;\n    }\n    /*Draw the object*/\n    else if(mode == LV_DESIGN_DRAW_MAIN) {\n\n        /* Store the real pointer because of 'lv_group'\n         * If the object is in focus 'lv_obj_get_style()' will give a pointer to tmp style\n         * and to the real object style. It is important because of style change tricks below*/\n        lv_style_t * style_ori_p = gauge->style_p;\n        lv_style_t * style = lv_obj_get_style(gauge);\n        lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);\n\n        lv_gauge_draw_scale(gauge, mask);\n\n        /*Draw the ancestor line meter with max value to show the rainbow like line colors*/\n        uint16_t line_cnt_tmp = ext->lmeter.line_cnt;\n        ancestor_design(gauge, mask, mode);           /*To draw lines*/\n\n        /*Temporally modify the line meter to draw thicker and longer lines where labels are*/\n        lv_style_t style_tmp;\n        lv_style_copy(&style_tmp, style);\n        ext->lmeter.line_cnt = ext->label_count;                        /*Only to labels*/\n        style_tmp.line.width = style_tmp.line.width * 2;                /*Ticker lines*/\n        style_tmp.body.padding.hor = style_tmp.body.padding.hor * 2;    /*Longer lines*/\n        gauge->style_p = &style_tmp;\n\n        ancestor_design(gauge, mask, mode);           /*To draw lines*/\n\n        ext->lmeter.line_cnt = line_cnt_tmp;          /*Restore the parameters*/\n        gauge->style_p = style_ori_p;                 /*Restore the ORIGINAL style pointer*/\n\n        lv_gauge_draw_needle(gauge, mask);\n\n    }\n    /*Post draw when the children are drawn*/\n    else if(mode == LV_DESIGN_DRAW_POST) {\n        ancestor_design(gauge, mask, mode);\n    }\n\n    return true;\n}\n\n/**\n * Signal function of the gauge\n * @param gauge pointer to a gauge object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_gauge_signal(lv_obj_t * gauge, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(gauge, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);\n    if(sign == LV_SIGNAL_CLEANUP) {\n        lv_mem_free(ext->values);\n        ext->values = NULL;\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_gauge\";\n    }\n\n    return res;\n}\n\n/**\n * Draw the scale on a gauge\n * @param gauge pointer to gauge object\n * @param mask mask of drawing\n */\nstatic void lv_gauge_draw_scale(lv_obj_t * gauge, const lv_area_t * mask)\n{\n    char scale_txt[16];\n\n    lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);\n    lv_style_t * style = lv_obj_get_style(gauge);\n    lv_opa_t opa_scale = lv_obj_get_opa_scale(gauge);\n    lv_coord_t r = lv_obj_get_width(gauge) / 2 - (3 * style->body.padding.hor) - style->body.padding.inner;\n    lv_coord_t x_ofs = lv_obj_get_width(gauge) / 2 + gauge->coords.x1;\n    lv_coord_t y_ofs = lv_obj_get_height(gauge) / 2 + gauge->coords.y1;\n    int16_t scale_angle = lv_lmeter_get_scale_angle(gauge);\n    uint16_t label_num = ext->label_count;\n    int16_t angle_ofs = 90 + (360 - scale_angle) / 2;\n    int16_t min = lv_gauge_get_min_value(gauge);\n    int16_t max = lv_gauge_get_max_value(gauge);\n\n    uint8_t i;\n    for(i = 0; i < label_num; i++) {\n        /*Calculate the position a scale label*/\n        int16_t angle = (i * scale_angle) / (label_num - 1) + angle_ofs;\n\n        lv_coord_t y = (int32_t)((int32_t)lv_trigo_sin(angle) * r) / LV_TRIGO_SIN_MAX;\n        y += y_ofs;\n\n        lv_coord_t x = (int32_t)((int32_t)lv_trigo_sin(angle + 90) * r) / LV_TRIGO_SIN_MAX;\n        x += x_ofs;\n\n        int16_t scale_act = (int32_t)((int32_t)(max - min) * i) / (label_num - 1);\n        scale_act += min;\n        lv_math_num_to_str(scale_act, scale_txt);\n\n        lv_area_t label_cord;\n        lv_point_t label_size;\n        lv_txt_get_size(&label_size, scale_txt, style->text.font,\n                        style->text.letter_space, style->text.line_space, LV_COORD_MAX, LV_TXT_FLAG_NONE);\n\n        /*Draw the label*/\n        label_cord.x1 = x - label_size.x / 2;\n        label_cord.y1 = y - label_size.y / 2;\n        label_cord.x2 = label_cord.x1 + label_size.x;\n        label_cord.y2 = label_cord.y1 + label_size.y;\n\n        lv_draw_label(&label_cord, mask, style, opa_scale, scale_txt, LV_TXT_FLAG_NONE, NULL);\n    }\n}\n/**\n * Draw the needles of a gauge\n * @param gauge pointer to gauge object\n * @param mask mask of drawing\n */\nstatic void lv_gauge_draw_needle(lv_obj_t * gauge, const lv_area_t * mask)\n{\n    lv_style_t style_needle;\n    lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);\n    lv_style_t * style = lv_gauge_get_style(gauge);\n    lv_opa_t opa_scale = lv_obj_get_opa_scale(gauge);\n\n    lv_coord_t r = lv_obj_get_width(gauge) / 2 - style->body.padding.hor;\n    lv_coord_t x_ofs = lv_obj_get_width(gauge) / 2 + gauge->coords.x1;\n    lv_coord_t y_ofs = lv_obj_get_height(gauge) / 2 + gauge->coords.y1;\n    uint16_t angle = lv_lmeter_get_scale_angle(gauge);\n    int16_t angle_ofs = 90 + (360 - angle) / 2;\n    int16_t min = lv_gauge_get_min_value(gauge);\n    int16_t max = lv_gauge_get_max_value(gauge);\n    lv_point_t p_mid;\n    lv_point_t p_end;\n    lv_point_t p_end_low;\n    lv_point_t p_end_high;\n    uint8_t i;\n\n    lv_style_copy(&style_needle, style);\n\n    p_mid.x = x_ofs;\n    p_mid.y = y_ofs;\n    for(i = 0; i < ext->needle_count; i++) {\n        /*Calculate the end point of a needle*/\n        int16_t needle_angle = (ext->values[i] - min) * angle * (1 << LV_GAUGE_INTERPOLATE_SHIFT)  / (max - min); //+ angle_ofs;\n\n\n        int16_t needle_angle_low = (needle_angle >> LV_GAUGE_INTERPOLATE_SHIFT) + angle_ofs;\n        int16_t needle_angle_high = needle_angle_low + 1;\n\n\n        p_end_low.y = (lv_trigo_sin(needle_angle_low) * r) / LV_TRIGO_SIN_MAX + y_ofs;\n        p_end_low.x = (lv_trigo_sin(needle_angle_low + 90) * r) / LV_TRIGO_SIN_MAX + x_ofs;\n\n        p_end_high.y = (lv_trigo_sin(needle_angle_high) * r) / LV_TRIGO_SIN_MAX + y_ofs;\n        p_end_high.x = (lv_trigo_sin(needle_angle_high + 90) * r) / LV_TRIGO_SIN_MAX + x_ofs;\n\n        uint16_t rem = needle_angle & ((1 << LV_GAUGE_INTERPOLATE_SHIFT) - 1);\n        int16_t x_mod = ((LV_MATH_ABS(p_end_high.x  - p_end_low.x)) * rem) >> LV_GAUGE_INTERPOLATE_SHIFT;\n        int16_t y_mod = ((LV_MATH_ABS(p_end_high.y  - p_end_low.y)) * rem) >> LV_GAUGE_INTERPOLATE_SHIFT;\n\n        if(p_end_high.x < p_end_low.x) x_mod = -x_mod;\n        if(p_end_high.y < p_end_low.y) y_mod = -y_mod;\n\n        p_end.x = p_end_low.x + x_mod;\n        p_end.y = p_end_low.y + y_mod;\n\n        /*Draw the needle with the corresponding color*/\n        if(ext->needle_colors == NULL) style_needle.line.color = LV_GAUGE_DEF_NEEDLE_COLOR;\n        else style_needle.line.color = ext->needle_colors[i];\n\n        lv_draw_line(&p_mid, &p_end, mask, &style_needle, opa_scale);\n    }\n\n    /*Draw the needle middle area*/\n    lv_style_t style_neddle_mid;\n    lv_style_copy(&style_neddle_mid, &lv_style_plain);\n    style_neddle_mid.body.main_color = style->body.border.color;\n    style_neddle_mid.body.grad_color = style->body.border.color;\n    style_neddle_mid.body.radius = LV_RADIUS_CIRCLE;\n\n    lv_area_t nm_cord;\n    nm_cord.x1 = x_ofs - style->body.padding.ver;\n    nm_cord.y1 = y_ofs - style->body.padding.ver;\n    nm_cord.x2 = x_ofs + style->body.padding.ver;\n    nm_cord.y2 = y_ofs + style->body.padding.ver;\n\n    lv_draw_rect(&nm_cord, mask, &style_neddle_mid, lv_obj_get_opa_scale(gauge));\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_gauge.h",
    "content": "/**\n * @file lv_gauge.h\n *\n */\n\n#ifndef LV_GAUGE_H\n#define LV_GAUGE_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_GAUGE != 0\n\n/*Testing of dependencies*/\n#if USE_LV_LMETER == 0\n#error \"lv_gauge: lv_lmeter is required. Enable it in lv_conf.h (USE_LV_LMETER  1) \"\n#endif\n\n#include \"../lv_core/lv_obj.h\"\n#include \"lv_lmeter.h\"\n#include \"lv_label.h\"\n#include \"lv_line.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/*Data of gauge*/\ntypedef struct\n{\n    lv_lmeter_ext_t lmeter;     /*Ext. of ancestor*/\n    /*New data for this type */\n    int16_t * values;               /*Array of the set values (for needles) */\n    const lv_color_t * needle_colors;        /*Color of the needles (lv_color_t my_colors[needle_num])*/\n    uint8_t needle_count;             /*Number of needles*/\n    uint8_t label_count;              /*Number of labels on the scale*/\n} lv_gauge_ext_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a gauge objects\n * @param par pointer to an object, it will be the parent of the new gauge\n * @param copy pointer to a gauge object, if not NULL then the new object will be copied from it\n * @return pointer to the created gauge\n */\nlv_obj_t * lv_gauge_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set the number of needles\n * @param gauge pointer to gauge object\n * @param needle_cnt new count of needles\n * @param colors an array of colors for needles (with 'num' elements)\n */\nvoid lv_gauge_set_needle_count(lv_obj_t * gauge, uint8_t needle_cnt, const lv_color_t * colors);\n\n/**\n * Set the value of a needle\n * @param gauge pointer to a gauge\n * @param needle_id the id of the needle\n * @param value the new value\n */\nvoid lv_gauge_set_value(lv_obj_t * gauge, uint8_t needle_id, int16_t value);\n\n/**\n * Set minimum and the maximum values of a gauge\n * @param gauge pointer to he gauge object\n * @param min minimum value\n * @param max maximum value\n */\nstatic inline void lv_gauge_set_range(lv_obj_t *gauge, int16_t min, int16_t max)\n{\n    lv_lmeter_set_range(gauge, min, max);\n}\n\n/**\n * Set a critical value on the scale. After this value 'line.color' scale lines will be drawn\n * @param gauge pointer to a gauge object\n * @param value the critical value\n */\nstatic inline void lv_gauge_set_critical_value(lv_obj_t * gauge, int16_t value)\n{\n    lv_lmeter_set_value(gauge, value);\n}\n\n/**\n * Set the scale settings of a gauge\n * @param gauge pointer to a gauge object\n * @param angle angle of the scale (0..360)\n * @param line_cnt count of scale lines.\n * The get a given \"subdivision\" lines between label, `line_cnt` = (sub_div + 1) * (label_cnt - 1) + 1\n * @param label_cnt count of scale labels.\n */\nvoid lv_gauge_set_scale(lv_obj_t * gauge, uint16_t angle, uint8_t line_cnt, uint8_t label_cnt);\n\n/**\n * Set the styles of a gauge\n * @param gauge pointer to a gauge object\n * @param bg set the style of the gauge\n *  */\nstatic inline void lv_gauge_set_style(lv_obj_t *gauge, lv_style_t *bg)\n{\n    lv_obj_set_style(gauge, bg);\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the value of a needle\n * @param gauge pointer to gauge object\n * @param needle the id of the needle\n * @return the value of the needle [min,max]\n */\nint16_t lv_gauge_get_value(const lv_obj_t * gauge,  uint8_t needle);\n\n/**\n * Get the count of needles on a gauge\n * @param gauge pointer to gauge\n * @return count of needles\n */\nuint8_t lv_gauge_get_needle_count(const lv_obj_t * gauge);\n\n/**\n * Get the minimum value of a gauge\n * @param gauge pointer to a gauge object\n * @return the minimum value of the gauge\n */\nstatic inline int16_t lv_gauge_get_min_value(const lv_obj_t * lmeter)\n{\n    return lv_lmeter_get_min_value(lmeter);\n}\n\n/**\n * Get the maximum value of a gauge\n * @param gauge pointer to a gauge object\n * @return the maximum value of the gauge\n */\nstatic inline int16_t lv_gauge_get_max_value(const lv_obj_t * lmeter)\n{\n    return lv_lmeter_get_max_value(lmeter);\n}\n\n/**\n * Get a critical value on the scale.\n * @param gauge pointer to a gauge object\n * @return the critical value\n */\nstatic inline int16_t lv_gauge_get_critical_value(const lv_obj_t * gauge)\n{\n    return lv_lmeter_get_value(gauge);\n}\n\n/**\n * Set the number of labels (and the thicker lines too)\n * @param gauge pointer to a gauge object\n * @return count of labels\n */\nuint8_t lv_gauge_get_label_count(const lv_obj_t * gauge);\n\n/**\n * Get the scale number of a gauge\n * @param gauge pointer to a gauge object\n * @return number of the scale units\n */\nstatic inline uint8_t lv_gauge_get_line_count(const lv_obj_t * gauge)\n{\n    return lv_lmeter_get_line_count(gauge);\n}\n\n/**\n * Get the scale angle of a gauge\n * @param gauge pointer to a gauge object\n * @return angle of the scale\n */\nstatic inline uint16_t lv_gauge_get_scale_angle(const lv_obj_t * gauge)\n{\n    return lv_lmeter_get_scale_angle(gauge);\n}\n\n/**\n * Get the style of a gauge\n * @param gauge pointer to a gauge object\n * @return pointer to the gauge's style\n */\nstatic inline lv_style_t * lv_gauge_get_style(const lv_obj_t *gauge)\n{\n    return lv_obj_get_style(gauge);\n}\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_GAUGE*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_GAUGE_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_img.c",
    "content": "/**\n * @file lv_img.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_img.h\"\n#if USE_LV_IMG != 0\n\n/*Testing of dependencies*/\n#if USE_LV_LABEL == 0\n#error \"lv_img: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL  1) \"\n#endif\n\n#include \"../lv_core/lv_lang.h\"\n#include \"../lv_themes/lv_theme.h\"\n#include \"../lv_misc/lv_fs.h\"\n#include \"../lv_misc/lv_ufs.h\"\n#include \"../lv_misc/lv_txt.h\"\n#include \"../lv_misc/lv_log.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool lv_img_design(lv_obj_t * img, const lv_area_t * mask, lv_design_mode_t mode);\nstatic lv_res_t lv_img_signal(lv_obj_t * img, lv_signal_t sign, void * param);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create an image objects\n * @param par pointer to an object, it will be the parent of the new button\n * @param copy pointer to a image object, if not NULL then the new object will be copied from it\n * @return pointer to the created image\n */\nlv_obj_t * lv_img_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"image create started\");\n\n    lv_obj_t * new_img = NULL;\n\n    /*Create a basic object*/\n    new_img = lv_obj_create(par, copy);\n    lv_mem_assert(new_img);\n    if(new_img == NULL) return NULL;\n\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_img);\n\n    /*Extend the basic object to image object*/\n    lv_img_ext_t * ext = lv_obj_allocate_ext_attr(new_img, sizeof(lv_img_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    ext->src = NULL;\n    ext->src_type = LV_IMG_SRC_UNKNOWN;\n    ext->cf = LV_IMG_CF_UNKOWN;\n    ext->w = lv_obj_get_width(new_img);\n    ext->h = lv_obj_get_height(new_img);\n    ext->auto_size = 1;\n#if USE_LV_MULTI_LANG\n    ext->lang_txt_id = LV_LANG_TXT_ID_NONE;\n#endif\n\n    /*Init the new object*/\n    lv_obj_set_signal_func(new_img, lv_img_signal);\n    lv_obj_set_design_func(new_img, lv_img_design);\n\n    if(copy == NULL) {\n        lv_obj_set_click(new_img, false);\n        /* Enable auto size for non screens\n         * because image screens are wallpapers\n         * and must be screen sized*/\n        if(par != NULL) {\n            ext->auto_size = 1;\n            lv_obj_set_style(new_img, NULL);                        /*Inherit the style  by default*/\n        } else {\n            ext->auto_size = 0;\n            lv_obj_set_style(new_img, &lv_style_plain);            /*Set a style for screens*/\n        }\n    } else {\n        lv_img_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        ext->auto_size = copy_ext->auto_size;\n        lv_img_set_src(new_img, copy_ext->src);\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_img);\n    }\n\n\n    LV_LOG_INFO(\"image created\");\n\n    return new_img;\n}\n\n\n/*=====================\n * Setter functions\n *====================*/\n\n\n/**\n * Set the pixel map to display by the image\n * @param img pointer to an image object\n * @param data the image data\n */\nvoid lv_img_set_src(lv_obj_t * img, const void * src_img)\n{\n    lv_img_src_t src_type = lv_img_src_get_type(src_img);\n    lv_img_ext_t * ext = lv_obj_get_ext_attr(img);\n\n#if LV_LOG_LEVEL >= LV_LOG_LEVEL_INFO\n    switch(src_type) {\n        case LV_IMG_SRC_FILE:\n            LV_LOG_TRACE(\"lv_img_set_src: `LV_IMG_SRC_FILE` type found\");\n            break;\n        case LV_IMG_SRC_VARIABLE:\n            LV_LOG_TRACE(\"lv_img_set_src: `LV_IMG_SRC_VARIABLE` type found\");\n            break;\n        case LV_IMG_SRC_SYMBOL:\n            LV_LOG_TRACE(\"lv_img_set_src: `LV_IMG_SRC_SYMBOL` type found\");\n            break;\n        default:\n            LV_LOG_WARN(\"lv_img_set_src: unknown type\");\n    }\n#endif\n\n    /*If the new source type is unknown free the memories of the old source*/\n    if(src_type == LV_IMG_SRC_UNKNOWN) {\n        LV_LOG_WARN(\"lv_img_set_src: unknown image type\");\n        if(ext->src_type == LV_IMG_SRC_SYMBOL || ext->src_type == LV_IMG_SRC_FILE) {\n            lv_mem_free(ext->src);\n        }\n        ext->src = NULL;\n        ext->src_type = LV_IMG_SRC_UNKNOWN;\n        return;\n    }\n\n    lv_img_header_t header;\n    lv_img_dsc_get_info(src_img, &header);\n\n\n\n    /*Save the source*/\n    if(src_type == LV_IMG_SRC_VARIABLE) {\n        LV_LOG_INFO(\"lv_img_set_src:  `LV_IMG_SRC_VARIABLE` type found\");\n\n        /*If memory was allocated because of the previous `src_type` then free it*/\n        if(ext->src_type == LV_IMG_SRC_FILE || ext->src_type == LV_IMG_SRC_SYMBOL) {\n            lv_mem_free(ext->src);\n        }\n        ext->src = src_img;\n    } else if(src_type == LV_IMG_SRC_FILE || src_type == LV_IMG_SRC_SYMBOL) {\n        /* If the new and the old src are the same then it was only a refresh.*/\n        if(ext->src != src_img) {\n        \t/*If memory was allocated because of the previous `src_type` then free it*/\n            if(ext->src_type == LV_IMG_SRC_FILE || ext->src_type == LV_IMG_SRC_SYMBOL) {\n                lv_mem_free(ext->src);\n            }\n        \tchar * new_str = lv_mem_alloc(strlen(src_img) + 1);\n            lv_mem_assert(new_str);\n            if(new_str == NULL) return;\n            strcpy(new_str, src_img);\n            ext->src = new_str;\n        }\n    }\n\n    if(src_type == LV_IMG_SRC_SYMBOL) {\n        /*`lv_img_dsc_get_info` couldn't set the with and height of a font so set it here*/\n        lv_style_t * style = lv_img_get_style(img);\n        lv_point_t size;\n        lv_txt_get_size(&size, src_img, style->text.font, style->text.letter_space, style->text.line_space, LV_COORD_MAX, LV_TXT_FLAG_NONE);\n        header.w = size.x;\n        header.h = size.y;\n    }\n\n    ext->src_type = src_type;\n    ext->w = header.w;\n    ext->h = header.h;\n    ext->cf = header.cf;\n\n    if(lv_img_get_auto_size(img) != false) {\n        lv_obj_set_size(img, ext->w, ext->h);\n    }\n\n    lv_obj_invalidate(img);\n}\n\n#if USE_LV_MULTI_LANG\n/**\n * Set an ID which means a the same source but in different languages\n * @param img pointer to an image object\n * @param src_id ID of the source\n */\nvoid lv_img_set_src_id(lv_obj_t * img, uint32_t src_id)\n{\n    lv_img_ext_t * ext = lv_obj_get_ext_attr(img);\n    ext->lang_txt_id = src_id;\n\n    /*Apply the new language*/\n    img->signal_func(img, LV_SIGNAL_LANG_CHG, NULL);\n}\n#endif\n\n/**\n * Enable the auto size feature.\n * If enabled the object size will be same as the picture size.\n * @param img pointer to an image\n * @param en true: auto size enable, false: auto size disable\n */\nvoid lv_img_set_auto_size(lv_obj_t * img, bool en)\n{\n    lv_img_ext_t * ext = lv_obj_get_ext_attr(img);\n\n    ext->auto_size = (en == false ? 0 : 1);\n}\n\n\n/*=====================\n * Getter functions\n *====================*/\n\n\n/**\n * Get the source of the image\n * @param img pointer to an image object\n * @return the image source (symbol, file name or C array)\n */\nconst void * lv_img_get_src(lv_obj_t * img)\n{\n    lv_img_ext_t * ext = lv_obj_get_ext_attr(img);\n\n    return ext->src;\n}\n\n/**\n * Get the name of the file set for an image\n * @param img pointer to an image\n * @return file name\n */\nconst char * lv_img_get_file_name(const lv_obj_t * img)\n{\n    lv_img_ext_t * ext = lv_obj_get_ext_attr(img);\n\n    if(ext->src_type == LV_IMG_SRC_FILE) return ext->src;\n    else return \"\";\n}\n\n#if USE_LV_MULTI_LANG\n/**\n * Get the source ID of the image. (Used by the multi-language feature)\n * @param img pointer to an image\n * @return ID of the source\n */\nuint16_t lv_img_get_src_id(lv_obj_t * img)\n{\n    lv_img_ext_t * ext = lv_obj_get_ext_attr(img);\n    return ext->lang_txt_id;\n}\n#endif\n\n/**\n * Get the auto size enable attribute\n * @param img pointer to an image\n * @return true: auto size is enabled, false: auto size is disabled\n */\nbool lv_img_get_auto_size(const lv_obj_t * img)\n{\n    lv_img_ext_t * ext = lv_obj_get_ext_attr(img);\n\n    return ext->auto_size == 0 ? false : true;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Handle the drawing related tasks of the images\n * @param img pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_img_design(lv_obj_t * img, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    lv_style_t * style = lv_obj_get_style(img);\n    lv_img_ext_t * ext = lv_obj_get_ext_attr(img);\n\n    if(mode == LV_DESIGN_COVER_CHK) {\n        bool cover = false;\n        if(ext->src_type == LV_IMG_SRC_UNKNOWN || ext->src_type == LV_IMG_SRC_SYMBOL) return false;\n\n        if(ext->cf == LV_IMG_CF_TRUE_COLOR || ext->cf == LV_IMG_CF_RAW) cover = lv_area_is_in(mask, &img->coords);\n\n        return cover;\n    } else if(mode == LV_DESIGN_DRAW_MAIN) {\n        if(ext->h == 0 || ext->w == 0) return true;\n        lv_area_t coords;\n        lv_opa_t opa_scale = lv_obj_get_opa_scale(img);\n\n        lv_obj_get_coords(img, &coords);\n\n        if(ext->src_type == LV_IMG_SRC_FILE || ext->src_type == LV_IMG_SRC_VARIABLE) {\n            LV_LOG_TRACE(\"lv_img_design: start to draw image\");\n            lv_area_t cords_tmp;\n            cords_tmp.y1 = coords.y1;\n            cords_tmp.y2 = coords.y1 + ext->h - 1;\n\n            for(; cords_tmp.y1 < coords.y2; cords_tmp.y1 += ext->h, cords_tmp.y2 += ext->h) {\n                cords_tmp.x1 = coords.x1;\n                cords_tmp.x2 = coords.x1 + ext->w - 1;\n                for(; cords_tmp.x1 < coords.x2; cords_tmp.x1 += ext->w, cords_tmp.x2 += ext->w) {\n                    lv_draw_img(&cords_tmp, mask, ext->src, style, opa_scale);\n                }\n            }\n        } else if(ext->src_type == LV_IMG_SRC_SYMBOL) {\n            LV_LOG_TRACE(\"lv_img_design: start to draw symbol\");\n            lv_style_t style_mod;\n            lv_style_copy(&style_mod, style);\n            style_mod.text.color = style->image.color;\n            lv_draw_label(&coords, mask, &style_mod, opa_scale, ext->src, LV_TXT_FLAG_NONE, NULL);\n        } else {\n            /*Trigger the error handler of image drawer*/\n            LV_LOG_WARN(\"lv_img_design: image source type is unknown\");\n            lv_draw_img(&img->coords, mask, NULL, style, opa_scale);\n        }\n    }\n\n    return true;\n}\n\n\n/**\n * Signal function of the image\n * @param img pointer to an image object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_img_signal(lv_obj_t * img, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(img, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    lv_img_ext_t * ext = lv_obj_get_ext_attr(img);\n    if(sign == LV_SIGNAL_CLEANUP) {\n        if(ext->src_type == LV_IMG_SRC_FILE || ext->src_type == LV_IMG_SRC_SYMBOL) {\n            lv_mem_free(ext->src);\n            ext->src = NULL;\n            ext->src_type = LV_IMG_SRC_UNKNOWN;\n        }\n    } else if(sign == LV_SIGNAL_STYLE_CHG) {\n        /*Refresh the file name to refresh the symbol text size*/\n        if(ext->src_type == LV_IMG_SRC_SYMBOL) {\n            lv_img_set_src(img, ext->src);\n\n        }\n    } else if(sign == LV_SIGNAL_LANG_CHG) {\n#if USE_LV_MULTI_LANG\n        if(ext->lang_txt_id != LV_LANG_TXT_ID_NONE) {\n            const char * lang_src = lv_lang_get_text(ext->lang_txt_id);\n            if(lang_src) {\n                lv_img_set_src(img, lang_src);\n            } else {\n                LV_LOG_WARN(\"lv_lang_get_text return NULL for an image's source\");\n            }\n        }\n#endif\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_img\";\n    }\n\n    return res;\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_img.h",
    "content": "/**\n * @file lv_img.h\n *\n */\n\n#ifndef LV_IMG_H\n#define LV_IMG_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_IMG != 0\n\n#include \"../lv_core/lv_obj.h\"\n#include \"../lv_misc/lv_fs.h\"\n#include \"../lv_misc/lv_symbol_def.h\"\n#include \"lv_label.h\"\n#include \"../lv_draw/lv_draw.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n/*Data of image*/\ntypedef struct\n{\n    /*No inherited ext. because inherited from the base object*/ /*Ext. of ancestor*/\n    /*New data for this type */\n    const void * src;             /*Image source: Pointer to an array or a file or a symbol*/\n\n    lv_coord_t w;               /*Width of the image (Handled by the library)*/\n    lv_coord_t h;               /*Height of the image (Handled by the library)*/\n#if USE_LV_MULTI_LANG\n    uint16_t lang_txt_id;       /*The ID of the image to display. */\n#endif\n    uint8_t src_type  :2;       /*See: lv_img_src_t*/\n    uint8_t auto_size :1;       /*1: automatically set the object size to the image size*/\n    uint8_t cf :5;              /*Color format from `lv_img_color_format_t`*/\n} lv_img_ext_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create an image objects\n * @param par pointer to an object, it will be the parent of the new button\n * @param copy pointer to a image object, if not NULL then the new object will be copied from it\n * @return pointer to the created image\n */\nlv_obj_t * lv_img_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set the pixel map to display by the image\n * @param img pointer to an image object\n * @param data the image data\n */\nvoid lv_img_set_src(lv_obj_t * img, const void * src_img);\n\n#if USE_LV_MULTI_LANG\n/**\n * Set an ID which means a the same source but on different languages\n * @param img pointer to an image object\n * @param src_id ID of the source\n */\nvoid lv_img_set_src_id(lv_obj_t * img, uint32_t txt_id);\n#endif\n\n/**\n * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0.\n * Use 'lv_img_set_src()' instead.\n * @param img -\n * @param fn -\n */\nstatic inline void lv_img_set_file(lv_obj_t * img, const char * fn)\n{\n    (void) img;\n    (void) fn;\n}\n\n/**\n * Enable the auto size feature.\n * If enabled the object size will be same as the picture size.\n * @param img pointer to an image\n * @param en true: auto size enable, false: auto size disable\n */\nvoid lv_img_set_auto_size(lv_obj_t * img, bool autosize_en);\n\n/**\n * Set the style of an image\n * @param img pointer to an image object\n * @param style pointer to a style\n */\nstatic inline void lv_img_set_style(lv_obj_t *img, lv_style_t *style)\n{\n    lv_obj_set_style(img, style);\n}\n\n/**\n * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0\n * @param img -\n * @param upscale -\n */\nstatic inline void lv_img_set_upscale(lv_obj_t * img, bool upcale)\n{\n    (void) img;\n    (void) upcale;\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the source of the image\n * @param img pointer to an image object\n * @return the image source (symbol, file name or C array)\n */\nconst void * lv_img_get_src(lv_obj_t * img);\n\n/**\n * Get the name of the file set for an image\n * @param img pointer to an image\n * @return file name\n */\nconst char * lv_img_get_file_name(const lv_obj_t * img);\n\n#if USE_LV_MULTI_LANG\n/**\n * Get the source ID of the image. (Used by the multi-language feature)\n * @param img pointer to an image\n * @return ID of the source\n */\nuint16_t lv_img_get_src_id(lv_obj_t * img);\n#endif\n\n/**\n * Get the auto size enable attribute\n * @param img pointer to an image\n * @return true: auto size is enabled, false: auto size is disabled\n */\nbool lv_img_get_auto_size(const lv_obj_t * img);\n\n/**\n * Get the style of an image object\n * @param img pointer to an image object\n * @return pointer to the image's style\n */\nstatic inline lv_style_t* lv_img_get_style(const lv_obj_t *img)\n{\n    return lv_obj_get_style(img);\n}\n\n/**\n * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0\n * @param img -\n * @return false\n */\nstatic inline bool lv_img_get_upscale(const lv_obj_t * img)\n{\n    (void)img;\n    return false;\n}\n\n/**********************\n *      MACROS\n **********************/\n\n/*Use this macro to declare an image in a c file*/\n#define LV_IMG_DECLARE(var_name) extern const lv_img_dsc_t var_name;\n\n#endif  /*USE_LV_IMG*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_IMG_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_imgbtn.c",
    "content": "/**\n * @file lv_imgbtn.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_imgbtn.h\"\n#if USE_LV_IMGBTN != 0\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool lv_imgbtn_design(lv_obj_t * imgbtn, const lv_area_t * mask, lv_design_mode_t mode);\nstatic lv_res_t lv_imgbtn_signal(lv_obj_t * imgbtn, lv_signal_t sign, void * param);\nstatic void refr_img(lv_obj_t * imgbtn);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\nstatic lv_design_func_t ancestor_design;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a image button object\n * @param par pointer to an object, it will be the parent of the new image button\n * @param copy pointer to a image button object, if not NULL then the new object will be copied from it\n * @return pointer to the created image button\n */\nlv_obj_t * lv_imgbtn_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"image button create started\");\n\n    /*Create the ancestor of image button*/\n    lv_obj_t * new_imgbtn = lv_btn_create(par, copy);\n    lv_mem_assert(new_imgbtn);\n    if(new_imgbtn == NULL) return NULL;\n\n    /*Allocate the image button type specific extended data*/\n    lv_imgbtn_ext_t * ext = lv_obj_allocate_ext_attr(new_imgbtn, sizeof(lv_imgbtn_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_imgbtn);\n    if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_imgbtn);\n\n    /*Initialize the allocated 'ext' */\n#if LV_IMGBTN_TILED == 0\n    memset(ext->img_src, 0, sizeof(ext->img_src));\n#else\n    memset(ext->img_src_left, 0, sizeof(ext->img_src_left));\n    memset(ext->img_src_mid, 0, sizeof(ext->img_src_mid));\n    memset(ext->img_src_right, 0, sizeof(ext->img_src_right));\n#endif\n\n    ext->act_cf = LV_IMG_CF_UNKOWN;\n\n    /*The signal and design functions are not copied so set them here*/\n    lv_obj_set_signal_func(new_imgbtn, lv_imgbtn_signal);\n    lv_obj_set_design_func(new_imgbtn, lv_imgbtn_design);\n\n    /*Init the new image button image button*/\n    if(copy == NULL) {\n\n    }\n    /*Copy an existing image button*/\n    else {\n        lv_imgbtn_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n#if LV_IMGBTN_TILED == 0\n        memcpy(ext->img_src, copy_ext->img_src, sizeof(ext->img_src));\n#else\n        memcpy(ext->img_src_left, copy_ext->img_src_left, sizeof(ext->img_src_left));\n        memcpy(ext->img_src_mid, copy_ext->img_src_mid, sizeof(ext->img_src_mid));\n        memcpy(ext->img_src_right, copy_ext->img_src_right, sizeof(ext->img_src_right));\n#endif\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_imgbtn);\n    }\n\n    LV_LOG_INFO(\"image button created\");\n\n    return new_imgbtn;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n#if LV_IMGBTN_TILED == 0\n/**\n * Set images for a state of the image button\n * @param imgbtn pointer to an image button object\n * @param state for which state set the new image (from `lv_btn_state_t`) `\n * @param src pointer to an image source (a C array or path to a file)\n */\nvoid lv_imgbtn_set_src(lv_obj_t * imgbtn, lv_btn_state_t state, const void * src)\n{\n    lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn);\n\n    ext->img_src[state] = src;\n\n    refr_img(imgbtn);\n}\n\n#else\n/**\n * Set images for a state of the image button\n * @param imgbtn pointer to an image button object\n * @param state for which state set the new image (from `lv_btn_state_t`) `\n * @param src_left pointer to an image source for the left side of the button (a C array or path to a file)\n * @param src_mid pointer to an image source for the middle of the button (ideally 1px wide) (a C array or path to a file)\n * @param src_right pointer to an image source for the right side of the button (a C array or path to a file)\n */\nvoid lv_imgbtn_set_src(lv_obj_t * imgbtn, lv_btn_state_t state, const void * src_left, const void * src_mid, const void * src_right)\n{\n    lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn);\n\n    ext->img_src_left[state] = src_left;\n    ext->img_src_mid[state] = src_mid;\n    ext->img_src_right[state] = src_right;\n\n    refr_img(imgbtn);\n}\n\n#endif\n\n/**\n * Set a style of a image button.\n * @param imgbtn pointer to image button object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_imgbtn_set_style(lv_obj_t * imgbtn, lv_imgbtn_style_t type, lv_style_t * style)\n{\n    lv_btn_set_style(imgbtn, type, style);\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n#if LV_IMGBTN_TILED == 0\n/**\n * Get the images in a  given state\n * @param imgbtn pointer to an image button object\n * @param state the state where to get the image (from `lv_btn_state_t`) `\n * @return pointer to an image source (a C array or path to a file)\n */\nconst void * lv_imgbtn_get_src(lv_obj_t * imgbtn, lv_btn_state_t state)\n{\n    lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn);\n\n    return ext->img_src[state];\n}\n#else\n\n/**\n * Get the left image in a given state\n * @param imgbtn pointer to an image button object\n * @param state the state where to get the image (from `lv_btn_state_t`) `\n * @return pointer to the left image source (a C array or path to a file)\n */\nconst void * lv_imgbtn_get_src_left(lv_obj_t * imgbtn, lv_btn_state_t state)\n{\n    lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn);\n\n    return ext->img_src_left[state];\n}\n\n/**\n * Get the middle image in a given state\n * @param imgbtn pointer to an image button object\n * @param state the state where to get the image (from `lv_btn_state_t`) `\n * @return pointer to the middle image source (a C array or path to a file)\n */\nconst void * lv_imgbtn_get_src_middle(lv_obj_t * imgbtn, lv_btn_state_t state)\n{\n    lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn);\n\n    return ext->img_src_mid[state];\n}\n\n/**\n * Get the right image in a given state\n * @param imgbtn pointer to an image button object\n * @param state the state where to get the image (from `lv_btn_state_t`) `\n * @return pointer to the left image source (a C array or path to a file)\n */\nconst void * lv_imgbtn_get_src_right(lv_obj_t * imgbtn, lv_btn_state_t state)\n{\n    lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn);\n\n    return ext->img_src_right[state];\n}\n\n#endif\n\n/**\n * Get style of a image button.\n * @param imgbtn pointer to image button object\n * @param type which style should be get\n * @return style pointer to the style\n */\nlv_style_t * lv_imgbtn_get_style(const lv_obj_t * imgbtn, lv_imgbtn_style_t type)\n{\n    return lv_btn_get_style(imgbtn, type);\n}\n\n/*=====================\n * Other functions\n *====================*/\n\n/*\n * New object specific \"other\" functions come here\n */\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Handle the drawing related tasks of the image buttons\n * @param imgbtn pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_imgbtn_design(lv_obj_t * imgbtn, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    /*Return false if the object is not covers the mask_p area*/\n    if(mode == LV_DESIGN_COVER_CHK) {\n        lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn);\n        bool cover = false;\n        if(ext->act_cf == LV_IMG_CF_TRUE_COLOR || ext->act_cf == LV_IMG_CF_RAW) {\n            cover = lv_area_is_in(mask, &imgbtn->coords);\n        }\n\n        return cover;\n    }\n    /*Draw the object*/\n    else if(mode == LV_DESIGN_DRAW_MAIN) {\n        /*Just draw an image*/\n        lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn);\n        lv_btn_state_t state = lv_imgbtn_get_state(imgbtn);\n        lv_style_t * style = lv_imgbtn_get_style(imgbtn, state);\n        lv_opa_t opa_scale = lv_obj_get_opa_scale(imgbtn);\n\n#if LV_IMGBTN_TILED == 0\n        const void * src = ext->img_src[state];\n        lv_draw_img(&imgbtn->coords, mask, src, style, opa_scale);\n#else\n        const void * src;\n        lv_img_header_t header;\n        lv_area_t coords;\n        lv_coord_t left_w = 0;\n        lv_coord_t right_w = 0;\n\n        src = ext->img_src_left[state];\n        if(src) {\n            lv_img_dsc_get_info(src, &header);\n            left_w = header.w;\n            coords.x1 = imgbtn->coords.x1;\n            coords.y1 = imgbtn->coords.y1;\n            coords.x2 = coords.x1 + header.w - 1;\n            coords.y2 = coords.y1 + header.h - 1;\n            lv_draw_img(&coords, mask, src, style, opa_scale);\n        }\n\n        src = ext->img_src_right[state];\n        if(src) {\n            lv_img_dsc_get_info(src, &header);\n            right_w = header.w;\n            coords.x1 = imgbtn->coords.x2 - header.w + 1;\n            coords.y1 = imgbtn->coords.y1;\n            coords.x2 = imgbtn->coords.x2;\n            coords.y2 = imgbtn->coords.y1 + header.h - 1;\n            lv_draw_img(&coords, mask, src, style, opa_scale);\n        }\n\n        src = ext->img_src_mid[state];\n        if(src) {\n            lv_coord_t obj_w = lv_obj_get_width(imgbtn);\n            lv_coord_t i;\n            lv_img_dsc_get_info(src, &header);\n\n            coords.x1 = imgbtn->coords.x1 + left_w ;\n            coords.y1 = imgbtn->coords.y1;\n            coords.x2 = coords.x1 + header.w - 1;\n            coords.y2 = imgbtn->coords.y1 + header.h - 1;\n\n            for(i = 0; i < obj_w - right_w - left_w; i += header.w) {\n                lv_draw_img(&coords, mask, src, style, opa_scale);\n                coords.x1 = coords.x2 + 1;\n                coords.x2 += header.w;\n            }\n        }\n\n\n#endif\n\n    }\n    /*Post draw when the children are drawn*/\n    else if(mode == LV_DESIGN_DRAW_POST) {\n\n    }\n\n    return true;\n}\n\n/**\n * Signal function of the image button\n * @param imgbtn pointer to a image button object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_imgbtn_signal(lv_obj_t * imgbtn, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(imgbtn, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    if(sign == LV_SIGNAL_STYLE_CHG) {\n        /* If the style changed then the button was clicked, released etc. so probably the state was changed as well\n         * Set the new image for the new state.*/\n        refr_img(imgbtn);\n    } else if(sign == LV_SIGNAL_CLEANUP) {\n        /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_imgbtn\";\n    }\n\n    return res;\n}\n\n\nstatic void refr_img(lv_obj_t * imgbtn)\n{\n    lv_imgbtn_ext_t * ext = lv_obj_get_ext_attr(imgbtn);\n    lv_btn_state_t state = lv_imgbtn_get_state(imgbtn);\n    lv_img_header_t header;\n\n#if LV_IMGBTN_TILED == 0\n    const void * src = ext->img_src[state];\n#else\n    const void * src = ext->img_src_mid[state];\n#endif\n\n    lv_res_t info_res;\n    info_res = lv_img_dsc_get_info(src, &header);\n    if(info_res == LV_RES_OK) {\n        ext->act_cf = header.cf;\n#if LV_IMGBTN_TILED == 0\n        lv_obj_set_size(imgbtn, header.w, header.h);\n#else\n        lv_obj_set_height(imgbtn, header.h);\n#endif\n    } else {\n        ext->act_cf = LV_IMG_CF_UNKOWN;\n    }\n\n    lv_obj_invalidate(imgbtn);\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_imgbtn.h",
    "content": "/**\n * @file lv_imgbtn.h\n *\n */\n\n#ifndef LV_IMGBTN_H\n#define LV_IMGBTN_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_IMGBTN != 0\n\n/*Testing of dependencies*/\n#if USE_LV_BTN == 0\n#error \"lv_imgbtn: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN  1) \"\n#endif\n\n#include \"../lv_core/lv_obj.h\"\n#include \"lv_btn.h\"\n#include \"../lv_draw/lv_draw_img.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n/*Data of image button*/\ntypedef struct {\n    lv_btn_ext_t btn; /*Ext. of ancestor*/\n    /*New data for this type */\n    int idx;\n#if LV_IMGBTN_TILED == 0\n    const void * img_src[LV_BTN_STATE_NUM];       /*Store images to each state*/\n#else\n    const void * img_src_left[LV_BTN_STATE_NUM];       /*Store left side images to each state*/\n    const void * img_src_mid[LV_BTN_STATE_NUM];        /*Store center images to each state*/\n    const void * img_src_right[LV_BTN_STATE_NUM];      /*Store right side images to each state*/\n#endif\n    lv_img_cf_t act_cf;           /*Color format of the currently active image*/\n} lv_imgbtn_ext_t;\n\n\n/*Styles*/\nenum {\n    LV_IMGBTN_STYLE_REL,\n    LV_IMGBTN_STYLE_PR,\n    LV_IMGBTN_STYLE_TGL_REL,\n    LV_IMGBTN_STYLE_TGL_PR,\n    LV_IMGBTN_STYLE_INA,\n};\ntypedef uint8_t lv_imgbtn_style_t;\n\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a image button objects\n * @param par pointer to an object, it will be the parent of the new image button\n * @param copy pointer to a image button object, if not NULL then the new object will be copied from it\n * @return pointer to the created image button\n */\nlv_obj_t * lv_imgbtn_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n\n/*=====================\n * Setter functions\n *====================*/\n\n#if LV_IMGBTN_TILED == 0\n/**\n * Set images for a state of the image button\n * @param imgbtn pointer to an image button object\n * @param state for which state set the new image (from `lv_btn_state_t`) `\n * @param src pointer to an image source (a C array or path to a file)\n */\nvoid lv_imgbtn_set_src(lv_obj_t * imgbtn, lv_btn_state_t state, const void * src);\n#else\n/**\n * Set images for a state of the image button\n * @param imgbtn pointer to an image button object\n * @param state for which state set the new image (from `lv_btn_state_t`) `\n * @param src_left pointer to an image source for the left side of the button (a C array or path to a file)\n * @param src_mid pointer to an image source for the middle of the button (ideally 1px wide) (a C array or path to a file)\n * @param src_right pointer to an image source for the right side of the button (a C array or path to a file)\n */\nvoid lv_imgbtn_set_src(lv_obj_t * imgbtn, lv_btn_state_t state, const void * src_left, const void * src_mid, const void * src_right);\n\n#endif\n\n/**\n * Enable the toggled states. On release the button will change from/to toggled state.\n * @param imgbtn pointer to an image button object\n * @param tgl true: enable toggled states, false: disable\n */\nstatic inline void lv_imgbtn_set_toggle(lv_obj_t * imgbtn, bool tgl)\n{\n    lv_btn_set_toggle(imgbtn, tgl);\n}\n\n/**\n * Set the state of the image button\n * @param imgbtn pointer to an image button object\n * @param state the new state of the button (from lv_btn_state_t enum)\n */\nstatic inline void lv_imgbtn_set_state(lv_obj_t * imgbtn, lv_btn_state_t state)\n{\n    lv_btn_set_state(imgbtn, state);\n}\n\n/**\n * Toggle the state of the image button (ON->OFF, OFF->ON)\n * @param imgbtn pointer to a image button object\n */\nstatic inline void lv_imgbtn_toggle(lv_obj_t * imgbtn)\n{\n    lv_btn_toggle(imgbtn);\n}\n\n/**\n * Set a function to call when a button event happens\n * @param imgbtn pointer to an image button object\n * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat)\n */\nstatic inline void lv_imgbtn_set_action(lv_obj_t * imgbtn, lv_btn_action_t type, lv_action_t action)\n{\n    lv_btn_set_action(imgbtn, type, action);\n}\n\n/**\n * Set a style of a image button.\n * @param imgbtn pointer to image button object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_imgbtn_set_style(lv_obj_t * imgbtn, lv_imgbtn_style_t type, lv_style_t *style);\n\n/*=====================\n * Getter functions\n *====================*/\n\n\n#if LV_IMGBTN_TILED == 0\n/**\n * Get the images in a  given state\n * @param imgbtn pointer to an image button object\n * @param state the state where to get the image (from `lv_btn_state_t`) `\n * @return pointer to an image source (a C array or path to a file)\n */\nconst void * lv_imgbtn_get_src(lv_obj_t * imgbtn, lv_btn_state_t state);\n\n#else\n\n/**\n * Get the left image in a given state\n * @param imgbtn pointer to an image button object\n * @param state the state where to get the image (from `lv_btn_state_t`) `\n * @return pointer to the left image source (a C array or path to a file)\n */\nconst void * lv_imgbtn_get_src_left(lv_obj_t * imgbtn, lv_btn_state_t state);\n\n/**\n * Get the middle image in a given state\n * @param imgbtn pointer to an image button object\n * @param state the state where to get the image (from `lv_btn_state_t`) `\n * @return pointer to the middle image source (a C array or path to a file)\n */\nconst void * lv_imgbtn_get_src_middle(lv_obj_t * imgbtn, lv_btn_state_t state);\n\n/**\n * Get the right image in a given state\n * @param imgbtn pointer to an image button object\n * @param state the state where to get the image (from `lv_btn_state_t`) `\n * @return pointer to the left image source (a C array or path to a file)\n */\nconst void * lv_imgbtn_get_src_right(lv_obj_t * imgbtn, lv_btn_state_t state);\n\n#endif\n/**\n * Get the current state of the image button\n * @param imgbtn pointer to a image button object\n * @return the state of the button (from lv_btn_state_t enum)\n */\nstatic inline lv_btn_state_t lv_imgbtn_get_state(const lv_obj_t * imgbtn)\n{\n    return lv_btn_get_state(imgbtn);\n}\n\n/**\n * Get the toggle enable attribute of the image button\n * @param imgbtn pointer to a image button object\n * @return ture: toggle enabled, false: disabled\n */\nstatic inline bool lv_imgbtn_get_toggle(const lv_obj_t * imgbtn)\n{\n    return lv_btn_get_toggle(imgbtn);\n}\n\n/**\n * Get the release action of a image button\n * @param imgbtn pointer to a image button object\n * @return pointer to the release action function\n */\nstatic inline lv_action_t lv_imgbtn_get_action(const lv_obj_t * imgbtn, lv_btn_action_t type)\n{\n    return lv_btn_get_action(imgbtn, type);\n}\n\n/**\n * Get style of a image button.\n * @param imgbtn pointer to image button object\n * @param type which style should be get\n * @return style pointer to the style\n */\nlv_style_t * lv_imgbtn_get_style(const lv_obj_t * imgbtn, lv_imgbtn_style_t type);\n\n/*=====================\n * Other functions\n *====================*/\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_IMGBTN*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_IMGBTN_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_kb.c",
    "content": "/*\n * Copyright (c) 2019-2020 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * @file lv_kb.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_kb.h\"\n#if USE_LV_KB != 0\n\n#include \"lv_ta.h\"\n#include \"../lv_themes/lv_theme.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic lv_res_t lv_kb_signal(lv_obj_t * kb, lv_signal_t sign, void * param);\nstatic lv_res_t lv_kb_def_action(lv_obj_t * kb, const char * txt);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\n\nstatic const char * kb_map_lc[] = {\n    \"\\2051#\", \"\\204q\", \"\\204w\", \"\\204e\", \"\\204r\", \"\\204t\", \"\\204y\", \"\\204u\", \"\\204i\", \"\\204o\", \"\\204p\", \"\\207Bksp\", \"\\n\",\n    \"\\226ABC\", \"\\203a\", \"\\203s\", \"\\203d\", \"\\203f\", \"\\203g\", \"\\203h\", \"\\203j\", \"\\203k\", \"\\203l\", \"\\207Enter\", \"\\n\",\n    \"_\", \"-\", \"z\", \"x\", \"c\", \"v\", \"b\", \"n\", \"m\", \".\", \",\", \":\", \"\\n\",\n    \"\\202\"SYMBOL_CLOSE, \"\\202\"SYMBOL_LEFT, \"\\206 \", \"\\202\"SYMBOL_RIGHT, \"\\202\"SYMBOL_OK, \"\"\n};\n\nstatic const char * kb_map_uc[] = {\n    \"\\2051#\", \"\\204Q\", \"\\204W\", \"\\204E\", \"\\204R\", \"\\204T\", \"\\204Y\", \"\\204U\", \"\\204I\", \"\\204O\", \"\\204P\", \"\\207Bksp\", \"\\n\",\n    \"\\226abc\", \"\\203A\", \"\\203S\", \"\\203D\", \"\\203F\", \"\\203G\", \"\\203H\", \"\\203J\", \"\\203K\", \"\\203L\", \"\\207Enter\", \"\\n\",\n    \"_\", \"-\", \"Z\", \"X\", \"C\", \"V\", \"B\", \"N\", \"M\", \".\", \",\", \":\", \"\\n\",\n    \"\\202\"SYMBOL_CLOSE, \"\\202\"SYMBOL_LEFT, \"\\206 \", \"\\202\"SYMBOL_RIGHT, \"\\202\"SYMBOL_OK, \"\"\n};\n\nstatic const char * kb_map_spec[] = {\n    \"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"\\202Bksp\", \"\\n\",\n    \"\\222abc\", \"+\", \"-\", \"/\", \"*\", \"=\", \"%\", \"!\", \"?\", \"#\", \"<\", \">\", \"\\n\",\n    \"\\\\\", \"@\", \"$\", \"(\", \")\", \"{\", \"}\", \"[\", \"]\", \";\", \"\\\"\", \"'\", \"\\n\",\n    \"\\202\"SYMBOL_CLOSE, \"\\202\"SYMBOL_LEFT, \"\\206 \", \"\\202\"SYMBOL_RIGHT, \"\\202\"SYMBOL_OK, \"\"\n};\n\nstatic const char * kb_map_num[] = {\n    \"1\", \"2\", \"3\", \"\\202\"SYMBOL_CLOSE, \"\\n\",\n    \"4\", \"5\", \"6\", \"\\202\"SYMBOL_OK, \"\\n\",\n    \"7\", \"8\", \"9\", \"\\202Bksp\", \"\\n\",\n    \"+/-\", \"0\", \".\", SYMBOL_LEFT, SYMBOL_RIGHT, \"\"\n};\n\nstatic const char * kb_map_hex[] = {\n\t\"1\", \"2\", \"3\", \"A\", \"D\", \"\\212\", \"\\n\",\n\t\"4\", \"5\", \"6\", \"B\", \"E\", \"\\202Bksp\", \"\\n\",\n\t\"7\", \"8\", \"9\", \"C\", \"F\", \"\\202\"SYMBOL_OK, \"\\n\",\n\t\"\\211\", \"0\", \"\\213\", SYMBOL_LEFT, SYMBOL_RIGHT, \"\"\n};\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a keyboard objects\n * @param par pointer to an object, it will be the parent of the new keyboard\n * @param copy pointer to a keyboard object, if not NULL then the new object will be copied from it\n * @return pointer to the created keyboard\n */\nlv_obj_t * lv_kb_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"keyboard create started\");\n\n    /*Create the ancestor of keyboard*/\n    lv_obj_t * new_kb = lv_btnm_create(par, copy);\n    lv_mem_assert(new_kb);\n    if(new_kb == NULL) return NULL;\n\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_kb);\n\n    /*Allocate the keyboard type specific extended data*/\n    lv_kb_ext_t * ext = lv_obj_allocate_ext_attr(new_kb, sizeof(lv_kb_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    /*Initialize the allocated 'ext' */\n\n    ext->ta = NULL;\n    ext->mode = LV_KB_MODE_TEXT;\n    ext->cursor_mng = 0;\n    ext->hide_action = NULL;\n    ext->ok_action = NULL;\n\n    /*The signal and design functions are not copied so set them here*/\n    lv_obj_set_signal_func(new_kb, lv_kb_signal);\n\n    /*Init the new keyboard keyboard*/\n    if(copy == NULL) {\n        lv_obj_set_size(new_kb, LV_HOR_RES, LV_VER_RES / 2);\n        lv_obj_align(new_kb, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0);\n        lv_btnm_set_action(new_kb, lv_kb_def_action);\n        lv_btnm_set_map(new_kb, kb_map_lc);\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_kb_set_style(new_kb, LV_KB_STYLE_BG, th->kb.bg);\n            lv_kb_set_style(new_kb, LV_KB_STYLE_BTN_REL, th->kb.btn.rel);\n            lv_kb_set_style(new_kb, LV_KB_STYLE_BTN_PR, th->kb.btn.pr);\n            lv_kb_set_style(new_kb, LV_KB_STYLE_BTN_TGL_REL, th->kb.btn.tgl_rel);\n            lv_kb_set_style(new_kb, LV_KB_STYLE_BTN_TGL_PR, th->kb.btn.tgl_pr);\n            lv_kb_set_style(new_kb, LV_KB_STYLE_BTN_INA, th->kb.btn.ina);\n        } else {\n            /*Let the button matrix's styles*/\n        }\n    }\n    /*Copy an existing keyboard*/\n    else {\n        lv_kb_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        ext->ta = NULL;\n        ext->ta = copy_ext->ta;\n        ext->mode = copy_ext->mode;\n        ext->cursor_mng = copy_ext->cursor_mng;\n        ext->hide_action = copy_ext->hide_action;\n        ext->ok_action = copy_ext->ok_action;\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_kb);\n    }\n\n\n    LV_LOG_INFO(\"keyboard created\");\n\n\n    return new_kb;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Assign a Text Area to the Keyboard. The pressed characters will be put there.\n * @param kb pointer to a Keyboard object\n * @param ta pointer to a Text Area object to write there\n */\nvoid lv_kb_set_ta(lv_obj_t * kb, lv_obj_t * ta)\n{\n    lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb);\n    lv_cursor_type_t cur_type;\n\n    /*Hide the cursor of the old Text area if cursor management is enabled*/\n    if(ext->ta && ext->cursor_mng) {\n        cur_type = lv_ta_get_cursor_type(ext->ta);\n        lv_ta_set_cursor_type(ext->ta,  cur_type | LV_CURSOR_HIDDEN);\n    }\n\n    ext->ta = ta;\n\n    /*Show the cursor of the new Text area if cursor management is enabled*/\n    if(ext->ta && ext->cursor_mng) {\n        cur_type = lv_ta_get_cursor_type(ext->ta);\n        lv_ta_set_cursor_type(ext->ta,  cur_type & (~LV_CURSOR_HIDDEN));\n    }\n}\n\n/**\n * Set a new a mode (text or number map)\n * @param kb pointer to a Keyboard object\n * @param mode the mode from 'lv_kb_mode_t'\n */\nvoid lv_kb_set_mode(lv_obj_t * kb, lv_kb_mode_t mode)\n{\n    lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb);\n    if(ext->mode == mode) return;\n\n    ext->mode = mode;\n    if(mode == LV_KB_MODE_TEXT) lv_btnm_set_map(kb, kb_map_lc);\n    else if(mode == LV_KB_MODE_NUM) lv_btnm_set_map(kb, kb_map_num);\n\telse if (mode == LV_KB_MODE_HEX) lv_btnm_set_map(kb, kb_map_hex);\n}\n\n\n/**\n * Automatically hide or show the cursor of Text Area\n * @param kb pointer to a Keyboard object\n * @param en true: show cursor on the current text area, false: hide cursor\n */\nvoid lv_kb_set_cursor_manage(lv_obj_t * kb, bool en)\n{\n    lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb);\n    if(ext->cursor_mng == en) return;\n\n    ext->cursor_mng = en == false ? 0 : 1;\n\n    if(ext->ta) {\n        lv_cursor_type_t cur_type;\n        cur_type = lv_ta_get_cursor_type(ext->ta);\n\n        if(ext->cursor_mng) {\n            lv_ta_set_cursor_type(ext->ta,  cur_type & (~LV_CURSOR_HIDDEN));\n        } else {\n            lv_ta_set_cursor_type(ext->ta,  cur_type | LV_CURSOR_HIDDEN);\n        }\n    }\n}\n\n/**\n * Set call back to call when the \"Ok\" button is pressed\n * @param kb pointer to Keyboard object\n * @param action a callback with 'lv_action_t' type\n */\nvoid lv_kb_set_ok_action(lv_obj_t * kb, lv_action_t action)\n{\n    lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb);\n    ext->ok_action = action;\n}\n\n/**\n * Set call back to call when the \"Hide\" button is pressed\n * @param kb pointer to Keyboard object\n * @param action a callback with 'lv_action_t' type\n */\nvoid lv_kb_set_hide_action(lv_obj_t * kb, lv_action_t action)\n{\n    lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb);\n    ext->hide_action = action;\n}\n\n/**\n * Set a style of a keyboard\n * @param kb pointer to a keyboard object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_kb_set_style(lv_obj_t * kb, lv_kb_style_t type, lv_style_t * style)\n{\n    switch(type) {\n        case LV_KB_STYLE_BG:\n            lv_btnm_set_style(kb, LV_BTNM_STYLE_BG, style);\n            break;\n        case LV_KB_STYLE_BTN_REL:\n            lv_btnm_set_style(kb, LV_BTNM_STYLE_BTN_REL, style);\n            break;\n        case LV_KB_STYLE_BTN_PR:\n            lv_btnm_set_style(kb, LV_BTNM_STYLE_BTN_PR, style);\n            break;\n        case LV_KB_STYLE_BTN_TGL_REL:\n            lv_btnm_set_style(kb, LV_BTNM_STYLE_BTN_TGL_REL, style);\n            break;\n        case LV_KB_STYLE_BTN_TGL_PR:\n            lv_btnm_set_style(kb, LV_BTNM_STYLE_BTN_TGL_PR, style);\n            break;\n        case LV_KB_STYLE_BTN_INA:\n            lv_btnm_set_style(kb, LV_BTNM_STYLE_BTN_INA, style);\n            break;\n    }\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Assign a Text Area to the Keyboard. The pressed characters will be put there.\n * @param kb pointer to a Keyboard object\n * @return pointer to the assigned Text Area object\n */\nlv_obj_t * lv_kb_get_ta(const lv_obj_t * kb)\n{\n    lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb);\n    return ext->ta;\n}\n\n/**\n * Set a new a mode (text or number map)\n * @param kb pointer to a Keyboard object\n * @return the current mode from 'lv_kb_mode_t'\n */\nlv_kb_mode_t lv_kb_get_mode(const lv_obj_t * kb)\n{\n    lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb);\n    return ext->mode;\n}\n\n\n/**\n * Get the current cursor manage mode.\n * @param kb pointer to a Keyboard object\n * @return true: show cursor on the current text area, false: hide cursor\n */\nbool lv_kb_get_cursor_manage(const lv_obj_t * kb)\n{\n    lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb);\n    return ext->cursor_mng == 0 ? false : true;\n}\n\n/**\n * Get the callback to call when the \"Ok\" button is pressed\n * @param kb pointer to Keyboard object\n * @return the ok callback\n */\nlv_action_t lv_kb_get_ok_action(const lv_obj_t * kb)\n{\n    lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb);\n    return ext->ok_action;\n}\n\n/**\n * Get the callback to call when the \"Hide\" button is pressed\n * @param kb pointer to Keyboard object\n * @return the close callback\n */\nlv_action_t lv_kb_get_hide_action(const lv_obj_t * kb)\n{\n    lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb);\n    return ext->hide_action;\n}\n\n/**\n * Get a style of a keyboard\n * @param kb pointer to a keyboard object\n * @param type which style should be get\n * @return style pointer to a style\n */\nlv_style_t * lv_kb_get_style(const lv_obj_t * kb, lv_kb_style_t type)\n{\n    lv_style_t * style = NULL;\n\n    switch(type) {\n        case LV_KB_STYLE_BG:\n            style = lv_btnm_get_style(kb, LV_BTNM_STYLE_BG);\n            break;\n        case LV_KB_STYLE_BTN_REL:\n            style = lv_btnm_get_style(kb, LV_BTNM_STYLE_BTN_REL);\n            break;\n        case LV_KB_STYLE_BTN_PR:\n            style = lv_btnm_get_style(kb, LV_BTNM_STYLE_BTN_PR);\n            break;\n        case LV_KB_STYLE_BTN_TGL_REL:\n            style = lv_btnm_get_style(kb, LV_BTNM_STYLE_BTN_TGL_REL);\n            break;\n        case LV_KB_STYLE_BTN_TGL_PR:\n            style = lv_btnm_get_style(kb, LV_BTNM_STYLE_BTN_TGL_PR);\n            break;\n        case LV_KB_STYLE_BTN_INA:\n            style = lv_btnm_get_style(kb, LV_BTNM_STYLE_BTN_INA);\n            break;\n        default:\n            style = NULL;\n            break;\n    }\n\n    return style;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Signal function of the keyboard\n * @param kb pointer to a keyboard object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_kb_signal(lv_obj_t * kb, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(kb, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    if(sign == LV_SIGNAL_CLEANUP) {\n        /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_kb\";\n    }\n\n    return res;\n}\n\n/**\n * Called when a button of 'kb_btnm' is released\n * @param btnm pointer to 'kb_btnm'\n * @param i the index of the released button from the current btnm map\n * @return LV_ACTION_RES_INV if the btnm is deleted else LV_ACTION_RES_OK\n */\nstatic lv_res_t lv_kb_def_action(lv_obj_t * kb, const char * txt)\n{\n    lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb);\n    lv_res_t res = LV_RES_OK;\n\n    /*Do the corresponding action according to the text of the button*/\n    if(strcmp(txt, \"abc\") == 0) {\n        lv_btnm_set_map(kb, kb_map_lc);\n        return LV_RES_OK;\n    } else if(strcmp(txt, \"ABC\") == 0) {\n        lv_btnm_set_map(kb, kb_map_uc);\n        return LV_RES_OK;\n    } else if(strcmp(txt, \"1#\") == 0) {\n        lv_btnm_set_map(kb, kb_map_spec);\n        return LV_RES_OK;\n    } else if(strcmp(txt, SYMBOL_CLOSE) == 0) {\n        if(ext->hide_action) res = ext->hide_action(kb);\n        else {\n            lv_kb_set_ta(kb, NULL);         /*De-assign the text area  to hide it cursor if needed*/\n            lv_obj_del(kb);\n        }\n        return res;\n    } else if(strcmp(txt, SYMBOL_OK) == 0) {\n        if(ext->ok_action) res = ext->ok_action(kb);\n        else {\n            lv_kb_set_ta(kb, NULL);         /*De-assign the text area to hide it cursor if needed*/\n            res = lv_obj_del(kb);\n        }\n        return res;\n    }\n\n    if(res != LV_RES_OK) return res;\t/*The keyboard might be deleted in the actions*/\n\n    /*Add the characters to the text area if set*/\n    if(ext->ta == NULL) return res;\n\n    if(strcmp(txt, \"Enter\") == 0)lv_ta_add_char(ext->ta, '\\n');\n    else if(strcmp(txt, SYMBOL_LEFT) == 0) lv_ta_cursor_left(ext->ta);\n    else if(strcmp(txt, SYMBOL_RIGHT) == 0) lv_ta_cursor_right(ext->ta);\n    else if(strcmp(txt, \"Bksp\") == 0)  lv_ta_del_char(ext->ta);\n    else if(strcmp(txt, \"+/-\") == 0) {\n        uint16_t cur = lv_ta_get_cursor_pos(ext->ta);\n        const char * ta_txt = lv_ta_get_text(ext->ta);\n        if(ta_txt[0] == '-') {\n            lv_ta_set_cursor_pos(ext->ta, 1);\n            lv_ta_del_char(ext->ta);\n            lv_ta_add_char(ext->ta, '+');\n            lv_ta_set_cursor_pos(ext->ta, cur);\n        } else if(ta_txt[0] == '+') {\n            lv_ta_set_cursor_pos(ext->ta, 1);\n            lv_ta_del_char(ext->ta);\n            lv_ta_add_char(ext->ta, '-');\n            lv_ta_set_cursor_pos(ext->ta, cur);\n        } else {\n            lv_ta_set_cursor_pos(ext->ta, 0);\n            lv_ta_add_char(ext->ta, '-');\n            lv_ta_set_cursor_pos(ext->ta, cur + 1);\n        }\n    } else {\n        lv_ta_add_text(ext->ta, txt);\n    }\n    return LV_RES_OK;\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_kb.h",
    "content": "/*\n * Copyright (c) 2019-2020 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * @file lv_kb.h\n *\n */\n\n#ifndef LV_KB_H\n#define LV_KB_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_KB != 0\n\n/*Testing of dependencies*/\n#if USE_LV_BTNM == 0\n#error \"lv_kb: lv_btnm is required. Enable it in lv_conf.h (USE_LV_BTNM  1) \"\n#endif\n\n#if USE_LV_TA == 0\n#error \"lv_kb: lv_ta is required. Enable it in lv_conf.h (USE_LV_TA  1) \"\n#endif\n\n#include \"../lv_core/lv_obj.h\"\n#include \"lv_btnm.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\nenum {\n    LV_KB_MODE_TEXT,\n    LV_KB_MODE_NUM,\n\tLV_KB_MODE_HEX\n};\ntypedef uint8_t lv_kb_mode_t;\n\n/*Data of keyboard*/\ntypedef struct {\n    lv_btnm_ext_t btnm;     /*Ext. of ancestor*/\n    /*New data for this type */\n    lv_obj_t *ta;               /*Pointer to the assigned text area*/\n    lv_kb_mode_t mode;          /*Key map type*/\n    uint8_t cursor_mng      :1; /*1: automatically show/hide cursor when a text area is assigned or left*/\n    lv_action_t  ok_action;     /*Called when the \"Ok\" button is clicked*/\n    lv_action_t  hide_action;  /*Called when the \"Hide\" button is clicked*/\n} lv_kb_ext_t;\n\nenum {\n    LV_KB_STYLE_BG,\n    LV_KB_STYLE_BTN_REL,\n    LV_KB_STYLE_BTN_PR,\n    LV_KB_STYLE_BTN_TGL_REL,\n    LV_KB_STYLE_BTN_TGL_PR,\n    LV_KB_STYLE_BTN_INA,\n};\ntypedef uint8_t lv_kb_style_t;\n\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a keyboard objects\n * @param par pointer to an object, it will be the parent of the new keyboard\n * @param copy pointer to a keyboard object, if not NULL then the new object will be copied from it\n * @return pointer to the created keyboard\n */\nlv_obj_t * lv_kb_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Assign a Text Area to the Keyboard. The pressed characters will be put there.\n * @param kb pointer to a Keyboard object\n * @param ta pointer to a Text Area object to write there\n */\nvoid lv_kb_set_ta(lv_obj_t * kb, lv_obj_t * ta);\n\n/**\n * Set a new a mode (text or number map)\n * @param kb pointer to a Keyboard object\n * @param mode the mode from 'lv_kb_mode_t'\n */\nvoid lv_kb_set_mode(lv_obj_t * kb, lv_kb_mode_t mode);\n\n/**\n * Automatically hide or show the cursor of the current Text Area\n * @param kb pointer to a Keyboard object\n * @param en true: show cursor on the current text area, false: hide cursor\n */\nvoid lv_kb_set_cursor_manage(lv_obj_t * kb, bool en);\n\n/**\n * Set call back to call when the \"Ok\" button is pressed\n * @param kb pointer to Keyboard object\n * @param action a callback with 'lv_action_t' type\n */\nvoid lv_kb_set_ok_action(lv_obj_t * kb, lv_action_t action);\n\n/**\n * Set call back to call when the \"Hide\" button is pressed\n * @param kb pointer to Keyboard object\n * @param action a callback with 'lv_action_t' type\n */\nvoid lv_kb_set_hide_action(lv_obj_t * kb, lv_action_t action);\n\n/**\n * Set a new map for the keyboard\n * @param kb pointer to a Keyboard object\n * @param map pointer to a string array to describe the map.\n *            See 'lv_btnm_set_map()' for more info.\n */\nstatic inline void lv_kb_set_map(lv_obj_t *kb, const char ** map)\n{\n    lv_btnm_set_map(kb, map);\n}\n\n/**\n * Set a style of a keyboard\n * @param kb pointer to a keyboard object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_kb_set_style(lv_obj_t *kb, lv_kb_style_t type, lv_style_t *style);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Assign a Text Area to the Keyboard. The pressed characters will be put there.\n * @param kb pointer to a Keyboard object\n * @return pointer to the assigned Text Area object\n */\nlv_obj_t * lv_kb_get_ta(const lv_obj_t * kb);\n\n/**\n * Set a new a mode (text or number map)\n * @param kb pointer to a Keyboard object\n * @return the current mode from 'lv_kb_mode_t'\n */\nlv_kb_mode_t lv_kb_get_mode(const lv_obj_t * kb);\n\n/**\n * Get the current cursor manage mode.\n * @param kb pointer to a Keyboard object\n * @return true: show cursor on the current text area, false: hide cursor\n */\nbool lv_kb_get_cursor_manage(const lv_obj_t * kb);\n\n/**\n * Get the callback to call when the \"Ok\" button is pressed\n * @param kb pointer to Keyboard object\n * @return the ok callback\n */\nlv_action_t lv_kb_get_ok_action(const lv_obj_t * kb);\n\n/**\n * Get the callback to call when the \"Hide\" button is pressed\n * @param kb pointer to Keyboard object\n * @return the close callback\n */\nlv_action_t lv_kb_get_hide_action(const lv_obj_t * kb);\n\n/**\n * Get a style of a keyboard\n * @param kb pointer to a keyboard object\n * @param type which style should be get\n * @return style pointer to a style\n */\nlv_style_t * lv_kb_get_style(const lv_obj_t *kb, lv_kb_style_t type);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_KB*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_KB_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_label.c",
    "content": "/**\n * @file lv_rect.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_label.h\"\n#if USE_LV_LABEL != 0\n\n#include \"../lv_core/lv_obj.h\"\n#include \"../lv_core/lv_group.h\"\n#include \"../lv_core/lv_lang.h\"\n#include \"../lv_draw/lv_draw.h\"\n#include \"../lv_misc/lv_color.h\"\n#include \"../lv_misc/lv_math.h\"\n\n/*********************\n *      DEFINES\n *********************/\n/*Test configurations*/\n#ifndef LV_LABEL_SCROLL_SPEED\n#define LV_LABEL_SCROLL_SPEED       (25) /*Hor, or ver. scroll speed (px/sec) in 'LV_LABEL_LONG_SCROLL/ROLL' mode*/\n#endif\n\n#define ANIM_WAIT_CHAR_COUNT 3\n\n#define LV_LABEL_DOT_END_INV 0xFFFF\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic lv_res_t lv_label_signal(lv_obj_t * label, lv_signal_t sign, void * param);\nstatic bool lv_label_design(lv_obj_t * label, const lv_area_t * mask, lv_design_mode_t mode);\nstatic void lv_label_refr_text(lv_obj_t * label);\nstatic void lv_label_revert_dots(lv_obj_t * label);\n\n#if USE_LV_ANIMATION\nstatic void lv_label_set_offset_x(lv_obj_t * label, lv_coord_t x);\nstatic void lv_label_set_offset_y(lv_obj_t * label, lv_coord_t y);\n#endif\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a label objects\n * @param par pointer to an object, it will be the parent of the new label\n * @param copy pointer to a button object, if not NULL then the new object will be copied from it\n * @return pointer to the created button\n */\nlv_obj_t * lv_label_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"label create started\");\n\n    /*Create a basic object*/\n    lv_obj_t * new_label = lv_obj_create(par, copy);\n    lv_mem_assert(new_label);\n    if(new_label == NULL) return NULL;\n\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_label);\n\n    /*Extend the basic object to a label object*/\n    lv_obj_allocate_ext_attr(new_label, sizeof(lv_label_ext_t));\n\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(new_label);\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    ext->text = NULL;\n    ext->static_txt = 0;\n    ext->recolor = 0;\n    ext->body_draw = 0;\n    ext->align = LV_LABEL_ALIGN_LEFT;\n    ext->dot_end = LV_LABEL_DOT_END_INV;\n    ext->long_mode = LV_LABEL_LONG_EXPAND;\n    ext->anim_speed = LV_LABEL_SCROLL_SPEED;\n    ext->offset.x = 0;\n    ext->offset.y = 0;\n#if USE_LV_MULTI_LANG\n    ext->lang_txt_id = LV_LANG_TXT_ID_NONE;\n#endif\n    lv_obj_set_design_func(new_label, lv_label_design);\n    lv_obj_set_signal_func(new_label, lv_label_signal);\n\n    /*Init the new label*/\n    if(copy == NULL) {\n        lv_obj_set_click(new_label, false);\n        lv_label_set_long_mode(new_label, LV_LABEL_LONG_EXPAND);\n        lv_label_set_text(new_label, \"Text\");\n        lv_label_set_style(new_label, NULL);        /*Inherit parent's style*/\n    }\n    /*Copy 'copy' if not NULL*/\n    else {\n        lv_label_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        lv_label_set_long_mode(new_label, lv_label_get_long_mode(copy));\n        lv_label_set_recolor(new_label, lv_label_get_recolor(copy));\n        lv_label_set_body_draw(new_label, lv_label_get_body_draw(copy));\n        lv_label_set_align(new_label, lv_label_get_align(copy));\n        if(copy_ext->static_txt == 0) lv_label_set_text(new_label, lv_label_get_text(copy));\n        else lv_label_set_static_text(new_label, lv_label_get_text(copy));\n\n        /*In DOT mode save the text byte-to-byte because a '\\0' can be in the middle*/\n        if(copy_ext->long_mode == LV_LABEL_LONG_DOT) {\n            ext->text = lv_mem_realloc(ext->text, lv_mem_get_size(copy_ext->text));\n            lv_mem_assert(ext->text);\n            if(ext->text == NULL) return NULL;\n            memcpy(ext->text, copy_ext->text, lv_mem_get_size(copy_ext->text));\n        }\n\n        memcpy(ext->dot_tmp, copy_ext->dot_tmp, sizeof(ext->dot_tmp));\n        ext->dot_end = copy_ext->dot_end;\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_label);\n    }\n\n\n    LV_LOG_INFO(\"label created\");\n\n    return new_label;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a new text for a label. Memory will be allocated to store the text by the label.\n * @param label pointer to a label object\n * @param text '\\0' terminated character string. NULL to refresh with the current text.\n */\nvoid lv_label_set_text(lv_obj_t * label, const char * text)\n{\n    lv_obj_invalidate(label);\n\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n\n    /*If text is NULL then refresh */\n    if(text == NULL) {\n        lv_label_refr_text(label);\n        return;\n    }\n\n    if(ext->text == text && ext->static_txt == 0) {\n        /*If set its own text then reallocate it (maybe its size changed)*/\n        ext->text = lv_mem_realloc(ext->text, strlen(ext->text) + 1);\n        lv_mem_assert(ext->text);\n        if(ext->text == NULL) return;\n    } else {\n        /*Allocate space for the new text*/\n        uint32_t len = strlen(text) + 1;\n        if(ext->text != NULL && ext->static_txt == 0) {\n            lv_mem_free(ext->text);\n            ext->text = NULL;\n        }\n\n        ext->text = lv_mem_alloc(len);\n        lv_mem_assert(ext->text);\n        if(ext->text == NULL) return;\n\n        strcpy(ext->text, text);\n        ext->static_txt = 0;    /*Now the text is dynamically allocated*/\n    }\n\n    lv_label_refr_text(label);\n}\n\n/**\n * Set a new text for a label from a character array. The array don't has to be '\\0' terminated.\n * Memory will be allocated to store the array by the label.\n * @param label pointer to a label object\n * @param array array of characters or NULL to refresh the label\n * @param size the size of 'array' in bytes\n */\nvoid lv_label_set_array_text(lv_obj_t * label, const char * array, uint16_t size)\n{\n    lv_obj_invalidate(label);\n\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n\n    /*If trying to set its own text or the array is NULL then refresh */\n    if(array == ext->text || array == NULL) {\n        lv_label_refr_text(label);\n        return;\n    }\n\n    /*Allocate space for the new text*/\n    if(ext->text != NULL && ext->static_txt == 0) {\n        lv_mem_free(ext->text);\n        ext->text = NULL;\n    }\n    ext->text = lv_mem_alloc(size + 1);\n    lv_mem_assert(ext->text);\n    if(ext->text == NULL) return;\n\n    memcpy(ext->text, array, size);\n    ext->text[size] = '\\0';\n    ext->static_txt = 0;    /*Now the text is dynamically allocated*/\n\n    lv_label_refr_text(label);\n}\n\n/**\n * Set a static text. It will not be saved by the label so the 'text' variable\n * has to be 'alive' while the label exist.\n * @param label pointer to a label object\n * @param text pointer to a text. NULL to refresh with the current text.\n */\nvoid lv_label_set_static_text(lv_obj_t * label, const char * text)\n{\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n    if(ext->static_txt == 0 && ext->text != NULL) {\n        lv_mem_free(ext->text);\n        ext->text = NULL;\n    }\n\n    if(text != NULL) {\n        ext->static_txt = 1;\n        ext->text = (char *) text;\n    }\n\n    lv_label_refr_text(label);\n}\n\n#if USE_LV_MULTI_LANG\n/**\n *Set a text ID which refers a the same text but in a different languages\n * @param label pointer to a label object\n * @param txt_id ID of the text\n */\nvoid lv_label_set_text_id(lv_obj_t * label, uint32_t txt_id)\n{\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n    ext->lang_txt_id = txt_id;\n\n    /*Apply the new language*/\n    label->signal_func(label, LV_SIGNAL_LANG_CHG, NULL);\n}\n#endif\n\n/**\n * Set the behavior of the label with longer text then the object size\n * @param label pointer to a label object\n * @param long_mode the new mode from 'lv_label_long_mode' enum.\n *                  In LV_LONG_BREAK/LONG/ROLL the size of the label should be set AFTER this function\n */\nvoid lv_label_set_long_mode(lv_obj_t * label, lv_label_long_mode_t long_mode)\n{\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n\n#if USE_LV_ANIMATION\n    /*Delete the old animation (if exists)*/\n    lv_anim_del(label, (lv_anim_fp_t) lv_obj_set_x);\n    lv_anim_del(label, (lv_anim_fp_t) lv_obj_set_y);\n    lv_anim_del(label, (lv_anim_fp_t) lv_label_set_offset_x);\n    lv_anim_del(label, (lv_anim_fp_t) lv_label_set_offset_y);\n#endif\n    ext->offset.x = 0;\n    ext->offset.y = 0;\n\n    if(long_mode == LV_LABEL_LONG_ROLL || long_mode == LV_LABEL_LONG_CROP) ext->expand = 1;\n    else ext->expand = 0;\n\n    /*Restore the character under the dots*/\n    if(ext->long_mode == LV_LABEL_LONG_DOT && ext->dot_end != LV_LABEL_DOT_END_INV) {\n        lv_label_revert_dots(label);\n    }\n\n    ext->long_mode = long_mode;\n    lv_label_refr_text(label);\n}\n\n/**\n * Set the align of the label (left or center)\n * @param label pointer to a label object\n * @param align 'LV_LABEL_ALIGN_LEFT' or 'LV_LABEL_ALIGN_LEFT'\n */\nvoid lv_label_set_align(lv_obj_t * label, lv_label_align_t align)\n{\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n    if(ext->align == align) return;\n\n    ext->align = align;\n\n    lv_obj_invalidate(label);       /*Enough to invalidate because alignment is only drawing related (lv_refr_label_text() not required)*/\n}\n\n/**\n * Enable the recoloring by in-line commands\n * @param label pointer to a label object\n * @param en true: enable recoloring, false: disable\n */\nvoid lv_label_set_recolor(lv_obj_t * label, bool en)\n{\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n    if(ext->recolor == en) return;\n\n    ext->recolor = en == false ? 0 : 1;\n\n    lv_label_refr_text(label);  /*Refresh the text because the potential colo codes in text needs to be hided or revealed*/\n}\n\n/**\n * Set the label to draw (or not draw) background specified in its style's body\n * @param label pointer to a label object\n * @param en true: draw body; false: don't draw body\n */\nvoid lv_label_set_body_draw(lv_obj_t * label, bool en)\n{\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n    if(ext->body_draw == en) return;\n\n    ext->body_draw = en == false ? 0 : 1;\n\n    lv_obj_refresh_ext_size(label);\n\n    lv_obj_invalidate(label);\n}\n\n/**\n * Set the label's animation speed in LV_LABEL_LONG_ROLL and SCROLL modes\n * @param label pointer to a label object\n * @param anim_speed speed of animation in px/sec unit\n */\nvoid lv_label_set_anim_speed(lv_obj_t * label, uint16_t anim_speed)\n{\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n    if(ext->anim_speed == anim_speed) return;\n\n    ext->anim_speed = anim_speed;\n\n    if(ext->long_mode == LV_LABEL_LONG_ROLL || ext->long_mode == LV_LABEL_LONG_SCROLL) {\n        lv_label_refr_text(label);\n    }\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the text of a label\n * @param label pointer to a label object\n * @return the text of the label\n */\nchar * lv_label_get_text(const lv_obj_t * label)\n{\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n\n    return ext->text;\n}\n\n#if USE_LV_MULTI_LANG\n/**\n * Get the text ID of the label. (Used by the multi-language feature)\n * @param label pointer to a label object\n * @return ID of the text\n */\nuint16_t lv_label_get_text_id(lv_obj_t * label)\n{\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n    return ext->lang_txt_id;\n}\n#endif\n\n/**\n * Get the long mode of a label\n * @param label pointer to a label object\n * @return the long mode\n */\nlv_label_long_mode_t lv_label_get_long_mode(const lv_obj_t * label)\n{\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n    return ext->long_mode;\n}\n\n/**\n * Get the align attribute\n * @param label pointer to a label object\n * @return LV_LABEL_ALIGN_LEFT or LV_LABEL_ALIGN_CENTER\n */\nlv_label_align_t lv_label_get_align(const lv_obj_t * label)\n{\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n    return ext->align;\n}\n\n/**\n * Get the recoloring attribute\n * @param label pointer to a label object\n * @return true: recoloring is enabled, false: disable\n */\nbool lv_label_get_recolor(const lv_obj_t * label)\n{\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n    return ext->recolor == 0 ? false : true;\n}\n\n/**\n * Get the body draw attribute\n * @param label pointer to a label object\n * @return true: draw body; false: don't draw body\n */\nbool lv_label_get_body_draw(const lv_obj_t * label)\n{\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n    return ext->body_draw == 0 ? false : true;\n}\n\n/**\n * Get the label's animation speed in LV_LABEL_LONG_ROLL and SCROLL modes\n * @param label pointer to a label object\n * @return speed of animation in px/sec unit\n */\nuint16_t lv_label_get_anim_speed(const lv_obj_t * label)\n{\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n    return ext->anim_speed;\n}\n\n/**\n * Get the relative x and y coordinates of a letter\n * @param label pointer to a label object\n * @param index index of the letter [0 ... text length]. Expressed in character index, not byte index (different in UTF-8)\n * @param pos store the result here (E.g. index = 0 gives 0;0 coordinates)\n */\nvoid lv_label_get_letter_pos(const lv_obj_t * label, uint16_t index, lv_point_t * pos)\n{\n    const char * txt = lv_label_get_text(label);\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n    uint32_t line_start = 0;\n    uint32_t new_line_start = 0;\n    lv_coord_t max_w = lv_obj_get_width(label);\n    lv_style_t * style = lv_obj_get_style(label);\n    const lv_font_t * font = style->text.font;\n    uint8_t letter_height = lv_font_get_height(font);\n    lv_coord_t y = 0;\n    lv_txt_flag_t flag = LV_TXT_FLAG_NONE;\n\n    if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR;\n    if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND;\n    if(ext->align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER;\n\n    /*If the width will be expanded  the set the max length to very big */\n    if(ext->long_mode == LV_LABEL_LONG_EXPAND || ext->long_mode == LV_LABEL_LONG_SCROLL) {\n        max_w = LV_COORD_MAX;\n    }\n\n    index = lv_txt_encoded_get_byte_id(txt, index);\n\n    /*Search the line of the index letter */;\n    while(txt[new_line_start] != '\\0') {\n        new_line_start += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, max_w, flag);\n        if(index < new_line_start || txt[new_line_start] == '\\0') break; /*The line of 'index' letter begins at 'line_start'*/\n\n        y += letter_height + style->text.line_space;\n        line_start = new_line_start;\n    }\n\n    /*If the last character is line break then go to the next line*/\n    if(index > 0) {\n        if((txt[index - 1] == '\\n' || txt[index - 1] == '\\r') && txt[index] == '\\0') {\n            y += letter_height + style->text.line_space;\n            line_start = index;\n        }\n    }\n\n    /*Calculate the x coordinate*/\n    lv_coord_t x = lv_txt_get_width(&txt[line_start], index - line_start,\n                            font, style->text.letter_space, flag);\n\n    if(index != line_start) x += style->text.letter_space;\n\n    if(ext->align == LV_LABEL_ALIGN_CENTER) {\n        lv_coord_t line_w;\n        line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start,\n                                  font, style->text.letter_space, flag);\n        x += lv_obj_get_width(label) / 2 - line_w / 2;\n\n    } else if(ext->align == LV_LABEL_ALIGN_RIGHT) {\n        lv_coord_t line_w;\n        line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start,\n                                  font, style->text.letter_space, flag);\n\n        x += lv_obj_get_width(label) - line_w;\n    }\n    pos->x = x;\n    pos->y = y;\n}\n\n/**\n * Get the index of letter on a relative point of a label\n * @param label pointer to label object\n * @param pos pointer to point with coordinates on a the label\n * @return the index of the letter on the 'pos_p' point (E.g. on 0;0 is the 0. letter)\n * Expressed in character index and not byte index (different in UTF-8)\n */\nuint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos)\n{\n    const char * txt = lv_label_get_text(label);\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n    uint32_t line_start = 0;\n    uint32_t new_line_start = 0;\n    lv_coord_t max_w = lv_obj_get_width(label);\n    lv_style_t * style = lv_obj_get_style(label);\n    const lv_font_t * font = style->text.font;\n    uint8_t letter_height = lv_font_get_height(font);\n    lv_coord_t y = 0;\n    lv_txt_flag_t flag = LV_TXT_FLAG_NONE;\n\n    if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR;\n    if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND;\n    if(ext->align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER;\n\n    /*If the width will be expanded set the max length to very big */\n    if(ext->long_mode == LV_LABEL_LONG_EXPAND || ext->long_mode == LV_LABEL_LONG_SCROLL) {\n        max_w = LV_COORD_MAX;\n    }\n\n    /*Search the line of the index letter */;\n    while(txt[line_start] != '\\0') {\n        new_line_start += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, max_w, flag);\n\n        if(pos->y <= y + letter_height) break; /*The line is found (stored in 'line_start')*/\n        y += letter_height + style->text.line_space;\n\n        line_start = new_line_start;\n    }\n\n    /*Calculate the x coordinate*/\n    lv_coord_t x = 0;\n    if(ext->align == LV_LABEL_ALIGN_CENTER) {\n        lv_coord_t line_w;\n        line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start,\n                                  font, style->text.letter_space, flag);\n        x += lv_obj_get_width(label) / 2 - line_w / 2;\n    }\n\n    lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT;\n    uint32_t i = line_start;\n    uint32_t i_current = i;\n    uint32_t letter;\n    while(i < new_line_start - 1) {\n        letter = lv_txt_encoded_next(txt, &i);    /*Be careful 'i' already points to the next character*/\n        /*Handle the recolor command*/\n        if((flag & LV_TXT_FLAG_RECOLOR) != 0) {\n            if(lv_txt_is_cmd(&cmd_state, txt[i]) != false) {\n                continue; /*Skip the letter is it is part of a command*/\n            }\n        }\n\n        x += lv_font_get_width(font, letter);\n        if(pos->x < x) {\n            i = i_current;\n            break;\n        }\n        x += style->text.letter_space;\n        i_current = i;\n    }\n\n    return lv_encoded_get_char_id(txt, i);\n}\n\n\n/*=====================\n * Other functions\n *====================*/\n\n/**\n * Insert a text to the label. The label text can not be static.\n * @param label pointer to a label object\n * @param pos character index to insert. Expressed in character index and not byte index (Different in UTF-8)\n *            0: before first char.\n *            LV_LABEL_POS_LAST: after last char.\n * @param txt pointer to the text to insert\n */\nvoid lv_label_ins_text(lv_obj_t * label, uint32_t pos,  const char * txt)\n{\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n\n    /*Can not append to static text*/\n    if(ext->static_txt != 0) return;\n\n    lv_obj_invalidate(label);\n\n    /*Allocate space for the new text*/\n    uint32_t old_len = strlen(ext->text);\n    uint32_t ins_len = strlen(txt);\n    uint32_t new_len = ins_len + old_len;\n    ext->text = lv_mem_realloc(ext->text, new_len + 1);\n    lv_mem_assert(ext->text);\n    if(ext->text == NULL) return;\n\n    if(pos == LV_LABEL_POS_LAST) {\n#if LV_TXT_UTF8 == 0\n        pos = old_len;\n#else\n        pos = lv_txt_get_encoded_length(ext->text);\n#endif\n    }\n\n    lv_txt_ins(ext->text, pos, txt);\n\n    lv_label_refr_text(label);\n}\n\n/**\n * Delete characters from a label. The label text can not be static.\n * @param label pointer to a label object\n * @param pos character index to insert. Expressed in character index and not byte index (Different in UTF-8)\n *            0: before first char.\n * @param cnt number of characters to cut\n */\nvoid lv_label_cut_text(lv_obj_t * label, uint32_t pos,  uint32_t cnt)\n{\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n\n    /*Can not append to static text*/\n    if(ext->static_txt != 0) return;\n\n    lv_obj_invalidate(label);\n\n    char * label_txt = lv_label_get_text(label);\n    /*Delete the characters*/\n    lv_txt_cut(label_txt, pos, cnt);\n\n    /*Refresh the label*/\n    lv_label_refr_text(label);\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Handle the drawing related tasks of the labels\n * @param label pointer to a label object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_label_design(lv_obj_t * label, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    /* A label never covers an area */\n    if(mode == LV_DESIGN_COVER_CHK) return false;\n    else if(mode == LV_DESIGN_DRAW_MAIN) {\n        lv_area_t coords;\n        lv_style_t * style = lv_obj_get_style(label);\n        lv_opa_t opa_scale = lv_obj_get_opa_scale(label);\n        lv_obj_get_coords(label, &coords);\n\n#if USE_LV_GROUP\n        lv_group_t * g = lv_obj_get_group(label);\n        if(lv_group_get_focused(g) == label) {\n            lv_draw_rect(&coords, mask, style, opa_scale);\n        }\n#endif\n\n        lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n\n        if(ext->body_draw) {\n            lv_area_t bg;\n            lv_obj_get_coords(label, &bg);\n            bg.x1 -= style->body.padding.hor;\n            bg.x2 += style->body.padding.hor;\n            bg.y1 -= style->body.padding.ver;\n            bg.y2 += style->body.padding.ver;\n\n            lv_draw_rect(&bg, mask, style, lv_obj_get_opa_scale(label));\n        }\n\n        /*TEST: draw a background for the label*/\n        //lv_draw_rect(&label->coords, mask, &lv_style_plain_color, LV_OPA_COVER);\n\n        lv_txt_flag_t flag = LV_TXT_FLAG_NONE;\n        if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR;\n        if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND;\n        if(ext->align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER;\n        if(ext->align == LV_LABEL_ALIGN_RIGHT) flag |= LV_TXT_FLAG_RIGHT;\n\n        /* In ROLL mode the CENTER and RIGHT are pointless so remove them.\n         * (In addition they will result mis-alignment is this case)*/\n        if((ext->long_mode == LV_LABEL_LONG_ROLL) &&\n                (ext->align == LV_LABEL_ALIGN_CENTER || ext->align == LV_LABEL_ALIGN_RIGHT)) {\n            lv_point_t size;\n            lv_txt_get_size(&size, ext->text, style->text.font, style->text.letter_space, style->text.line_space, LV_COORD_MAX, flag);\n            if(size.x > lv_obj_get_width(label)) {\n                flag &= ~LV_TXT_FLAG_RIGHT;\n                flag &= ~LV_TXT_FLAG_CENTER;\n            }\n        }\n\n        lv_draw_label(&coords, mask, style, opa_scale, ext->text, flag, &ext->offset);\n    }\n    return true;\n}\n\n\n\n/**\n * Signal function of the label\n * @param label pointer to a label object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_label_signal(lv_obj_t * label, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(label, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n    if(sign ==  LV_SIGNAL_CLEANUP) {\n        if(ext->static_txt == 0) {\n            lv_mem_free(ext->text);\n            ext->text = NULL;\n        }\n    } else if(sign == LV_SIGNAL_STYLE_CHG) {\n        /*Revert dots for proper refresh*/\n        lv_label_revert_dots(label);\n\n        lv_label_refr_text(label);\n    } else if(sign == LV_SIGNAL_CORD_CHG) {\n        if(lv_area_get_width(&label->coords) != lv_area_get_width(param) ||\n                lv_area_get_height(&label->coords) != lv_area_get_height(param)) {\n            lv_label_revert_dots(label);\n            lv_label_refr_text(label);\n        }\n    } else if(sign == LV_SIGNAL_REFR_EXT_SIZE) {\n        if(ext->body_draw) {\n            lv_style_t * style = lv_label_get_style(label);\n            label->ext_size = LV_MATH_MAX(label->ext_size, style->body.padding.hor);\n            label->ext_size = LV_MATH_MAX(label->ext_size, style->body.padding.ver);\n        }\n    } else if(sign == LV_SIGNAL_LANG_CHG) {\n#if USE_LV_MULTI_LANG\n        if(ext->lang_txt_id != LV_LANG_TXT_ID_NONE) {\n            const char * lang_txt = lv_lang_get_text(ext->lang_txt_id);\n            if(lang_txt) {\n                lv_label_set_text(label, lang_txt);\n            } else {\n                LV_LOG_WARN(\"lv_lang_get_text return NULL for a label's text\");\n            }\n        }\n#endif\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_label\";\n    }\n\n    return res;\n}\n\n/**\n * Refresh the label with its text stored in its extended data\n * @param label pointer to a label object\n */\nstatic void lv_label_refr_text(lv_obj_t * label)\n{\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n\n    if(ext->text == NULL) return;\n\n    lv_coord_t max_w = lv_obj_get_width(label);\n    lv_style_t * style = lv_obj_get_style(label);\n    const lv_font_t * font = style->text.font;\n\n    /*If the width will be expanded set the max length to very big */\n    if(ext->long_mode == LV_LABEL_LONG_EXPAND ||\n            ext->long_mode == LV_LABEL_LONG_SCROLL) {\n        max_w = LV_COORD_MAX;\n    }\n\n    /*Calc. the height and longest line*/\n    lv_point_t size;\n    lv_txt_flag_t flag = LV_TXT_FLAG_NONE;\n    if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR;\n    if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND;\n    lv_txt_get_size(&size, ext->text, font, style->text.letter_space, style->text.line_space, max_w, flag);\n\n    /*Set the full size in expand mode*/\n    if(ext->long_mode == LV_LABEL_LONG_EXPAND || ext->long_mode == LV_LABEL_LONG_SCROLL) {\n        lv_obj_set_size(label, size.x, size.y);\n\n        /*Start scrolling if the label is greater then its parent*/\n        if(ext->long_mode == LV_LABEL_LONG_SCROLL) {\n#if USE_LV_ANIMATION\n            lv_obj_t * parent = lv_obj_get_parent(label);\n\n            /*Delete the potential previous scroller animations*/\n            lv_anim_del(label, (lv_anim_fp_t) lv_obj_set_x);\n            lv_anim_del(label, (lv_anim_fp_t) lv_obj_set_y);\n\n            lv_anim_t anim;\n            anim.var = label;\n            anim.repeat = 1;\n            anim.playback = 1;\n            anim.start = 0;\n            anim.act_time = 0;\n            anim.end_cb = NULL;\n            anim.path = lv_anim_path_linear;\n\n            anim.playback_pause = (((lv_font_get_width(style->text.font, ' ') +\n                                     style->text.letter_space) * 1000) / ext->anim_speed) * ANIM_WAIT_CHAR_COUNT;\n            anim.repeat_pause = anim.playback_pause;\n\n            if(lv_obj_get_width(label) > lv_obj_get_width(parent)) {\n                anim.end = lv_obj_get_width(parent) - lv_obj_get_width(label);\n                anim.fp = (lv_anim_fp_t) lv_obj_set_x;\n                anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end);\n                lv_anim_create(&anim);\n            } else if(lv_obj_get_height(label) > lv_obj_get_height(parent)) {\n                anim.end =  lv_obj_get_height(parent) - lv_obj_get_height(label) - lv_font_get_height(font);\n                anim.fp = (lv_anim_fp_t)lv_obj_set_y;\n                anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end);\n                lv_anim_create(&anim);\n            }\n#endif\n        }\n    }\n    /*In roll mode keep the size but start offset animations*/\n    else if(ext->long_mode == LV_LABEL_LONG_ROLL) {\n#if USE_LV_ANIMATION\n        lv_anim_t anim;\n        anim.var = label;\n        anim.repeat = 1;\n        anim.playback = 1;\n        anim.start = 0;\n        anim.act_time = 0;\n        anim.end_cb = NULL;\n        anim.path = lv_anim_path_linear;\n        anim.playback_pause = (((lv_font_get_width(style->text.font, ' ') + style->text.letter_space) * 1000) / ext->anim_speed) * ANIM_WAIT_CHAR_COUNT;\n        anim.repeat_pause =  anim.playback_pause;\n\n        bool hor_anim = false;\n        if(size.x > lv_obj_get_width(label)) {\n            anim.end = lv_obj_get_width(label) - size.x;\n            anim.fp = (lv_anim_fp_t) lv_label_set_offset_x;\n            anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end);\n            lv_anim_create(&anim);\n            hor_anim = true;\n        } else {\n            /*Delete the offset animation if not required*/\n            lv_anim_del(label, (lv_anim_fp_t) lv_label_set_offset_x);\n            ext->offset.x = 0;\n        }\n\n        if(size.y > lv_obj_get_height(label) && hor_anim == false) {\n            anim.end =  lv_obj_get_height(label) - size.y - (lv_font_get_height(font));\n            anim.fp = (lv_anim_fp_t)lv_label_set_offset_y;\n            anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end);\n            lv_anim_create(&anim);\n        } else {\n            /*Delete the offset animation if not required*/\n            lv_anim_del(label, (lv_anim_fp_t) lv_label_set_offset_y);\n            ext->offset.y = 0;\n        }\n#endif\n    } else if(ext->long_mode == LV_LABEL_LONG_DOT) {\n        if(size.y <= lv_obj_get_height(label)) {                /*No dots are required, the text is short enough*/\n            ext->dot_end = LV_LABEL_DOT_END_INV;\n        } else if(lv_txt_get_encoded_length(ext->text) <= LV_LABEL_DOT_NUM) {     /*Don't turn to dots all the characters*/\n            ext->dot_end = LV_LABEL_DOT_END_INV;\n        } else {\n            lv_point_t p;\n            p.x = lv_obj_get_width(label) - (lv_font_get_width(style->text.font, '.') + style->text.letter_space) * LV_LABEL_DOT_NUM; /*Shrink with dots*/\n            p.y = lv_obj_get_height(label);\n            p.y -= p.y  % (lv_font_get_height(style->text.font) + style->text.line_space);   /*Round down to the last line*/\n            p.y -= style->text.line_space;                                                      /*Trim the last line space*/\n            uint32_t letter_id = lv_label_get_letter_on(label, &p);\n\n\n#if LV_TXT_UTF8 == 0\n            /*Save letters under the dots and replace them with dots*/\n            uint8_t i;\n            for(i = 0; i < LV_LABEL_DOT_NUM; i++)  {\n                ext->dot_tmp[i] = ext->text[letter_id + i];\n                ext->text[letter_id + i] = '.';\n            }\n\n            ext->dot_tmp[LV_LABEL_DOT_NUM] = ext->text[letter_id + LV_LABEL_DOT_NUM];\n            ext->text[letter_id + LV_LABEL_DOT_NUM] = '\\0';\n\n            ext->dot_end = letter_id + LV_LABEL_DOT_NUM;\n#else\n            /*Save letters under the dots and replace them with dots*/\n            uint32_t i;\n            uint32_t byte_id = lv_txt_encoded_get_byte_id(ext->text, letter_id);\n            uint32_t byte_id_ori = byte_id;\n            uint8_t len = 0;\n            for(i = 0; i <= LV_LABEL_DOT_NUM; i++)  {\n                len += lv_txt_encoded_size(&ext->text[byte_id]);\n                lv_txt_encoded_next(ext->text, &byte_id);\n            }\n\n            memcpy(ext->dot_tmp, &ext->text[byte_id_ori], len);\n            ext->dot_tmp[len] = '\\0';       /*Close with a zero*/\n\n            for(i = 0; i < LV_LABEL_DOT_NUM; i++) {\n                ext->text[byte_id_ori + i] = '.';\n            }\n            ext->text[byte_id_ori + LV_LABEL_DOT_NUM] = '\\0';\n\n            ext->dot_end = letter_id + LV_LABEL_DOT_NUM;\n#endif\n\n        }\n    }\n    /*In break mode only the height can change*/\n    else if(ext->long_mode == LV_LABEL_LONG_BREAK) {\n        lv_obj_set_height(label, size.y);\n    }\n    /*Do not set the size in Clip mode*/\n    else if(ext->long_mode == LV_LABEL_LONG_CROP) {\n        /*Do nothing*/\n    }\n\n\n    lv_obj_invalidate(label);\n}\n\nstatic void lv_label_revert_dots(lv_obj_t * label)\n{\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n    if(ext->long_mode != LV_LABEL_LONG_DOT) return;\n    if(ext->dot_end == LV_LABEL_DOT_END_INV) return;\n#if LV_TXT_UTF8 == 0\n    uint32_t i;\n    for(i = 0; i <= LV_LABEL_DOT_NUM; i++) {\n        ext->text[ext->dot_end - i] = ext->dot_tmp[LV_LABEL_DOT_NUM - i];\n    }\n#else\n    uint32_t letter_i = ext->dot_end - LV_LABEL_DOT_NUM;\n    uint32_t byte_i = lv_txt_encoded_get_byte_id(ext->text, letter_i);\n\n    /*Restore the characters*/\n    uint8_t i = 0;\n    while(ext->dot_tmp[i] != '\\0') {\n        ext->text[byte_i + i] = ext->dot_tmp[i];\n        i++;\n    }\n#endif\n\n    ext->dot_end = LV_LABEL_DOT_END_INV;\n}\n\n#if USE_LV_ANIMATION\nstatic void lv_label_set_offset_x(lv_obj_t * label, lv_coord_t x)\n{\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n    ext->offset.x = x;\n    lv_obj_invalidate(label);\n}\n\nstatic void lv_label_set_offset_y(lv_obj_t * label, lv_coord_t y)\n{\n    lv_label_ext_t * ext = lv_obj_get_ext_attr(label);\n    ext->offset.y = y;\n    lv_obj_invalidate(label);\n}\n#endif\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_label.h",
    "content": "/**\n * @file lv_rect.h\n *\n */\n\n#ifndef LV_LABEL_H\n#define LV_LABEL_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_LABEL != 0\n\n#include \"../lv_core/lv_obj.h\"\n#include \"../lv_misc/lv_font.h\"\n#include \"../lv_misc/lv_txt.h\"\n#include \"../lv_misc/lv_symbol_def.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_LABEL_DOT_NUM    3\n#define LV_LABEL_POS_LAST   0xFFFF\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/*Long mode behaviors. Used in 'lv_label_ext_t' */\nenum\n{\n    LV_LABEL_LONG_EXPAND,   /*Expand the object size to the text size*/\n    LV_LABEL_LONG_BREAK,    /*Keep the object width, break the too long lines and expand the object height*/\n    LV_LABEL_LONG_SCROLL,   /*Expand the object size and scroll the text on the parent (move the label object)*/\n    LV_LABEL_LONG_DOT,      /*Keep the size and write dots at the end if the text is too long*/\n    LV_LABEL_LONG_ROLL,     /*Keep the size and roll the text infinitely*/\n    LV_LABEL_LONG_CROP,     /*Keep the size and crop the text out of it*/\n};\ntypedef uint8_t lv_label_long_mode_t;\n\n/*Label align policy*/\nenum {\n    LV_LABEL_ALIGN_LEFT,\n    LV_LABEL_ALIGN_CENTER,\n    LV_LABEL_ALIGN_RIGHT,\n};\ntypedef uint8_t lv_label_align_t;\n\n/*Data of label*/\ntypedef struct\n{\n    /*Inherited from 'base_obj' so no inherited ext.*/  /*Ext. of ancestor*/\n    /*New data for this type */\n    char * text;                            /*Text of the label*/\n    lv_label_long_mode_t long_mode;         /*Determinate what to do with the long texts*/\n#if LV_TXT_UTF8 == 0\n    char dot_tmp[LV_LABEL_DOT_NUM + 1];     /*Store the character which are replaced by dots (Handled by the library)*/\n#else\n    char dot_tmp[LV_LABEL_DOT_NUM * 4 + 1]; /*Store the character which are replaced by dots (Handled by the library)*/\n#endif\n\n#if USE_LV_MULTI_LANG\n    uint16_t lang_txt_id;            /*The ID of the text to display*/\n#endif\n    uint16_t dot_end;               /*The text end position in dot mode (Handled by the library)*/\n    uint16_t anim_speed;            /*Speed of scroll and roll animation in px/sec unit*/\n    lv_point_t offset;              /*Text draw position offset*/\n    uint8_t static_txt  :1;         /*Flag to indicate the text is static*/\n    uint8_t align       :2;         /*Align type from 'lv_label_align_t'*/\n    uint8_t recolor     :1;         /*Enable in-line letter re-coloring*/\n    uint8_t expand      :1;         /*Ignore real width (used by the library with LV_LABEL_LONG_ROLL)*/\n    uint8_t body_draw   :1;         /*Draw background body*/\n} lv_label_ext_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n\n/**\n * Create a label objects\n * @param par pointer to an object, it will be the parent of the new label\n * @param copy pointer to a button object, if not NULL then the new object will be copied from it\n * @return pointer to the created button\n */\nlv_obj_t * lv_label_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a new text for a label. Memory will be allocated to store the text by the label.\n * @param label pointer to a label object\n * @param text '\\0' terminated character string. NULL to refresh with the current text.\n */\nvoid lv_label_set_text(lv_obj_t * label, const char * text);\n\n/**\n * Set a new text for a label from a character array. The array don't has to be '\\0' terminated.\n * Memory will be allocated to store the array by the label.\n * @param label pointer to a label object\n * @param array array of characters or NULL to refresh the label\n * @param size the size of 'array' in bytes\n */\nvoid lv_label_set_array_text(lv_obj_t * label, const char * array, uint16_t size);\n\n/**\n * Set a static text. It will not be saved by the label so the 'text' variable\n * has to be 'alive' while the label exist.\n * @param label pointer to a label object\n * @param text pointer to a text. NULL to refresh with the current text.\n */\nvoid lv_label_set_static_text(lv_obj_t * label, const char * text);\n\n/**\n *Set a text ID which means a the same text but on different languages\n * @param label pointer to a label object\n * @param txt_id ID of the text\n */\n#if USE_LV_MULTI_LANG\nvoid lv_label_set_text_id(lv_obj_t * label, uint32_t txt_id);\n#endif\n\n/**\n * Set the behavior of the label with longer text then the object size\n * @param label pointer to a label object\n * @param long_mode the new mode from 'lv_label_long_mode' enum.\n *                  In LV_LONG_BREAK/LONG/ROLL the size of the label should be set AFTER this function\n */\nvoid lv_label_set_long_mode(lv_obj_t * label, lv_label_long_mode_t long_mode);\n\n/**\n * Set the align of the label (left or center)\n * @param label pointer to a label object\n * @param align 'LV_LABEL_ALIGN_LEFT' or 'LV_LABEL_ALIGN_LEFT'\n */\nvoid lv_label_set_align(lv_obj_t *label, lv_label_align_t align);\n\n/**\n * Enable the recoloring by in-line commands\n * @param label pointer to a label object\n * @param en true: enable recoloring, false: disable\n */\nvoid lv_label_set_recolor(lv_obj_t * label, bool en);\n\n/**\n * Set the label to draw (or not draw) background specified in its style's body\n * @param label pointer to a label object\n * @param en true: draw body; false: don't draw body\n */\nvoid lv_label_set_body_draw(lv_obj_t *label, bool en);\n\n/**\n * Set the label's animation speed in LV_LABEL_LONG_ROLL and SCROLL modes\n * @param label pointer to a label object\n * @param anim_speed speed of animation in px/sec unit\n */\nvoid lv_label_set_anim_speed(lv_obj_t *label, uint16_t anim_speed);\n\n/**\n * Set the style of an label\n * @param label pointer to an label object\n * @param style pointer to a style\n */\nstatic inline void lv_label_set_style(lv_obj_t *label, lv_style_t *style)\n{\n    lv_obj_set_style(label, style);\n}\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the text of a label\n * @param label pointer to a label object\n * @return the text of the label\n */\nchar * lv_label_get_text(const lv_obj_t * label);\n\n#if USE_LV_MULTI_LANG\n/**\n * Get the text ID of the label. (Used by the multi-language feature)\n * @param label pointer to a label object\n * @return ID of the text\n */\nuint16_t lv_label_get_text_id(lv_obj_t * label);\n#endif\n\n/**\n * Get the long mode of a label\n * @param label pointer to a label object\n * @return the long mode\n */\nlv_label_long_mode_t lv_label_get_long_mode(const lv_obj_t * label);\n\n/**\n * Get the align attribute\n * @param label pointer to a label object\n * @return LV_LABEL_ALIGN_LEFT or LV_LABEL_ALIGN_CENTER\n */\nlv_label_align_t lv_label_get_align(const lv_obj_t * label);\n\n/**\n * Get the recoloring attribute\n * @param label pointer to a label object\n * @return true: recoloring is enabled, false: disable\n */\nbool lv_label_get_recolor(const lv_obj_t * label);\n\n/**\n * Get the body draw attribute\n * @param label pointer to a label object\n * @return true: draw body; false: don't draw body\n */\nbool lv_label_get_body_draw(const lv_obj_t *label);\n\n/**\n * Get the label's animation speed in LV_LABEL_LONG_ROLL and SCROLL modes\n * @param label pointer to a label object\n * @return speed of animation in px/sec unit\n */\nuint16_t lv_label_get_anim_speed(const lv_obj_t *label);\n\n/**\n * Get the relative x and y coordinates of a letter\n * @param label pointer to a label object\n * @param index index of the letter [0 ... text length]. Expressed in character index, not byte index (different in UTF-8)\n * @param pos store the result here (E.g. index = 0 gives 0;0 coordinates)\n */\nvoid lv_label_get_letter_pos(const lv_obj_t * label, uint16_t index, lv_point_t * pos);\n\n/**\n * Get the index of letter on a relative point of a label\n * @param label pointer to label object\n * @param pos pointer to point with coordinates on a the label\n * @return the index of the letter on the 'pos_p' point (E.g. on 0;0 is the 0. letter)\n * Expressed in character index and not byte index (different in UTF-8)\n */\nuint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos);\n\n/**\n * Get the style of an label object\n * @param label pointer to an label object\n * @return pointer to the label's style\n */\nstatic inline lv_style_t* lv_label_get_style(const lv_obj_t *label)\n{\n    return lv_obj_get_style(label);\n}\n\n/*=====================\n * Other functions\n *====================*/\n\n/**\n * Insert a text to the label. The label text can not be static.\n * @param label pointer to a label object\n * @param pos character index to insert. Expressed in character index and not byte index (Different in UTF-8)\n *            0: before first char.\n *            LV_LABEL_POS_LAST: after last char.\n * @param txt pointer to the text to insert\n */\nvoid lv_label_ins_text(lv_obj_t * label, uint32_t pos,  const char * txt);\n\n/**\n * Delete characters from a label. The label text can not be static.\n * @param label pointer to a label object\n * @param pos character index to insert. Expressed in character index and not byte index (Different in UTF-8)\n *            0: before first char.\n * @param cnt number of characters to cut\n */\nvoid lv_label_cut_text(lv_obj_t * label, uint32_t pos,  uint32_t cnt);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_LABEL*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_LABEL_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_led.c",
    "content": "/**\n * @file lv_led.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_led.h\"\n#if USE_LV_LED != 0\n\n#include \"../lv_themes/lv_theme.h\"\n#include \"../lv_draw/lv_draw.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_LED_WIDTH_DEF    (LV_DPI / 3)\n#define LV_LED_HEIGHT_DEF   (LV_DPI / 3)\n#define LV_LED_BRIGHT_OFF   100\n#define LV_LED_BRIGHT_ON    255\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool lv_led_design(lv_obj_t * led, const lv_area_t * mask, lv_design_mode_t mode);\nstatic lv_res_t lv_led_signal(lv_obj_t * led, lv_signal_t sign, void * param);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_design_func_t ancestor_design_f;\nstatic lv_signal_func_t ancestor_signal;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a led objects\n * @param par pointer to an object, it will be the parent of the new led\n * @param copy pointer to a led object, if not NULL then the new object will be copied from it\n * @return pointer to the created led\n */\nlv_obj_t * lv_led_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"led create started\");\n\n    /*Create the ancestor basic object*/\n    lv_obj_t * new_led = lv_obj_create(par, copy);\n    lv_mem_assert(new_led);\n    if(new_led == NULL) return NULL;\n\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_led);\n    if(ancestor_design_f == NULL) ancestor_design_f = lv_obj_get_design_func(new_led);\n\n    /*Allocate the object type specific extended data*/\n    lv_led_ext_t * ext = lv_obj_allocate_ext_attr(new_led, sizeof(lv_led_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    ext->bright = LV_LED_BRIGHT_ON;\n\n    lv_obj_set_signal_func(new_led, lv_led_signal);\n    lv_obj_set_design_func(new_led, lv_led_design);\n\n    /*Init the new led object*/\n    if(copy == NULL) {\n        lv_obj_set_size(new_led, LV_LED_WIDTH_DEF, LV_LED_HEIGHT_DEF);\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_led_set_style(new_led, th->led);\n        } else {\n            lv_led_set_style(new_led, &lv_style_pretty_color);\n        }\n    }\n    /*Copy an existing object*/\n    else {\n        lv_led_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        ext->bright = copy_ext->bright;\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_led);\n    }\n\n\n    LV_LOG_INFO(\"led created\");\n\n    return new_led;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set the brightness of a LED object\n * @param led pointer to a LED object\n * @param bright 0 (max. dark) ... 255 (max. light)\n */\nvoid lv_led_set_bright(lv_obj_t * led, uint8_t bright)\n{\n    /*Set the brightness*/\n    lv_led_ext_t * ext = lv_obj_get_ext_attr(led);\n    if(ext->bright == bright) return;\n\n    ext->bright = bright;\n\n    /*Invalidate the object there fore it will be redrawn*/\n    lv_obj_invalidate(led);\n}\n\n/**\n * Light on a LED\n * @param led pointer to a LED object\n */\nvoid lv_led_on(lv_obj_t * led)\n{\n    lv_led_set_bright(led, LV_LED_BRIGHT_ON);\n}\n\n/**\n * Light off a LED\n * @param led pointer to a LED object\n */\nvoid lv_led_off(lv_obj_t * led)\n{\n    lv_led_set_bright(led, LV_LED_BRIGHT_OFF);\n}\n\n\n/**\n * Toggle the state of a LED\n * @param led pointer to a LED object\n */\nvoid lv_led_toggle(lv_obj_t * led)\n{\n    uint8_t bright = lv_led_get_bright(led);\n    if(bright > (LV_LED_BRIGHT_OFF + LV_LED_BRIGHT_ON) >> 1) lv_led_off(led);\n    else lv_led_on(led);\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the brightness of a LEd object\n * @param led pointer to LED object\n * @return bright 0 (max. dark) ... 255 (max. light)\n */\nuint8_t lv_led_get_bright(const lv_obj_t * led)\n{\n    lv_led_ext_t * ext = lv_obj_get_ext_attr(led);\n    return ext->bright;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Handle the drawing related tasks of the leds\n * @param led pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_led_design(lv_obj_t * led, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    if(mode == LV_DESIGN_COVER_CHK) {\n        /*Return false if the object is not covers the mask area*/\n        return ancestor_design_f(led, mask, mode);\n    } else if(mode == LV_DESIGN_DRAW_MAIN) {\n        /*Make darker colors in a temporary style according to the brightness*/\n        lv_led_ext_t * ext = lv_obj_get_ext_attr(led);\n        lv_style_t * style = lv_obj_get_style(led);\n\n        /* Store the real pointer because of 'lv_group'\n         * If the object is in focus 'lv_obj_get_style()' will give a pointer to tmp style\n         * and to the real object style. It is important because of style change tricks below*/\n        lv_style_t * style_ori_p = led->style_p;\n\n        /*Create a temporal style*/\n        lv_style_t leds_tmp;\n        memcpy(&leds_tmp, style, sizeof(leds_tmp));\n\n        /*Mix. the color with black proportionally with brightness*/\n        leds_tmp.body.main_color = lv_color_mix(leds_tmp.body.main_color, LV_COLOR_BLACK, ext->bright);\n        leds_tmp.body.grad_color = lv_color_mix(leds_tmp.body.grad_color, LV_COLOR_BLACK, ext->bright);\n        leds_tmp.body.border.color = lv_color_mix(leds_tmp.body.border.color, LV_COLOR_BLACK, ext->bright);\n\n        /*Set the current swidth according to brightness proportionally between LV_LED_BRIGHT_OFF and LV_LED_BRIGHT_ON*/\n        uint16_t bright_tmp = ext->bright;\n        leds_tmp.body.shadow.width = ((bright_tmp - LV_LED_BRIGHT_OFF) * style->body.shadow.width) / (LV_LED_BRIGHT_ON - LV_LED_BRIGHT_OFF);\n\n        led->style_p = &leds_tmp;\n        ancestor_design_f(led, mask, mode);\n        led->style_p = style_ori_p;                 /*Restore the ORIGINAL style pointer*/\n    }\n    return true;\n}\n\n/**\n * Signal function of the led\n * @param led pointer to a led object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_led_signal(lv_obj_t * led, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(led, sign, param);\n    if(res != LV_RES_OK) return res;\n\n\n    if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_led\";\n    }\n\n    return res;\n}\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_led.h",
    "content": "/**\n * @file lv_led.h\n *\n */\n\n#ifndef LV_LED_H\n#define LV_LED_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_LED != 0\n\n#include \"../lv_core/lv_obj.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/*Data of led*/\ntypedef struct\n{\n    /*No inherited ext.*/\n    /*New data for this type */\n    uint8_t bright;         /*Current brightness of the LED (0..255)*/\n} lv_led_ext_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a led objects\n * @param par pointer to an object, it will be the parent of the new led\n * @param copy pointer to a led object, if not NULL then the new object will be copied from it\n * @return pointer to the created led\n */\nlv_obj_t * lv_led_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/**\n * Set the brightness of a LED object\n * @param led pointer to a LED object\n * @param bright 0 (max. dark) ... 255 (max. light)\n */\nvoid lv_led_set_bright(lv_obj_t * led, uint8_t bright);\n\n/**\n * Light on a LED\n * @param led pointer to a LED object\n */\nvoid lv_led_on(lv_obj_t * led);\n\n/**\n * Light off a LED\n * @param led pointer to a LED object\n */\nvoid lv_led_off(lv_obj_t * led);\n\n/**\n * Toggle the state of a LED\n * @param led pointer to a LED object\n */\nvoid lv_led_toggle(lv_obj_t * led);\n\n/**\n * Set the style of a led\n * @param led pointer to a led object\n * @param style pointer to a style\n */\nstatic inline void lv_led_set_style(lv_obj_t *led, lv_style_t *style)\n{\n    lv_obj_set_style(led, style);\n}\n\n/**\n * Get the brightness of a LEd object\n * @param led pointer to LED object\n * @return bright 0 (max. dark) ... 255 (max. light)\n */\nuint8_t lv_led_get_bright(const lv_obj_t * led);\n\n/**\n * Get the style of an led object\n * @param led pointer to an led object\n * @return pointer to the led's style\n */\nstatic inline lv_style_t* lv_led_get_style(const lv_obj_t *led)\n{\n    return lv_obj_get_style(led);\n}\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_LED*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_LED_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_line.c",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * @file lv_line.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_line.h\"\n\n#if USE_LV_LINE != 0\n#include \"../lv_draw/lv_draw.h\"\n#include \"../lv_misc/lv_math.h\"\n#include <stdint.h>\n#include <string.h>\n\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool lv_line_design(lv_obj_t * line, const lv_area_t * mask, lv_design_mode_t mode);\nstatic lv_res_t lv_line_signal(lv_obj_t * line, lv_signal_t sign, void * param);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a line objects\n * @param par pointer to an object, it will be the parent of the new line\n * @return pointer to the created line\n */\nlv_obj_t * lv_line_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"line create started\");\n\n    /*Create a basic object*/\n    lv_obj_t * new_line = lv_obj_create(par, copy);\n    lv_mem_assert(new_line);\n    if(new_line == NULL) return NULL;\n\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_line);\n\n    /*Extend the basic object to line object*/\n    lv_line_ext_t * ext = lv_obj_allocate_ext_attr(new_line, sizeof(lv_line_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    ext->point_num = 0;\n    ext->point_array = NULL;\n    ext->auto_size = 1;\n    ext->y_inv = 0;\n\n    lv_obj_set_design_func(new_line, lv_line_design);\n    lv_obj_set_signal_func(new_line, lv_line_signal);\n\n    /*Init the new line*/\n    if(copy == NULL) {\n        lv_obj_set_size(new_line, LV_DPI, LV_DPI);  /*Auto size is enables, but set default size until no points are added*/\n        lv_obj_set_style(new_line, NULL);           /*Inherit parent's style*/\n        lv_obj_set_click(new_line, false);\n    }\n    /*Copy an existing object*/\n    else {\n        lv_line_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        lv_line_set_auto_size(new_line, lv_line_get_auto_size(copy));\n        lv_line_set_y_invert(new_line, lv_line_get_y_invert(copy));\n        lv_line_set_auto_size(new_line, lv_line_get_auto_size(copy));\n        lv_line_set_points(new_line, copy_ext->point_array, copy_ext->point_num);\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_line);\n    }\n\n\n    LV_LOG_INFO(\"line created\");\n\n    return new_line;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set an array of points. The line object will connect these points.\n * @param line pointer to a line object\n * @param point_a an array of points. Only the address is saved,\n * so the array can NOT be a local variable which will be destroyed\n * @param point_num number of points in 'point_a'\n */\nvoid lv_line_set_points(lv_obj_t * line, const lv_point_t * point_a, uint16_t point_num)\n{\n    lv_line_ext_t * ext = lv_obj_get_ext_attr(line);\n    ext->point_array = point_a;\n    ext->point_num = point_num;\n\n    if(point_num > 0 && ext->auto_size != 0) {\n        uint16_t i;\n        lv_coord_t xmax = LV_COORD_MIN;\n        lv_coord_t ymax = LV_COORD_MIN;\n        for(i = 0; i < point_num; i++) {\n            xmax = LV_MATH_MAX(point_a[i].x, xmax);\n            ymax = LV_MATH_MAX(point_a[i].y, ymax);\n        }\n\n        lv_style_t * style = lv_line_get_style(line);\n        lv_obj_set_size(line, xmax + style->line.width, ymax + style->line.width);\n    }\n\n    lv_obj_invalidate(line);\n}\n\n/**\n * Enable (or disable) the auto-size option. The size of the object will fit to its points.\n * (set width to x max and height to y max)\n * @param line pointer to a line object\n * @param en true: auto size is enabled, false: auto size is disabled\n */\nvoid lv_line_set_auto_size(lv_obj_t * line, bool en)\n{\n    lv_line_ext_t * ext = lv_obj_get_ext_attr(line);\n    if(ext->auto_size == en) return;\n\n    ext->auto_size = en == false ? 0 : 1;\n\n    /*Refresh the object*/\n    if(en) lv_line_set_points(line, ext->point_array, ext->point_num);\n}\n\n/**\n * Enable (or disable) the y coordinate inversion.\n * If enabled then y will be subtracted from the height of the object,\n * therefore the y=0 coordinate will be on the bottom.\n * @param line pointer to a line object\n * @param en true: enable the y inversion, false:disable the y inversion\n */\nvoid lv_line_set_y_invert(lv_obj_t * line, bool en)\n{\n    lv_line_ext_t * ext = lv_obj_get_ext_attr(line);\n    if(ext->y_inv == en) return;\n\n    ext->y_inv = en == false ? 0 : 1;\n\n    lv_obj_invalidate(line);\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the auto size attribute\n * @param line pointer to a line object\n * @return true: auto size is enabled, false: disabled\n */\nbool lv_line_get_auto_size(const lv_obj_t * line)\n{\n    lv_line_ext_t * ext = lv_obj_get_ext_attr(line);\n\n    return ext->auto_size == 0 ? false : true;\n}\n\n/**\n * Get the y inversion attribute\n * @param line pointer to a line object\n * @return true: y inversion is enabled, false: disabled\n */\nbool lv_line_get_y_invert(const lv_obj_t * line)\n{\n    lv_line_ext_t * ext = lv_obj_get_ext_attr(line);\n\n    return ext->y_inv == 0 ? false : true;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Handle the drawing related tasks of the lines\n * @param line pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_line_design(lv_obj_t * line, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    /*A line never covers an area*/\n    if(mode == LV_DESIGN_COVER_CHK) return false;\n    else if(mode == LV_DESIGN_DRAW_MAIN) {\n        lv_line_ext_t * ext = lv_obj_get_ext_attr(line);\n\n        if(ext->point_num == 0 || ext->point_array == NULL) return false;\n\n        lv_style_t * style = lv_obj_get_style(line);\n        lv_opa_t opa_scale = lv_obj_get_opa_scale(line);\n        lv_area_t area;\n        lv_obj_get_coords(line, &area);\n        lv_coord_t x_ofs = area.x1;\n        lv_coord_t y_ofs = area.y1;\n        lv_point_t p1;\n        lv_point_t p2;\n        lv_coord_t h = lv_obj_get_height(line);\n        uint16_t i;\n\n        lv_style_t circle_style;    /*If rounded...*/\n        lv_style_copy(&circle_style, style);\n        circle_style.body.radius = LV_RADIUS_CIRCLE;\n        circle_style.body.main_color = style->line.color;\n        circle_style.body.grad_color = style->line.color;\n        circle_style.body.opa = style->line.opa;\n        lv_area_t circle_area;\n\n        /*Read all points and draw the lines*/\n        for(i = 0; i < ext->point_num - 1; i++) {\n\n            p1.x = ext->point_array[i].x + x_ofs;\n            p2.x = ext->point_array[i + 1].x + x_ofs;\n\n            if(ext->y_inv == 0) {\n                p1.y = ext->point_array[i].y + y_ofs;\n                p2.y = ext->point_array[i + 1].y + y_ofs;\n            } else {\n                p1.y = h - ext->point_array[i].y  + y_ofs;\n                p2.y = h - ext->point_array[i + 1].y + y_ofs;\n            }\n            lv_draw_line(&p1, &p2, mask, style, opa_scale);\n\n            /*Draw circle on the joints if enabled*/\n            if(style->line.rounded) {\n                circle_area.x1 = p1.x - ((style->line.width - 1) >> 1) - ((style->line.width - 1) & 0x1);\n                circle_area.y1 = p1.y - ((style->line.width - 1) >> 1) - ((style->line.width - 1) & 0x1);\n                circle_area.x2 = p1.x + ((style->line.width - 1) >> 1);\n                circle_area.y2 = p1.y + ((style->line.width - 1) >> 1);\n                lv_draw_rect(&circle_area, mask, &circle_style, opa_scale);\n            }\n        }\n\n        /*Draw circle on the last point too if enabled*/\n        if(style->line.rounded) {\n            circle_area.x1 = p2.x - ((style->line.width - 1) >> 1) - ((style->line.width - 1) & 0x1);\n            circle_area.y1 = p2.y - ((style->line.width - 1) >> 1) - ((style->line.width - 1) & 0x1);\n            circle_area.x2 = p2.x + ((style->line.width - 1) >> 1);\n            circle_area.y2 = p2.y + ((style->line.width - 1) >> 1);\n            lv_draw_rect(&circle_area, mask, &circle_style, opa_scale);\n        }\n    }\n    return true;\n}\n\n/**\n * Signal function of the line\n * @param line pointer to a line object\n * @param sign a signal type from lv_signal_t enum\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_line_signal(lv_obj_t * line, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(line, sign, param);\n    if(res != LV_RES_OK) return res;\n\n\n    if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_line\";\n    } else if(sign == LV_SIGNAL_REFR_EXT_SIZE) {\n        lv_style_t * style = lv_line_get_style(line);\n        if(line->ext_size < style->line.width) line->ext_size = style->line.width;\n    }\n\n\n    return res;\n}\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_line.h",
    "content": "/**\n * @file lv_line.h\n *\n */\n\n#ifndef LV_LINE_H\n#define LV_LINE_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_LINE != 0\n\n#include \"../lv_core/lv_obj.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/*Data of line*/\ntypedef struct\n{\n    /*Inherited from 'base_obj' so no inherited ext.*/  /*Ext. of ancestor*/\n    const lv_point_t * point_array;    /*Pointer to an array with the points of the line*/\n    uint16_t  point_num;            /*Number of points in 'point_array' */\n    uint8_t  auto_size  :1;         /*1: set obj. width to x max and obj. height to y max */\n    uint8_t  y_inv      :1;         /*1: y == 0 will be on the bottom*/\n} lv_line_ext_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n\n/**\n * Create a line objects\n * @param par pointer to an object, it will be the parent of the new line\n * @return pointer to the created line\n */\nlv_obj_t * lv_line_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set an array of points. The line object will connect these points.\n * @param line pointer to a line object\n * @param point_a an array of points. Only the address is saved,\n * so the array can NOT be a local variable which will be destroyed\n * @param point_num number of points in 'point_a'\n */\nvoid lv_line_set_points(lv_obj_t * line, const lv_point_t * point_a, uint16_t point_num);\n\n/**\n * Enable (or disable) the auto-size option. The size of the object will fit to its points.\n * (set width to x max and height to y max)\n * @param line pointer to a line object\n * @param en true: auto size is enabled, false: auto size is disabled\n */\nvoid lv_line_set_auto_size(lv_obj_t * line, bool en);\n\n/**\n * Enable (or disable) the y coordinate inversion.\n * If enabled then y will be subtracted from the height of the object,\n * therefore the y=0 coordinate will be on the bottom.\n * @param line pointer to a line object\n * @param en true: enable the y inversion, false:disable the y inversion\n */\nvoid lv_line_set_y_invert(lv_obj_t * line, bool en);\n\n#define lv_line_set_y_inv lv_line_set_y_invert      /*The name was inconsistent. In v.6.0 only `lv_line_set_y_invert`will work */\n\n/**\n * Set the style of a line\n * @param line pointer to a line object\n * @param style pointer to a style\n */\nstatic inline void lv_line_set_style(lv_obj_t *line, lv_style_t *style)\n{\n    lv_obj_set_style(line, style);\n}\n\n/**\n * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0\n * @param line -\n * @param upscale -\n */\nstatic inline void lv_line_set_upscale(lv_obj_t * line, bool upcale)\n{\n    (void) line;\n    (void) upcale;\n}\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the auto size attribute\n * @param line pointer to a line object\n * @return true: auto size is enabled, false: disabled\n */\nbool lv_line_get_auto_size(const lv_obj_t * line);\n\n/**\n * Get the y inversion attribute\n * @param line pointer to a line object\n * @return true: y inversion is enabled, false: disabled\n */\nbool lv_line_get_y_invert(const lv_obj_t * line);\n\n/**\n * Get the style of an line object\n * @param line pointer to an line object\n * @return pointer to the line's style\n */\nstatic inline lv_style_t* lv_line_get_style(const lv_obj_t *line)\n{\n    return lv_obj_get_style(line);\n}\n\n/**\n * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0\n * @param line -\n * @return false\n */\nstatic inline bool lv_line_get_upscale(const lv_obj_t * line)\n{\n    (void) line;\n    return false;\n}\n\n\n/**********************\n *      MACROS\n **********************/\n\n#endif /*USE_LV_LINE*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_LINE_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_list.c",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * @file lv_list.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_list.h\"\n#if USE_LV_LIST != 0\n\n#include \"../lv_core/lv_group.h\"\n#include \"../lv_themes/lv_theme.h\"\n#include \"../lv_misc/lv_anim.h\"\n#include \"../lv_misc/lv_math.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_LIST_LAYOUT_DEF  LV_LAYOUT_COL_M\n\n#if USE_LV_ANIMATION\n#  ifndef LV_LIST_FOCUS_TIME\n#    define LV_LIST_FOCUS_TIME  100 /*Animation time of focusing to the a list element [ms] (0: no animation)  */\n#  endif\n#else\n#  undef  LV_LIST_FOCUS_TIME\n#  define LV_LIST_FOCUS_TIME    0   /*No animations*/\n#endif\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic lv_res_t lv_list_signal(lv_obj_t * list, lv_signal_t sign, void * param);\nstatic lv_res_t lv_list_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param);\nstatic void refr_btn_width(lv_obj_t * list);\nstatic void lv_list_btn_single_selected(lv_obj_t *btn);\nstatic bool lv_list_is_list_btn(lv_obj_t * list_btn);\nstatic bool lv_list_is_list_img(lv_obj_t * list_btn);\nstatic bool lv_list_is_list_label(lv_obj_t * list_btn);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n#if USE_LV_IMG\nstatic lv_signal_func_t img_signal;\n#endif\nstatic lv_signal_func_t label_signal;\nstatic lv_signal_func_t ancestor_page_signal;\nstatic lv_signal_func_t ancestor_btn_signal;\n#if USE_LV_GROUP\n/*Used to make the last clicked button pressed (selected) when the list become focused and `click_focus == 1`*/\nstatic lv_obj_t * last_clicked_btn;\n#endif\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a list objects\n * @param par pointer to an object, it will be the parent of the new list\n * @param copy pointer to a list object, if not NULL then the new object will be copied from it\n * @return pointer to the created list\n */\nlv_obj_t * lv_list_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"list create started\");\n\n    /*Create the ancestor basic object*/\n    lv_obj_t * new_list = lv_page_create(par, copy);\n    lv_mem_assert(new_list);\n    if(new_list == NULL) return NULL;\n\n    if(ancestor_page_signal == NULL) ancestor_page_signal = lv_obj_get_signal_func(new_list);\n\n    lv_list_ext_t * ext = lv_obj_allocate_ext_attr(new_list, sizeof(lv_list_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n\t// Important!\n    static lv_style_t img_btn_color;\n    lv_style_copy( &img_btn_color, &lv_style_plain);\n    img_btn_color.image.color = LV_COLOR_HEX(0xDDDDDD);\n    img_btn_color.image.intense = LV_OPA_50;\n    ext->style_img = &img_btn_color;\n    ext->styles_btn[LV_BTN_STATE_REL] = &lv_style_btn_rel;\n    ext->styles_btn[LV_BTN_STATE_PR] = &lv_style_btn_pr;\n    ext->styles_btn[LV_BTN_STATE_TGL_REL] = &lv_style_btn_tgl_rel;\n    ext->styles_btn[LV_BTN_STATE_TGL_PR] = &lv_style_btn_tgl_pr;\n    ext->styles_btn[LV_BTN_STATE_INA] = &lv_style_btn_ina;\n    ext->anim_time = LV_LIST_FOCUS_TIME;\n    ext->single_mode = false;\n    ext->size = 0;\n\n#if USE_LV_GROUP\n    ext->last_sel = NULL;\n    ext->selected_btn = NULL;\n#endif\n\n    lv_obj_set_signal_func(new_list, lv_list_signal);\n\n    /*Init the new list object*/\n    if(copy == NULL) {\n        lv_obj_set_size(new_list, 2 * LV_DPI, 3 * LV_DPI);\n        lv_page_set_scrl_layout(new_list, LV_LIST_LAYOUT_DEF);\n        lv_list_set_sb_mode(new_list, LV_SB_MODE_DRAG);\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_list_set_style(new_list, LV_LIST_STYLE_BG, th->list.bg);\n            lv_list_set_style(new_list, LV_LIST_STYLE_SCRL, th->list.scrl);\n            lv_list_set_style(new_list, LV_LIST_STYLE_SB, th->list.sb);\n            lv_list_set_style(new_list, LV_LIST_STYLE_BTN_REL, th->list.btn.rel);\n            lv_list_set_style(new_list, LV_LIST_STYLE_BTN_PR, th->list.btn.pr);\n            lv_list_set_style(new_list, LV_LIST_STYLE_BTN_TGL_REL, th->list.btn.tgl_rel);\n            lv_list_set_style(new_list, LV_LIST_STYLE_BTN_TGL_PR, th->list.btn.tgl_pr);\n            lv_list_set_style(new_list, LV_LIST_STYLE_BTN_INA, th->list.btn.ina);\n        } else {\n            lv_list_set_style(new_list, LV_LIST_STYLE_BG, &lv_style_transp_fit);\n            lv_list_set_style(new_list, LV_LIST_STYLE_SCRL, &lv_style_pretty);\n        }\n    } else {\n        lv_list_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n\n        lv_obj_t * copy_btn = lv_list_get_next_btn(copy, NULL);\n        while(copy_btn) {\n            const void * img_src = NULL;\n#if USE_LV_IMG\n            lv_obj_t * copy_img = lv_list_get_btn_img(copy_btn);\n            if(copy_img) img_src = lv_img_get_src(copy_img);\n#endif\n            lv_list_add(new_list, img_src, lv_list_get_btn_text(copy_btn), lv_btn_get_action(copy_btn, LV_BTN_ACTION_CLICK));\n            copy_btn = lv_list_get_next_btn(copy, copy_btn);\n        }\n\n        lv_list_set_style(new_list, LV_LIST_STYLE_BTN_REL, copy_ext->styles_btn[LV_BTN_STATE_REL]);\n        lv_list_set_style(new_list, LV_LIST_STYLE_BTN_PR, copy_ext->styles_btn[LV_BTN_STATE_PR]);\n        lv_list_set_style(new_list, LV_LIST_STYLE_BTN_TGL_REL, copy_ext->styles_btn[LV_BTN_STATE_TGL_REL]);\n        lv_list_set_style(new_list, LV_LIST_STYLE_BTN_TGL_PR, copy_ext->styles_btn[LV_BTN_STATE_TGL_REL]);\n        lv_list_set_style(new_list, LV_LIST_STYLE_BTN_INA, copy_ext->styles_btn[LV_BTN_STATE_INA]);\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_list);\n    }\n\n\n    LV_LOG_INFO(\"list created\");\n\n\n    return new_list;\n}\n\n/**\n * Delete all children of the scrl object, without deleting scrl child.\n * @param obj pointer to an object\n */\nvoid lv_list_clean(lv_obj_t * obj)\n{\n    lv_obj_t * scrl = lv_page_get_scrl(obj);\n    lv_obj_clean(scrl);\n    lv_list_ext_t * ext = lv_obj_get_ext_attr(obj);\n    ext->size = 0;\n}\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n/**\n * Add a list element to the list\n * @param list pointer to list object\n * @param img_fn file name of an image before the text (NULL if unused)\n * @param txt text of the list element (NULL if unused)\n * @param rel_action pointer to release action function (like with lv_btn)\n * @return pointer to the new list element which can be customized (a button)\n */\nlv_obj_t * lv_list_add(lv_obj_t * list, const void * img_src, const char * txt, lv_action_t rel_action)\n{\n    lv_style_t * style = lv_obj_get_style(list);\n    lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n    ext->size ++;\n    /*Create a list element with the image an the text*/\n    lv_obj_t * liste;\n    liste = lv_btn_create(list, NULL);\n\n    /*Save the original signal function because it will be required in `lv_list_btn_signal`*/\n    if(ancestor_btn_signal == NULL) ancestor_btn_signal = lv_obj_get_signal_func(liste);\n\n    /*Set the default styles*/\n    lv_btn_set_style(liste, LV_BTN_STYLE_REL, ext->styles_btn[LV_BTN_STATE_REL]);\n    lv_btn_set_style(liste, LV_BTN_STYLE_PR, ext->styles_btn[LV_BTN_STATE_PR]);\n    lv_btn_set_style(liste, LV_BTN_STYLE_TGL_REL, ext->styles_btn[LV_BTN_STATE_TGL_REL]);\n    lv_btn_set_style(liste, LV_BTN_STYLE_TGL_PR, ext->styles_btn[LV_BTN_STATE_TGL_PR]);\n    lv_btn_set_style(liste, LV_BTN_STYLE_INA, ext->styles_btn[LV_BTN_STATE_INA]);\n\n    lv_btn_set_action(liste, LV_BTN_ACTION_CLICK, rel_action);\n    lv_page_glue_obj(liste, true);\n    lv_btn_set_layout(liste, LV_LAYOUT_ROW_M);\n    lv_btn_set_fit(liste, false, true);\n    lv_obj_set_protect(liste, LV_PROTECT_PRESS_LOST);\n    lv_obj_set_signal_func(liste, lv_list_btn_signal);\n\n    /*Make the size adjustment*/\n    lv_coord_t w = lv_obj_get_width(list);\n    lv_style_t  * style_scrl = lv_obj_get_style(lv_page_get_scrl(list));\n    lv_coord_t pad_hor_tot = style->body.padding.hor + style_scrl->body.padding.hor;\n    w -= pad_hor_tot * 2;\n\n    lv_obj_set_width(liste, w);\n#if USE_LV_IMG != 0\n    lv_obj_t * img = NULL;\n    if(img_src) {\n        img = lv_img_create(liste, NULL);\n        lv_img_set_src(img, img_src);\n        lv_obj_set_style(img, ext->style_img);\n        lv_obj_set_click(img, false);\n        if(img_signal == NULL) img_signal = lv_obj_get_signal_func(img);\n    }\n#endif\n    if(txt != NULL) {\n        lv_coord_t btn_hor_pad = ext->styles_btn[LV_BTN_STYLE_REL]->body.padding.hor;\n        lv_obj_t * label = lv_label_create(liste, NULL);\n        lv_label_set_text(label, txt);\n        lv_obj_set_click(label, false);\n        lv_label_set_long_mode(label, LV_LABEL_LONG_ROLL);\n        lv_obj_set_width(label, liste->coords.x2 - label->coords.x1 - btn_hor_pad);\n        if(label_signal == NULL) label_signal = lv_obj_get_signal_func(label);\n    }\n#if USE_LV_GROUP\n    /* If this is the first item to be added to the list and the list is\n     * focussed, select it */\n    {\n        lv_group_t *g = lv_obj_get_group(list);\n        if(ext->size == 1 && lv_group_get_focused(g) == list) {\n            lv_list_set_btn_selected(list, liste);\n        }\n    }\n#endif\n\n    return liste;\n}\n\n/**\n * Remove the index of the button in the list\n * @param list pointer to a list object\n * @param index pointer to a the button's index in the list, index must be 0 <= index < lv_list_ext_t.size\n * @return true: successfully deleted\n */\nbool lv_list_remove(const lv_obj_t * list, uint32_t index)\n{\n    lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n    if(index >= ext->size) return false;\n    uint32_t count = 0;\n    lv_obj_t * e = lv_list_get_next_btn(list, NULL);\n    while(e != NULL) {\n        if(count == index) {\n            lv_obj_del(e);\n            ext->size --;\n            return true;\n        }\n        e = lv_list_get_next_btn(list, e);\n        count ++;\n    }\n    return false;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set single button selected mode, only one button will be selected if enabled.\n * @param list pointer to the currently pressed list object\n * @param mode, enable(true)/disable(false) single selected mode.\n */\nvoid lv_list_set_single_mode(lv_obj_t *list, bool mode)\n{\n    lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n\n    ext->single_mode = mode;\n}\n\n#if USE_LV_GROUP\n\n/**\n * Make a button selected\n * @param list pointer to a list object\n * @param btn pointer to a button to selectthe\n */\nvoid lv_list_set_btn_selected(lv_obj_t * list, lv_obj_t * btn)\n{\n    lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n\n    if(ext->selected_btn) {\n        lv_btn_state_t s = lv_btn_get_state(ext->selected_btn);\n        if(s == LV_BTN_STATE_PR) lv_btn_set_state(ext->selected_btn, LV_BTN_STATE_REL);\n        else if(s == LV_BTN_STATE_TGL_PR) lv_btn_set_state(ext->selected_btn, LV_BTN_STATE_TGL_REL);\n    }\n\n    ext->selected_btn = btn;\n    if( btn != NULL ) {\n        ext->last_sel = btn;\n    }\n\n    if(ext->selected_btn) {\n        lv_btn_state_t s = lv_btn_get_state(ext->selected_btn);\n        if(s == LV_BTN_STATE_REL) lv_btn_set_state(ext->selected_btn, LV_BTN_STATE_PR);\n        else if(s == LV_BTN_STATE_TGL_REL) lv_btn_set_state(ext->selected_btn, LV_BTN_STATE_TGL_PR);\n\n        lv_page_focus(list, ext->selected_btn, ext->anim_time);\n    }\n}\n\n#endif\n\n/**\n * Set scroll animation duration on 'list_up()' 'list_down()' 'list_focus()'\n * @param list pointer to a list object\n * @param anim_time duration of animation [ms]\n */\nvoid lv_list_set_anim_time(lv_obj_t * list, uint16_t anim_time)\n{\n    lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n#if USE_LV_ANIMATION == 0\n    anim_time = 0;\n#endif\n\n    if(ext->anim_time == anim_time) return;\n    ext->anim_time = anim_time;\n}\n\n/**\n * Set a style of a list\n * @param list pointer to a list object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_list_set_style(lv_obj_t * list, lv_list_style_t type, lv_style_t * style)\n{\n    lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n    lv_btn_style_t btn_style_refr = LV_BTN_STYLE_REL;\n    lv_obj_t * btn;\n\n    switch(type) {\n        case LV_LIST_STYLE_BG:\n            lv_page_set_style(list, LV_PAGE_STYLE_BG, style);\n            /*style change signal will call 'refr_btn_width' */\n            break;\n        case LV_LIST_STYLE_SCRL:\n            lv_page_set_style(list, LV_PAGE_STYLE_SCRL, style);\n            refr_btn_width(list);\n            break;\n        case LV_LIST_STYLE_SB:\n            lv_page_set_style(list, LV_PAGE_STYLE_SB, style);\n            break;\n        case LV_LIST_STYLE_EDGE_FLASH:\n            lv_page_set_style(list, LV_PAGE_STYLE_EDGE_FLASH, style);\n            break;\n        case LV_LIST_STYLE_BTN_REL:\n            ext->styles_btn[LV_BTN_STATE_REL] = style;\n            btn_style_refr = LV_BTN_STYLE_REL;\n            break;\n        case LV_LIST_STYLE_BTN_PR:\n            ext->styles_btn[LV_BTN_STATE_PR] = style;\n            btn_style_refr = LV_BTN_STYLE_PR;\n            break;\n        case LV_LIST_STYLE_BTN_TGL_REL:\n            ext->styles_btn[LV_BTN_STATE_TGL_REL] = style;\n            btn_style_refr = LV_BTN_STYLE_TGL_REL;\n            break;\n        case LV_LIST_STYLE_BTN_TGL_PR:\n            ext->styles_btn[LV_BTN_STATE_TGL_PR] = style;\n            btn_style_refr = LV_BTN_STYLE_TGL_PR;\n            break;\n        case LV_LIST_STYLE_BTN_INA:\n            ext->styles_btn[LV_BTN_STATE_INA] = style;\n            btn_style_refr = LV_BTN_STYLE_INA;\n            break;\n    }\n\n\n    /*Refresh existing buttons' style*/\n    if(type == LV_LIST_STYLE_BTN_PR || type == LV_LIST_STYLE_BTN_REL ||\n            type == LV_LIST_STYLE_BTN_TGL_REL || type == LV_LIST_STYLE_BTN_TGL_PR ||\n            type == LV_LIST_STYLE_BTN_INA) {\n        btn = lv_list_get_prev_btn(list, NULL);\n        while(btn != NULL) {\n            lv_btn_set_style(btn, btn_style_refr, ext->styles_btn[btn_style_refr]);\n            btn = lv_list_get_prev_btn(list, btn);\n        }\n    }\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get single button selected mode.\n * @param list pointer to the currently pressed list object.\n */\nbool lv_list_get_single_mode(lv_obj_t *list)\n{\n    lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n\n    return (ext->single_mode);\n}\n\n/**\n * Get the text of a list element\n * @param btn pointer to list element\n * @return pointer to the text\n */\nconst char * lv_list_get_btn_text(const lv_obj_t * btn)\n{\n    lv_obj_t * label = lv_list_get_btn_label(btn);\n    if(label == NULL) return \"\";\n    return lv_label_get_text(label);\n}\n\n/**\n * Get the label object from a list element\n * @param btn pointer to a list element (button)\n * @return pointer to the label from the list element or NULL if not found\n */\nlv_obj_t * lv_list_get_btn_label(const lv_obj_t * btn)\n{\n    lv_obj_t * label = lv_obj_get_child(btn, NULL);\n    if(label == NULL) return NULL;\n\n    while(lv_list_is_list_label(label) == false) {\n        label = lv_obj_get_child(btn, label);\n        if(label == NULL) break;\n    }\n\n    return label;\n}\n\n/**\n * Get the image object from a list element\n * @param btn pointer to a list element (button)\n * @return pointer to the image from the list element or NULL if not found\n */\nlv_obj_t * lv_list_get_btn_img(const lv_obj_t * btn)\n{\n#if USE_LV_IMG != 0\n    lv_obj_t * img = lv_obj_get_child(btn, NULL);\n    if(img == NULL) return NULL;\n\n    while(lv_list_is_list_img(img) == false) {\n        img = lv_obj_get_child(btn, img);\n        if(img == NULL) break;\n    }\n\n    return img;\n#else\n    return NULL;\n#endif\n}\n\n/**\n * Get the previous button from list. (Starts from the top button)\n * @param list pointer to a list object\n * @param prev_btn pointer to button. Search the previous before it.\n * @return pointer to the previous button or NULL when no more buttons\n */\nlv_obj_t * lv_list_get_prev_btn(const lv_obj_t * list, lv_obj_t * prev_btn)\n{\n    /* Not a good practice but user can add/create objects to the lists manually.\n     * When getting the next button try to be sure that it is at least a button */\n\n    lv_obj_t * btn ;\n    lv_obj_t * scrl = lv_page_get_scrl(list);\n\n    btn = lv_obj_get_child(scrl, prev_btn);\n    if(btn == NULL) return NULL;\n\n    while(lv_list_is_list_btn(btn) == false) {\n        btn = lv_obj_get_child(scrl, btn);\n        if(btn == NULL) break;\n    }\n\n    return btn;\n}\n\n\n\n /**\n * Get the next button from list. (Starts from the bottom button)\n * @param list pointer to a list object\n * @param prev_btn pointer to button. Search the next after it.\n * @return pointer to the next button or NULL when no more buttons\n */\nlv_obj_t * lv_list_get_next_btn(const lv_obj_t * list, lv_obj_t * prev_btn)\n{\n    /* Not a good practice but user can add/create objects to the lists manually.\n     * When getting the next button try to be sure that it is at least a button */\n\n    lv_obj_t * btn ;\n    lv_obj_t * scrl = lv_page_get_scrl(list);\n\n    btn = lv_obj_get_child_back(scrl, prev_btn);\n    if(btn == NULL) return NULL;\n\n    while(lv_list_is_list_btn(btn) == false) {\n        btn = lv_obj_get_child_back(scrl, btn);\n        if(btn == NULL) break;\n    }\n\n    return btn;\n}\n\n/**\n * Get the index of the button in the list\n * @param list pointer to a list object. If NULL, assumes btn is part of a list.\n * @param btn pointer to a list element (button)\n * @return the index of the button in the list, or -1 of the button not in this list\n */\nint32_t lv_list_get_btn_index(const lv_obj_t * list, const lv_obj_t * btn)\n{\n    int index = 0;\n    if( list == NULL ){\n        /* no list provided, assuming btn is part of a list */\n        list = lv_obj_get_parent(lv_obj_get_parent(btn));\n    }\n    lv_obj_t * e = lv_list_get_next_btn(list, NULL);\n    while(e != NULL) {\n        if(e == btn) {\n            return index;\n        }\n        index ++;\n        e = lv_list_get_next_btn(list, e);\n    }\n    return -1;\n}\n\n/**\n * Get the number of buttons in the list\n * @param list pointer to a list object\n * @return the number of buttons in the list\n */\nuint32_t lv_list_get_size(const lv_obj_t * list)\n{\n    lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n    return ext->size;\n}\n\n#if USE_LV_GROUP\n/**\n * Get the currently selected button\n * @param list pointer to a list object\n * @return pointer to the selected button\n */\nlv_obj_t * lv_list_get_btn_selected(const lv_obj_t * list)\n{\n    lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n    return ext->selected_btn;\n}\n\n#endif\n\n/**\n * Get scroll animation duration\n * @param list pointer to a list object\n * @return duration of animation [ms]\n */\nuint16_t lv_list_get_anim_time(const lv_obj_t * list)\n{\n    lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n    return ext->anim_time;\n}\n\n/**\n * Get a style of a list\n * @param list pointer to a list object\n * @param type which style should be get\n * @return style pointer to a style\n *  */\nlv_style_t * lv_list_get_style(const lv_obj_t * list, lv_list_style_t type)\n{\n    lv_style_t * style = NULL;\n    lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n\n    switch(type) {\n        case LV_LIST_STYLE_BG:\n            style = lv_page_get_style(list, LV_PAGE_STYLE_BG);\n            break;\n        case LV_LIST_STYLE_SCRL:\n            style = lv_page_get_style(list, LV_PAGE_STYLE_SB);\n            break;\n        case LV_LIST_STYLE_SB:\n            style = lv_page_get_style(list, LV_PAGE_STYLE_SCRL);\n            break;\n        case LV_LIST_STYLE_EDGE_FLASH:\n            style = lv_page_get_style(list, LV_PAGE_STYLE_EDGE_FLASH);\n            break;\n        case LV_LIST_STYLE_BTN_REL:\n            style = ext->styles_btn[LV_BTN_STATE_REL];\n            break;\n        case LV_LIST_STYLE_BTN_PR:\n            style = ext->styles_btn[LV_BTN_STATE_PR];\n            break;\n        case LV_LIST_STYLE_BTN_TGL_REL:\n            style = ext->styles_btn[LV_BTN_STATE_TGL_REL];\n            break;\n        case LV_LIST_STYLE_BTN_TGL_PR:\n            style = ext->styles_btn[LV_BTN_STATE_TGL_PR];\n            break;\n        case LV_LIST_STYLE_BTN_INA:\n            style = ext->styles_btn[LV_BTN_STATE_INA];\n            break;\n        default:\n            style = NULL;\n            break;\n    }\n\n    return style;\n}\n/*=====================\n * Other functions\n *====================*/\n\n/**\n * Move the list elements up by one\n * @param list pointer a to list object\n */\nvoid lv_list_up(const lv_obj_t * list)\n{\n    /*Search the first list element which 'y' coordinate is below the parent\n     * and position the list to show this element on the bottom*/\n    lv_obj_t * scrl = lv_page_get_scrl(list);\n    lv_obj_t * e;\n    lv_obj_t * e_prev = NULL;\n    e = lv_list_get_prev_btn(list, NULL);\n    while(e != NULL) {\n        if(e->coords.y2 <= list->coords.y2) {\n            if(e_prev != NULL) {\n                lv_coord_t new_y = lv_obj_get_height(list) - (lv_obj_get_y(e_prev) + lv_obj_get_height(e_prev));\n                lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n                if(ext->anim_time == 0) {\n                    lv_obj_set_y(scrl, new_y);\n                } else {\n#if USE_LV_ANIMATION\n                    lv_anim_t a;\n                    a.var = scrl;\n                    a.start = lv_obj_get_y(scrl);\n                    a.end = new_y;\n                    a.fp = (lv_anim_fp_t)lv_obj_set_y;\n                    a.path = lv_anim_path_linear;\n                    a.end_cb = NULL;\n                    a.act_time = 0;\n                    a.time = LV_LIST_FOCUS_TIME;\n                    a.playback = 0;\n                    a.playback_pause = 0;\n                    a.repeat = 0;\n                    a.repeat_pause = 0;\n                    lv_anim_create(&a);\n#endif\n                }\n            }\n            break;\n        }\n        e_prev = e;\n        e = lv_list_get_prev_btn(list, e);\n    }\n}\n\n/**\n * Move the list elements down by one\n * @param list pointer to a list object\n */\nvoid lv_list_down(const lv_obj_t * list)\n{\n    /*Search the first list element which 'y' coordinate is above the parent\n     * and position the list to show this element on the top*/\n    lv_obj_t * scrl = lv_page_get_scrl(list);\n    lv_obj_t * e;\n    e = lv_list_get_prev_btn(list, NULL);\n    while(e != NULL) {\n        if(e->coords.y1 < list->coords.y1) {\n            lv_coord_t new_y = -lv_obj_get_y(e);\n            lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n            if(ext->anim_time == 0) {\n                lv_obj_set_y(scrl, new_y);\n            } else {\n#if USE_LV_ANIMATION\n                lv_anim_t a;\n                a.var = scrl;\n                a.start = lv_obj_get_y(scrl);\n                a.end = new_y;\n                a.fp = (lv_anim_fp_t)lv_obj_set_y;\n                a.path = lv_anim_path_linear;\n                a.end_cb = NULL;\n                a.act_time = 0;\n                a.time = LV_LIST_FOCUS_TIME;\n                a.playback = 0;\n                a.playback_pause = 0;\n                a.repeat = 0;\n                a.repeat_pause = 0;\n                lv_anim_create(&a);\n\n#endif\n            }\n            break;\n        }\n        e = lv_list_get_prev_btn(list, e);\n    }\n}\n\n/**\n * Focus on a list button. It ensures that the button will be visible on the list.\n * @param btn pointer to a list button to focus\n * @param anim_en true: scroll with animation, false: without animation\n */\nvoid lv_list_focus(const lv_obj_t * btn, bool anim_en)\n{\n\n#if USE_LV_ANIMATION == 0\n    anim_en = false;\n#endif\n\n    lv_obj_t * list = lv_obj_get_parent(lv_obj_get_parent(btn));\n\n    lv_page_focus(list, btn, anim_en == false ? 0 : lv_list_get_anim_time(list));\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Signal function of the list\n * @param list pointer to a list object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_list_signal(lv_obj_t * list, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_page_signal(list, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    if(sign == LV_SIGNAL_CORD_CHG) {\n        /*Be sure the width of the buttons are correct*/\n        lv_coord_t w = lv_obj_get_width(list);\n        if(w != lv_area_get_width(param)) {   /*Width changed*/\n            refr_btn_width(list);\n        }\n    } else if(sign == LV_SIGNAL_STYLE_CHG) {\n        /*Because of the possible change of horizontal and vertical padding refresh buttons width */\n        refr_btn_width(list);\n    } else if(sign == LV_SIGNAL_FOCUS) {\n\n#if USE_LV_GROUP\n        lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act());\n        /*With ENCODER select the first button only in edit mode*/\n        if(indev_type == LV_INDEV_TYPE_ENCODER) {\n            lv_group_t * g = lv_obj_get_group(list);\n            if(lv_group_get_editing(g)) {\n                lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n                if(ext->last_sel) {\n                    /* Select the    last used button */\n                    lv_list_set_btn_selected(list, ext->last_sel);\n                }\n                else {\n                    /*Get the first button and mark it as selected*/\n                    lv_list_set_btn_selected(list, lv_list_get_next_btn(list, NULL));\n                }\n            } else {\n                lv_list_set_btn_selected(list, NULL);\n            }\n        }\n        /*Else select the clicked button*/\n        else {\n            /*Mark the last clicked button (if any) as selected because it triggered the focus*/\n            if(last_clicked_btn) {\n                lv_list_set_btn_selected(list, last_clicked_btn);\n            } else {\n                lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n                if(ext->last_sel) {\n                    /* Select the last used button */\n                    lv_list_set_btn_selected(list, ext->last_sel);\n                }\n                else {\n                    /*Get the first button and mark it as selected*/\n                    lv_list_set_btn_selected(list, lv_list_get_next_btn(list, NULL));\n                }\n            }\n        }\n#endif\n    } else if(sign == LV_SIGNAL_DEFOCUS) {\n\n#if USE_LV_GROUP\n        /*De-select the selected btn*/\n        lv_list_set_btn_selected(list, NULL);\n        last_clicked_btn = NULL;        /*button click will be set if click happens before focus*/\n        lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n        ext->selected_btn = NULL;\n#endif\n    } else if(sign == LV_SIGNAL_GET_EDITABLE) {\n        bool * editable = (bool *)param;\n        *editable = true;\n    } else if(sign == LV_SIGNAL_CONTROLL) {\n\n#if USE_LV_GROUP\n        char c = *((char *)param);\n        if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_DOWN) {\n            lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n            /*If there is a valid selected button the make the previous selected*/\n            if(ext->selected_btn) {\n                lv_obj_t * btn_prev = lv_list_get_next_btn(list, ext->selected_btn);\n                if(btn_prev) lv_list_set_btn_selected(list, btn_prev);\n            }\n            /*If there is no selected button the make the first selected*/\n            else {\n                lv_obj_t * btn = lv_list_get_next_btn(list, NULL);\n                if(btn) lv_list_set_btn_selected(list, btn);    /*If there are no buttons on the list then there is no first button*/\n            }\n        } else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_UP) {\n            lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n            /*If there is a valid selected button the make the next selected*/\n            if(ext->selected_btn != NULL) {\n                lv_obj_t * btn_next = lv_list_get_prev_btn(list, ext->selected_btn);\n                if(btn_next) lv_list_set_btn_selected(list, btn_next);\n            }\n            /*If there is no selected button the make the first selected*/\n            else {\n                lv_obj_t * btn = lv_list_get_next_btn(list, NULL);\n                if(btn) lv_list_set_btn_selected(list, btn);\n            }\n        } else if(c == LV_GROUP_KEY_ENTER) {\n            /*Get the 'pressed' button*/\n            lv_obj_t * btn = NULL;\n            btn = lv_list_get_prev_btn(list, btn);\n            while(btn != NULL) {\n                if(lv_btn_get_state(btn) == LV_BTN_STATE_PR) break;\n                btn = lv_list_get_prev_btn(list, btn);\n            }\n\n            if(btn != NULL) {\n                lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n                ext->last_sel = btn;\n                lv_action_t rel_action;\n                rel_action = lv_btn_get_action(btn, LV_BTN_ACTION_CLICK);\n                if(rel_action != NULL) rel_action(btn);\n            }\n        }\n#endif\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_list\";\n    }\n    return res;\n}\n\n\n/**\n * Signal function of the list buttons\n * @param btn pointer to a button on the list\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_list_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_btn_signal(btn, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    if(sign == LV_SIGNAL_RELEASED) {\n        lv_obj_t * list = lv_obj_get_parent(lv_obj_get_parent(btn));\n        lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n        ext->page.scroll_prop_ip = 0;\n\n#if USE_LV_GROUP\n        lv_group_t * g = lv_obj_get_group(list);\n        if(lv_group_get_focused(g) == list && lv_indev_is_dragging(lv_indev_get_act()) == false) {\n            /* Is the list is focused then be sure only the button being released\n             * has a pressed state to indicate the selected state on the list*/\n            lv_obj_t * btn_i = lv_list_get_prev_btn(list, NULL);\n            while(btn_i) {\n                lv_btn_state_t s = lv_btn_get_state(btn_i);\n                if(s == LV_BTN_STATE_PR) lv_btn_set_state(btn_i, LV_BTN_STATE_REL);\n                else if(s == LV_BTN_STATE_TGL_PR) lv_btn_set_state(btn_i, LV_BTN_STATE_TGL_REL);\n                btn_i = lv_list_get_prev_btn(list, btn_i);\n            }\n\n            /*Make the released button \"selected\"*/\n            lv_list_set_btn_selected(list, btn);\n        }\n\n        /* If `click_focus == 1` then LV_SIGNAL_FOCUS need to know which button triggered the focus\n         * to mark it as selected (pressed state)*/\n        last_clicked_btn = btn;\n#endif\n        if(lv_indev_is_dragging(lv_indev_get_act()) == false && ext->single_mode)\n        {\n            lv_list_btn_single_selected(btn);\n        }\n    }\n    else if(sign == LV_SIGNAL_PRESS_LOST) {\n        lv_obj_t * list = lv_obj_get_parent(lv_obj_get_parent(btn));\n        lv_list_ext_t * ext = lv_obj_get_ext_attr(list);\n        ext->page.scroll_prop_ip = 0;\n    }\n    else if(sign == LV_SIGNAL_CLEANUP) {\n\n#if USE_LV_GROUP\n        lv_obj_t * list = lv_obj_get_parent(lv_obj_get_parent(btn));\n        lv_obj_t * sel = lv_list_get_btn_selected(list);\n        if(sel == btn) lv_list_set_btn_selected(list, lv_list_get_next_btn(list, btn));\n#endif\n    }\n\n\n    return res;\n}\n\nstatic void refr_btn_width(lv_obj_t * list)\n{\n    lv_style_t * style = lv_list_get_style(list, LV_LIST_STYLE_BG);\n    lv_style_t * style_scrl = lv_obj_get_style(lv_page_get_scrl(list));\n    lv_coord_t w = lv_obj_get_width(list);\n    lv_coord_t btn_w = w - (style->body.padding.hor + style_scrl->body.padding.hor) * 2;\n\n    lv_obj_t * btn = lv_list_get_prev_btn(list, NULL);\n    while(btn) {\n        /*Make the size adjustment for each buttons*/\n        if(lv_obj_get_width(btn) != btn_w) {\n            lv_obj_set_width(btn, btn_w);\n            /*Set the label size to roll its text*/\n            lv_obj_t * label = lv_list_get_btn_label(btn);\n            lv_obj_set_width(label, btn->coords.x2 - label->coords.x1);\n            lv_label_set_text(label, NULL);\n        }\n        btn = lv_list_get_prev_btn(list, btn);\n    }\n}\n\n/**\n * Make a single button selected in the list, deselect others, should be called in list btns call back.\n * @param btn pointer to the currently pressed list btn object\n */\nstatic void lv_list_btn_single_selected(lv_obj_t *btn)\n{\n    lv_obj_t *list = lv_obj_get_parent(lv_obj_get_parent(btn));\n\n    lv_obj_t * e = lv_list_get_next_btn(list, NULL);\n    do\n    {\n        if(e == btn)\n        {\n            lv_btn_set_state(e, LV_BTN_STATE_TGL_REL);\n        }\n        else\n        {\n            lv_btn_set_state(e, LV_BTN_STATE_REL);\n        }\n        e = lv_list_get_next_btn(list, e);\n    } while (e != NULL);\n}\n\n/**\n * Check if this is really a list button or another object.\n * @param list_btn List button\n */\nstatic bool lv_list_is_list_btn(lv_obj_t * list_btn)\n{\n    lv_obj_type_t type;\n\n    lv_obj_get_type(list_btn, &type);\n    uint8_t cnt;\n    for(cnt = 0; cnt < LV_MAX_ANCESTOR_NUM; cnt++) {\n        if(type.type[cnt] == NULL) break;\n        if(!strcmp(type.type[cnt], \"lv_btn\"))\n            return true;\n    }\n    return false;\n}\n\n/**\n * Check if this is really a list label or another object.\n * @param list_label List label\n */\nstatic bool lv_list_is_list_label(lv_obj_t * list_label)\n{\n    lv_obj_type_t type;\n\n    lv_obj_get_type(list_label, &type);\n    uint8_t cnt;\n    for(cnt = 0; cnt < LV_MAX_ANCESTOR_NUM; cnt++) {\n        if(type.type[cnt] == NULL) break;\n        if(!strcmp(type.type[cnt], \"lv_label\"))\n            return true;\n    }\n    return false;\n}\n\n/**\n * Check if this is really a list image or another object.\n * @param list_image List image\n */\nstatic bool lv_list_is_list_img(lv_obj_t * list_img)\n{\n    lv_obj_type_t type;\n\n    lv_obj_get_type(list_img, &type);\n    uint8_t cnt;\n    for(cnt = 0; cnt < LV_MAX_ANCESTOR_NUM; cnt++) {\n        if(type.type[cnt] == NULL) break;\n        if(!strcmp(type.type[cnt], \"lv_img\"))\n            return true;\n    }\n    return false;\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_list.h",
    "content": "/**\n * @file lv_list.h\n *\n */\n\n#ifndef LV_LIST_H\n#define LV_LIST_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_LIST != 0\n\n/*Testing of dependencies*/\n#if USE_LV_PAGE == 0\n#error \"lv_list: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE  1) \"\n#endif\n\n#if USE_LV_BTN == 0\n#error \"lv_list: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN  1) \"\n#endif\n\n#if USE_LV_LABEL == 0\n#error \"lv_list: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL  1) \"\n#endif\n\n\n#include \"../lv_core/lv_obj.h\"\n#include \"lv_page.h\"\n#include \"lv_btn.h\"\n#include \"lv_label.h\"\n#include \"lv_img.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n/*Data of list*/\ntypedef struct\n{\n    lv_page_ext_t page; /*Ext. of ancestor*/\n    /*New data for this type */\n    uint16_t anim_time;                          /*Scroll animation time*/\n    lv_style_t *styles_btn[LV_BTN_STATE_NUM];    /*Styles of the list element buttons*/\n    lv_style_t *style_img;                       /*Style of the list element images on buttons*/\n    uint32_t size; /*the number of items(buttons) in the list*/\n    bool single_mode; /* whether single selected mode is enabled */\n#if USE_LV_GROUP\n    lv_obj_t * last_sel;                          /* The last selected button. It will be reverted when the list is focused again */\n    lv_obj_t * selected_btn;                      /* The button is currently being selected*/\n#endif\n} lv_list_ext_t;\n\nenum {\n    LV_LIST_STYLE_BG,\n    LV_LIST_STYLE_SCRL,\n    LV_LIST_STYLE_SB,\n    LV_LIST_STYLE_EDGE_FLASH,\n    LV_LIST_STYLE_BTN_REL,\n    LV_LIST_STYLE_BTN_PR,\n    LV_LIST_STYLE_BTN_TGL_REL,\n    LV_LIST_STYLE_BTN_TGL_PR,\n    LV_LIST_STYLE_BTN_INA,\n};\ntypedef uint8_t lv_list_style_t;\n\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a list objects\n * @param par pointer to an object, it will be the parent of the new list\n * @param copy pointer to a list object, if not NULL then the new object will be copied from it\n * @return pointer to the created list\n */\nlv_obj_t * lv_list_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/**\n * Delete all children of the scrl object, without deleting scrl child.\n * @param obj pointer to an object\n */\nvoid lv_list_clean(lv_obj_t *obj);\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n/**\n * Add a list element to the list\n * @param list pointer to list object\n * @param img_fn file name of an image before the text (NULL if unused)\n * @param txt text of the list element (NULL if unused)\n * @param rel_action pointer to release action function (like with lv_btn)\n * @return pointer to the new list element which can be customized (a button)\n */\nlv_obj_t * lv_list_add(lv_obj_t * list, const void * img_src, const char * txt, lv_action_t rel_action);\n\n/**\n * Remove the index of the button in the list\n * @param list pointer to a list object\n * @param index pointer to a the button's index in the list, index must be 0 <= index < lv_list_ext_t.size\n * @return true: successfully deleted\n */\nbool lv_list_remove(const lv_obj_t * list, uint32_t index);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set single button selected mode, only one button will be selected if enabled.\n * @param list pointer to the currently pressed list object\n * @param mode, enable(true)/disable(false) single selected mode.\n */\nvoid lv_list_set_single_mode(lv_obj_t *list, bool mode);\n\n#if USE_LV_GROUP\n\n/**\n * Make a button selected. Can be used while navigating in the list with a keypad.\n * @param list pointer to a list object\n * @param btn pointer to a button to select\n */\nvoid lv_list_set_btn_selected(lv_obj_t * list, lv_obj_t * btn);\n#endif\n\n/**\n * Set scroll animation duration on 'list_up()' 'list_down()' 'list_focus()'\n * @param list pointer to a list object\n * @param anim_time duration of animation [ms]\n */\nvoid lv_list_set_anim_time(lv_obj_t *list, uint16_t anim_time);\n\n/**\n * Set the scroll bar mode of a list\n * @param list pointer to a list object\n * @param sb_mode the new mode from 'lv_page_sb_mode_t' enum\n */\nstatic inline void lv_list_set_sb_mode(lv_obj_t * list, lv_sb_mode_t mode)\n{\n    lv_page_set_sb_mode(list, mode);\n}\n\n/**\n * Enable the scroll propagation feature. If enabled then the List will move its parent if there is no more space to scroll.\n * @param list pointer to a List\n * @param en true or false to enable/disable scroll propagation\n */\nstatic inline void lv_list_set_scroll_propagation(lv_obj_t * list, bool en)\n{\n    lv_page_set_scroll_propagation(list, en);\n}\n\n/**\n * Enable the edge flash effect. (Show an arc when the an edge is reached)\n * @param list pointer to a List\n * @param en true or false to enable/disable end flash\n */\nstatic inline void lv_list_set_edge_flash(lv_obj_t * list, bool en)\n{\n    lv_page_set_edge_flash(list, en);\n}\n\n/**\n * Set a style of a list\n * @param list pointer to a list object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_list_set_style(lv_obj_t *list, lv_list_style_t type, lv_style_t *style);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get single button selected mode.\n * @param list pointer to the currently pressed list object.\n */\nbool lv_list_get_single_mode(lv_obj_t *list);\n\n/**\n * Get the text of a list element\n * @param btn pointer to list element\n * @return pointer to the text\n */\nconst char * lv_list_get_btn_text(const lv_obj_t * btn);\n/**\n * Get the label object from a list element\n * @param btn pointer to a list element (button)\n * @return pointer to the label from the list element or NULL if not found\n */\nlv_obj_t * lv_list_get_btn_label(const lv_obj_t * btn);\n\n/**\n * Get the image object from a list element\n * @param btn pointer to a list element (button)\n * @return pointer to the image from the list element or NULL if not found\n */\nlv_obj_t * lv_list_get_btn_img(const lv_obj_t * btn);\n\n/**\n * Get the next button from list. (Starts from the bottom button)\n * @param list pointer to a list object\n * @param prev_btn pointer to button. Search the next after it.\n * @return pointer to the next button or NULL when no more buttons\n */\nlv_obj_t * lv_list_get_prev_btn(const lv_obj_t * list, lv_obj_t * prev_btn);\n\n/**\n * Get the previous button from list. (Starts from the top button)\n * @param list pointer to a list object\n * @param prev_btn pointer to button. Search the previous before it.\n * @return pointer to the previous button or NULL when no more buttons\n */\nlv_obj_t * lv_list_get_next_btn(const lv_obj_t * list, lv_obj_t * prev_btn);\n\n/**\n * Get the index of the button in the list\n * @param list pointer to a list object. If NULL, assumes btn is part of a list.\n * @param btn pointer to a list element (button)\n * @return the index of the button in the list, or -1 of the button not in this list\n */\nint32_t lv_list_get_btn_index(const lv_obj_t * list, const lv_obj_t * btn);\n\n/**\n * Get the number of buttons in the list\n * @param list pointer to a list object\n * @return the number of buttons in the list\n */\nuint32_t lv_list_get_size(const lv_obj_t * list);\n\n#if USE_LV_GROUP\n/**\n * Get the currently selected button. Can be used while navigating in the list with a keypad.\n * @param list pointer to a list object\n * @return pointer to the selected button\n */\nlv_obj_t * lv_list_get_btn_selected(const lv_obj_t * list);\n#endif\n\n\n/**\n * Get scroll animation duration\n * @param list pointer to a list object\n * @return duration of animation [ms]\n */\nuint16_t lv_list_get_anim_time(const lv_obj_t *list);\n\n\n/**\n * Get the scroll bar mode of a list\n * @param list pointer to a list object\n * @return scrollbar mode from 'lv_page_sb_mode_t' enum\n */\nstatic inline lv_sb_mode_t lv_list_get_sb_mode(const lv_obj_t * list)\n{\n    return lv_page_get_sb_mode(list);\n}\n\n/**\n * Get the scroll propagation property\n * @param list pointer to a List\n * @return true or false\n */\nstatic inline bool lv_list_get_scroll_propagation(lv_obj_t * list)\n{\n    return lv_page_get_scroll_propagation(list);\n}\n\n/**\n * Get the scroll propagation property\n * @param list pointer to a List\n * @return true or false\n */\nstatic inline bool lv_list_get_edge_flash(lv_obj_t * list)\n{\n    return lv_page_get_edge_flash(list);\n}\n\n/**\n * Get a style of a list\n * @param list pointer to a list object\n * @param type which style should be get\n * @return style pointer to a style\n *  */\nlv_style_t * lv_list_get_style(const lv_obj_t *list, lv_list_style_t type);\n\n/*=====================\n * Other functions\n *====================*/\n\n/**\n * Move the list elements up by one\n * @param list pointer a to list object\n */\nvoid lv_list_up(const lv_obj_t * list);\n/**\n * Move the list elements down by one\n * @param list pointer to a list object\n */\nvoid lv_list_down(const lv_obj_t * list);\n\n/**\n * Focus on a list button. It ensures that the button will be visible on the list.\n * @param btn pointer to a list button to focus\n * @param anim_en true: scroll with animation, false: without animation\n */\nvoid lv_list_focus(const lv_obj_t *btn, bool anim_en);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_LIST*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_LIST_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_lmeter.c",
    "content": "/**\n * @file lv_lmeter.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_lmeter.h\"\n#if USE_LV_LMETER != 0\n\n#include \"../lv_draw/lv_draw.h\"\n#include \"../lv_themes/lv_theme.h\"\n#include \"../lv_core/lv_group.h\"\n#include \"../lv_misc/lv_math.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_LMETER_LINE_UPSCALE          5                   /*2^x upscale of line to make rounding*/\n#define LV_LMETER_LINE_UPSCALE_MASK     ((1 << LV_LMETER_LINE_UPSCALE) - 1)\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool lv_lmeter_design(lv_obj_t * lmeter, const lv_area_t * mask, lv_design_mode_t mode);\nstatic lv_res_t lv_lmeter_signal(lv_obj_t * lmeter, lv_signal_t sign, void * param);\nstatic lv_coord_t lv_lmeter_coord_round(int32_t x);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a line meter objects\n * @param par pointer to an object, it will be the parent of the new line meter\n * @param copy pointer to a line meter object, if not NULL then the new object will be copied from it\n * @return pointer to the created line meter\n */\nlv_obj_t * lv_lmeter_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"line meter create started\");\n\n    /*Create the ancestor of line meter*/\n    lv_obj_t * new_lmeter = lv_obj_create(par, copy);\n    lv_mem_assert(new_lmeter);\n    if(new_lmeter == NULL) return NULL;\n\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_lmeter);\n\n    /*Allocate the line meter type specific extended data*/\n    lv_lmeter_ext_t * ext = lv_obj_allocate_ext_attr(new_lmeter, sizeof(lv_lmeter_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    /*Initialize the allocated 'ext' */\n    ext->min_value = 0;\n    ext->max_value = 100;\n    ext->cur_value = 0;\n    ext->line_cnt = 21;    /*Odd scale number looks better*/\n    ext->scale_angle = 240; /*(scale_num - 1) * N looks better */\n\n    /*The signal and design functions are not copied so set them here*/\n    lv_obj_set_signal_func(new_lmeter, lv_lmeter_signal);\n    lv_obj_set_design_func(new_lmeter, lv_lmeter_design);\n\n    /*Init the new line meter line meter*/\n    if(copy == NULL) {\n        lv_obj_set_size(new_lmeter, LV_DPI, LV_DPI);\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_lmeter_set_style(new_lmeter, th->lmeter);\n        } else {\n            lv_lmeter_set_style(new_lmeter, &lv_style_pretty_color);\n        }\n    }\n    /*Copy an existing line meter*/\n    else {\n        lv_lmeter_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        ext->scale_angle = copy_ext->scale_angle;\n        ext->line_cnt = copy_ext->line_cnt;\n        ext->min_value = copy_ext->min_value;\n        ext->max_value = copy_ext->max_value;\n        ext->cur_value = copy_ext->cur_value;\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_lmeter);\n    }\n\n    LV_LOG_INFO(\"line meter created\");\n\n    return new_lmeter;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a new value on the line meter\n * @param lmeter pointer to a line meter object\n * @param value new value\n */\nvoid lv_lmeter_set_value(lv_obj_t * lmeter, int16_t value)\n{\n    lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);\n    if(ext->cur_value == value) return;\n\n    ext->cur_value = value > ext->max_value ? ext->max_value : value;\n    ext->cur_value = ext->cur_value < ext->min_value ? ext->min_value : ext->cur_value;\n    lv_obj_invalidate(lmeter);\n}\n\n/**\n * Set minimum and the maximum values of a line meter\n * @param lmeter pointer to he line meter object\n * @param min minimum value\n * @param max maximum value\n */\nvoid lv_lmeter_set_range(lv_obj_t * lmeter, int16_t min, int16_t max)\n{\n    lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);\n    if(ext->min_value == min && ext->max_value == max) return;\n\n    ext->max_value = max;\n    ext->min_value = min;\n    if(ext->cur_value > max) {\n        ext->cur_value = max;\n        lv_lmeter_set_value(lmeter, ext->cur_value);\n    }\n    if(ext->cur_value < min) {\n        ext->cur_value = min;\n        lv_lmeter_set_value(lmeter, ext->cur_value);\n    }\n    lv_obj_invalidate(lmeter);\n}\n\n/**\n * Set the scale settings of a line meter\n * @param lmeter pointer to a line meter object\n * @param angle angle of the scale (0..360)\n * @param line_cnt number of lines\n */\nvoid lv_lmeter_set_scale(lv_obj_t * lmeter, uint16_t angle, uint8_t line_cnt)\n{\n    lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);\n    if(ext->scale_angle == angle && ext->line_cnt == line_cnt) return;\n\n    ext->scale_angle = angle;\n    ext->line_cnt = line_cnt;\n\n    lv_obj_invalidate(lmeter);\n}\n\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the value of a line meter\n * @param lmeter pointer to a line meter object\n * @return the value of the line meter\n */\nint16_t lv_lmeter_get_value(const lv_obj_t * lmeter)\n{\n    lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);\n    return ext->cur_value;\n}\n\n/**\n * Get the minimum value of a line meter\n * @param lmeter pointer to a line meter object\n * @return the minimum value of the line meter\n */\nint16_t lv_lmeter_get_min_value(const lv_obj_t * lmeter)\n{\n    lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);\n    return ext->min_value;\n}\n\n/**\n * Get the maximum value of a line meter\n * @param lmeter pointer to a line meter object\n * @return the maximum value of the line meter\n */\nint16_t lv_lmeter_get_max_value(const lv_obj_t * lmeter)\n{\n    lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);\n    return ext->max_value;\n}\n\n/**\n * Get the scale number of a line meter\n * @param lmeter pointer to a line meter object\n * @return number of the scale units\n */\nuint8_t lv_lmeter_get_line_count(const lv_obj_t * lmeter)\n{\n    lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);\n    return ext->line_cnt ;\n}\n\n/**\n * Get the scale angle of a line meter\n * @param lmeter pointer to a line meter object\n * @return angle of the scale\n */\nuint16_t lv_lmeter_get_scale_angle(const lv_obj_t * lmeter)\n{\n    lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);\n    return ext->scale_angle;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n\n/**\n * Handle the drawing related tasks of the line meters\n * @param lmeter pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_lmeter_design(lv_obj_t * lmeter, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    /*Return false if the object is not covers the mask_p area*/\n    if(mode == LV_DESIGN_COVER_CHK) {\n        return false;\n    }\n    /*Draw the object*/\n    else if(mode == LV_DESIGN_DRAW_MAIN) {\n        lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);\n        lv_style_t * style = lv_obj_get_style(lmeter);\n        lv_opa_t opa_scale = lv_obj_get_opa_scale(lmeter);\n        lv_style_t style_tmp;\n        memcpy(&style_tmp, style, sizeof(lv_style_t));\n\n\n#if USE_LV_GROUP\n        lv_group_t * g = lv_obj_get_group(lmeter);\n        if(lv_group_get_focused(g) == lmeter) {\n            style_tmp.line.width += 1;\n        }\n#endif\n\n        lv_coord_t r_out = lv_obj_get_width(lmeter) / 2;\n        lv_coord_t r_in = r_out - style->body.padding.hor;\n        if(r_in < 1) r_in = 1;\n\n        lv_coord_t x_ofs = lv_obj_get_width(lmeter) / 2 + lmeter->coords.x1;\n        lv_coord_t y_ofs = lv_obj_get_height(lmeter) / 2 + lmeter->coords.y1;\n        int16_t angle_ofs = 90 + (360 - ext->scale_angle) / 2;\n        int16_t level = (int32_t)((int32_t)(ext->cur_value - ext->min_value) * ext->line_cnt) / (ext->max_value - ext->min_value);\n        uint8_t i;\n\n        style_tmp.line.color = style->body.main_color;\n\n        /*Calculate every coordinate in a bigger size to make rounding later*/\n        r_out = r_out << LV_LMETER_LINE_UPSCALE;\n        r_in = r_in << LV_LMETER_LINE_UPSCALE;\n\n        for(i = 0; i < ext->line_cnt; i++) {\n            /*Calculate the position a scale label*/\n            int16_t angle = (i * ext->scale_angle) / (ext->line_cnt - 1) + angle_ofs;\n\n            lv_coord_t y_out = (int32_t)((int32_t)lv_trigo_sin(angle) * r_out) >> LV_TRIGO_SHIFT;\n            lv_coord_t x_out = (int32_t)((int32_t)lv_trigo_sin(angle + 90) * r_out) >> LV_TRIGO_SHIFT;\n            lv_coord_t y_in = (int32_t)((int32_t)lv_trigo_sin(angle) * r_in) >> LV_TRIGO_SHIFT;\n            lv_coord_t x_in = (int32_t)((int32_t)lv_trigo_sin(angle + 90) * r_in) >> LV_TRIGO_SHIFT;\n\n            /*Rounding*/\n            x_out = lv_lmeter_coord_round(x_out);\n            x_in  = lv_lmeter_coord_round(x_in);\n            y_out = lv_lmeter_coord_round(y_out);\n            y_in  = lv_lmeter_coord_round(y_in);\n\n            lv_point_t p1;\n            lv_point_t p2;\n\n            p2.x = x_in + x_ofs;\n            p2.y = y_in +  y_ofs;\n\n            p1.x = x_out + x_ofs;\n            p1.y = y_out + y_ofs;\n\n            if(i >= level) style_tmp.line.color = style->line.color;\n            else {\n                style_tmp.line.color = lv_color_mix(style->body.grad_color, style->body.main_color, (255 * i) /  ext->line_cnt);\n            }\n\n            lv_draw_line(&p1, &p2, mask, &style_tmp, opa_scale);\n        }\n\n    }\n    /*Post draw when the children are drawn*/\n    else if(mode == LV_DESIGN_DRAW_POST) {\n\n    }\n\n    return true;\n}\n\n/**\n * Signal function of the line meter\n * @param lmeter pointer to a line meter object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_lmeter_signal(lv_obj_t * lmeter, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(lmeter, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    if(sign == LV_SIGNAL_CLEANUP) {\n        /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/\n    } else if(sign == LV_SIGNAL_STYLE_CHG) {\n        lv_obj_refresh_ext_size(lmeter);\n    } else if(sign == LV_SIGNAL_REFR_EXT_SIZE) {\n        lv_style_t * style = lv_lmeter_get_style(lmeter);\n        lmeter->ext_size = LV_MATH_MAX(lmeter->ext_size, style->line.width);\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_lmeter\";\n    }\n\n    return res;\n}\n\n/**\n * Round a coordinate which is upscaled  (>=x.5 -> x + 1;   <x.5 -> x)\n * @param x a coordinate which is greater then it should be\n * @return the downscaled and rounded coordinate  (+-1)\n */\nstatic lv_coord_t lv_lmeter_coord_round(int32_t x)\n{\n#if LV_LMETER_LINE_UPSCALE > 0\n    bool was_negative = false;\n    if(x < 0) {\n        was_negative = true;\n        x = -x;\n    }\n\n    x = (x >> LV_LMETER_LINE_UPSCALE) + ((x & LV_LMETER_LINE_UPSCALE_MASK) >> (LV_LMETER_LINE_UPSCALE - 1));\n\n    if(was_negative) x = -x;\n\n    return x;\n#else\n    return x;\n#endif\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_lmeter.h",
    "content": "/**\n * @file lv_lmeter.h\n *\n */\n\n#ifndef LV_LMETER_H\n#define LV_LMETER_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_LMETER != 0\n\n#include \"../lv_core/lv_obj.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n/*Data of line meter*/\ntypedef struct\n{\n    /*No inherited ext.*/            /*Ext. of ancestor*/\n    /*New data for this type */\n    uint16_t scale_angle;        /*Angle of the scale in deg. (0..360)*/\n    uint8_t line_cnt;            /*Count of lines */\n    int16_t cur_value;\n    int16_t min_value;\n    int16_t max_value;\n} lv_lmeter_ext_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a line meter objects\n * @param par pointer to an object, it will be the parent of the new line meter\n * @param copy pointer to a line meter object, if not NULL then the new object will be copied from it\n * @return pointer to the created line meter\n */\nlv_obj_t * lv_lmeter_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a new value on the line meter\n * @param lmeter pointer to a line meter object\n * @param value new value\n */\nvoid lv_lmeter_set_value(lv_obj_t *lmeter, int16_t value);\n\n/**\n * Set minimum and the maximum values of a line meter\n * @param lmeter pointer to he line meter object\n * @param min minimum value\n * @param max maximum value\n */\nvoid lv_lmeter_set_range(lv_obj_t *lmeter, int16_t min, int16_t max);\n\n/**\n * Set the scale settings of a line meter\n * @param lmeter pointer to a line meter object\n * @param angle angle of the scale (0..360)\n * @param line_cnt number of lines\n */\nvoid lv_lmeter_set_scale(lv_obj_t * lmeter, uint16_t angle, uint8_t line_cnt);\n\n/**\n * Set the styles of a line meter\n * @param lmeter pointer to a line meter object\n * @param bg set the style of the line meter\n */\nstatic inline void lv_lmeter_set_style(lv_obj_t *lmeter, lv_style_t *bg)\n{\n    lv_obj_set_style(lmeter, bg);\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the value of a line meter\n * @param lmeter pointer to a line meter object\n * @return the value of the line meter\n */\nint16_t lv_lmeter_get_value(const lv_obj_t *lmeter);\n\n/**\n * Get the minimum value of a line meter\n * @param lmeter pointer to a line meter object\n * @return the minimum value of the line meter\n */\nint16_t lv_lmeter_get_min_value(const lv_obj_t * lmeter);\n\n/**\n * Get the maximum value of a line meter\n * @param lmeter pointer to a line meter object\n * @return the maximum value of the line meter\n */\nint16_t lv_lmeter_get_max_value(const lv_obj_t * lmeter);\n\n/**\n * Get the scale number of a line meter\n * @param lmeter pointer to a line meter object\n * @return number of the scale units\n */\nuint8_t lv_lmeter_get_line_count(const lv_obj_t * lmeter);\n\n/**\n * Get the scale angle of a line meter\n * @param lmeter pointer to a line meter object\n * @return angle of the scale\n */\nuint16_t lv_lmeter_get_scale_angle(const lv_obj_t * lmeter);\n\n/**\n * Get the style of a line meter\n * @param lmeter pointer to a line meter object\n * @return pointer to the line meter's style\n */\nstatic inline lv_style_t * lv_lmeter_get_style(const lv_obj_t * lmeter)\n{\n    return lv_obj_get_style(lmeter);\n}\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_LMETER*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_LMETER_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_mbox.c",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * @file lv_mbox.c\n *\n */\n\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_mbox.h\"\n#if USE_LV_MBOX != 0\n\n#include \"../lv_core/lv_group.h\"\n#include \"../lv_themes/lv_theme.h\"\n#include \"../lv_misc/lv_anim.h\"\n#include \"../lv_misc/lv_math.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n#if USE_LV_ANIMATION\n#  ifndef LV_MBOX_CLOSE_ANIM_TIME\n#    define LV_MBOX_CLOSE_ANIM_TIME  200 /*List close animation time)  */\n#  endif\n#else\n#  undef  LV_MBOX_CLOSE_ANIM_TIME\n#  define LV_MBOX_CLOSE_ANIM_TIME   0   /*No animations*/\n#endif\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic lv_res_t lv_mbox_signal(lv_obj_t * mbox, lv_signal_t sign, void * param);\nstatic void mbox_realign(lv_obj_t * mbox);\nstatic lv_res_t lv_mbox_close_action(lv_obj_t * btn, const char * txt);\n#if USE_LV_ANIMATION\nstatic void lv_mbox_close_end_cb(lv_obj_t * mbox);\n#endif\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a message box objects\n * @param par pointer to an object, it will be the parent of the new message box\n * @param copy pointer to a message box object, if not NULL then the new object will be copied from it\n * @return pointer to the created message box\n */\nlv_obj_t * lv_mbox_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"mesasge box create started\");\n\n    /*Create the ancestor message box*/\n    lv_obj_t * new_mbox = lv_cont_create(par, copy);\n    lv_mem_assert(new_mbox);\n    if(new_mbox == NULL) return NULL;\n\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_mbox);\n\n    /*Allocate the message box type specific extended data*/\n    lv_mbox_ext_t * ext = lv_obj_allocate_ext_attr(new_mbox, sizeof(lv_mbox_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    ext->text = NULL;\n    ext->btnm = NULL;\n    ext->anim_time = LV_MBOX_CLOSE_ANIM_TIME;\n\n    /*The signal and design functions are not copied so set them here*/\n    lv_obj_set_signal_func(new_mbox, lv_mbox_signal);\n\n    /*Init the new message box message box*/\n    if(copy == NULL) {\n        ext->text = lv_label_create(new_mbox, NULL);\n        lv_label_set_align(ext->text, LV_LABEL_ALIGN_CENTER);\n        lv_label_set_long_mode(ext->text, LV_LABEL_LONG_BREAK);\n        lv_label_set_text(ext->text, \"Message\");\n\n        lv_cont_set_layout(new_mbox, LV_LAYOUT_COL_M);\n        lv_cont_set_fit(new_mbox, false, true);\n        lv_obj_set_width(new_mbox, LV_HOR_RES / 2);\n        lv_obj_align(new_mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_mbox_set_style(new_mbox, LV_MBOX_STYLE_BG, th->mbox.bg);\n        } else {\n            lv_mbox_set_style(new_mbox, LV_MBOX_STYLE_BG, &lv_style_pretty);\n        }\n\n    }\n    /*Copy an existing message box*/\n    else {\n        lv_mbox_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n\n        ext->text = lv_label_create(new_mbox, copy_ext->text);\n\n        /*Copy the buttons and the label on them*/\n        if(copy_ext->btnm) ext->btnm = lv_btnm_create(new_mbox, copy_ext->btnm);\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_mbox);\n    }\n\n\n    LV_LOG_INFO(\"mesasge box created\");\n\n    return new_mbox;\n}\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n/**\n * Add button to the message box\n * @param mbox pointer to message box object\n * @param btn_map button descriptor (button matrix map).\n *                E.g.  a const char *txt[] = {\"ok\", \"close\", \"\"} (Can not be local variable)\n * @param action a function which will be called when a button is released\n */\nvoid lv_mbox_add_btns(lv_obj_t * mbox, const char ** btn_map, lv_btnm_action_t action)\n{\n    lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);\n\n    /*Create a button matrix if not exists yet*/\n    if(ext->btnm == NULL) {\n        ext->btnm = lv_btnm_create(mbox, NULL);\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_mbox_set_style(mbox, LV_MBOX_STYLE_BTN_BG, th->mbox.btn.bg);\n            lv_mbox_set_style(mbox, LV_MBOX_STYLE_BTN_REL, th->mbox.btn.rel);\n            lv_mbox_set_style(mbox, LV_MBOX_STYLE_BTN_PR, th->mbox.btn.pr);\n        } else {\n            lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BG, &lv_style_transp_fit);\n        }\n    }\n\n    lv_btnm_set_map(ext->btnm, btn_map);\n    if(action == NULL) lv_btnm_set_action(ext->btnm, lv_mbox_close_action); /*Set a default action anyway*/\n    else  lv_btnm_set_action(ext->btnm, action);\n\n    mbox_realign(mbox);\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set the text of the message box\n * @param mbox pointer to a message box\n * @param txt a '\\0' terminated character string which will be the message box text\n */\nvoid lv_mbox_set_text(lv_obj_t * mbox, const char * txt)\n{\n    lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);\n    lv_label_set_text(ext->text, txt);\n\n    mbox_realign(mbox);\n}\n\n\n/**\n * Stop the action to call when button is released\n * @param pointer to an 'lv_btnm_action_t' action. In the action you need to use `lv_mbox_get_from_btn()` to get the `mbox`.\n * @param pointer to an 'lv_btnm_action_t' action\n */\nvoid lv_mbox_set_action(lv_obj_t * mbox, lv_btnm_action_t action)\n{\n    lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);\n    lv_btnm_set_action(ext->btnm, action);\n}\n\n\n/**\n * Set animation duration\n * @param mbox pointer to a message box object\n * @param anim_time animation length in  milliseconds (0: no animation)\n */\nvoid lv_mbox_set_anim_time(lv_obj_t * mbox, uint16_t anim_time)\n{\n    lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);\n#if USE_LV_ANIMATION == 0\n    anim_time = 0;\n#endif\n\n    ext->anim_time = anim_time;\n}\n\n/**\n * Automatically delete the message box after a given time\n * @param mbox pointer to a message box object\n * @param delay a time (in milliseconds) to wait before delete the message box\n */\nvoid lv_mbox_start_auto_close(lv_obj_t * mbox, uint16_t delay)\n{\n#if USE_LV_ANIMATION\n    lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);\n\n    if(ext->anim_time != 0) {\n        /*Add shrinking animations*/\n        lv_obj_animate(mbox, LV_ANIM_GROW_H | LV_ANIM_OUT, ext->anim_time, delay, NULL);\n        lv_obj_animate(mbox, LV_ANIM_GROW_V | LV_ANIM_OUT, ext->anim_time, delay, lv_mbox_close_end_cb);\n\n        /*Disable fit to let shrinking work*/\n        lv_cont_set_fit(mbox, false, false);\n    } else {\n        lv_obj_animate(mbox, LV_ANIM_NONE, ext->anim_time, delay, lv_mbox_close_end_cb);\n    }\n#else\n    (void)delay; /*Unused*/\n    lv_obj_del(mbox);\n#endif\n}\n\n/**\n * Stop the auto. closing of message box\n * @param mbox pointer to a message box object\n */\nvoid lv_mbox_stop_auto_close(lv_obj_t * mbox)\n{\n#if USE_LV_ANIMATION\n    lv_anim_del(mbox, NULL);\n#else\n    (void)mbox; /*Unused*/\n#endif\n}\n\n/**\n * Set a style of a message box\n * @param mbox pointer to a message box object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_mbox_set_style(lv_obj_t * mbox, lv_mbox_style_t type, lv_style_t * style)\n{\n    lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);\n\n    switch(type) {\n        case LV_MBOX_STYLE_BG:\n            lv_obj_set_style(mbox, style);\n            break;\n        case LV_MBOX_STYLE_BTN_BG:\n            lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BG, style);\n            break;\n        case LV_MBOX_STYLE_BTN_REL:\n            lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BTN_REL, style);\n            break;\n        case LV_MBOX_STYLE_BTN_PR:\n            lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BTN_PR, style);\n            break;\n        case LV_MBOX_STYLE_BTN_TGL_REL:\n            lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BTN_TGL_REL, style);\n            break;\n        case LV_MBOX_STYLE_BTN_TGL_PR:\n            lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BTN_TGL_PR, style);\n            break;\n        case LV_MBOX_STYLE_BTN_INA:\n            lv_btnm_set_style(ext->btnm, LV_BTNM_STYLE_BTN_INA, style);\n            break;\n    }\n\n    mbox_realign(mbox);\n\n}\n\n/**\n * Set whether recoloring is enabled\n * @param btnm pointer to button matrix object\n * @param en whether recoloring is enabled\n */\nvoid lv_mbox_set_recolor(lv_obj_t * mbox, bool en)\n{\n\tlv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);\n\n\tif(ext->btnm)\n\t\tlv_btnm_set_recolor(ext->btnm, en);\n}\n\nvoid lv_mbox_set_recolor_text(lv_obj_t * mbox, bool en)\n{\n\tlv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);\n\n\tif (ext->text)\n\t\tlv_label_set_recolor(ext->text, en);\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the text of the message box\n * @param mbox pointer to a message box object\n * @return pointer to the text of the message box\n */\nconst char * lv_mbox_get_text(const lv_obj_t * mbox)\n{\n    lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);\n\n    return lv_label_get_text(ext->text);\n}\n\n/**\n * Get the message box object from one of its button.\n * It is useful in the button release actions where only the button is known\n * @param btn pointer to a button of a message box\n * @return pointer to the button's message box\n */\nlv_obj_t * lv_mbox_get_from_btn(const lv_obj_t * btn)\n{\n    lv_obj_t * mbox = lv_obj_get_parent(btn);\n\n    return mbox;\n}\n\n/**\n * Get the animation duration (close animation time)\n * @param mbox pointer to a message box object\n * @return animation length in  milliseconds (0: no animation)\n */\nuint16_t lv_mbox_get_anim_time(const lv_obj_t * mbox)\n{\n    lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);\n    return ext->anim_time;\n}\n\n/**\n * Get a style of a message box\n * @param mbox pointer to a message box object\n * @param type which style should be get\n * @return style pointer to a style\n */\nlv_style_t * lv_mbox_get_style(const lv_obj_t * mbox, lv_mbox_style_t type)\n{\n    lv_style_t * style = NULL;\n    lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);\n\n    switch(type) {\n        case LV_MBOX_STYLE_BG:\n            style = lv_obj_get_style(mbox);\n            break;\n        case LV_MBOX_STYLE_BTN_BG:\n            style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BG);\n            break;\n        case LV_MBOX_STYLE_BTN_REL:\n            style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BTN_REL);\n            break;\n        case LV_MBOX_STYLE_BTN_PR:\n            style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BTN_PR);\n            break;\n        case LV_MBOX_STYLE_BTN_TGL_REL:\n            style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BTN_TGL_REL);\n            break;\n        case LV_MBOX_STYLE_BTN_TGL_PR:\n            style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BTN_TGL_PR);\n            break;\n        case LV_MBOX_STYLE_BTN_INA:\n            style = lv_btnm_get_style(ext->btnm, LV_BTNM_STYLE_BTN_INA);\n            break;\n        default:\n            style = NULL;\n            break;\n    }\n\n    return style;\n}\n\n/**\n * Get whether recoloring is enabled\n * @param btnm pointer to button matrix object\n * @return whether recoloring is enabled\n */\nbool lv_mbox_get_recolor(const lv_obj_t * mbox)\n{\n\tlv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);\n\n\tif(!ext->btnm)\n\t\treturn false;\n\n\treturn lv_btnm_get_recolor(ext->btnm);\n}\n\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Signal function of the message box\n * @param mbox pointer to a message box object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_mbox_signal(lv_obj_t * mbox, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /*Translate LV_GROUP_KEY_UP/DOWN to LV_GROUP_KEY_LEFT/RIGHT */\n    char c_trans = 0;\n    if(sign == LV_SIGNAL_CONTROLL) {\n        c_trans = *((char *)param);\n        if(c_trans == LV_GROUP_KEY_DOWN) c_trans = LV_GROUP_KEY_LEFT;\n        if(c_trans == LV_GROUP_KEY_UP) c_trans = LV_GROUP_KEY_RIGHT;\n\n        param = &c_trans;\n    }\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(mbox, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);\n    if(sign == LV_SIGNAL_CORD_CHG) {\n        if(lv_obj_get_width(mbox) != lv_area_get_width(param)) {\n            mbox_realign(mbox);\n        }\n    } else if(sign == LV_SIGNAL_STYLE_CHG) {\n        mbox_realign(mbox);\n\n    } else if(sign == LV_SIGNAL_FOCUS || sign == LV_SIGNAL_DEFOCUS ||\n              sign == LV_SIGNAL_CONTROLL || sign == LV_SIGNAL_GET_EDITABLE) {\n        if(ext->btnm) {\n            ext->btnm->signal_func(ext->btnm, sign, param);\n        }\n\n        /* The button matrix with ENCODER input supposes it's in a group but in this case it isn't (Only the message box's container)\n         * So so some actions here instead*/\n        if(sign == LV_SIGNAL_FOCUS) {\n#if USE_LV_GROUP\n            lv_indev_t * indev = lv_indev_get_act();\n            lv_hal_indev_type_t indev_type = lv_indev_get_type(indev);\n            if(indev_type == LV_INDEV_TYPE_ENCODER) {\n                /*In navigation mode don't select any button but in edit mode select the fist*/\n                lv_btnm_ext_t * btnm_ext = lv_obj_get_ext_attr(ext->btnm);\n                if(lv_group_get_editing(lv_obj_get_group(mbox))) btnm_ext->btn_id_pr = 0;\n                else btnm_ext->btn_id_pr = LV_BTNM_PR_NONE;\n            }\n#endif\n        }\n\n\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_mbox\";\n    }\n\n    return res;\n}\n\n/**\n * Resize the button holder to fit\n * @param mbox pointer to message box object\n */\nstatic void mbox_realign(lv_obj_t * mbox)\n{\n    lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);\n\n    lv_style_t * style = lv_mbox_get_style(mbox, LV_MBOX_STYLE_BG);\n    lv_coord_t w = lv_obj_get_width(mbox) - 2 * style->body.padding.hor;\n\n    if(ext->text) {\n        lv_obj_set_width(ext->text, w);\n    }\n\n    if(ext->btnm) {\n        lv_style_t * btn_bg_style = lv_mbox_get_style(mbox, LV_MBOX_STYLE_BTN_BG);\n        lv_style_t * btn_rel_style = lv_mbox_get_style(mbox, LV_MBOX_STYLE_BTN_REL);\n        lv_coord_t font_h = lv_font_get_height(btn_rel_style->text.font);\n        lv_obj_set_size(ext->btnm, w, font_h + 2 * btn_rel_style->body.padding.ver + 2 * btn_bg_style->body.padding.ver);\n    }\n}\n\nstatic lv_res_t lv_mbox_close_action(lv_obj_t * btn, const char * txt)\n{\n    lv_obj_t * mbox = lv_mbox_get_from_btn(btn);\n\n    if(txt[0] != '\\0') {\n        lv_mbox_start_auto_close(mbox, 0);\n        return LV_RES_INV;\n    }\n\n    return LV_RES_OK;\n}\n\n#if USE_LV_ANIMATION\nstatic void lv_mbox_close_end_cb(lv_obj_t * mbox)\n{\n    lv_obj_del(mbox);\n}\n#endif\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_mbox.h",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * @file lv_mbox.h\n *\n */\n\n#ifndef LV_MBOX_H\n#define LV_MBOX_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_MBOX != 0\n\n/*Testing of dependencies*/\n#if USE_LV_CONT == 0\n#error \"lv_mbox: lv_cont is required. Enable it in lv_conf.h (USE_LV_CONT  1) \"\n#endif\n\n#if USE_LV_BTNM == 0\n#error \"lv_mbox: lv_btnm is required. Enable it in lv_conf.h (USE_LV_BTNM  1) \"\n#endif\n\n#if USE_LV_LABEL == 0\n#error \"lv_mbox: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL  1) \"\n#endif\n\n\n#include \"../lv_core/lv_obj.h\"\n#include \"lv_cont.h\"\n#include \"lv_btnm.h\"\n#include \"lv_label.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/*Data of message box*/\ntypedef struct\n{\n    lv_cont_ext_t bg; /*Ext. of ancestor*/\n    /*New data for this type */\n    lv_obj_t *text;             /*Text of the message box*/\n    lv_obj_t *btnm;            /*Button matrix for the buttons*/\n    uint16_t anim_time;         /*Duration of close animation [ms] (0: no animation)*/\n} lv_mbox_ext_t;\n\nenum {\n    LV_MBOX_STYLE_BG,\n    LV_MBOX_STYLE_BTN_BG,\n    LV_MBOX_STYLE_BTN_REL,\n    LV_MBOX_STYLE_BTN_PR,\n    LV_MBOX_STYLE_BTN_TGL_REL,\n    LV_MBOX_STYLE_BTN_TGL_PR,\n    LV_MBOX_STYLE_BTN_INA,\n};\ntypedef uint8_t lv_mbox_style_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a message box objects\n * @param par pointer to an object, it will be the parent of the new message box\n * @param copy pointer to a message box object, if not NULL then the new object will be copied from it\n * @return pointer to the created message box\n */\nlv_obj_t * lv_mbox_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n/**\n * Add button to the message box\n * @param mbox pointer to message box object\n * @param btn_map button descriptor (button matrix map).\n *                E.g.  a const char *txt[] = {\"ok\", \"close\", \"\"} (Can not be local variable)\n * @param action a function which will be called when a button is released\n */\nvoid lv_mbox_add_btns(lv_obj_t * mbox, const char **btn_map, lv_btnm_action_t action);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set the text of the message box\n * @param mbox pointer to a message box\n * @param txt a '\\0' terminated character string which will be the message box text\n */\nvoid lv_mbox_set_text(lv_obj_t * mbox, const char * txt);\n\n/**\n * Stop the action to call when button is released\n * @param mbox pointer to a message box object\n * @param pointer to an 'lv_btnm_action_t' action. In the action you need to use `lv_mbox_get_from_btn()` to get the `mbox`.\n */\nvoid lv_mbox_set_action(lv_obj_t * mbox, lv_btnm_action_t action);\n\n/**\n * Set animation duration\n * @param mbox pointer to a message box object\n * @param anim_time animation length in  milliseconds (0: no animation)\n */\nvoid lv_mbox_set_anim_time(lv_obj_t * mbox, uint16_t anim_time);\n\n/**\n * Automatically delete the message box after a given time\n * @param mbox pointer to a message box object\n * @param delay a time (in milliseconds) to wait before delete the message box\n */\nvoid lv_mbox_start_auto_close(lv_obj_t * mbox, uint16_t delay);\n\n/**\n * Stop the auto. closing of message box\n * @param mbox pointer to a message box object\n */\nvoid lv_mbox_stop_auto_close(lv_obj_t * mbox);\n\n/**\n * Set a style of a message box\n * @param mbox pointer to a message box object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_mbox_set_style(lv_obj_t *mbox, lv_mbox_style_t type, lv_style_t *style);\n\n/**\n * Set whether recoloring is enabled. Must be called after `lv_mbox_add_btns`.\n * @param btnm pointer to button matrix object\n * @param en whether recoloring is enabled\n */\nvoid lv_mbox_set_recolor(lv_obj_t * mbox, bool en);\n\nvoid lv_mbox_set_recolor_text(lv_obj_t * mbox, bool en);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the text of the message box\n * @param mbox pointer to a message box object\n * @return pointer to the text of the message box\n */\nconst char * lv_mbox_get_text(const lv_obj_t * mbox);\n\n/**\n * Get the message box object from one of its button.\n * It is useful in the button release actions where only the button is known\n * @param btn pointer to a button of a message box\n * @return pointer to the button's message box\n */\nlv_obj_t * lv_mbox_get_from_btn(const lv_obj_t * btn);\n\n/**\n * Get the animation duration (close animation time)\n * @param mbox pointer to a message box object\n * @return animation length in  milliseconds (0: no animation)\n */\nuint16_t lv_mbox_get_anim_time(const lv_obj_t * mbox);\n\n\n/**\n * Get a style of a message box\n * @param mbox pointer to a message box object\n * @param type which style should be get\n * @return style pointer to a style\n */\nlv_style_t * lv_mbox_get_style(const lv_obj_t *mbox, lv_mbox_style_t type);\n\n/**\n * Get whether recoloring is enabled\n * @param btnm pointer to button matrix object\n * @return whether recoloring is enabled\n */\nbool lv_mbox_get_recolor(const lv_obj_t * mbox);\n\n/**********************\n *      MACROS\n **********************/\n\n\n#endif  /*USE_LV_MBOX*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_MBOX_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_objx.mk",
    "content": "CSRCS += lv_arc.c\nCSRCS += lv_bar.c\nCSRCS += lv_cb.c\nCSRCS += lv_ddlist.c\nCSRCS += lv_kb.c\nCSRCS += lv_line.c\nCSRCS += lv_mbox.c\nCSRCS += lv_preload.c\nCSRCS += lv_roller.c\nCSRCS += lv_table.c\nCSRCS += lv_tabview.c\nCSRCS += lv_tileview.c\nCSRCS += lv_btn.c\nCSRCS += lv_calendar.c\nCSRCS += lv_chart.c\nCSRCS += lv_canvas.c\nCSRCS += lv_gauge.c\nCSRCS += lv_label.c\nCSRCS += lv_list.c\nCSRCS += lv_slider.c\nCSRCS += lv_ta.c\nCSRCS += lv_spinbox.c\nCSRCS += lv_btnm.c\nCSRCS += lv_cont.c\nCSRCS += lv_img.c\nCSRCS += lv_imgbtn.c\nCSRCS += lv_led.c\nCSRCS += lv_lmeter.c\nCSRCS += lv_page.c\nCSRCS += lv_sw.c\nCSRCS += lv_win.c\n\nDEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_objx\nVPATH += :$(LVGL_DIR)/lvgl/lv_objx\n\nCFLAGS += \"-I$(LVGL_DIR)/lvgl/lv_objx\"\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_objx_templ.c",
    "content": "/**\n * @file lv_templ.c\n *\n */\n\n/* TODO Remove these instructions\n * Search an replace: template -> object normal name with lower case (e.g. button, label etc.)\n *                    templ -> object short name with lower case(e.g. btn, label etc)\n *                    TEMPL -> object short name with upper case (e.g. BTN, LABEL etc.)\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n//#include \"lv_templ.h\" /*TODO uncomment this*/\n#if USE_LV_TEMPL != 0\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool lv_templ_design(lv_obj_t * templ, const lv_area_t * mask, lv_design_mode_t mode);\nstatic lv_res_t lv_templ_signal(lv_obj_t * templ, lv_signal_t sign, void * param);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\nstatic lv_design_func_t ancestor_design;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a template object\n * @param par pointer to an object, it will be the parent of the new template\n * @param copy pointer to a template object, if not NULL then the new object will be copied from it\n * @return pointer to the created template\n */\nlv_obj_t * lv_templ_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"template create started\");\n\n    /*Create the ancestor of template*/\n    /*TODO modify it to the ancestor create function */\n    lv_obj_t * new_templ = lv_ANCESTOR_create(par, copy);\n    lv_mem_assert(new_templ);\n    if(new_templ == NULL) return NULL;\n\n    /*Allocate the template type specific extended data*/\n    lv_templ_ext_t * ext = lv_obj_allocate_ext_attr(new_templ, sizeof(lv_templ_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_templ);\n    if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_templ);\n\n    /*Initialize the allocated 'ext' */\n    ext->xyz = 0;\n\n    /*The signal and design functions are not copied so set them here*/\n    lv_obj_set_signal_func(new_templ, lv_templ_signal);\n    lv_obj_set_design_func(new_templ, lv_templ_design);\n\n    /*Init the new template template*/\n    if(copy == NULL) {\n\n    }\n    /*Copy an existing template*/\n    else {\n        lv_templ_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_templ);\n    }\n\n    LV_LOG_INFO(\"template created\");\n\n    return new_templ;\n}\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n/*\n * New object specific \"add\" or \"remove\" functions come here\n */\n\n\n/*=====================\n * Setter functions\n *====================*/\n\n/*\n * New object specific \"set\" functions come here\n */\n\n\n/**\n * Set a style of a template.\n * @param templ pointer to template object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_templ_set_style(lv_obj_t * templ, lv_templ_style_t type, lv_style_t * style)\n{\n    lv_templ_ext_t * ext = lv_obj_get_ext_attr(templ);\n\n    switch(type) {\n        case LV_TEMPL_STYLE_X:\n            break;\n        case LV_TEMPL_STYLE_Y:\n            break;\n    }\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/*\n * New object specific \"get\" functions come here\n */\n\n/**\n * Get style of a template.\n * @param templ pointer to template object\n * @param type which style should be get\n * @return style pointer to the style\n */\nlv_style_t * lv_templ_get_style(const lv_obj_t * templ, lv_templ_style_t type)\n{\n    lv_templ_ext_t * ext = lv_obj_get_ext_attr(templ);\n    lv_style_t * style = NULL;\n\n    switch(type) {\n        case LV_TEMPL_STYLE_X:\n            style =  NULL;      /*Replace NULL with a pointer to the style*/\n        case LV_TEMPL_STYLE_Y:\n            style = NULL;       /*Replace NULL with a pointer to the style*/\n        default:\n            style =  NULL;\n    }\n\n    return style;\n}\n\n/*=====================\n * Other functions\n *====================*/\n\n/*\n * New object specific \"other\" functions come here\n */\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Handle the drawing related tasks of the templates\n * @param templ pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_templ_design(lv_obj_t * templ, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    /*Return false if the object is not covers the mask_p area*/\n    if(mode == LV_DESIGN_COVER_CHK) {\n        return false;\n    }\n    /*Draw the object*/\n    else if(mode == LV_DESIGN_DRAW_MAIN) {\n\n    }\n    /*Post draw when the children are drawn*/\n    else if(mode == LV_DESIGN_DRAW_POST) {\n\n    }\n\n    return true;\n}\n\n/**\n * Signal function of the template\n * @param templ pointer to a template object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_templ_signal(lv_obj_t * templ, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(templ, sign, param);\n    if(res != LV_RES_OK) return res;\n\n\n    if(sign == LV_SIGNAL_CLEANUP) {\n        /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_templ\";\n    }\n\n    return res;\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_objx_templ.h",
    "content": "/**\n * @file lv_templ.h\n *\n */\n\n\n/* TODO Remove these instructions\n * Search an replace: template -> object normal name with lower case (e.g. button, label etc.)\n *                    templ -> object short name with lower case(e.g. btn, label etc)\n *                    TEMPL -> object short name with upper case (e.g. BTN, LABEL etc.)\n *\n */\n\n#ifndef LV_TEMPL_H\n#define LV_TEMPL_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_TEMPL != 0\n\n#include \"../lv_core/lv_obj.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n/*Data of template*/\ntypedef struct {\n    lv_ANCESTOR_ext_t ANCESTOR; /*Ext. of ancestor*/\n    /*New data for this type */\n} lv_templ_ext_t;\n\n\n/*Styles*/\nenum {\n    LV_TEMPL_STYLE_X,\n    LV_TEMPL_STYLE_Y,\n};\ntypedef uint8_t lv_templ_style_t;\n\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a template objects\n * @param par pointer to an object, it will be the parent of the new template\n * @param copy pointer to a template object, if not NULL then the new object will be copied from it\n * @return pointer to the created template\n */\nlv_obj_t * lv_templ_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a style of a template.\n * @param templ pointer to template object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_templ_set_style(lv_obj_t * templ, lv_templ_style_t type, lv_style_t *style);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get style of a template.\n * @param templ pointer to template object\n * @param type which style should be get\n * @return style pointer to the style\n */\nlv_style_t * lv_templ_get_style(const lv_obj_t * templ, lv_templ_style_t type);\n\n/*=====================\n * Other functions\n *====================*/\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_TEMPL*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_TEMPL_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_page.c",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * @file lv_page.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"../lv_objx/lv_page.h\"\n#if USE_LV_PAGE != 0\n\n#include \"../lv_core/lv_group.h\"\n#include \"../lv_draw/lv_draw.h\"\n#include \"../lv_themes/lv_theme.h\"\n#include \"../lv_core/lv_refr.h\"\n#include \"../lv_misc/lv_anim.h\"\n#include \"../lv_misc/lv_math.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_PAGE_SB_MIN_SIZE             (LV_DPI / 8)\n#define LV_PAGE_SCROLL_ANIM_TIME        200           /*[ms] Scroll anim time on `lv_page_scroll_up/down/left/rigth`*/\n#define LV_PAGE_END_FLASH_SIZE          (LV_DPI / 4)\n#define LV_PAGE_END_ANIM_TIME           300\n#define LV_PAGE_END_ANIM_WAIT_TIME      300\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic void lv_page_sb_refresh(lv_obj_t * page);\nstatic bool lv_page_design(lv_obj_t * page, const lv_area_t * mask, lv_design_mode_t mode);\nstatic bool lv_scrl_design(lv_obj_t * scrl, const lv_area_t * mask, lv_design_mode_t mode);\nstatic lv_res_t lv_page_signal(lv_obj_t * page, lv_signal_t sign, void * param);\nstatic lv_res_t lv_page_scrollable_signal(lv_obj_t * scrl, lv_signal_t sign, void * param);\n#if USE_LV_ANIMATION\nstatic void edge_flash_anim(void * page, int32_t v);\nstatic void edge_flash_anim_end(void * page);\n#endif\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_design_func_t ancestor_design;\nstatic lv_signal_func_t ancestor_signal;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a page objects\n * @param par pointer to an object, it will be the parent of the new page\n * @param copy pointer to a page object, if not NULL then the new object will be copied from it\n * @return pointer to the created page\n */\nlv_obj_t * lv_page_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"page create started\");\n\n    /*Create the ancestor object*/\n    lv_obj_t * new_page = lv_cont_create(par, copy);\n    lv_mem_assert(new_page);\n    if(new_page == NULL) return NULL;\n\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_page);\n    if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_page);\n\n    /*Allocate the object type specific extended data*/\n    lv_page_ext_t * ext = lv_obj_allocate_ext_attr(new_page, sizeof(lv_page_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    ext->scrl = NULL;\n    ext->pr_action = NULL;\n    ext->rel_action = NULL;\n    ext->sb.hor_draw = 0;\n    ext->sb.ver_draw = 0;\n\text->bgo = NULL;\n\text->pr = NULL;\n    ext->sb.style = &lv_style_pretty;\n    ext->sb.mode = LV_SB_MODE_AUTO;\n    ext->edge_flash.enabled = 0;\n    ext->edge_flash.bottom_ip = 0;\n    ext->edge_flash.top_ip = 0;\n    ext->edge_flash.left_ip = 0;\n    ext->edge_flash.right_ip = 0;\n    ext->edge_flash.state = 0;\n    ext->edge_flash.style = &lv_style_plain_color;\n    ext->arrow_scroll = 0;\n    ext->scroll_prop = 0;\n    ext->scroll_prop_ip = 0;\n\n    /*Init the new page object*/\n    if(copy == NULL) {\n        ext->scrl = lv_cont_create(new_page, NULL);\n        lv_obj_set_signal_func(ext->scrl, lv_page_scrollable_signal);\n        lv_obj_set_design_func(ext->scrl, lv_scrl_design);\n        lv_obj_set_drag(ext->scrl, true);\n        lv_obj_set_drag_throw(ext->scrl, true);\n        lv_obj_set_protect(ext->scrl, LV_PROTECT_PARENT | LV_PROTECT_PRESS_LOST);\n        lv_cont_set_fit(ext->scrl, false, true);\n\n        /* Add the signal function only if 'scrolling' is created\n         * because everything has to be ready before any signal is received*/\n        lv_obj_set_signal_func(new_page, lv_page_signal);\n        lv_obj_set_design_func(new_page, lv_page_design);\n\n        lv_page_set_sb_mode(new_page, ext->sb.mode);\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            if(par == NULL) { /*Different styles if it is screen*/\n                lv_page_set_style(new_page, LV_PAGE_STYLE_BG, th->bg);\n                lv_page_set_style(new_page, LV_PAGE_STYLE_SCRL, &lv_style_transp);\n            } else {\n                lv_page_set_style(new_page, LV_PAGE_STYLE_BG, th->page.bg);\n                lv_page_set_style(new_page, LV_PAGE_STYLE_SCRL, th->page.scrl);\n\n            }\n            lv_page_set_style(new_page, LV_PAGE_STYLE_SB, th->page.sb);\n        } else {\n            lv_page_set_style(new_page, LV_PAGE_STYLE_BG, &lv_style_pretty_color);\n            lv_page_set_style(new_page, LV_PAGE_STYLE_SCRL, &lv_style_pretty);\n            lv_page_set_style(new_page, LV_PAGE_STYLE_SB, &lv_style_pretty_color);\n        }\n\n    } else {\n        lv_page_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        ext->scrl = lv_cont_create(new_page, copy_ext->scrl);\n\t\text->bgo = lv_page_get_style(copy, LV_PAGE_STYLE_BGO);\n\t\text->pr = lv_page_get_style(copy, LV_PAGE_STYLE_PR);\n        lv_obj_set_signal_func(ext->scrl, lv_page_scrollable_signal);\n\n        lv_page_set_pr_action(new_page, copy_ext->pr_action);\n        lv_page_set_rel_action(new_page, copy_ext->rel_action);\n        lv_page_set_sb_mode(new_page, copy_ext->sb.mode);\n        lv_page_set_arrow_scroll(new_page, copy_ext->arrow_scroll);\n\n\n        lv_page_set_style(new_page, LV_PAGE_STYLE_BG, lv_page_get_style(copy, LV_PAGE_STYLE_BG));\n        lv_page_set_style(new_page, LV_PAGE_STYLE_SCRL, lv_page_get_style(copy, LV_PAGE_STYLE_SCRL));\n        lv_page_set_style(new_page, LV_PAGE_STYLE_SB, lv_page_get_style(copy, LV_PAGE_STYLE_SB));\n\n        /* Add the signal function only if 'scrolling' is created\n         * because everything has to be ready before any signal is received*/\n        lv_obj_set_signal_func(new_page, lv_page_signal);\n        lv_obj_set_design_func(new_page, lv_page_design);\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_page);\n    }\n\n    lv_page_sb_refresh(new_page);\n\n    LV_LOG_INFO(\"page created\");\n\n    return new_page;\n}\n\n/**\n * Delete all children of the scrl object, without deleting scrl child.\n * @param obj pointer to an object\n */\nvoid lv_page_clean(lv_obj_t * obj)\n{\n    lv_obj_t * scrl = lv_page_get_scrl(obj);\n    lv_obj_clean(scrl);\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a release action for the page\n * @param page pointer to a page object\n * @param rel_action a function to call when the page is release\n */\nvoid lv_page_set_rel_action(lv_obj_t * page, lv_action_t rel_action)\n{\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n    ext->rel_action = rel_action;\n}\n\n/**\n * Set a press action for the page\n * @param page pointer to a page object\n * @param pr_action a function to call when the page is pressed\n */\nvoid lv_page_set_pr_action(lv_obj_t * page, lv_action_t pr_action)\n{\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n    ext->pr_action = pr_action;\n}\n\n/**\n * Set the scroll bar mode on a page\n * @param page pointer to a page object\n * @param sb_mode the new mode from 'lv_page_sb.mode_t' enum\n */\nvoid lv_page_set_sb_mode(lv_obj_t * page, lv_sb_mode_t sb_mode)\n{\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n    if(ext->sb.mode == sb_mode) return;\n\n    if(sb_mode == LV_SB_MODE_HIDE) ext->sb.mode |= LV_SB_MODE_HIDE;                 /*Set the hidden flag*/\n    else if(sb_mode == LV_SB_MODE_UNHIDE) ext->sb.mode &= (~LV_SB_MODE_HIDE);       /*Clear the hidden flag*/\n    else {\n        if(ext->sb.mode & LV_SB_MODE_HIDE) sb_mode |= LV_SB_MODE_HIDE;\n        ext->sb.mode = sb_mode;\n    }\n\n    ext->sb.hor_draw = 0;\n    ext->sb.ver_draw = 0;\n\n    lv_page_sb_refresh(page);\n    lv_obj_invalidate(page);\n}\n\n/**\n * Enable/Disable scrolling with arrows if the page is in group (arrows: LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN)\n * @param page pointer to a page object\n * @param en true: enable scrolling with arrows\n */\nvoid lv_page_set_arrow_scroll(lv_obj_t * page, bool en)\n{\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n    ext->arrow_scroll = en ? 1 : 0;\n}\n\n/**\n * Enable the scroll propagation feature. If enabled then the page will move its parent if there is no more space to scroll.\n * @param page pointer to a Page\n * @param en true or false to enable/disable scroll propagation\n */\nvoid lv_page_set_scroll_propagation(lv_obj_t * page, bool en)\n{\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n    ext->scroll_prop = en ? 1 : 0;\n}\n\n/**\n * Enable the edge flash effect. (Show an arc when the an edge is reached)\n * @param page pointer to a Page\n * @param en true or false to enable/disable end flash\n */\nvoid lv_page_set_edge_flash(lv_obj_t * page, bool en)\n{\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n    ext->edge_flash.enabled = en ? 1 : 0;\n}\n\n/**\n * Set a style of a page\n * @param page pointer to a page object\n * @param type which style should be set\n * @param style pointer to a style\n *  */\nvoid lv_page_set_style(lv_obj_t * page, lv_page_style_t type, lv_style_t * style)\n{\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n\n    switch(type) {\n        case LV_PAGE_STYLE_BG:\n            lv_obj_set_style(page, style);\n            break;\n\t\tcase LV_PAGE_STYLE_BGO:\n\t\t\text->bgo = style;\n\t\t\tbreak;\n\t\tcase LV_PAGE_STYLE_PR:\n\t\t\text->pr = style;\n\t\t\tbreak;\n        case LV_PAGE_STYLE_SCRL:\n            lv_obj_set_style(ext->scrl, style);\n            break;\n        case LV_PAGE_STYLE_SB:\n            ext->sb.style = style;\n            lv_area_set_height(&ext->sb.hor_area, ext->sb.style->body.padding.inner);\n            lv_area_set_width(&ext->sb.ver_area, ext->sb.style->body.padding.inner);\n            lv_page_sb_refresh(page);\n            lv_obj_refresh_ext_size(page);\n            lv_obj_invalidate(page);\n            break;\n        case LV_PAGE_STYLE_EDGE_FLASH:\n            ext->edge_flash.style = style;\n            break;\n    }\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the scrollable object of a page\n * @param page pointer to a page object\n * @return pointer to a container which is the scrollable part of the page\n */\nlv_obj_t * lv_page_get_scrl(const lv_obj_t * page)\n{\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n\n    return ext->scrl;\n}\n\n/**\n * Get the press action of the page\n * @param page pointer to a page object\n * @return a function to call when the page is pressed\n */\nlv_action_t lv_page_get_pr_action(lv_obj_t * page)\n{\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n    return ext->pr_action;\n}\n\n/**\n * Get the release action of the page\n * @param page pointer to a page object\n * @return a function to call when the page is released\n */\nlv_action_t lv_page_get_rel_action(lv_obj_t * page)\n{\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n    return ext->rel_action;\n}\n\n/**\n * Set the scroll bar mode on a page\n * @param page pointer to a page object\n * @return the mode from 'lv_page_sb.mode_t' enum\n */\nlv_sb_mode_t lv_page_get_sb_mode(const lv_obj_t * page)\n{\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n    return ext->sb.mode;\n}\n\n/**\n * Get the the scrolling with arrows (LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN) is enabled or not\n * @param page pointer to a page object\n * @return true: scrolling with arrows is enabled\n */\nbool lv_page_get_arrow_scroll(const lv_obj_t * page)\n{\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n    return ext->arrow_scroll ? true : false;\n}\n\n/**\n * Get the scroll propagation property\n * @param page pointer to a Page\n * @return true or false\n */\nbool lv_page_get_scroll_propagation(lv_obj_t * page)\n{\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n    return ext->scroll_prop == 0 ? false : true;\n}\n\n/**\n * Get the edge flash effect property.\n * @param page pointer to a Page\n * return true or false\n */\nbool lv_page_get_edge_flash(lv_obj_t * page)\n{\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n    return ext->edge_flash.enabled == 0 ? false : true;\n}\n\n/**\n * Get that width which can be set to the children to still not cause overflow (show scrollbars)\n * @param page pointer to a page object\n * @return the width which still fits into the page\n */\nlv_coord_t lv_page_get_fit_width(lv_obj_t * page)\n{\n    lv_style_t * bg_style = lv_page_get_style(page, LV_PAGE_STYLE_BG);\n    lv_style_t * scrl_style = lv_page_get_style(page, LV_PAGE_STYLE_SCRL);\n\n    return lv_obj_get_width(page) - 2 * (bg_style->body.padding.hor + scrl_style->body.padding.hor);\n}\n\n/**\n * Get that height which can be set to the children to still not cause overflow (show scrollbars)\n * @param page pointer to a page object\n * @return the height which still fits into the page\n */\nlv_coord_t lv_page_get_fit_height(lv_obj_t * page)\n{\n    lv_style_t * bg_style = lv_page_get_style(page, LV_PAGE_STYLE_BG);\n    lv_style_t * scrl_style = lv_page_get_style(page, LV_PAGE_STYLE_SCRL);\n\n    return lv_obj_get_height(page) - 2 * (bg_style->body.padding.ver + scrl_style->body.padding.ver);\n}\n\n/**\n * Get a style of a page\n * @param page pointer to page object\n * @param type which style should be get\n * @return style pointer to a style\n *  */\nlv_style_t * lv_page_get_style(const lv_obj_t * page, lv_page_style_t type)\n{\n    lv_style_t * style = NULL;\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n\n    switch(type) {\n\t\tcase LV_PAGE_STYLE_BG:\n\t\t\tstyle = lv_obj_get_style(page);\n\t\t\tbreak;\n        case LV_PAGE_STYLE_BGO:\n\t\t\tstyle = ext->bgo;\n\t\t\tbreak;\n\t\tcase LV_PAGE_STYLE_PR:\n            style = ext->pr;\n            break;\n        case LV_PAGE_STYLE_SCRL:\n            style = lv_obj_get_style(ext->scrl);\n            break;\n        case LV_PAGE_STYLE_SB:\n            style = ext->sb.style;\n            break;\n        case LV_PAGE_STYLE_EDGE_FLASH:\n            style = ext->edge_flash.style;\n            break;\n        default:\n            style = NULL;\n            break;\n    }\n\n    return style;\n}\n\n/*=====================\n * Other functions\n *====================*/\n\n/**\n * Glue the object to the page. After it the page can be moved (dragged) with this object too.\n * @param obj pointer to an object on a page\n * @param glue true: enable glue, false: disable glue\n */\nvoid lv_page_glue_obj(lv_obj_t * obj, bool glue)\n{\n    lv_obj_set_drag_parent(obj, glue);\n    lv_obj_set_drag(obj, glue);\n}\n\n/**\n * Focus on an object. It ensures that the object will be visible on the page.\n * @param page pointer to a page object\n * @param obj pointer to an object to focus (must be on the page)\n * @param anim_time scroll animation time in milliseconds (0: no animation)\n */\nvoid lv_page_focus(lv_obj_t * page, const lv_obj_t * obj, uint16_t anim_time)\n{\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n\n#if USE_LV_ANIMATION == 0\n    anim_time = 0;\n#else\n    /* Be sure there is no position changing animation in progress\n     * because it can overide the current changes*/\n    lv_anim_del(page, (lv_anim_fp_t)lv_obj_set_y);\n    lv_anim_del(page, (lv_anim_fp_t)lv_obj_set_pos);\n    lv_anim_del(ext->scrl, (lv_anim_fp_t)lv_obj_set_y);\n    lv_anim_del(ext->scrl, (lv_anim_fp_t)lv_obj_set_pos);\n#endif\n\n    lv_style_t * style = lv_page_get_style(page, LV_PAGE_STYLE_BG);\n    lv_style_t * style_scrl = lv_page_get_style(page, LV_PAGE_STYLE_SCRL);\n\n    lv_coord_t obj_y = obj->coords.y1 - ext->scrl->coords.y1;\n    lv_coord_t obj_h = lv_obj_get_height(obj);\n    lv_coord_t scrlable_y = lv_obj_get_y(ext->scrl);\n    lv_coord_t page_h = lv_obj_get_height(page);\n\n    lv_coord_t top_err = -(scrlable_y + obj_y);\n    lv_coord_t bot_err = scrlable_y + obj_y + obj_h - page_h;\n\n    /*If obj is higher then the page focus where the \"error\" is smaller*/\n\n    /*Out of the page on the top*/\n    if((obj_h <= page_h && top_err > 0) ||\n            (obj_h > page_h && top_err < bot_err)) {\n        /*Calculate a new position and let some space above*/\n        scrlable_y = -(obj_y - style_scrl->body.padding.ver - style->body.padding.ver);\n        scrlable_y += style_scrl->body.padding.ver;\n    }\n    /*Out of the page on the bottom*/\n    else if((obj_h <= page_h && bot_err > 0) ||\n            (obj_h > page_h && top_err >= bot_err)) {\n        /*Calculate a new position and let some space below*/\n        scrlable_y = -(obj_y + style_scrl->body.padding.ver + style->body.padding.ver);\n        scrlable_y -= style_scrl->body.padding.ver;\n        scrlable_y += page_h - obj_h;\n    } else {\n        /*Already in focus*/\n        return;\n    }\n\n    if(anim_time == 0) {\n        lv_obj_set_y(ext->scrl, scrlable_y);\n#if USE_LV_ANIMATION\n    } else {\n        lv_anim_t a;\n        a.act_time = 0;\n        a.start = lv_obj_get_y(ext->scrl);\n        a.end = scrlable_y;\n        a.time = anim_time;\n        a.end_cb = NULL;\n        a.playback = 0;\n        a.repeat = 0;\n        a.var = ext->scrl;\n        a.path = lv_anim_path_linear;\n        a.fp = (lv_anim_fp_t) lv_obj_set_y;\n        lv_anim_create(&a);\n#endif\n    }\n}\n\n/**\n * Scroll the page horizontally\n * @param page pointer to a page object\n * @param dist the distance to scroll (< 0: scroll right; > 0 scroll left)\n */\nvoid lv_page_scroll_hor(lv_obj_t * page, lv_coord_t dist)\n{\n    lv_obj_t * scrl = lv_page_get_scrl(page);\n\n#if USE_LV_ANIMATION\n    lv_anim_t a;\n    a.var = scrl;\n    a.start = lv_obj_get_x(scrl);\n    a.end = a.start + dist;\n    a.fp = (lv_anim_fp_t)lv_obj_set_x;\n    a.path = lv_anim_path_linear;\n    a.end_cb = NULL;\n    a.act_time = 0;\n    a.time = LV_PAGE_SCROLL_ANIM_TIME;\n    a.playback = 0;\n    a.playback_pause = 0;\n    a.repeat = 0;\n    a.repeat_pause = 0;\n    lv_anim_create(&a);\n#else\n    lv_obj_set_x(scrl, lv_obj_get_x(scrl) + dist);\n#endif\n}\n\n/**\n * Scroll the page vertically\n * @param page pointer to a page object\n * @param dist the distance to scroll (< 0: scroll down; > 0 scroll up)\n */\nvoid lv_page_scroll_ver(lv_obj_t * page, lv_coord_t dist)\n{\n    lv_obj_t * scrl = lv_page_get_scrl(page);\n\n#if USE_LV_ANIMATION\n    lv_anim_t a;\n    a.var = scrl;\n    a.start = lv_obj_get_y(scrl);\n    a.end = a.start + dist;\n    a.fp = (lv_anim_fp_t)lv_obj_set_y;\n    a.path = lv_anim_path_linear;\n    a.end_cb = NULL;\n    a.act_time = 0;\n    a.time = LV_PAGE_SCROLL_ANIM_TIME;\n    a.playback = 0;\n    a.playback_pause = 0;\n    a.repeat = 0;\n    a.repeat_pause = 0;\n    lv_anim_create(&a);\n#else\n    lv_obj_set_y(scrl, lv_obj_get_y(scrl) + dist);\n#endif\n}\n\n/**\n * Not intended to use directly by the user but by other object types internally.\n * Start an edge flash animation. Exactly one `ext->edge_flash.xxx_ip` should be set\n * @param page\n */\nvoid lv_page_start_edge_flash(lv_obj_t * page)\n{\n#if USE_LV_ANIMATION\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n    if(ext->edge_flash.enabled) {\n        lv_anim_t a;\n        a.var = page;\n        a.start = 0;\n        a.end = LV_PAGE_END_FLASH_SIZE;\n        a.fp = (lv_anim_fp_t)edge_flash_anim;\n        a.path = lv_anim_path_linear;\n        a.end_cb = edge_flash_anim_end;\n        a.act_time = 0;\n        a.time = LV_PAGE_END_ANIM_TIME;\n        a.playback = 1;\n        a.playback_pause = LV_PAGE_END_ANIM_WAIT_TIME;\n        a.repeat = 0;\n        a.repeat_pause = 0;\n        lv_anim_create(&a);\n    }\n#endif\n}\n\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Handle the drawing related tasks of the pages\n * @param page pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_page_design(lv_obj_t * page, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    if(mode == LV_DESIGN_COVER_CHK) {\n        return ancestor_design(page, mask, mode);\n    } else if(mode == LV_DESIGN_DRAW_MAIN) {\n        /*Draw without border*/\n        lv_style_t * style = lv_page_get_style(page, LV_PAGE_STYLE_BG);\n        lv_coord_t border_width_tmp =  style->body.border.width;\n        style->body.border.width = 0;\n        lv_draw_rect(&page->coords, mask, style, lv_obj_get_opa_scale(page));\n        style->body.border.width = border_width_tmp;\n\n    } else if(mode == LV_DESIGN_DRAW_POST) { /*Draw the scroll bars finally*/\n\n        /*Draw only a border*/\n        lv_style_t * style = lv_page_get_style(page, LV_PAGE_STYLE_BG);\n        lv_coord_t shadow_width_tmp =  style->body.shadow.width;\n        uint8_t empty_tmp =  style->body.empty;\n        style->body.shadow.width = 0;\n        style->body.empty = 1;\n        lv_draw_rect(&page->coords, mask, style, lv_obj_get_opa_scale(page));\n        style->body.shadow.width = shadow_width_tmp;\n        style->body.empty = empty_tmp;\n\n        lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n\n        /*Draw the scrollbars*/\n        lv_area_t sb_area;\n        if(ext->sb.hor_draw && (ext->sb.mode & LV_SB_MODE_HIDE) == 0) {\n            /*Convert the relative coordinates to absolute*/\n            lv_area_copy(&sb_area, &ext->sb.hor_area);\n            sb_area.x1 += page->coords.x1;\n            sb_area.y1 += page->coords.y1;\n            sb_area.x2 += page->coords.x1;\n            sb_area.y2 += page->coords.y1;\n            lv_draw_rect(&sb_area, mask, ext->sb.style, lv_obj_get_opa_scale(page));\n        }\n\n        if(ext->sb.ver_draw && (ext->sb.mode & LV_SB_MODE_HIDE) == 0) {\n            /*Convert the relative coordinates to absolute*/\n            lv_area_copy(&sb_area, &ext->sb.ver_area);\n            sb_area.x1 += page->coords.x1;\n            sb_area.y1 += page->coords.y1;\n            sb_area.x2 += page->coords.x1;\n            sb_area.y2 += page->coords.y1;\n            lv_draw_rect(&sb_area, mask, ext->sb.style, lv_obj_get_opa_scale(page));\n        }\n\n\n        lv_coord_t page_w = lv_obj_get_width(page);\n        lv_coord_t page_h = lv_obj_get_height(page);\n        lv_area_t flash_area;\n\n        if(ext->edge_flash.top_ip) {\n            flash_area.x1 = page->coords.x1 - page_w;\n            flash_area.x2 = page->coords.x2 + page_w;\n            flash_area.y1 = page->coords.y1 - 3 * page_w + ext->edge_flash.state;\n            flash_area.y2 = page->coords.y1 + ext->edge_flash.state;\n        }\n        else if(ext->edge_flash.bottom_ip) {\n            flash_area.x1 = page->coords.x1 - page_w;\n            flash_area.x2 = page->coords.x2 + page_w;\n            flash_area.y1 = page->coords.y2 - ext->edge_flash.state;\n            flash_area.y2 = page->coords.y2 + 3 * page_w - ext->edge_flash.state;\n        }\n        else if(ext->edge_flash.right_ip) {\n            flash_area.x1 = page->coords.x2 - ext->edge_flash.state;\n            flash_area.x2 = page->coords.x2 + 3 * page_h - ext->edge_flash.state;\n            flash_area.y1 = page->coords.y1 - page_h;\n            flash_area.y2 = page->coords.y2 + page_h;\n        }\n        else if(ext->edge_flash.left_ip) {\n            flash_area.x1 = page->coords.x1 - 3 * page_h + ext->edge_flash.state;\n            flash_area.x2 = page->coords.x1 + ext->edge_flash.state;\n            flash_area.y1 = page->coords.y1 - page_h;\n            flash_area.y2 = page->coords.y2 + page_h;\n        }\n\n        if(ext->edge_flash.left_ip || ext->edge_flash.right_ip || ext->edge_flash.top_ip || ext->edge_flash.bottom_ip) {\n            lv_style_t flash_style;\n            lv_style_copy(&flash_style, ext->edge_flash.style);\n            flash_style.body.radius = LV_RADIUS_CIRCLE;\n            uint32_t opa = (flash_style.body.opa * ext->edge_flash.state) / LV_PAGE_END_FLASH_SIZE;\n            flash_style.body.opa = opa;\n            lv_draw_rect(&flash_area, mask, &flash_style, lv_obj_get_opa_scale(page));\n        }\n\n    }\n\n    return true;\n}\n\n/**\n * Handle the drawing related tasks of the scrollable object\n * @param scrl pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_scrl_design(lv_obj_t * scrl, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    if(mode == LV_DESIGN_COVER_CHK) {\n        return ancestor_design(scrl, mask, mode);\n    } else if(mode == LV_DESIGN_DRAW_MAIN) {\n#if USE_LV_GROUP\n        /* If the page is focused in a group and\n         * the background object is not visible (transparent or empty)\n         * then \"activate\" the style of the scrollable*/\n        lv_style_t * style_scrl_ori = lv_obj_get_style(scrl);\n        lv_obj_t * page = lv_obj_get_parent(scrl);\n        lv_style_t * style_page = lv_obj_get_style(page);\n        lv_group_t * g = lv_obj_get_group(page);\n        if((style_page->body.empty || style_page->body.opa == LV_OPA_TRANSP) && style_page->body.border.width == 0) { /*Is the background visible?*/\n            if(lv_group_get_focused(g) == page) {\n                lv_style_t * style_mod;\n                style_mod = lv_group_mod_style(g, style_scrl_ori);\n                scrl->style_p = style_mod;  /*Temporally change the style to the activated */\n            }\n        }\n#endif\n        ancestor_design(scrl, mask, mode);\n\n#if USE_LV_GROUP\n        scrl->style_p = style_scrl_ori;  /*Revert the style*/\n#endif\n    } else if(mode == LV_DESIGN_DRAW_POST) {\n        ancestor_design(scrl, mask, mode);\n    }\n\n    return true;\n}\n\n/**\n * Signal function of the page\n * @param page pointer to a page object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_page_signal(lv_obj_t * page, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(page, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n    lv_style_t * style = lv_obj_get_style(page);\n    lv_obj_t * child;\n    if(sign == LV_SIGNAL_CHILD_CHG) { /*Automatically move children to the scrollable object*/\n        child = lv_obj_get_child(page, NULL);\n        while(child != NULL) {\n            if(lv_obj_is_protected(child, LV_PROTECT_PARENT) == false) {\n                lv_obj_t * tmp = child;\n                child = lv_obj_get_child(page, child); /*Get the next child before move this*/\n                lv_obj_set_parent(tmp, ext->scrl);\n            } else {\n                child = lv_obj_get_child(page, child);\n            }\n        }\n    } else if(sign == LV_SIGNAL_STYLE_CHG) {\n        /*If no hor_fit enabled set the scrollable's width to the page's width*/\n        if(lv_cont_get_hor_fit(ext->scrl) == false) {\n            lv_obj_set_width(ext->scrl, lv_obj_get_width(page) - 2 * style->body.padding.hor);\n        } else {\n            ext->scrl->signal_func(ext->scrl, LV_SIGNAL_CORD_CHG, &ext->scrl->coords);\n        }\n\n        /*The scrollbars are important only if they are visible now*/\n        if(ext->sb.hor_draw || ext->sb.ver_draw) lv_page_sb_refresh(page);\n\n        /*Refresh the ext. size because the scrollbars might be positioned out of the page*/\n        lv_obj_refresh_ext_size(page);\n    } else if(sign == LV_SIGNAL_CORD_CHG) {\n        /*Refresh the scrollbar and notify the scrl if the size is changed*/\n        if(ext->scrl != NULL && (lv_obj_get_width(page) != lv_area_get_width(param) ||\n                                 lv_obj_get_height(page) != lv_area_get_height(param))) {\n            /*If no hor_fit enabled set the scrollable's width to the page's width*/\n            if(lv_cont_get_hor_fit(ext->scrl) == false) {\n                lv_obj_set_width(ext->scrl, lv_obj_get_width(page) - 2 * style->body.padding.hor);\n            }\n\n            ext->scrl->signal_func(ext->scrl, LV_SIGNAL_CORD_CHG, &ext->scrl->coords);\n\n            /*The scrollbars are important only if they are visible now*/\n            if(ext->sb.hor_draw || ext->sb.ver_draw) lv_page_sb_refresh(page);\n        }\n    } else if(sign == LV_SIGNAL_PRESSED) {\n        if(ext->pr_action != NULL) {\n            res = ext->pr_action(page);\n        }\n    } else if(sign == LV_SIGNAL_RELEASED) {\n        if(lv_indev_is_dragging(lv_indev_get_act()) == false) {\n            if(ext->rel_action != NULL) {\n                res = ext->rel_action(page);\n            }\n        }\n    } else if(sign == LV_SIGNAL_REFR_EXT_SIZE) {\n        /*Ensure ext. size for the scrollbars if they are out of the page*/\n        if(page->ext_size < (-ext->sb.style->body.padding.hor)) page->ext_size = -ext->sb.style->body.padding.hor;\n        if(page->ext_size < (-ext->sb.style->body.padding.ver)) page->ext_size = -ext->sb.style->body.padding.ver;\n    } else if(sign == LV_SIGNAL_CONTROLL) {\n        uint32_t c = *((uint32_t *) param);\n\n        if((c == LV_GROUP_KEY_DOWN) && ext->arrow_scroll) {\n            lv_page_scroll_ver(page, - lv_obj_get_height(page) / 4);\n        } else if((c == LV_GROUP_KEY_UP) && ext->arrow_scroll) {\n            lv_page_scroll_ver(page, lv_obj_get_height(page) / 4);\n        } else if((c == LV_GROUP_KEY_RIGHT) && ext->arrow_scroll) {\n            /*If the page can be scrolled horizontally because it's not wide enough then scroll it vertically*/\n            if(lv_page_get_scrl_width(page) < lv_obj_get_width(page)) lv_page_scroll_ver(page, - lv_obj_get_height(page) / 4);\n            else lv_page_scroll_hor(page, - lv_obj_get_width(page) / 4);\n        } else if((c == LV_GROUP_KEY_LEFT) && ext->arrow_scroll) {\n            /*If the page can be scrolled horizontally because it's not wide enough then scroll it vertically*/\n            if(lv_page_get_scrl_width(page) < lv_obj_get_width(page)) lv_page_scroll_ver(page, lv_obj_get_height(page) / 4);\n            else lv_page_scroll_hor(page,  lv_obj_get_width(page) / 4);\n        }\n    } else if(sign == LV_SIGNAL_GET_EDITABLE) {\n        bool * editable = (bool *)param;\n        *editable = lv_page_get_arrow_scroll(page);\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_page\";\n    }\n\n    return res;\n}\n\n/**\n * Signal function of the scrollable part of a page\n * @param scrl pointer to the scrollable object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_page_scrollable_signal(lv_obj_t * scrl, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(scrl, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    lv_obj_t * page = lv_obj_get_parent(scrl);\n    lv_style_t * page_style = lv_obj_get_style(page);\n    lv_page_ext_t * page_ext = lv_obj_get_ext_attr(page);\n\n    if(sign == LV_SIGNAL_CORD_CHG) {\n        /*Limit the position of the scrollable object to be always visible\n         * (Do not let its edge inner then its parent respective edge)*/\n        lv_coord_t new_x = lv_obj_get_x(scrl);\n        lv_coord_t new_y = lv_obj_get_y(scrl);\n        bool refr_x = false;\n        bool refr_y = false;\n        lv_area_t page_coords;\n        lv_area_t scrl_coords;\n        lv_obj_get_coords(scrl, &scrl_coords);\n        lv_obj_get_coords(page, &page_coords);\n\n        lv_area_t * ori_coords = (lv_area_t *) param;\n        lv_coord_t diff_x = scrl->coords.x1 - ori_coords->x1;\n        lv_coord_t diff_y = scrl->coords.y1 - ori_coords->y1;\n        lv_coord_t hpad = page_style->body.padding.hor;\n        lv_coord_t vpad = page_style->body.padding.ver;\n        lv_obj_t * page_parent = lv_obj_get_parent(page);\n\n        lv_indev_t * indev = lv_indev_get_act();\n        lv_point_t drag_vect;\n        lv_indev_get_vect(indev, &drag_vect);\n\n\n        /* Start the scroll propagation if there is drag vector on the indev, but the drag is not started yet\n         * and the scrollable is in a corner. It will enable the scroll propagation only when a new scroll begins and not\n         * when the scrollable is already being scrolled.*/\n        if(page_ext->scroll_prop && page_ext->scroll_prop_ip == 0 && lv_indev_is_dragging(indev) == false) {\n            if(((drag_vect.y > 0 && scrl_coords.y1 == page_coords.y1 + vpad) ||\n                (drag_vect.y < 0 && scrl_coords.y2 == page_coords.y2 - vpad)) &&\n               ((drag_vect.x > 0 && scrl_coords.x1 == page_coords.x1 + hpad) ||\n                (drag_vect.x < 0 && scrl_coords.x2 == page_coords.x2 - hpad))) {\n\n                if(lv_obj_get_parent(page_parent) != NULL) {    /*Do not propagate the scroll to a screen*/\n                    page_ext->scroll_prop_ip = 1;\n                }\n            }\n        }\n\n        /*scrollable width smaller then page width? -> align to left*/\n        if(lv_area_get_width(&scrl_coords) + 2 * hpad <= lv_area_get_width(&page_coords)) {\n            if(scrl_coords.x1 != page_coords.x1 + hpad) {\n                new_x = hpad;\n                refr_x = true;\n            }\n        } else {\n            /*If the scroll propagation is in progress revert the original coordinates (don't let the page scroll)*/\n            if(page_ext->scroll_prop_ip) {\n                if(drag_vect.x == diff_x) {   /*`scrl` is bouncing: drag pos. it somewhere and here it is reverted. Handle only the pos. because of drag*/\n                    new_x = ori_coords->x1 - page_coords.x1;\n                    refr_x = true;\n                }\n            }\n            /*The edges of the scrollable can not be in the page (minus hpad) */\n            else if(scrl_coords.x2  < page_coords.x2 - hpad) {\n                new_x =  lv_area_get_width(&page_coords) - lv_area_get_width(&scrl_coords) - hpad;   /* Right align */\n                refr_x = true;\n                if(page_ext->edge_flash.enabled &&\n                        page_ext->edge_flash.left_ip == 0 && page_ext->edge_flash.right_ip == 0 &&\n                        page_ext->edge_flash.top_ip == 0 && page_ext->edge_flash.bottom_ip == 0) {\n                    lv_page_start_edge_flash(page);\n                    page_ext->edge_flash.right_ip = 1;\n                }\n            }\n            else if(scrl_coords.x1 > page_coords.x1 + hpad) {\n                new_x = hpad;  /*Left align*/\n                refr_x = true;\n                if(page_ext->edge_flash.enabled &&\n                        page_ext->edge_flash.left_ip == 0 && page_ext->edge_flash.right_ip == 0 &&\n                        page_ext->edge_flash.top_ip == 0 && page_ext->edge_flash.bottom_ip == 0) {\n                    lv_page_start_edge_flash(page);\n                    page_ext->edge_flash.left_ip = 1;\n                }\n            }\n        }\n\n        /*scrollable height smaller then page height? -> align to left*/\n        if(lv_area_get_height(&scrl_coords) + 2 * vpad <= lv_area_get_height(&page_coords)) {\n            if(scrl_coords.y1 != page_coords.y1 + vpad) {\n                new_y = vpad;\n                refr_y = true;\n            }\n        } else {\n            /*If the scroll propagation is in progress revert the original coordinates (don't let the page scroll)*/\n            if(page_ext->scroll_prop_ip) {\n              if(drag_vect.y == diff_y) {   /*`scrl` is bouncing: drag pos. it somewhere and here it is reverted. Handle only the pos. because of drag*/\n                    new_y = ori_coords->y1 - page_coords.y1;\n                    refr_y = true;\n                }\n            }\n            /*The edges of the scrollable can not be in the page (minus vpad) */\n            else if(scrl_coords.y2 < page_coords.y2 - vpad) {\n                new_y =  lv_area_get_height(&page_coords) - lv_area_get_height(&scrl_coords) - vpad;   /* Bottom align */\n                refr_y = true;\n                if(page_ext->edge_flash.enabled &&\n                        page_ext->edge_flash.left_ip == 0 && page_ext->edge_flash.right_ip == 0 &&\n                        page_ext->edge_flash.top_ip == 0 && page_ext->edge_flash.bottom_ip == 0) {\n                    lv_page_start_edge_flash(page);\n                    page_ext->edge_flash.bottom_ip = 1;\n                }\n            }\n            else if(scrl_coords.y1  > page_coords.y1 + vpad) {\n                new_y = vpad;  /*Top align*/\n                refr_y = true;\n                if(page_ext->edge_flash.enabled &&\n                        page_ext->edge_flash.left_ip == 0 && page_ext->edge_flash.right_ip == 0 &&\n                        page_ext->edge_flash.top_ip == 0 && page_ext->edge_flash.bottom_ip == 0) {\n                    lv_page_start_edge_flash(page);\n                    page_ext->edge_flash.top_ip = 1;\n                }\n            }\n        }\n\n        if(refr_x || refr_y) {\n            lv_obj_set_pos(scrl, new_x, new_y);\n\n            if(page_ext->scroll_prop_ip) {\n                if(refr_y) lv_obj_set_y(page_parent, lv_obj_get_y(page_parent) + diff_y);\n                if(refr_x) lv_obj_set_x(page_parent, lv_obj_get_x(page_parent) + diff_x);\n            }\n        }\n\n        lv_page_sb_refresh(page);\n    }\n    else if(sign == LV_SIGNAL_DRAG_END) {\n\n        /*Scroll propagation is finished on drag end*/\n        page_ext->scroll_prop_ip = 0;\n\n        /*Hide scrollbars if required*/\n        if(page_ext->sb.mode == LV_SB_MODE_DRAG) {\n            lv_area_t sb_area_tmp;\n            if(page_ext->sb.hor_draw) {\n                lv_area_copy(&sb_area_tmp, &page_ext->sb.hor_area);\n                sb_area_tmp.x1 += page->coords.x1;\n                sb_area_tmp.y1 += page->coords.y1;\n                sb_area_tmp.x2 += page->coords.x1;\n                sb_area_tmp.y2 += page->coords.y1;\n                lv_inv_area(&sb_area_tmp);\n                page_ext->sb.hor_draw = 0;\n            }\n            if(page_ext->sb.ver_draw)  {\n                lv_area_copy(&sb_area_tmp, &page_ext->sb.ver_area);\n                sb_area_tmp.x1 += page->coords.x1;\n                sb_area_tmp.y1 += page->coords.y1;\n                sb_area_tmp.x2 += page->coords.x1;\n                sb_area_tmp.y2 += page->coords.y1;\n                lv_inv_area(&sb_area_tmp);\n                page_ext->sb.ver_draw = 0;\n            }\n        }\n    } else if(sign == LV_SIGNAL_PRESSED) {\n        if(page_ext->pr_action != NULL) {\n            res = page_ext->pr_action(page);\n        }\n    } else if(sign == LV_SIGNAL_RELEASED) {\n        if(lv_indev_is_dragging(lv_indev_get_act()) == false) {\n            if(page_ext->rel_action != NULL) {\n                res = page_ext->rel_action(page);\n            }\n        }\n    }\n\n    return res;\n}\n\n\n/**\n * Refresh the position and size of the scroll bars.\n * @param page pointer to a page object\n */\nstatic void lv_page_sb_refresh(lv_obj_t * page)\n{\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n    lv_style_t * style = lv_obj_get_style(page);\n    lv_obj_t * scrl = ext->scrl;\n    lv_coord_t size_tmp;\n    lv_coord_t scrl_w = lv_obj_get_width(scrl);\n    lv_coord_t scrl_h =  lv_obj_get_height(scrl);\n    lv_coord_t hpad = style->body.padding.hor;\n    lv_coord_t vpad = style->body.padding.ver;\n    lv_coord_t obj_w = lv_obj_get_width(page);\n    lv_coord_t obj_h = lv_obj_get_height(page);\n\n    /*Always let 'scrollbar width' padding above, under, left and right to the scrollbars\n     * else:\n     * - horizontal and vertical scrollbars can overlap on the corners\n     * - if the page has radius the scrollbar can be out of the radius  */\n    lv_coord_t sb_hor_pad = LV_MATH_MAX(ext->sb.style->body.padding.inner, style->body.padding.hor);\n    lv_coord_t sb_ver_pad = LV_MATH_MAX(ext->sb.style->body.padding.inner, style->body.padding.ver);\n\n    if(ext->sb.mode == LV_SB_MODE_OFF) return;\n\n    if(ext->sb.mode == LV_SB_MODE_ON) {\n        ext->sb.hor_draw = 1;\n        ext->sb.ver_draw = 1;\n    }\n\n    /*Invalidate the current (old) scrollbar areas*/\n    lv_area_t sb_area_tmp;\n    if(ext->sb.hor_draw != 0) {\n        lv_area_copy(&sb_area_tmp, &ext->sb.hor_area);\n        sb_area_tmp.x1 += page->coords.x1;\n        sb_area_tmp.y1 += page->coords.y1;\n        sb_area_tmp.x2 += page->coords.x1;\n        sb_area_tmp.y2 += page->coords.y1;\n        lv_inv_area(&sb_area_tmp);\n    }\n    if(ext->sb.ver_draw != 0)  {\n        lv_area_copy(&sb_area_tmp, &ext->sb.ver_area);\n        sb_area_tmp.x1 += page->coords.x1;\n        sb_area_tmp.y1 += page->coords.y1;\n        sb_area_tmp.x2 += page->coords.x1;\n        sb_area_tmp.y2 += page->coords.y1;\n        lv_inv_area(&sb_area_tmp);\n    }\n\n\n    if(ext->sb.mode == LV_SB_MODE_DRAG && lv_indev_is_dragging(lv_indev_get_act()) == false) {\n        ext->sb.hor_draw = 0;\n        ext->sb.ver_draw = 0;\n        return;\n\n    }\n\n    /*Horizontal scrollbar*/\n    if(scrl_w <= obj_w - 2 * hpad) {        /*Full sized scroll bar*/\n        lv_area_set_width(&ext->sb.hor_area, obj_w - 2 * sb_hor_pad);\n        lv_area_set_pos(&ext->sb.hor_area, sb_hor_pad, obj_h - ext->sb.style->body.padding.inner - ext->sb.style->body.padding.ver);\n        if(ext->sb.mode == LV_SB_MODE_AUTO || ext->sb.mode == LV_SB_MODE_DRAG)  ext->sb.hor_draw = 0;\n    } else {\n        size_tmp = (obj_w * (obj_w - (2 * sb_hor_pad))) / (scrl_w + 2 * hpad);\n        if(size_tmp < LV_PAGE_SB_MIN_SIZE) size_tmp = LV_PAGE_SB_MIN_SIZE;\n        lv_area_set_width(&ext->sb.hor_area,  size_tmp);\n\n        lv_area_set_pos(&ext->sb.hor_area, sb_hor_pad +\n                        (-(lv_obj_get_x(scrl) - hpad) * (obj_w - size_tmp -  2 * sb_hor_pad)) /\n                        (scrl_w + 2 * hpad - obj_w),\n                        obj_h - ext->sb.style->body.padding.inner - ext->sb.style->body.padding.ver);\n\n        if(ext->sb.mode == LV_SB_MODE_AUTO || ext->sb.mode == LV_SB_MODE_DRAG)  ext->sb.hor_draw = 1;\n    }\n\n    /*Vertical scrollbar*/\n    if(scrl_h <= obj_h - 2 * vpad) {        /*Full sized scroll bar*/\n        lv_area_set_height(&ext->sb.ver_area,  obj_h - 2 * sb_ver_pad);\n        lv_area_set_pos(&ext->sb.ver_area, obj_w - ext->sb.style->body.padding.inner - ext->sb.style->body.padding.hor, sb_ver_pad);\n        if(ext->sb.mode == LV_SB_MODE_AUTO || ext->sb.mode == LV_SB_MODE_DRAG)  ext->sb.ver_draw = 0;\n    } else {\n        size_tmp = (obj_h * (obj_h - (2 * sb_ver_pad))) / (scrl_h + 2 * vpad);\n        if(size_tmp < LV_PAGE_SB_MIN_SIZE) size_tmp = LV_PAGE_SB_MIN_SIZE;\n        lv_area_set_height(&ext->sb.ver_area,  size_tmp);\n\n        lv_area_set_pos(&ext->sb.ver_area,  obj_w - ext->sb.style->body.padding.inner - ext->sb.style->body.padding.hor,\n                        sb_ver_pad +\n                        (-(lv_obj_get_y(scrl) - vpad) * (obj_h - size_tmp -  2 * sb_ver_pad)) /\n                        (scrl_h + 2 * vpad - obj_h));\n\n        if(ext->sb.mode == LV_SB_MODE_AUTO || ext->sb.mode == LV_SB_MODE_DRAG)  ext->sb.ver_draw = 1;\n    }\n\n    /*Invalidate the new scrollbar areas*/\n    if(ext->sb.hor_draw != 0) {\n        lv_area_copy(&sb_area_tmp, &ext->sb.hor_area);\n        sb_area_tmp.x1 += page->coords.x1;\n        sb_area_tmp.y1 += page->coords.y1;\n        sb_area_tmp.x2 += page->coords.x1;\n        sb_area_tmp.y2 += page->coords.y1;\n        lv_inv_area(&sb_area_tmp);\n    }\n    if(ext->sb.ver_draw != 0)  {\n        lv_area_copy(&sb_area_tmp, &ext->sb.ver_area);\n        sb_area_tmp.x1 += page->coords.x1;\n        sb_area_tmp.y1 += page->coords.y1;\n        sb_area_tmp.x2 += page->coords.x1;\n        sb_area_tmp.y2 += page->coords.y1;\n        lv_inv_area(&sb_area_tmp);\n    }\n}\n\n#if USE_LV_ANIMATION\nstatic void edge_flash_anim(void * page, int32_t v)\n{\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n    ext->edge_flash.state = v;\n    lv_obj_invalidate(page);\n}\n\nstatic void edge_flash_anim_end(void * page)\n{\n    lv_page_ext_t * ext = lv_obj_get_ext_attr(page);\n    ext->edge_flash.top_ip = 0;\n    ext->edge_flash.bottom_ip = 0;\n    ext->edge_flash.left_ip = 0;\n    ext->edge_flash.right_ip = 0;\n    lv_obj_invalidate(page);\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_page.h",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * @file lv_page.h\n *\n */\n\n#ifndef LV_PAGE_H\n#define LV_PAGE_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_PAGE != 0\n\n/*Testing of dependencies*/\n#if USE_LV_CONT == 0\n#error \"lv_page: lv_cont is required. Enable it in lv_conf.h (USE_LV_CONT  1) \"\n#endif\n\n#include \"lv_cont.h\"\n#include \"../lv_core/lv_indev.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/*Scrollbar modes: shows when should the scrollbars be visible*/\nenum\n{\n    LV_SB_MODE_OFF  = 0x0,      /*Never show scrollbars*/\n    LV_SB_MODE_ON   = 0x1,      /*Always show scrollbars*/\n    LV_SB_MODE_DRAG = 0x2,      /*Show scrollbars when page is being dragged*/\n    LV_SB_MODE_AUTO = 0x3,      /*Show scrollbars when the scrollable container is large enough to be scrolled*/\n    LV_SB_MODE_HIDE = 0x4,      /*Hide the scroll bar temporally*/\n    LV_SB_MODE_UNHIDE = 0x5,    /*Unhide the previously hidden scrollbar. Recover it's type too*/\n};\ntypedef uint8_t lv_sb_mode_t;\n\n/*Data of page*/\ntypedef struct\n{\n    lv_cont_ext_t bg; /*Ext. of ancestor*/\n    /*New data for this type */\n    lv_obj_t * scrl;            /*The scrollable object on the background*/\n\tlv_style_t *bgo;            /*The scrollable object on the background*/\n\tlv_style_t *pr;            /*The scrollable object on the background*/\n    lv_action_t rel_action;     /*Function to call when the page is released*/\n    lv_action_t pr_action;      /*Function to call when the page is pressed*/\n    struct {\n        lv_style_t *style;          /*Style of scrollbars*/\n        lv_area_t hor_area;            /*Horizontal scrollbar area relative to the page. (Handled by the library) */\n        lv_area_t ver_area;            /*Vertical scrollbar area relative to the page (Handled by the library)*/\n        uint8_t hor_draw :1;        /*1: horizontal scrollbar is visible now (Handled by the library)*/\n        uint8_t ver_draw :1;        /*1: vertical scrollbar is visible now (Handled by the library)*/\n        lv_sb_mode_t mode:3;        /*Scrollbar visibility from 'lv_page_sb_mode_t'*/\n    } sb;\n    struct {\n        uint16_t state;  /*Store the current size of the edge flash effect*/\n        lv_style_t *style;    /*Style of edge flash effect (usually homogeneous circle)*/\n        uint8_t enabled    :1;     /*1: Show a flash animation on the edge*/\n        uint8_t top_ip     :1;     /*Used internally to show that top most position is reached (flash is In Progress)*/\n        uint8_t bottom_ip  :1;     /*Used internally to show that bottom most position is reached (flash is In Progress)*/\n        uint8_t right_ip   :1;     /*Used internally to show that right most position is reached (flash is In Progress)*/\n        uint8_t left_ip    :1;     /*Used internally to show that left most position is reached (flash is In Progress)*/\n    }edge_flash;\n\n    uint8_t arrow_scroll   :1;        /*1: Enable scrolling with LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN*/\n    uint8_t scroll_prop    :1;        /*1: Propagate the scrolling the the parent if the edge is reached*/\n    uint8_t scroll_prop_ip :1;        /*1: Scroll propagation is in progress (used by the library)*/\n} lv_page_ext_t;\n\nenum {\n    LV_PAGE_STYLE_BG,\n\tLV_PAGE_STYLE_BGO,\n\tLV_PAGE_STYLE_PR,\n    LV_PAGE_STYLE_SCRL,\n    LV_PAGE_STYLE_SB,\n    LV_PAGE_STYLE_EDGE_FLASH,\n};\ntypedef uint8_t lv_page_style_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a page objects\n * @param par pointer to an object, it will be the parent of the new page\n * @param copy pointer to a page object, if not NULL then the new object will be copied from it\n * @return pointer to the created page\n */\nlv_obj_t * lv_page_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/**\n * Delete all children of the scrl object, without deleting scrl child.\n * @param obj pointer to an object\n */\nvoid lv_page_clean(lv_obj_t *obj);\n\n/**\n * Get the press action of the page\n * @param page pointer to a page object\n * @return a function to call when the page is pressed\n */\nlv_action_t lv_page_get_pr_action(lv_obj_t * page);\n\n/**\n * Get the release action of the page\n * @param page pointer to a page object\n * @return a function to call when the page is released\n */\nlv_action_t lv_page_get_rel_action(lv_obj_t * page);\n\n/**\n * Get the scrollable object of a page\n * @param page pointer to a page object\n * @return pointer to a container which is the scrollable part of the page\n */\nlv_obj_t * lv_page_get_scrl(const lv_obj_t * page);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a release action for the page\n * @param page pointer to a page object\n * @param rel_action a function to call when the page is released\n */\nvoid lv_page_set_rel_action(lv_obj_t * page, lv_action_t rel_action);\n\n/**\n * Set a press action for the page\n * @param page pointer to a page object\n * @param pr_action a function to call when the page is pressed\n */\nvoid lv_page_set_pr_action(lv_obj_t * page, lv_action_t pr_action);\n\n/**\n * Set the scroll bar mode on a page\n * @param page pointer to a page object\n * @param sb_mode the new mode from 'lv_page_sb.mode_t' enum\n */\nvoid lv_page_set_sb_mode(lv_obj_t * page, lv_sb_mode_t sb_mode);\n\n/**\n * Enable/Disable scrolling with arrows if the page is in group (arrows: LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN)\n * @param page pointer to a page object\n * @param en true: enable scrolling with arrows\n */\nvoid lv_page_set_arrow_scroll(lv_obj_t * page, bool en);\n\n/**\n * Enable the scroll propagation feature. If enabled then the page will move its parent if there is no more space to scroll.\n * @param page pointer to a Page\n * @param en true or false to enable/disable scroll propagation\n */\nvoid lv_page_set_scroll_propagation(lv_obj_t * page, bool en);\n\n/**\n * Enable the edge flash effect. (Show an arc when the an edge is reached)\n * @param page pointer to a Page\n * @param en true or false to enable/disable end flash\n */\nvoid lv_page_set_edge_flash(lv_obj_t * page, bool en);\n\n/**\n * Set the fit attribute of the scrollable part of a page.\n * It means it can set its size automatically to involve all children.\n * (Can be set separately horizontally and vertically)\n * @param page pointer to a page object\n * @param hor_en true: enable horizontal fit\n * @param ver_en true: enable vertical fit\n */\nstatic inline void lv_page_set_scrl_fit(lv_obj_t *page, bool hor_en, bool ver_en)\n{\n    lv_cont_set_fit(lv_page_get_scrl(page), hor_en, ver_en);\n}\n\n/**\n * Set width of the scrollable part of a page\n * @param page pointer to a page object\n * @param w the new width of the scrollable (it ha no effect is horizontal fit is enabled)\n */\nstatic inline void lv_page_set_scrl_width(lv_obj_t *page, lv_coord_t w)\n{\n    lv_obj_set_width(lv_page_get_scrl(page), w);\n}\n\n/**\n * Set height of the scrollable part of a page\n * @param page pointer to a page object\n * @param h the new height of the scrollable (it ha no effect is vertical fit is enabled)\n */\nstatic inline void lv_page_set_scrl_height(lv_obj_t *page, lv_coord_t h)\n{\n    lv_obj_set_height(lv_page_get_scrl(page), h);\n\n}\n\n/**\n* Set the layout of the scrollable part of the page\n* @param page pointer to a page object\n* @param layout a layout from 'lv_cont_layout_t'\n*/\nstatic inline void lv_page_set_scrl_layout(lv_obj_t * page, lv_layout_t layout)\n{\n    lv_cont_set_layout(lv_page_get_scrl(page), layout);\n}\n\n/**\n * Set a style of a page\n * @param page pointer to a page object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_page_set_style(lv_obj_t *page, lv_page_style_t type, lv_style_t *style);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Set the scroll bar mode on a page\n * @param page pointer to a page object\n * @return the mode from 'lv_page_sb.mode_t' enum\n */\nlv_sb_mode_t lv_page_get_sb_mode(const lv_obj_t * page);\n\n\n/**\n * Get the the scrolling with arrows (LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN) is enabled or not\n * @param page pointer to a page object\n * @return true: scrolling with arrows is enabled\n */\nbool lv_page_get_arrow_scroll(const lv_obj_t * page);\n\n/**\n * Get the scroll propagation property\n * @param page pointer to a Page\n * @return true or false\n */\nbool lv_page_get_scroll_propagation(lv_obj_t * page);\n\n/**\n * Get the edge flash effect property.\n * @param page pointer to a Page\n * return true or false\n */\nbool lv_page_get_edge_flash(lv_obj_t * page);\n\n/**\n * Get that width which can be set to the children to still not cause overflow (show scrollbars)\n * @param page pointer to a page object\n * @return the width which still fits into the page\n */\nlv_coord_t lv_page_get_fit_width(lv_obj_t * page);\n\n/**\n * Get that height which can be set to the children to still not cause overflow (show scrollbars)\n * @param page pointer to a page object\n * @return the height which still fits into the page\n */\nlv_coord_t lv_page_get_fit_height(lv_obj_t * page);\n\n/**\n * Get width of the scrollable part of a page\n * @param page pointer to a page object\n * @return the width of the scrollable\n */\nstatic inline lv_coord_t lv_page_get_scrl_width(const lv_obj_t *page)\n{\n    return lv_obj_get_width(lv_page_get_scrl(page));\n}\n\n/**\n * Get height of the scrollable part of a page\n * @param page pointer to a page object\n * @return the height of the scrollable\n */\nstatic inline lv_coord_t lv_page_get_scrl_height(const lv_obj_t *page)\n{\n    return lv_obj_get_height(lv_page_get_scrl(page));\n}\n\n/**\n* Get the layout of the scrollable part of a page\n* @param page pointer to page object\n* @return the layout from 'lv_cont_layout_t'\n*/\nstatic inline lv_layout_t lv_page_get_scrl_layout(const lv_obj_t * page)\n{\n    return lv_cont_get_layout(lv_page_get_scrl(page));\n}\n\n/**\n* Get horizontal fit attribute of the scrollable part of a page\n* @param page pointer to a page object\n* @return true: horizontal fit is enabled; false: disabled\n*/\nstatic inline bool lv_page_get_scrl_hor_fit(const lv_obj_t * page)\n{\n    return lv_cont_get_hor_fit(lv_page_get_scrl(page));\n}\n\n/**\n* Get vertical fit attribute of the scrollable part of a page\n* @param page pointer to a page object\n* @return true: vertical fit is enabled; false: disabled\n*/\nstatic inline bool lv_page_get_scrl_fit_ver(const lv_obj_t * page)\n{\n    return lv_cont_get_ver_fit(lv_page_get_scrl(page));\n}\n\n/**\n * Get a style of a page\n * @param page pointer to page object\n * @param type which style should be get\n * @return style pointer to a style\n */\nlv_style_t * lv_page_get_style(const lv_obj_t *page, lv_page_style_t type);\n\n/*=====================\n * Other functions\n *====================*/\n\n/**\n * Glue the object to the page. After it the page can be moved (dragged) with this object too.\n * @param obj pointer to an object on a page\n * @param glue true: enable glue, false: disable glue\n */\nvoid lv_page_glue_obj(lv_obj_t * obj, bool glue);\n\n/**\n * Focus on an object. It ensures that the object will be visible on the page.\n * @param page pointer to a page object\n * @param obj pointer to an object to focus (must be on the page)\n * @param anim_time scroll animation time in milliseconds (0: no animation)\n */\nvoid lv_page_focus(lv_obj_t * page, const lv_obj_t * obj, uint16_t anim_time);\n\n/**\n * Scroll the page horizontally\n * @param page pointer to a page object\n * @param dist the distance to scroll (< 0: scroll left; > 0 scroll right)\n */\nvoid lv_page_scroll_hor(lv_obj_t * page, lv_coord_t dist);\n\n/**\n * Scroll the page vertically\n * @param page pointer to a page object\n * @param dist the distance to scroll (< 0: scroll down; > 0 scroll up)\n */\nvoid lv_page_scroll_ver(lv_obj_t * page, lv_coord_t dist);\n\n/**\n * Not intended to use directly by the user but by other object types internally.\n * Start an edge flash animation. Exactly one `ext->edge_flash.xxx_ip` should be set\n * @param page\n */\nvoid lv_page_start_edge_flash(lv_obj_t * page);\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_PAGE*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_PAGE_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_preload.c",
    "content": "/**\n * @file lv_preload.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_preload.h\"\n#if USE_LV_PRELOAD != 0\n\n#include \"../lv_misc/lv_math.h\"\n#include \"../lv_draw/lv_draw_rect.h\"\n#include \"../lv_draw/lv_draw_arc.h\"\n#include \"../lv_themes/lv_theme.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#ifndef LV_PRELOAD_DEF_ARC_LENGTH\n# define LV_PRELOAD_DEF_ARC_LENGTH  60      /*[deg]*/\n#endif\n\n#ifndef LV_PRELOAD_DEF_SPIN_TIME\n# define LV_PRELOAD_DEF_SPIN_TIME   1000    /*[ms]*/\n#endif\n\n#ifndef LV_PRELOAD_DEF_ANIM\n# define LV_PRELOAD_DEF_ANIM        LV_PRELOAD_TYPE_SPINNING_ARC    /*animation type*/\n#endif\n\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool lv_preload_design(lv_obj_t * preload, const lv_area_t * mask, lv_design_mode_t mode);\nstatic lv_res_t lv_preload_signal(lv_obj_t * preload, lv_signal_t sign, void * param);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\nstatic lv_design_func_t ancestor_design;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a pre loader object\n * @param par pointer to an object, it will be the parent of the new pre loader\n * @param copy pointer to a pre loader object, if not NULL then the new object will be copied from it\n * @return pointer to the created pre loader\n */\nlv_obj_t * lv_preload_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"preload create started\");\n\n    /*Create the ancestor of pre loader*/\n    lv_obj_t * new_preload = lv_arc_create(par, copy);\n    lv_mem_assert(new_preload);\n    if(new_preload == NULL) return NULL;\n\n    /*Allocate the pre loader type specific extended data*/\n    lv_preload_ext_t * ext = lv_obj_allocate_ext_attr(new_preload, sizeof(lv_preload_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_preload);\n    if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_preload);\n\n    /*Initialize the allocated 'ext' */\n    ext->arc_length = LV_PRELOAD_DEF_ARC_LENGTH;\n    ext->anim_type = LV_PRELOAD_DEF_ANIM;\n\n    /*The signal and design functions are not copied so set them here*/\n    lv_obj_set_signal_func(new_preload, lv_preload_signal);\n    lv_obj_set_design_func(new_preload, lv_preload_design);\n\n\n    /*Init the new pre loader pre loader*/\n    if(copy == NULL) {\n        lv_obj_set_size(new_preload, LV_DPI / 2, LV_DPI / 2);\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_preload_set_style(new_preload, LV_PRELOAD_STYLE_MAIN, th->preload);\n        } else {\n            lv_obj_set_style(new_preload, &lv_style_pretty_color);\n        }\n\n        ext->time = LV_PRELOAD_DEF_SPIN_TIME;\n\n    }\n    /*Copy an existing pre loader*/\n    else {\n        lv_preload_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        ext->arc_length = copy_ext->arc_length;\n        ext->time = copy_ext->time;\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_preload);\n    }\n\n    lv_preload_set_animation_type(new_preload, ext->anim_type);\n\n\n    LV_LOG_INFO(\"preload created\");\n\n    return new_preload;\n}\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n/**\n * Set the length of the spinning  arc in degrees\n * @param preload pointer to a preload object\n * @param deg length of the arc\n */\nvoid lv_preload_set_arc_length(lv_obj_t * preload, uint16_t deg)\n{\n    lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload);\n\n    ext->arc_length = deg;\n}\n\n/**\n * Set the spin time of the arc\n * @param preload pointer to a preload object\n * @param time time of one round in milliseconds\n */\nvoid lv_preload_set_spin_time(lv_obj_t * preload, uint16_t time)\n{\n    lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload);\n\n    ext->time = time;\n    lv_preload_set_animation_type(preload, ext->anim_type);\n}\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a style of a pre loader.\n * @param preload pointer to pre loader object\n * @param type which style should be set\n * @param style pointer to a style\n *  */\nvoid lv_preload_set_style(lv_obj_t * preload, lv_preload_style_t type, lv_style_t * style)\n{\n    switch(type) {\n    case LV_PRELOAD_STYLE_MAIN:\n        lv_arc_set_style(preload, LV_ARC_STYLE_MAIN, style);\n        break;\n    }\n}\n\n/**\n * Set the animation type of a preloadeer.\n * @param preload pointer to pre loader object\n * @param type animation type of the preload\n *  */\nvoid lv_preload_set_animation_type(lv_obj_t * preload, lv_preloader_type_t type)\n{\n#if USE_LV_ANIMATION\n    lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload);\n\n    /*delete previous animation*/\n    //lv_anim_del(preload, NULL);\n    switch(type)\n    {\n    case LV_PRELOAD_TYPE_FILLSPIN_ARC:\n    {\n        ext->anim_type = LV_PRELOAD_TYPE_FILLSPIN_ARC;\n        lv_anim_t a;\n        a.var = preload;\n        a.start = 0;\n        a.end = 360;\n        a.fp = (lv_anim_fp_t)lv_preload_spinner_animation;\n        a.path = lv_anim_path_ease_in_out;\n        a.end_cb = NULL;\n        a.act_time = 0;\n        a.time = ext->time;\n        a.playback = 0;\n        a.playback_pause = 0;\n        a.repeat = 1;\n        a.repeat_pause = 0;\n        lv_anim_create(&a);\n\n        lv_anim_t b;\n        b.var = preload;\n        b.start = ext->arc_length;\n        b.end = 360 - ext->arc_length;\n        b.fp = (lv_anim_fp_t)lv_preload_set_arc_length;\n        b.path = lv_anim_path_ease_in_out;\n        b.end_cb = NULL;\n        b.act_time = 0;\n        b.time = ext->time;\n        b.playback = 1;\n        b.playback_pause = 0;\n        b.repeat = 1;\n        b.repeat_pause = 0;\n        lv_anim_create(&b);\n        break;\n    }\n    case LV_PRELOAD_TYPE_SPINNING_ARC:\n    default:\n    {\n        ext->anim_type = LV_PRELOAD_TYPE_SPINNING_ARC;\n        lv_anim_t a;\n        a.var = preload;\n        a.start = 0;\n        a.end = 360;\n        a.fp = (lv_anim_fp_t)lv_preload_spinner_animation;\n        a.path = lv_anim_path_ease_in_out;\n        a.end_cb = NULL;\n        a.act_time = 0;\n        a.time = ext->time;\n        a.playback = 0;\n        a.playback_pause = 0;\n        a.repeat = 1;\n        a.repeat_pause = 0;\n        lv_anim_create(&a);\n        break;\n    }\n    }\n\n#endif //USE_LV_ANIMATION\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the arc length [degree] of the a pre loader\n * @param preload pointer to a pre loader object\n */\nuint16_t lv_preload_get_arc_length(const lv_obj_t * preload)\n{\n    lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload);\n    return ext->arc_length;\n\n}\n\n/**\n * Get the spin time of the arc\n * @param preload pointer to a pre loader object [milliseconds]\n */\nuint16_t lv_preload_get_spin_time(const lv_obj_t * preload)\n{\n    lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload);\n    return ext->time;\n}\n\n/**\n * Get style of a pre loader.\n * @param preload pointer to pre loader object\n * @param type which style should be get\n * @return style pointer to the style\n *  */\nlv_style_t * lv_preload_get_style(const lv_obj_t * preload, lv_preload_style_t type)\n{\n    lv_style_t * style = NULL;\n\n    switch(type) {\n    case LV_PRELOAD_STYLE_MAIN:\n        style = lv_arc_get_style(preload, LV_ARC_STYLE_MAIN);\n        break;\n    default:\n        style = NULL;\n        break;\n    }\n\n    return style;\n}\n\n/**\n * Get the animation type of a preloadeer.\n * @param preload pointer to pre loader object\n * @return animation type\n *  */\nlv_preloader_type_t lv_preload_get_animation_type(lv_obj_t * preload)\n{\n    lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload);\n    return ext->anim_type;\n}\n\n/*=====================\n * Other functions\n *====================*/\n\n/**\n * Automatically in an animation to rotate the arc of spinner.\n * @param ptr pointer to preloader\n * @param val the current desired value [0..360]\n */\nvoid lv_preload_spinner_animation(void * ptr, int32_t val)\n{\n    lv_obj_t * preload = ptr;\n    lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload);\n    int16_t angle_start = val - ext->arc_length / 2 + 180;\n    int16_t angle_end = angle_start + ext->arc_length;\n\n    angle_start = angle_start % 360;\n    angle_end = angle_end % 360;\n\n    lv_arc_set_angles(preload, angle_start, angle_end);\n\n}\n\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Handle the drawing related tasks of the pre loaders\n * @param preload pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_preload_design(lv_obj_t * preload, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    /*Return false if the object is not covers the mask_p area*/\n    if(mode == LV_DESIGN_COVER_CHK) {\n        return false;\n    }\n    /*Draw the object*/\n    else if(mode == LV_DESIGN_DRAW_MAIN) {\n\n        /*Draw a circle as background*/\n        lv_style_t * style = lv_arc_get_style(preload, LV_ARC_STYLE_MAIN);\n        if(style->body.border.width > 0) {\n            lv_coord_t r = (LV_MATH_MIN(lv_obj_get_width(preload), lv_obj_get_height(preload))) / 2;\n            r -= LV_MATH_MIN(style->body.padding.hor, style->body.padding.ver);\n\n            lv_coord_t x = preload->coords.x1 + lv_obj_get_width(preload) / 2;\n            lv_coord_t y = preload->coords.y1 + lv_obj_get_height(preload) / 2;\n\n            lv_style_t bg_style;\n            lv_style_copy(&bg_style, &lv_style_plain);\n            bg_style.body.empty = 1;\n            bg_style.body.radius = LV_RADIUS_CIRCLE;\n            bg_style.body.border.color = style->body.border.color;\n            bg_style.body.border.width = style->body.border.width;\n\n            lv_area_t bg_area;\n            bg_area.x1 = x - r;\n            bg_area.y1 = y - r;\n            bg_area.x2 = x + r;\n            bg_area.y2 = y + r;\n\n            lv_draw_rect(&bg_area, mask, &bg_style, lv_obj_get_opa_scale(preload));\n        }\n        /*Draw the arc above the background circle */\n        ancestor_design(preload, mask, mode);\n    }\n    /*Post draw when the children are drawn*/\n    else if(mode == LV_DESIGN_DRAW_POST) {\n\n    }\n\n    return true;\n}\n\n/**\n * Signal function of the pre loader\n * @param preload pointer to a pre loader object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_preload_signal(lv_obj_t * preload, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(preload, sign, param);\n    if(res != LV_RES_OK) return res;\n\n\n    if(sign == LV_SIGNAL_CLEANUP) {\n        /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_preload\";\n    }\n\n    return res;\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_preload.h",
    "content": "/**\n * @file lv_preload.h\n *\n */\n\n#ifndef LV_PRELOAD_H\n#define LV_PRELOAD_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_PRELOAD != 0\n\n/*Testing of dependencies*/\n#if USE_LV_ARC == 0\n#error \"lv_preload: lv_arc is required. Enable it in lv_conf.h (USE_LV_ARC  1) \"\n#endif\n\n#if USE_LV_ANIMATION == 0\n#error \"lv_preload: animations are required. Enable it in lv_conf.h (USE_LV_ANIMATION  1) \"\n#endif\n\n#include \"../lv_core/lv_obj.h\"\n#include \"lv_arc.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\nenum {\n    LV_PRELOAD_TYPE_SPINNING_ARC,\n    LV_PRELOAD_TYPE_FILLSPIN_ARC,\n};\ntypedef uint8_t lv_preloader_type_t;\n\n/*Data of pre loader*/\ntypedef struct {\n    lv_arc_ext_t arc; /*Ext. of ancestor*/\n    /*New data for this type */\n    uint16_t arc_length;            /*Length of the spinning indicator in degree*/\n    uint16_t time;                  /*Time of one round*/\n    lv_preloader_type_t anim_type;  /*Type of the arc animation*/\n} lv_preload_ext_t;\n\n\n/*Styles*/\nenum {\n    LV_PRELOAD_STYLE_MAIN,\n};\ntypedef uint8_t lv_preload_style_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a pre loader objects\n * @param par pointer to an object, it will be the parent of the new pre loader\n * @param copy pointer to a pre loader object, if not NULL then the new object will be copied from it\n * @return pointer to the created pre loader\n */\nlv_obj_t * lv_preload_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n/**\n * Set the length of the spinning  arc in degrees\n * @param preload pointer to a preload object\n * @param deg length of the arc\n */\nvoid lv_preload_set_arc_length(lv_obj_t * preload, uint16_t deg);\n\n/**\n * Set the spin time of the arc\n * @param preload pointer to a preload object\n * @param time time of one round in milliseconds\n */\nvoid lv_preload_set_spin_time(lv_obj_t * preload, uint16_t time);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a style of a pre loader.\n * @param preload pointer to pre loader object\n * @param type which style should be set\n * @param style pointer to a style\n *  */\nvoid lv_preload_set_style(lv_obj_t * preload, lv_preload_style_t type, lv_style_t *style);\n\n/**\n * Set the animation type of a preloadeer.\n * @param preload pointer to pre loader object\n * @param type animation type of the preload\n *  */\nvoid lv_preload_set_animation_type(lv_obj_t * preload, lv_preloader_type_t type);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the arc length [degree] of the a pre loader\n * @param preload pointer to a pre loader object\n */\nuint16_t lv_preload_get_arc_length(const lv_obj_t * preload);\n\n/**\n * Get the spin time of the arc\n * @param preload pointer to a pre loader object [milliseconds]\n */\nuint16_t lv_preload_get_spin_time(const lv_obj_t * preload);\n\n/**\n * Get style of a pre loader.\n * @param preload pointer to pre loader object\n * @param type which style should be get\n * @return style pointer to the style\n *  */\nlv_style_t * lv_preload_get_style(const lv_obj_t * preload, lv_preload_style_t type);\n\n/**\n * Get the animation type of a preloadeer.\n * @param preload pointer to pre loader object\n * @return animation type\n *  */\nlv_preloader_type_t lv_preload_get_animation_type(lv_obj_t * preload);\n\n/*=====================\n * Other functions\n *====================*/\n\n/**\n * Get style of a pre loader.\n * @param preload pointer to pre loader object\n * @param type which style should be get\n * @return style pointer to the style\n *  */\nvoid lv_preload_spinner_animation(void * ptr, int32_t val);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_PRELOAD*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_PRELOAD_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_roller.c",
    "content": "/**\n * @file lv_roller.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_roller.h\"\n#if USE_LV_ROLLER != 0\n\n#include \"../lv_draw/lv_draw.h\"\n#include \"../lv_core/lv_group.h\"\n#include \"../lv_themes/lv_theme.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#if USE_LV_ANIMATION\n#  ifndef LV_ROLLER_ANIM_TIME\n#    define LV_ROLLER_ANIM_TIME     200         /*ms*/\n#  endif\n#else\n#  undef  LV_ROLLER_ANIM_TIME\n#  define LV_ROLLER_ANIM_TIME       0           /*No animation*/\n#endif\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool lv_roller_design(lv_obj_t * roller, const lv_area_t * mask, lv_design_mode_t mode);\nstatic lv_res_t lv_roller_scrl_signal(lv_obj_t * roller_scrl, lv_signal_t sign, void * param);\nstatic lv_res_t lv_roller_signal(lv_obj_t * roller, lv_signal_t sign, void * param);\nstatic void refr_position(lv_obj_t * roller, bool anim_en);\nstatic void draw_bg(lv_obj_t * roller, const lv_area_t * mask);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\nstatic lv_signal_func_t ancestor_scrl_signal;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a roller object\n * @param par pointer to an object, it will be the parent of the new roller\n * @param copy pointer to a roller object, if not NULL then the new object will be copied from it\n * @return pointer to the created roller\n */\nlv_obj_t * lv_roller_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"roller create started\");\n\n    /*Create the ancestor of roller*/\n    lv_obj_t * new_roller = lv_ddlist_create(par, copy);\n    lv_mem_assert(new_roller);\n    if(new_roller == NULL) return NULL;\n\n    if(ancestor_scrl_signal == NULL) ancestor_scrl_signal = lv_obj_get_signal_func(lv_page_get_scrl(new_roller));\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_roller);\n\n    /*Allocate the roller type specific extended data*/\n    lv_roller_ext_t * ext = lv_obj_allocate_ext_attr(new_roller, sizeof(lv_roller_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n    ext->ddlist.draw_arrow = 0;  /*Do not draw arrow by default*/\n\n    /*The signal and design functions are not copied so set them here*/\n    lv_obj_set_signal_func(new_roller, lv_roller_signal);\n    lv_obj_set_design_func(new_roller, lv_roller_design);\n\n    /*Init the new roller roller*/\n    if(copy == NULL) {\n        lv_obj_t * scrl = lv_page_get_scrl(new_roller);\n        lv_obj_set_drag(scrl, true);                        /*In ddlist is might be disabled*/\n        lv_page_set_rel_action(new_roller, NULL);       /*Roller don't uses it (like ddlist)*/\n        lv_page_set_scrl_fit(new_roller, true, false);      /*Height is specified directly*/\n        lv_ddlist_open(new_roller, false);\n        lv_ddlist_set_anim_time(new_roller, LV_ROLLER_ANIM_TIME);\n        lv_roller_set_visible_row_count(new_roller, 3);\n        lv_label_set_align(ext->ddlist.label, LV_LABEL_ALIGN_CENTER);\n\n        lv_obj_set_signal_func(scrl, lv_roller_scrl_signal);\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_roller_set_style(new_roller, LV_ROLLER_STYLE_BG, th->roller.bg);\n            lv_roller_set_style(new_roller, LV_ROLLER_STYLE_SEL, th->roller.sel);\n        } else {\n            /*Let the ddlist's style*/\n            lv_obj_refresh_style(new_roller);                /*To set scrollable size automatically*/\n        }\n    }\n    /*Copy an existing roller*/\n    else {\n        lv_obj_t * scrl = lv_page_get_scrl(new_roller);\n        lv_ddlist_open(new_roller, false);\n        lv_obj_set_signal_func(scrl, lv_roller_scrl_signal);\n\n        lv_obj_refresh_style(new_roller);        /*Refresh the style with new signal function*/\n    }\n\n\n    LV_LOG_INFO(\"roller created\");\n\n\n    return new_roller;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set the align of the roller's options (left or center)\n * @param roller - pointer to a roller object\n * @param align - one of lv_label_align_t values (left, right, center)\n */\nvoid lv_roller_set_align(lv_obj_t * roller, lv_label_align_t align)\n{\n    lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller);\n    lv_mem_assert(ext);\n    if(ext->ddlist.label == NULL) return;   /*Probably the roller is being deleted if the label is NULL.*/\n    lv_label_set_align(ext->ddlist.label, align);\n}\n\n/**\n * Set the selected option\n * @param roller pointer to a roller object\n * @param sel_opt id of the selected option (0 ... number of option - 1);\n * @param anim_en true: set with animation; false set immediately\n */\nvoid lv_roller_set_selected(lv_obj_t * roller, uint16_t sel_opt, bool anim_en)\n{\n#if USE_LV_ANIMATION == 0\n    anim_en = false;\n#endif\n\n    if(lv_roller_get_selected(roller) == sel_opt) return;\n\n    lv_ddlist_set_selected(roller, sel_opt);\n    refr_position(roller, anim_en);\n}\n\n/**\n * Set the height to show the given number of rows (options)\n * @param roller pointer to a roller object\n * @param row_cnt number of desired visible rows\n */\nvoid lv_roller_set_visible_row_count(lv_obj_t * roller, uint8_t row_cnt)\n{\n    lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller);\n    lv_style_t * style_label = lv_obj_get_style(ext->ddlist.label);\n    uint8_t n_line_space = (row_cnt > 1) ? row_cnt - 1 : 1;\n    lv_ddlist_set_fix_height(roller, lv_font_get_height(style_label->text.font) * row_cnt + style_label->text.line_space * n_line_space);\n}\n\n/**\n * Set a style of a roller\n * @param roller pointer to a roller object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_roller_set_style(lv_obj_t * roller, lv_roller_style_t type, lv_style_t * style)\n{\n    switch(type) {\n        case LV_ROLLER_STYLE_BG:\n            lv_obj_set_style(roller, style);\n            break;\n        case LV_ROLLER_STYLE_SEL:\n            lv_ddlist_set_style(roller, LV_DDLIST_STYLE_SEL, style);\n            break;\n    }\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the align attribute. Default alignment after _create is LV_LABEL_ALIGN_CENTER\n * @param roller pointer to a roller object\n * @return LV_LABEL_ALIGN_LEFT, LV_LABEL_ALIGN_RIGHT or LV_LABEL_ALIGN_CENTER\n */\nlv_label_align_t lv_roller_get_align(const lv_obj_t * roller)\n{\n    lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller);\n    lv_mem_assert(ext);\n    lv_mem_assert(ext->ddlist.label);\n    return lv_label_get_align(ext->ddlist.label);\n}\n\n/**\n * Get the auto width set attribute\n * @param roller pointer to a roller object\n * @return true: auto size enabled; false: manual width settings enabled\n */\nbool lv_roller_get_hor_fit(const lv_obj_t * roller)\n{\n    return lv_page_get_scrl_hor_fit(roller);\n}\n\n/**\n * Get a style of a roller\n * @param roller pointer to a roller object\n * @param type which style should be get\n * @return style pointer to a style\n *  */\nlv_style_t * lv_roller_get_style(const lv_obj_t * roller, lv_roller_style_t type)\n{\n    switch(type) {\n        case LV_ROLLER_STYLE_BG:\n            return lv_obj_get_style(roller);\n        case LV_ROLLER_STYLE_SEL:\n            return lv_ddlist_get_style(roller, LV_DDLIST_STYLE_SEL);\n        default:\n            return NULL;\n    }\n\n    /*To avoid warning*/\n    return NULL;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Handle the drawing related tasks of the rollers\n * @param roller pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_roller_design(lv_obj_t * roller, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    /*Return false if the object is not covers the mask_p area*/\n    if(mode == LV_DESIGN_COVER_CHK) {\n        return false;\n    }\n    /*Draw the object*/\n    else if(mode == LV_DESIGN_DRAW_MAIN) {\n        draw_bg(roller, mask);\n\n        lv_style_t * style = lv_roller_get_style(roller, LV_ROLLER_STYLE_BG);\n        lv_opa_t opa_scale = lv_obj_get_opa_scale(roller);\n        const lv_font_t * font = style->text.font;\n        lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller);\n        lv_coord_t font_h = lv_font_get_height(font);\n        lv_area_t rect_area;\n        rect_area.y1 = roller->coords.y1 + lv_obj_get_height(roller) / 2 - font_h / 2 - style->text.line_space / 2;\n        if((font_h & 0x1) && (style->text.line_space & 0x1)) rect_area.y1 --;       /*Compensate the two rounding error*/\n        rect_area.y2 = rect_area.y1 + font_h + style->text.line_space - 1;\n        rect_area.x1 = roller->coords.x1;\n        rect_area.x2 = roller->coords.x2;\n\n        lv_draw_rect(&rect_area, mask, ext->ddlist.sel_style, opa_scale);\n    }\n    /*Post draw when the children are drawn*/\n    else if(mode == LV_DESIGN_DRAW_POST) {\n        lv_style_t * style = lv_roller_get_style(roller, LV_ROLLER_STYLE_BG);\n        lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller);\n        const lv_font_t * font = style->text.font;\n        lv_coord_t font_h = lv_font_get_height(font);\n        lv_opa_t opa_scale = lv_obj_get_opa_scale(roller);\n\n        /*Redraw the text on the selected area with a different color*/\n        lv_area_t rect_area;\n        rect_area.y1 = roller->coords.y1 + lv_obj_get_height(roller) / 2 - font_h / 2 - style->text.line_space / 2;\n        if((font_h & 0x1) && (style->text.line_space & 0x1)) rect_area.y1 --;       /*Compensate the two rounding error*/\n        rect_area.y2 = rect_area.y1 + font_h + style->text.line_space - 1;\n        rect_area.x1 = roller->coords.x1;\n        rect_area.x2 = roller->coords.x2;\n        lv_area_t mask_sel;\n        bool area_ok;\n        area_ok = lv_area_intersect(&mask_sel, mask, &rect_area);\n        if(area_ok) {\n            lv_style_t * sel_style = lv_roller_get_style(roller, LV_ROLLER_STYLE_SEL);\n            lv_style_t new_style;\n            lv_txt_flag_t txt_align = LV_TXT_FLAG_NONE;\n\n            {\n                lv_label_align_t label_align = lv_label_get_align(ext->ddlist.label);\n\n                if(LV_LABEL_ALIGN_CENTER == label_align) {\n                    txt_align |= LV_TXT_FLAG_CENTER;\n                } else if(LV_LABEL_ALIGN_RIGHT == label_align) {\n                    txt_align |= LV_TXT_FLAG_RIGHT;\n                }\n            }\n\n            lv_style_copy(&new_style, style);\n            new_style.text.color = sel_style->text.color;\n            new_style.text.opa = sel_style->text.opa;\n            lv_draw_label(&ext->ddlist.label->coords, &mask_sel, &new_style, opa_scale,\n                          lv_label_get_text(ext->ddlist.label), txt_align, NULL);\n        }\n    }\n\n    return true;\n}\n\n/**\n * Signal function of the roller\n * @param roller pointer to a roller object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_roller_signal(lv_obj_t * roller, lv_signal_t sign, void * param)\n{\n    lv_res_t res  = LV_RES_OK;\n\n    /*Don't let the drop down list to handle the control signals. It works differently*/\n    if(sign != LV_SIGNAL_CONTROLL && sign != LV_SIGNAL_FOCUS && sign != LV_SIGNAL_DEFOCUS) {\n        /* Include the ancient signal function */\n        res = ancestor_signal(roller, sign, param);\n        if(res != LV_RES_OK) return res;\n    }\n\n    lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller);\n    lv_align_t obj_align = LV_ALIGN_IN_LEFT_MID;\n    if(ext->ddlist.label) {\n        lv_label_align_t label_align = lv_label_get_align(ext->ddlist.label);\n        if(LV_LABEL_ALIGN_CENTER == label_align) obj_align = LV_ALIGN_CENTER;\n        else if(LV_LABEL_ALIGN_RIGHT == label_align) obj_align = LV_ALIGN_IN_RIGHT_MID;\n    }\n\n    if(sign == LV_SIGNAL_STYLE_CHG) {\n        lv_obj_set_height(lv_page_get_scrl(roller),\n                          lv_obj_get_height(ext->ddlist.label) + lv_obj_get_height(roller));\n        lv_obj_align(ext->ddlist.label, NULL, obj_align, 0, 0);\n        lv_ddlist_set_selected(roller, ext->ddlist.sel_opt_id);\n        refr_position(roller, false);\n    } else if(sign == LV_SIGNAL_CORD_CHG) {\n\n        if(lv_obj_get_width(roller) != lv_area_get_width(param) ||\n                lv_obj_get_height(roller) != lv_area_get_height(param)) {\n\n            lv_ddlist_set_fix_height(roller, lv_obj_get_height(roller));\n            lv_obj_set_height(lv_page_get_scrl(roller),\n                              lv_obj_get_height(ext->ddlist.label) + lv_obj_get_height(roller));\n\n            lv_obj_align(ext->ddlist.label, NULL, obj_align, 0, 0);\n            lv_ddlist_set_selected(roller, ext->ddlist.sel_opt_id);\n            refr_position(roller, false);\n        }\n    } else if(sign == LV_SIGNAL_FOCUS) {\n#if USE_LV_GROUP\n        lv_group_t * g = lv_obj_get_group(roller);\n        bool editing = lv_group_get_editing(g);\n        lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act());\n\n        /*Encoders need special handling*/\n        if(indev_type == LV_INDEV_TYPE_ENCODER) {\n            /*In navigate mode revert the original value*/\n            if(!editing) {\n                if(ext->ddlist.sel_opt_id != ext->ddlist.sel_opt_id_ori) {\n                    ext->ddlist.sel_opt_id = ext->ddlist.sel_opt_id_ori;\n                    refr_position(roller, true);\n                }\n            }\n            /*Save the current state when entered to edit mode*/\n            else {\n                ext->ddlist.sel_opt_id_ori = ext->ddlist.sel_opt_id;\n            }\n        } else {\n            ext->ddlist.sel_opt_id_ori = ext->ddlist.sel_opt_id;      /*Save the current value. Used to revert this state if ENER wont't be pressed*/\n\n        }\n#endif\n    } else if(sign == LV_SIGNAL_DEFOCUS) {\n#if USE_LV_GROUP\n        /*Revert the original state*/\n        if(ext->ddlist.sel_opt_id != ext->ddlist.sel_opt_id_ori) {\n            ext->ddlist.sel_opt_id = ext->ddlist.sel_opt_id_ori;\n            refr_position(roller, true);\n        }\n#endif\n    } else if(sign == LV_SIGNAL_CONTROLL) {\n        char c = *((char *)param);\n        if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_DOWN) {\n            if(ext->ddlist.sel_opt_id + 1 < ext->ddlist.option_cnt) {\n                lv_roller_set_selected(roller, ext->ddlist.sel_opt_id + 1, true);\n            }\n        } else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_UP) {\n            if(ext->ddlist.sel_opt_id > 0) {\n                lv_roller_set_selected(roller, ext->ddlist.sel_opt_id - 1, true);\n            }\n        } else if(c == LV_GROUP_KEY_ENTER) {\n            ext->ddlist.sel_opt_id_ori = ext->ddlist.sel_opt_id;        /*Set the entered value as default*/\n            if(ext->ddlist.action) ext->ddlist.action(roller);\n\n#if USE_LV_GROUP\n            lv_group_t * g = lv_obj_get_group(roller);\n            bool editing = lv_group_get_editing(g);\n            if(editing) lv_group_set_editing(g, false);     /*In edit mode go to navigate mode if an option is selected*/\n#endif\n        }\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_roller\";\n    }\n\n    return res;\n}\n\n/**\n * Signal function of the scrollable part of the roller.\n * @param roller_scrl ointer to the scrollable part of roller (page)\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_roller_scrl_signal(lv_obj_t * roller_scrl, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_scrl_signal(roller_scrl, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    lv_indev_t * indev = lv_indev_get_act();\n    int32_t id = -1;\n    lv_obj_t * roller = lv_obj_get_parent(roller_scrl);\n    lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller);\n\n    if(ext->ddlist.label == NULL) return LV_RES_INV;    /*On delete the ddlist signal deletes the label so nothing left to do here*/\n\n    lv_style_t * style_label = lv_obj_get_style(ext->ddlist.label);\n    const lv_font_t * font = style_label->text.font;\n    lv_coord_t font_h = lv_font_get_height(font);\n\n    if(sign == LV_SIGNAL_DRAG_END) {\n        /*If dragged then align the list to there be an element in the middle*/\n        lv_coord_t label_y1 = ext->ddlist.label->coords.y1 - roller->coords.y1;\n        lv_coord_t label_unit = font_h + style_label->text.line_space;\n        lv_coord_t mid = (roller->coords.y2 - roller->coords.y1) / 2;\n        id = (mid - label_y1 + style_label->text.line_space / 2) / label_unit;\n        if(id < 0) id = 0;\n        if(id >= ext->ddlist.option_cnt) id = ext->ddlist.option_cnt - 1;\n        ext->ddlist.sel_opt_id = id;\n        if(ext->ddlist.action) ext->ddlist.action(roller);\n    } else if(sign == LV_SIGNAL_RELEASED) {\n        /*If picked an option by clicking then set it*/\n        if(!lv_indev_is_dragging(indev)) {\n            lv_point_t p;\n            lv_indev_get_point(indev, &p);\n            p.y = p.y - ext->ddlist.label->coords.y1;\n            id = p.y / (font_h + style_label->text.line_space);\n            if(id < 0) id = 0;\n            if(id >= ext->ddlist.option_cnt) id = ext->ddlist.option_cnt - 1;\n            ext->ddlist.sel_opt_id = id;\n            if(ext->ddlist.action) ext->ddlist.action(roller);\n        }\n    }\n\n    /*Position the scrollable according to the new selected option*/\n    if(id != -1) {\n        refr_position(roller, true);\n    }\n\n    return res;\n}\n\n/**\n * Draw a rectangle which has gradient on its top and bottom\n * @param roller pointer to a roller object\n * @param mask pointer to the current mask (from the design function)\n */\nstatic void draw_bg(lv_obj_t * roller, const lv_area_t * mask)\n{\n    lv_style_t * style = lv_roller_get_style(roller, LV_ROLLER_STYLE_BG);\n    lv_area_t half_mask;\n    lv_area_t half_roller;\n    lv_coord_t h = lv_obj_get_height(roller);\n    bool union_ok;\n    lv_area_copy(&half_roller, &roller->coords);\n\n    half_roller.x1 -= roller->ext_size; /*Add ext size too (e.g. because of shadow draw) */\n    half_roller.x2 += roller->ext_size;\n    half_roller.y1 -= roller->ext_size;\n    half_roller.y2 = roller->coords.y1 + h / 2;\n\n    union_ok = lv_area_intersect(&half_mask, &half_roller, mask);\n\n    half_roller.x1 += roller->ext_size; /*Revert ext. size adding*/\n    half_roller.x2 -= roller->ext_size;\n    half_roller.y1 += roller->ext_size;\n    half_roller.y2 += style->body.radius;\n\n    if(union_ok) {\n        lv_draw_rect(&half_roller, &half_mask, style, lv_obj_get_opa_scale(roller));\n    }\n\n    half_roller.x1 -= roller->ext_size; /*Add ext size too (e.g. because of shadow draw) */\n    half_roller.x2 += roller->ext_size;\n    half_roller.y2 = roller->coords.y2 + roller->ext_size;\n    half_roller.y1 = roller->coords.y1 + h / 2;\n    if((h & 0x1) == 0) half_roller.y1++;    /*With even height the pixels in the middle would be drawn twice*/\n\n    union_ok = lv_area_intersect(&half_mask, &half_roller, mask);\n\n    half_roller.x1 += roller->ext_size; /*Revert ext. size adding*/\n    half_roller.x2 -= roller->ext_size;\n    half_roller.y2 -= roller->ext_size;\n    half_roller.y1 -= style->body.radius;\n\n    if(union_ok) {\n        lv_color_t main_tmp = style->body.main_color;\n        lv_color_t grad_tmp = style->body.grad_color;\n\n        style->body.main_color = grad_tmp;\n        style->body.grad_color = main_tmp;\n        lv_draw_rect(&half_roller, &half_mask, style, lv_obj_get_opa_scale(roller));\n        style->body.main_color = main_tmp;\n        style->body.grad_color = grad_tmp;\n    }\n}\n\n/**\n * Refresh the position of the roller. It uses the id stored in: ext->ddlist.selected_option_id\n * @param roller pointer to a roller object\n * @param anim_en true: refresh with animation; false: without animation\n */\nstatic void refr_position(lv_obj_t * roller, bool anim_en)\n{\n#if USE_LV_ANIMATION == 0\n    anim_en = false;\n#endif\n    lv_obj_t * roller_scrl = lv_page_get_scrl(roller);\n    lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller);\n    lv_style_t * style_label = lv_obj_get_style(ext->ddlist.label);\n    const lv_font_t * font = style_label->text.font;\n    lv_coord_t font_h = lv_font_get_height(font);\n    lv_coord_t h = lv_obj_get_height(roller);\n    int32_t id = ext->ddlist.sel_opt_id;\n    lv_coord_t line_y1 = id * (font_h + style_label->text.line_space) + ext->ddlist.label->coords.y1 - roller_scrl->coords.y1;\n    lv_coord_t new_y = - line_y1 + (h - font_h) / 2;\n\n    if(ext->ddlist.anim_time == 0 || anim_en == false) {\n        lv_obj_set_y(roller_scrl, new_y);\n    } else {\n#if USE_LV_ANIMATION\n        lv_anim_t a;\n        a.var = roller_scrl;\n        a.start = lv_obj_get_y(roller_scrl);\n        a.end = new_y;\n        a.fp = (lv_anim_fp_t)lv_obj_set_y;\n        a.path = lv_anim_path_linear;\n        a.end_cb = NULL;\n        a.act_time = 0;\n        a.time = ext->ddlist.anim_time;\n        a.playback = 0;\n        a.playback_pause = 0;\n        a.repeat = 0;\n        a.repeat_pause = 0;\n        lv_anim_create(&a);\n#endif\n    }\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_roller.h",
    "content": "/**\n * @file lv_roller.h\n *\n */\n\n#ifndef LV_ROLLER_H\n#define LV_ROLLER_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_ROLLER != 0\n\n/*Testing of dependencies*/\n#if USE_LV_DDLIST == 0\n#error \"lv_roller: lv_ddlist is required. Enable it in lv_conf.h (USE_LV_DDLIST  1) \"\n#endif\n\n#include \"../lv_core/lv_obj.h\"\n#include \"lv_ddlist.h\"\n#include \"lv_label.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n/*Data of roller*/\ntypedef struct {\n    lv_ddlist_ext_t ddlist; /*Ext. of ancestor*/\n    /*New data for this type */\n} lv_roller_ext_t;\n\nenum {\n    LV_ROLLER_STYLE_BG,\n    LV_ROLLER_STYLE_SEL,\n};\ntypedef uint8_t lv_roller_style_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a roller object\n * @param par pointer to an object, it will be the parent of the new roller\n * @param copy pointer to a roller object, if not NULL then the new object will be copied from it\n * @return pointer to the created roller\n */\nlv_obj_t * lv_roller_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set the align of the roller's options (left, right or center[default])\n * @param roller - pointer to a roller object\n * @param align - one of lv_label_align_t values (left, right, center)\n */\nvoid lv_roller_set_align(lv_obj_t * roller, lv_label_align_t align);\n\n/**\n * Set the options on a roller\n * @param roller pointer to roller object\n * @param options a string with '\\n' separated options. E.g. \"One\\nTwo\\nThree\"\n */\nstatic inline void lv_roller_set_options(lv_obj_t * roller, const char * options)\n{\n    lv_ddlist_set_options(roller, options);\n}\n\n/**\n * Set the selected option\n * @param roller pointer to a roller object\n * @param sel_opt id of the selected option (0 ... number of option - 1);\n * @param anim_en true: set with animation; false set immediately\n */\nvoid lv_roller_set_selected(lv_obj_t *roller, uint16_t sel_opt, bool anim_en);\n\n/**\n * Set a function to call when a new option is chosen\n * @param roller pointer to a roller\n * @param action pointer to a callback function\n */\nstatic inline void lv_roller_set_action(lv_obj_t * roller, lv_action_t action)\n{\n    lv_ddlist_set_action(roller, action);\n}\n\n/**\n * Set the height to show the given number of rows (options)\n * @param roller pointer to a roller object\n * @param row_cnt number of desired visible rows\n */\nvoid lv_roller_set_visible_row_count(lv_obj_t *roller, uint8_t row_cnt);\n\n/**\n * Enable or disable the horizontal fit to the content\n * @param roller pointer to a roller\n * @param en true: enable auto fit; false: disable auto fit\n */\nstatic inline void lv_roller_set_hor_fit(lv_obj_t * roller, bool en)\n{\n    lv_ddlist_set_hor_fit(roller, en);\n}\n\n/**\n * Set the open/close animation time.\n * @param roller pointer to a roller object\n * @param anim_time: open/close animation time [ms]\n */\nstatic inline void lv_roller_set_anim_time(lv_obj_t *roller, uint16_t anim_time)\n{\n    lv_ddlist_set_anim_time(roller, anim_time);\n}\n\n/**\n * Set a style of a roller\n * @param roller pointer to a roller object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_roller_set_style(lv_obj_t *roller, lv_roller_style_t type, lv_style_t *style);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the align attribute. Default alignment after _create is LV_LABEL_ALIGN_CENTER\n * @param roller pointer to a roller object\n * @return LV_LABEL_ALIGN_LEFT, LV_LABEL_ALIGN_RIGHT or LV_LABEL_ALIGN_CENTER\n */\nlv_label_align_t lv_roller_get_align(const lv_obj_t * roller);\n\n/**\n * Get the options of a roller\n * @param roller pointer to roller object\n * @return the options separated by '\\n'-s (E.g. \"Option1\\nOption2\\nOption3\")\n */\nstatic inline const char * lv_roller_get_options(const lv_obj_t *roller)\n{\n    return lv_ddlist_get_options(roller);\n}\n\n/**\n * Get the id of the selected option\n * @param roller pointer to a roller object\n * @return id of the selected option (0 ... number of option - 1);\n */\nstatic inline uint16_t lv_roller_get_selected(const lv_obj_t *roller)\n{\n    return lv_ddlist_get_selected(roller);\n}\n\n/**\n * Get the current selected option as a string\n * @param roller pointer to roller object\n * @param buf pointer to an array to store the string\n */\nstatic inline void lv_roller_get_selected_str(const lv_obj_t * roller, char * buf)\n{\n    lv_ddlist_get_selected_str(roller, buf);\n}\n\n/**\n * Get the \"option selected\" callback function\n * @param roller pointer to a roller\n * @return  pointer to the call back function\n */\nstatic inline lv_action_t lv_roller_get_action(const lv_obj_t * roller)\n{\n    return lv_ddlist_get_action(roller);\n}\n\n/**\n * Get the open/close animation time.\n * @param roller pointer to a roller\n * @return open/close animation time [ms]\n */\nstatic inline uint16_t lv_roller_get_anim_time(const lv_obj_t * roller)\n{\n    return lv_ddlist_get_anim_time(roller);\n}\n\n/**\n * Get the auto width set attribute\n * @param roller pointer to a roller object\n * @return true: auto size enabled; false: manual width settings enabled\n */\nbool lv_roller_get_hor_fit(const lv_obj_t *roller);\n\n/**\n * Get a style of a roller\n * @param roller pointer to a roller object\n * @param type which style should be get\n * @return style pointer to a style\n *  */\nlv_style_t * lv_roller_get_style(const lv_obj_t *roller, lv_roller_style_t type);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_ROLLER*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_ROLLER_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_slider.c",
    "content": "/*\n * Copyright (c) 2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * @file lv_slider.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_slider.h\"\n#if USE_LV_SLIDER != 0\n\n#include \"../lv_core/lv_group.h\"\n#include \"../lv_draw/lv_draw.h\"\n#include \"../lv_themes/lv_theme.h\"\n#include \"../lv_misc/lv_math.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_SLIDER_SIZE_MIN      4           /*hor. pad and ver. pad cannot make the bar or indicator smaller then this [px]*/\n#define LV_SLIDER_NOT_PRESSED   INT16_MIN\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool lv_slider_design(lv_obj_t * slider, const lv_area_t * mask, lv_design_mode_t mode);\nstatic lv_res_t lv_slider_signal(lv_obj_t * slider, lv_signal_t sign, void * param);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_design_func_t ancestor_design_f;\nstatic lv_signal_func_t ancestor_signal;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a slider objects\n * @param par pointer to an object, it will be the parent of the new slider\n * @param copy pointer to a slider object, if not NULL then the new object will be copied from it\n * @return pointer to the created slider\n */\nlv_obj_t * lv_slider_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"slider create started\");\n\n    /*Create the ancestor slider*/\n    lv_obj_t * new_slider = lv_bar_create(par, copy);\n    lv_mem_assert(new_slider);\n    if(new_slider == NULL) return NULL;\n\n    if(ancestor_design_f == NULL) ancestor_design_f = lv_obj_get_design_func(new_slider);\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_slider);\n\n    /*Allocate the slider type specific extended data*/\n    lv_slider_ext_t * ext = lv_obj_allocate_ext_attr(new_slider, sizeof(lv_slider_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    /*Initialize the allocated 'ext' */\n    ext->action = NULL;\n    ext->drag_value = LV_SLIDER_NOT_PRESSED;\n    ext->style_knob = &lv_style_pretty;\n    ext->knob_in = 0;\n\n    /*The signal and design functions are not copied so set them here*/\n    lv_obj_set_signal_func(new_slider, lv_slider_signal);\n    lv_obj_set_design_func(new_slider, lv_slider_design);\n\n    /*Init the new slider slider*/\n    if(copy == NULL) {\n        lv_obj_set_click(new_slider, true);\n        lv_obj_set_protect(new_slider, LV_PROTECT_PRESS_LOST);\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_slider_set_style(new_slider, LV_SLIDER_STYLE_BG, th->slider.bg);\n            lv_slider_set_style(new_slider, LV_SLIDER_STYLE_INDIC, th->slider.indic);\n            lv_slider_set_style(new_slider, LV_SLIDER_STYLE_KNOB, th->slider.knob);\n        } else {\n            lv_slider_set_style(new_slider, LV_SLIDER_STYLE_KNOB, ext->style_knob);\n        }\n    }\n    /*Copy an existing slider*/\n    else {\n        lv_slider_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        ext->style_knob = copy_ext->style_knob;\n        ext->action = copy_ext->action;\n        ext->knob_in = copy_ext->knob_in;\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_slider);\n    }\n\n\n    LV_LOG_INFO(\"slider created\");\n\n\n    return new_slider;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a function which will be called when a new value is set on the slider\n * @param slider pointer to slider object\n * @param action a callback function\n */\nvoid lv_slider_set_action(lv_obj_t * slider, lv_action_t action)\n{\n    lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider);\n    ext->action = action;\n}\n\n/**\n * Set the 'knob in' attribute of a slider\n * @param slider pointer to slider object\n * @param in true: the knob is drawn always in the slider;\n *           false: the knob can be out on the edges\n */\nvoid lv_slider_set_knob_in(lv_obj_t * slider, bool in)\n{\n    lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider);\n    if(ext->knob_in == in) return;\n\n    ext->knob_in = in == false ? 0 : 1;\n    lv_obj_invalidate(slider);\n}\n\n/**\n * Set a style of a slider\n * @param slider pointer to a slider object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_slider_set_style(lv_obj_t * slider, lv_slider_style_t type, lv_style_t * style)\n{\n    lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider);\n\n    switch(type) {\n        case LV_SLIDER_STYLE_BG:\n            lv_bar_set_style(slider, LV_BAR_STYLE_BG, style);\n            break;\n        case LV_SLIDER_STYLE_INDIC:\n            lv_bar_set_style(slider, LV_BAR_STYLE_INDIC, style);\n            break;\n        case LV_SLIDER_STYLE_KNOB:\n            ext->style_knob = style;\n            lv_obj_refresh_ext_size(slider);\n            break;\n    }\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the value of a slider\n * @param slider pointer to a slider object\n * @return the value of the slider\n */\nint16_t lv_slider_get_value(const lv_obj_t * slider)\n{\n    lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider);\n\n    if(ext->drag_value != LV_SLIDER_NOT_PRESSED) return ext->drag_value;\n    else return lv_bar_get_value(slider);\n}\n\n/**\n * Get the slider action function\n * @param slider pointer to slider object\n * @return the callback function\n */\nlv_action_t lv_slider_get_action(const lv_obj_t * slider)\n{\n    lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider);\n    return ext->action;\n}\n\n/**\n * Give the slider is being dragged or not\n * @param slider pointer to a slider object\n * @return true: drag in progress false: not dragged\n */\nbool lv_slider_is_dragged(const lv_obj_t * slider)\n{\n    lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider);\n    return ext->drag_value == LV_SLIDER_NOT_PRESSED ? false : true;\n}\n\n/**\n * Get the 'knob in' attribute of a slider\n * @param slider pointer to slider object\n * @return true: the knob is drawn always in the slider;\n *         false: the knob can be out on the edges\n */\nbool lv_slider_get_knob_in(const lv_obj_t * slider)\n{\n    lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider);\n    return ext->knob_in == 0 ? false : true;\n}\n\n/**\n * Get a style of a slider\n * @param slider pointer to a slider object\n * @param type which style should be get\n * @return style pointer to a style\n */\nlv_style_t * lv_slider_get_style(const lv_obj_t * slider, lv_slider_style_t type)\n{\n    lv_style_t * style = NULL;\n    lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider);\n\n    switch(type) {\n        case LV_SLIDER_STYLE_BG:\n            style = lv_bar_get_style(slider, LV_BAR_STYLE_BG);\n            break;\n        case LV_SLIDER_STYLE_INDIC:\n            style = lv_bar_get_style(slider, LV_BAR_STYLE_INDIC);\n            break;\n        case LV_SLIDER_STYLE_KNOB:\n            style = ext->style_knob;\n            break;\n        default:\n            style = NULL;\n            break;\n    }\n\n    return style;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n\n/**\n * Handle the drawing related tasks of the sliders\n * @param slider pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_slider_design(lv_obj_t * slider, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    /*Return false if the object is not covers the mask_p area*/\n    if(mode == LV_DESIGN_COVER_CHK) {\n        return false;\n    }\n    /*Draw the object*/\n    else if(mode == LV_DESIGN_DRAW_MAIN) {\n        lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider);\n\n        lv_style_t * style_bg = lv_slider_get_style(slider, LV_SLIDER_STYLE_BG);\n        lv_style_t * style_knob = lv_slider_get_style(slider, LV_SLIDER_STYLE_KNOB);\n        lv_style_t * style_indic = lv_slider_get_style(slider, LV_SLIDER_STYLE_INDIC);\n\n        lv_opa_t opa_scale = lv_obj_get_opa_scale(slider);\n\n        lv_coord_t slider_w = lv_area_get_width(&slider->coords);\n        lv_coord_t slider_h = lv_area_get_height(&slider->coords);\n\n        /*Draw the bar*/\n        lv_area_t area_bg;\n        lv_area_copy(&area_bg, &slider->coords);\n\n        /*Be sure at least LV_SLIDER_SIZE_MIN  size will remain*/\n        lv_coord_t pad_ver_bg = style_bg->body.padding.ver;\n        lv_coord_t pad_hor_bg = style_bg->body.padding.hor;\n        if(pad_ver_bg * 2 + LV_SLIDER_SIZE_MIN > lv_area_get_height(&area_bg)) {\n            pad_ver_bg = (lv_area_get_height(&area_bg) - LV_SLIDER_SIZE_MIN) >> 1;\n        }\n        if(pad_hor_bg * 2 + LV_SLIDER_SIZE_MIN > lv_area_get_width(&area_bg)) {\n            pad_hor_bg = (lv_area_get_width(&area_bg) - LV_SLIDER_SIZE_MIN) >> 1;\n        }\n\n        if(ext->knob_in) {  /*Enable extra size if the knob is inside */\n            area_bg.x1 += pad_hor_bg;\n            area_bg.x2 -= pad_hor_bg;\n            area_bg.y1 += pad_hor_bg;\n            area_bg.y2 -= pad_hor_bg;\n        } else  { /*Let space only in the perpendicular directions*/\n            area_bg.x1 += slider_w < slider_h ? pad_hor_bg : 0;   /*Pad only for vertical slider*/\n            area_bg.x2 -= slider_w < slider_h ? pad_hor_bg : 0;   /*Pad only for vertical slider*/\n            area_bg.y1 += slider_w > slider_h ? pad_ver_bg : 0;   /*Pad only for horizontal slider*/\n            area_bg.y2 -= slider_w > slider_h ? pad_ver_bg : 0;   /*Pad only for horizontal slider*/\n        }\n\n\n#if USE_LV_GROUP == 0\n        lv_draw_rect(&area_bg, mask, style_bg, lv_obj_get_opa_scale(slider));\n#else\n        /* Draw the borders later if the bar is focused.\n         * At value = 100% the indicator can cover to whole background and the focused style won't be visible*/\n        if(lv_obj_is_focused(slider)) {\n            lv_style_t style_tmp;\n            lv_style_copy(&style_tmp, style_bg);\n            style_tmp.body.border.width = 0;\n            lv_draw_rect(&area_bg, mask, &style_tmp, opa_scale);\n        } else {\n            lv_draw_rect(&area_bg, mask, style_bg, opa_scale);\n        }\n#endif\n\n\n        /*Draw the indicator*/\n        lv_area_t area_indic;\n        lv_area_copy(&area_indic, &area_bg);\n\n        /*Be sure at least ver pad/hor pad width indicator will remain*/\n        lv_coord_t pad_ver_indic = style_indic->body.padding.ver;\n        lv_coord_t pad_hor_indic = style_indic->body.padding.hor;\n        if(pad_ver_indic * 2 + LV_SLIDER_SIZE_MIN > lv_area_get_height(&area_bg)) {\n            pad_ver_indic = (lv_area_get_height(&area_bg) - LV_SLIDER_SIZE_MIN) >> 1;\n        }\n        if(pad_hor_indic * 2 + LV_SLIDER_SIZE_MIN > lv_area_get_width(&area_bg)) {\n            pad_hor_indic = (lv_area_get_width(&area_bg) - LV_SLIDER_SIZE_MIN) >> 1;\n        }\n\n        area_indic.x1 += pad_hor_indic;\n        area_indic.x2 -= pad_hor_indic;\n        area_indic.y1 += pad_ver_indic;\n        area_indic.y2 -= pad_ver_indic;\n\n\n        lv_coord_t cur_value = lv_slider_get_value(slider);\n        lv_coord_t min_value = lv_slider_get_min_value(slider);\n        lv_coord_t max_value = lv_slider_get_max_value(slider);\n\n        /*If dragged draw to the drag position*/\n        if(ext->drag_value != LV_SLIDER_NOT_PRESSED) cur_value = ext->drag_value;\n\n        if(slider_w >= slider_h) {\n            area_indic.x2 = (int32_t)((int32_t)(lv_area_get_width(&area_indic)) * (cur_value - min_value)) / (max_value - min_value);\n            area_indic.x2 = area_indic.x1 + area_indic.x2 - 1;\n\n        } else {\n            area_indic.y1 = (int32_t)((int32_t)(lv_area_get_height(&area_indic)) * (cur_value - min_value)) / (max_value - min_value);\n            area_indic.y1 = area_indic.y2 - area_indic.y1 + 1;\n        }\n\n        if(cur_value != min_value) lv_draw_rect(&area_indic, mask, style_indic, opa_scale);\n\n        /*Before the knob add the border if required*/\n#if USE_LV_GROUP\n        /* Draw the borders later if the bar is focused.\n         * At value = 100% the indicator can cover to whole background and the focused style won't be visible*/\n        if(lv_obj_is_focused(slider)) {\n            lv_style_t style_tmp;\n            lv_style_copy(&style_tmp, style_bg);\n            style_tmp.body.empty = 1;\n            style_tmp.body.shadow.width = 0;\n            lv_draw_rect(&area_bg, mask, &style_tmp, opa_scale);\n        }\n#endif\n\n        /*Draw the knob*/\n        lv_area_t knob_area;\n        lv_area_copy(&knob_area, &slider->coords);\n\n        if(slider_w >= slider_h) {\n            if(ext->knob_in == 0) {\n                knob_area.x1 = area_indic.x2 - slider_h / 2;\n                knob_area.x2 = knob_area.x1 + slider_h - 1;\n            } else {\n                knob_area.x1 = (int32_t)((int32_t)(slider_w - slider_h - 1) * (cur_value - min_value)) / (max_value - min_value);\n                knob_area.x1 += slider->coords.x1;\n                knob_area.x2 = knob_area.x1 + slider_h - 1;\n            }\n\n            knob_area.y1 = slider->coords.y1;\n            knob_area.y2 = slider->coords.y2;\n        } else {\n            if(ext->knob_in == 0) {\n                knob_area.y1 = area_indic.y1 - slider_w / 2;\n                knob_area.y2 = knob_area.y1 + slider_w - 1;\n            } else {\n                knob_area.y2 = (int32_t)((int32_t)(slider_h - slider_w - 1) * (cur_value - min_value)) / (max_value - min_value);\n                knob_area.y2 = slider->coords.y2 - knob_area.y2;\n                knob_area.y1 = knob_area.y2 - slider_w - 1;\n            }\n            knob_area.x1 = slider->coords.x1;\n            knob_area.x2 = slider->coords.x2;\n\n        }\n        lv_draw_rect(&knob_area, mask, style_knob, opa_scale);\n    }\n    /*Post draw when the children are drawn*/\n    else if(mode == LV_DESIGN_DRAW_POST) {\n\n    }\n\n    return true;\n}\n\n/**\n * Signal function of the slider\n * @param slider pointer to a slider object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_slider_signal(lv_obj_t * slider, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(slider, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    lv_slider_ext_t * ext = lv_obj_get_ext_attr(slider);\n    lv_point_t p;\n    lv_coord_t w = lv_obj_get_width(slider);\n    lv_coord_t h = lv_obj_get_height(slider);\n\n    if(sign == LV_SIGNAL_PRESSED) {\n        ext->drag_value = lv_slider_get_value(slider);\n    } else if(sign == LV_SIGNAL_PRESSING) {\n        lv_indev_get_point(param, &p);\n        int16_t tmp = 0;\n        if(w > h) {\n\t\t\tlv_coord_t knob_w = h;\n\t\t\tlv_coord_t offset = (ext->knob_in == 0) ? w : w - knob_w;\n\t\t\tp.x -= slider->coords.x1 + ((ext->knob_in == 0) ? 0 : knob_w / 2);\n\t\t\ttmp = ((int32_t)p.x * (ext->bar.max_value - ext->bar.min_value) + offset / 2) / offset;\n        } else {\n\t\t\tlv_coord_t knob_h = w;\n\t\t\tlv_coord_t offset = (ext->knob_in == 0) ? h : h - knob_h;\n\t\t\tp.y -= slider->coords.y1 + ((ext->knob_in == 0) ? 0 : knob_h / 2);\n\t\t\ttmp = ((int32_t)p.y * (ext->bar.max_value - ext->bar.min_value) + offset / 2) / offset;\n        }\n\t\ttmp += ext->bar.min_value;\n\n        if(tmp < ext->bar.min_value) tmp = ext->bar.min_value;\n        else if(tmp > ext->bar.max_value) tmp = ext->bar.max_value;\n\n        if(tmp != ext->drag_value) {\n            ext->drag_value = tmp;\n            lv_obj_invalidate(slider);\n            if(ext->action != NULL) res = ext->action(slider);\n        }\n    } else if(sign == LV_SIGNAL_RELEASED || sign == LV_SIGNAL_PRESS_LOST) {\n        lv_slider_set_value(slider, ext->drag_value);\n        ext->drag_value = LV_SLIDER_NOT_PRESSED;\n        if(ext->action != NULL) res = ext->action(slider);\n    } else if(sign == LV_SIGNAL_CORD_CHG) {\n        /* The knob size depends on slider size.\n         * During the drawing method the ext. size is used by the knob so refresh the ext. size.*/\n        if(lv_obj_get_width(slider) != lv_area_get_width(param) ||\n                lv_obj_get_height(slider) != lv_area_get_height(param)) {\n            slider->signal_func(slider, LV_SIGNAL_REFR_EXT_SIZE, NULL);\n        }\n    } else if(sign == LV_SIGNAL_REFR_EXT_SIZE) {\n        lv_style_t * style = lv_slider_get_style(slider, LV_SLIDER_STYLE_BG);\n        lv_style_t * knob_style = lv_slider_get_style(slider, LV_SLIDER_STYLE_KNOB);\n        lv_coord_t shadow_w = knob_style->body.shadow.width;\n        if(ext->knob_in == 0) {\n            /* The smaller size is the knob diameter*/\n            lv_coord_t x = LV_MATH_MIN(w / 2 + 1 + shadow_w, h / 2 + 1 + shadow_w);\n            if(slider->ext_size < x) slider->ext_size = x;\n        } else {\n            lv_coord_t pad = LV_MATH_MIN(style->body.padding.hor, style->body.padding.ver);\n            if(pad < 0) pad = -pad;\n            if(slider->ext_size < pad) slider->ext_size = pad;\n\n            if(slider->ext_size < shadow_w) slider->ext_size = shadow_w;\n        }\n    } else if(sign == LV_SIGNAL_CONTROLL) {\n        char c = *((char *)param);\n\n        ext->drag_value = LV_SLIDER_NOT_PRESSED;\n\n#if USE_LV_GROUP\n        lv_group_t * g = lv_obj_get_group(slider);\n        bool editing = lv_group_get_editing(g);\n        lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act());\n        /*Encoders need special handling*/\n        if(indev_type == LV_INDEV_TYPE_ENCODER && c == LV_GROUP_KEY_ENTER) {\n            if(editing) lv_group_set_editing(g, false);\n        }\n#endif\n        if(c == LV_GROUP_KEY_RIGHT || c == LV_GROUP_KEY_UP) {\n            lv_slider_set_value(slider, lv_slider_get_value(slider) + 1);\n            if(ext->action != NULL) res = ext->action(slider);\n        } else if(c == LV_GROUP_KEY_LEFT || c == LV_GROUP_KEY_DOWN) {\n            lv_slider_set_value(slider, lv_slider_get_value(slider) - 1);\n            if(ext->action != NULL) res = ext->action(slider);\n        }\n    } else if(sign == LV_SIGNAL_GET_EDITABLE) {\n        bool * editable = (bool *)param;\n        *editable = true;\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_slider\";\n    }\n\n    return res;\n}\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_slider.h",
    "content": "/**\n * @file lv_slider.h\n *\n */\n\n#ifndef LV_SLIDER_H\n#define LV_SLIDER_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_SLIDER != 0\n\n/*Testing of dependencies*/\n#if USE_LV_BAR == 0\n#error \"lv_slider: lv_bar is required. Enable it in lv_conf.h (USE_LV_BAR  1) \"\n#endif\n\n#include \"../lv_core/lv_obj.h\"\n#include \"lv_bar.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n/*Data of slider*/\ntypedef struct\n{\n    lv_bar_ext_t bar;       /*Ext. of ancestor*/\n    /*New data for this type */\n    lv_action_t action;             /*Function to call when a new value is set*/\n    lv_style_t *style_knob;    /*Style of the knob*/\n    int16_t drag_value;          /*Store a temporal value during press until release (Handled by the library)*/\n    uint8_t knob_in     :1;     /*1: Draw the knob inside the bar*/\n} lv_slider_ext_t;\n\n/*Built-in styles of slider*/\nenum\n{\n    LV_SLIDER_STYLE_BG,\n    LV_SLIDER_STYLE_INDIC,\n    LV_SLIDER_STYLE_KNOB,\n};\ntypedef uint8_t lv_slider_style_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a slider objects\n * @param par pointer to an object, it will be the parent of the new slider\n * @param copy pointer to a slider object, if not NULL then the new object will be copied from it\n * @return pointer to the created slider\n */\nlv_obj_t * lv_slider_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a new value on the slider\n * @param slider pointer to a slider object\n * @param value new value\n */\nstatic inline void lv_slider_set_value(lv_obj_t * slider, int16_t value)\n{\n    lv_bar_set_value(slider, value);\n}\n\n/**\n * Set a new value with animation on a slider\n * @param slider pointer to a slider object\n * @param value new value\n * @param anim_time animation time in milliseconds\n */\nstatic inline void lv_slider_set_value_anim(lv_obj_t * slider, int16_t value, uint16_t anim_time)\n{\n    lv_bar_set_value_anim(slider, value, anim_time);\n}\n\n/**\n * Set minimum and the maximum values of a bar\n * @param slider pointer to the slider object\n * @param min minimum value\n * @param max maximum value\n */\nstatic inline void lv_slider_set_range(lv_obj_t *slider, int16_t min, int16_t max)\n{\n    lv_bar_set_range(slider, min, max);\n}\n\n/**\n * Set a function which will be called when a new value is set on the slider\n * @param slider pointer to slider object\n * @param action a callback function\n */\nvoid lv_slider_set_action(lv_obj_t * slider, lv_action_t action);\n\n/**\n * Set the 'knob in' attribute of a slider\n * @param slider pointer to slider object\n * @param in true: the knob is drawn always in the slider;\n *           false: the knob can be out on the edges\n */\nvoid lv_slider_set_knob_in(lv_obj_t * slider, bool in);\n\n/**\n * Set a style of a slider\n * @param slider pointer to a slider object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_slider_set_style(lv_obj_t *slider, lv_slider_style_t type, lv_style_t *style);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the value of a slider\n * @param slider pointer to a slider object\n * @return the value of the slider\n */\nint16_t lv_slider_get_value(const lv_obj_t * slider);\n\n/**\n * Get the minimum value of a slider\n * @param slider pointer to a slider object\n * @return the minimum value of the slider\n */\nstatic inline int16_t lv_slider_get_min_value(const lv_obj_t * slider)\n{\n    return lv_bar_get_min_value(slider);\n}\n\n/**\n * Get the maximum value of a slider\n * @param slider pointer to a slider object\n * @return the maximum value of the slider\n */\nstatic inline int16_t lv_slider_get_max_value(const lv_obj_t * slider)\n{\n    return lv_bar_get_max_value(slider);\n}\n\n/**\n * Get the slider action function\n * @param slider pointer to slider object\n * @return the callback function\n */\nlv_action_t lv_slider_get_action(const lv_obj_t * slider);\n\n/**\n * Give the slider is being dragged or not\n * @param slider pointer to a slider object\n * @return true: drag in progress false: not dragged\n */\nbool lv_slider_is_dragged(const lv_obj_t * slider);\n\n/**\n * Get the 'knob in' attribute of a slider\n * @param slider pointer to slider object\n * @return true: the knob is drawn always in the slider;\n *         false: the knob can be out on the edges\n */\nbool lv_slider_get_knob_in(const lv_obj_t * slider);\n\n\n/**\n * Get a style of a slider\n * @param slider pointer to a slider object\n * @param type which style should be get\n * @return style pointer to a style\n */\nlv_style_t * lv_slider_get_style(const lv_obj_t *slider, lv_slider_style_t type);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_SLIDER*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_SLIDER_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_spinbox.c",
    "content": "/**\n * @file lv_spinbox.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_spinbox.h\"\n\n#if USE_LV_SPINBOX != 0\n#include \"../lv_themes/lv_theme.h\"\n#include \"../lv_misc/lv_math.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic lv_res_t lv_spinbox_signal(lv_obj_t * spinbox, lv_signal_t sign, void * param);\nstatic void lv_spinbox_updatevalue(lv_obj_t * spinbox);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\nstatic lv_design_func_t ancestor_design;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a spinbox object\n * @param par pointer to an object, it will be the parent of the new spinbox\n * @param copy pointer to a spinbox object, if not NULL then the new object will be copied from it\n * @return pointer to the created spinbox\n */\nlv_obj_t * lv_spinbox_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"spinbox create started\");\n\n    /*Create the ancestor of spinbox*/\n    lv_obj_t * new_spinbox = lv_ta_create(par, copy);\n    lv_mem_assert(new_spinbox);\n    if(new_spinbox == NULL) return NULL;\n\n    /*Allocate the spinbox type specific extended data*/\n    lv_spinbox_ext_t * ext = lv_obj_allocate_ext_attr(new_spinbox, sizeof(lv_spinbox_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_spinbox);\n    if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_spinbox);\n\n    /*Initialize the allocated 'ext'*/\n    ext->ta.one_line = 1;\n    ext->ta.pwd_mode = 0;\n    ext->ta.accapted_chars = \"1234567890+-. \";\n\n    ext->value = 0;\n    ext->dec_point_pos = 0;\n    ext->digit_count = 5;\n    ext->digit_padding_left = 0;\n    ext->step = 1;\n    ext->range_max = 99999;\n    ext->range_min = -99999;\n    ext->value_changed_cb = NULL;\n\n    lv_ta_set_cursor_type(new_spinbox, LV_CURSOR_BLOCK | LV_CURSOR_HIDDEN); /*hidden by default*/\n\n    /*The signal and design functions are not copied so set them here*/\n    lv_obj_set_signal_func(new_spinbox, lv_spinbox_signal);\n    lv_obj_set_design_func(new_spinbox, ancestor_design);        /*Leave the Text area's design function*/\n\n    /*Init the new spinbox spinbox*/\n    if(copy == NULL) {\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_spinbox_set_style(new_spinbox, LV_SPINBOX_STYLE_BG, th->spinbox.bg);\n            lv_spinbox_set_style(new_spinbox, LV_SPINBOX_STYLE_CURSOR, th->spinbox.cursor);\n            lv_spinbox_set_style(new_spinbox, LV_SPINBOX_STYLE_SB, th->spinbox.sb);\n        }\n    }\n    /*Copy an existing spinbox*/\n    else {\n        lv_spinbox_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n\n        lv_spinbox_set_value(new_spinbox, copy_ext->value);\n        lv_spinbox_set_digit_format(new_spinbox, copy_ext->digit_count, copy_ext->dec_point_pos);\n        lv_spinbox_set_range(new_spinbox, copy_ext->range_min, copy_ext->range_max);\n        lv_spinbox_set_step(new_spinbox, copy_ext->step);\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_spinbox);\n    }\n\n    lv_spinbox_updatevalue(new_spinbox);\n\n    LV_LOG_INFO(\"spinbox created\");\n\n    return new_spinbox;\n}\n\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set spinbox value\n * @param spinbox pointer to spinbox\n * @param i value to be set\n */\nvoid lv_spinbox_set_value(lv_obj_t * spinbox, int32_t i)\n{\n    lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox);\n    if(ext == NULL)\n        return;\n\n    if(i > ext->range_max)\n        i = ext->range_max;\n    if(i < ext->range_min)\n        i = ext->range_min;\n\n    ext->value = i;\n\n    lv_spinbox_updatevalue(spinbox);\n}\n\n/**\n * Set spinbox digit format (digit count and decimal format)\n * @param spinbox pointer to spinbox\n * @param digit_count number of digit excluding the decimal separator and the sign\n * @param separator_position number of digit before the decimal point. If 0, decimal point is not shown\n */\nvoid lv_spinbox_set_digit_format(lv_obj_t * spinbox, uint8_t digit_count, uint8_t separator_position)\n{\n    lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox);\n    if(ext == NULL)\n        return;\n\n    if(digit_count > LV_SPINBOX_MAX_DIGIT_COUNT)\n        digit_count = LV_SPINBOX_MAX_DIGIT_COUNT;\n\n    if(separator_position > LV_SPINBOX_MAX_DIGIT_COUNT)\n        separator_position = LV_SPINBOX_MAX_DIGIT_COUNT;\n\n    ext->digit_count = digit_count;\n    ext->dec_point_pos = separator_position;\n\n    lv_spinbox_updatevalue(spinbox);\n}\n\n/**\n * Set spinbox step\n * @param spinbox pointer to spinbox\n * @param step steps on increment/decrement\n */\nvoid lv_spinbox_set_step(lv_obj_t * spinbox, uint32_t step)\n{\n    lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox);\n    if(ext == NULL) return;\n\n    ext->step = step;\n}\n\n/**\n * Set spinbox value range\n * @param spinbox pointer to spinbox\n * @param range_min maximum value, inclusive\n * @param range_max minimum value, inclusive\n */\nvoid lv_spinbox_set_range(lv_obj_t * spinbox, int32_t range_min, int32_t range_max)\n{\n    lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox);\n    if(ext == NULL) return;\n\n    ext->range_max = range_max;\n    ext->range_min = range_min;\n\n    if(ext->value > ext->range_max)  {\n        ext->value = ext->range_max;\n        lv_obj_invalidate(spinbox);\n    }\n    if(ext->value < ext->range_min)  {\n        ext->value = ext->range_min;\n        lv_obj_invalidate(spinbox);\n    }\n}\n\n/**\n * Set spinbox callback on calue change\n * @param spinbox pointer to spinbox\n * @param cb Callback function called on value change event\n */\nvoid lv_spinbox_set_value_changed_cb(lv_obj_t * spinbox, lv_spinbox_value_changed_cb_t cb)\n{\n    lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox);\n    ext->value_changed_cb = cb;\n}\n\n/**\n * Set spinbox left padding in digits count (added between sign and first digit)\n * @param spinbox pointer to spinbox\n * @param cb Callback function called on value change event\n */\nvoid lv_spinbox_set_padding_left(lv_obj_t * spinbox, uint8_t padding)\n{\n    lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox);\n    ext->digit_padding_left = padding;\n    lv_spinbox_updatevalue(spinbox);\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the spinbox numeral value (user has to convert to float according to its digit format)\n * @param spinbox pointer to spinbox\n * @return value integer value of the spinbox\n */\nint32_t lv_spinbox_get_value(lv_obj_t * spinbox)\n{\n    lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox);\n\n    return ext->value;\n}\n\n/*=====================\n * Other functions\n *====================*/\n\n/**\n * Select next lower digit for edition by dividing the step by 10\n * @param spinbox pointer to spinbox\n */\nvoid lv_spinbox_step_next(lv_obj_t * spinbox)\n{\n    lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox);\n\n    int32_t new_step = ext->step / 10;\n    if((new_step) > 0) ext->step = new_step;\n    else ext->step = 1;\n\n    lv_spinbox_updatevalue(spinbox);\n}\n\n/**\n * Select next higher digit for edition by multiplying the step by 10\n * @param spinbox pointer to spinbox\n */\nvoid lv_spinbox_step_previous(lv_obj_t * spinbox)\n{\n    lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox);\n    int32_t step_limit;\n    step_limit = LV_MATH_MAX(ext->range_max, (ext->range_min < 0 ? (-ext->range_min) : ext->range_min));\n    int32_t new_step = ext->step * 10;\n    if(new_step <= step_limit) ext->step = new_step;\n\n    lv_spinbox_updatevalue(spinbox);\n}\n\n/**\n * Increment spinbox value by one step\n * @param spinbox pointer to spinbox\n */\nvoid lv_spinbox_increment(lv_obj_t * spinbox)\n{\n    lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox);\n\n    if(ext->value + ext->step <= ext->range_max) {\n        /*Special mode when zero crossing*/\n        if((ext->value + ext->step) > 0 && ext->value < 0) ext->value = -ext->value;\n        ext->value += ext->step;\n\n    } else {\n        ext->value = ext->range_max;\n    }\n\n    if(ext->value_changed_cb != NULL)  ext->value_changed_cb(spinbox, ext->value);\n    lv_spinbox_updatevalue(spinbox);\n}\n\n/**\n * Decrement spinbox value by one step\n * @param spinbox pointer to spinbox\n */\nvoid lv_spinbox_decrement(lv_obj_t * spinbox)\n{\n    lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox);\n\n    if(ext->value - ext->step >= ext->range_min) {\n        /*Special mode when zero crossing*/\n        if((ext->value - ext->step) < 0 && ext->value > 0) ext->value = -ext->value;\n        ext->value -= ext->step;\n    } else {\n        ext->value = ext->range_min;\n    }\n\n    if(ext->value_changed_cb != NULL) ext->value_changed_cb(spinbox, ext->value);\n    lv_spinbox_updatevalue(spinbox);\n}\n\n\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Signal function of the spinbox\n * @param spinbox pointer to a spinbox object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_spinbox_signal(lv_obj_t * spinbox, lv_signal_t sign, void * param)\n{\n\n    lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox);\n\n    lv_res_t res = LV_RES_OK;\n\n    /* Include the ancient signal function */\n    if(sign != LV_SIGNAL_CONTROLL)\n    {\n        res = ancestor_signal(spinbox, sign, param);\n        if(res != LV_RES_OK) return res;\n    }\n\n    if(sign == LV_SIGNAL_CLEANUP) {\n        /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/\n    } else if(sign == LV_SIGNAL_GET_TYPE)\n    {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++)\n        {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_spinbox\";\n    }\n    else if(sign == LV_SIGNAL_CONTROLL) {\n        lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act());\n\n        uint32_t c = *((uint32_t *)param);      /*uint32_t because can be UTF-8*/\n        if(c == LV_GROUP_KEY_RIGHT) {\n            if(indev_type == LV_INDEV_TYPE_ENCODER) lv_spinbox_increment(spinbox);\n            else lv_spinbox_step_next(spinbox);\n        }\n        else if(c == LV_GROUP_KEY_LEFT) {\n            if(indev_type == LV_INDEV_TYPE_ENCODER) lv_spinbox_decrement(spinbox);\n            else lv_spinbox_step_previous(spinbox);\n        }\n        else if(c == LV_GROUP_KEY_UP) {\n            lv_spinbox_increment(spinbox);\n        }\n        else if(c == LV_GROUP_KEY_DOWN)  {\n            lv_spinbox_decrement(spinbox);\n        }\n        else if(c == LV_GROUP_KEY_ENTER) {\n\n            if(ext->step > 1) {\n                lv_spinbox_step_next(spinbox);\n            } else {\n                /*Restart from the MSB*/\n                ext->step = 1;\n                uint32_t i;\n                for(i = 0; i < ext->digit_count; i++) {\n                    int32_t new_step = ext->step * 10;\n                    if(new_step >= ext->range_max) break;\n                    ext->step = new_step;\n                }\n                lv_spinbox_step_previous(spinbox);\n            }\n        }\n        else {\n            lv_ta_add_char(spinbox, c);\n        }\n    }\n\n    return res;\n}\n\nstatic void lv_spinbox_updatevalue(lv_obj_t * spinbox)\n{\n    lv_spinbox_ext_t * ext = lv_obj_get_ext_attr(spinbox);\n\n    char buf[LV_SPINBOX_MAX_DIGIT_COUNT + 8];\n    memset(buf, 0, sizeof(buf));\n    char * buf_p = buf;\n\n    /*Add the sign*/\n    (*buf_p) = ext->value >= 0 ? '+' : '-';\n    buf_p++;\n\n    int i;\n    /*padding left*/\n    for(i = 0; i < ext->digit_padding_left; i++) {\n        (*buf_p) = ' ';\n        buf_p++;\n    }\n\n    char digits[64];\n    /*Convert the numbers to string (the sign is already handled so always covert positive number)*/\n    lv_math_num_to_str(ext->value < 0 ? -ext->value : ext->value, digits);\n\n    /*Add leading zeros*/\n    int lz_cnt = ext->digit_count - (int)strlen(digits);\n    if(lz_cnt > 0) {\n        for(i = strlen(digits); i >= 0; i--) {\n            digits[i + lz_cnt] = digits[i];\n        }\n        for(i = 0; i < lz_cnt; i++) {\n            digits[i] = '0';\n        }\n    }\n\n    int32_t intDigits;\n    intDigits = (ext->dec_point_pos == 0) ? ext->digit_count : ext->dec_point_pos;\n\n    /*Add the decimal part*/\n    for(i = 0; i < intDigits && digits[i] != '\\0'; i++) {\n        (*buf_p) = digits[i];\n        buf_p++;\n    }\n\n    if(ext->dec_point_pos != 0) {\n        /*Insert the decimal point*/\n        (*buf_p) = '.';\n        buf_p++;\n\n        for(/*Leave i*/ ;i < ext->digit_count && digits[i] != '\\0'; i++) {\n            (*buf_p) = digits[i];\n            buf_p++;\n        }\n    }\n\n    /*Refresh the text*/\n    lv_ta_set_text(spinbox, (char*)buf);\n\n\n    /*Set the cursor position*/\n    int32_t step = ext->step;\n    uint8_t cur_pos = ext->digit_count;\n    while(step >= 10)\n    {\n        step /= 10;\n        cur_pos--;\n    }\n\n    if(cur_pos > intDigits ) cur_pos ++;   /*Skip teh decimal point*/\n\n    cur_pos += ext->digit_padding_left;\n\n    lv_ta_set_cursor_pos(spinbox, cur_pos);\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_spinbox.h",
    "content": "/**\n * @file lv_spinbox.h\n *\n */\n\n\n#ifndef LV_SPINBOX_H\n#define LV_SPINBOX_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_SPINBOX != 0\n\n/*Testing of dependencies*/\n#if USE_LV_TA == 0\n#error \"lv_spinbox: lv_ta is required. Enable it in lv_conf.h (USE_LV_TA  1) \"\n#endif\n\n#include \"../lv_core/lv_obj.h\"\n#include \"../lv_objx/lv_ta.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_SPINBOX_MAX_DIGIT_COUNT\t16\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/*callback on value change*/\ntypedef void (*lv_spinbox_value_changed_cb_t)(lv_obj_t * spinbox, int32_t new_value);\n\n/*Data of spinbox*/\ntypedef struct {\n    lv_ta_ext_t ta; /*Ext. of ancestor*/\n    /*New data for this type */\n    int32_t value;\n    int32_t range_max;\n    int32_t range_min;\n    int32_t step;\n    uint16_t digit_count:4;\n    uint16_t dec_point_pos:4;      /*if 0, there is no separator and the number is an integer*/\n    uint16_t digit_padding_left:4;\n    lv_spinbox_value_changed_cb_t value_changed_cb;\n} lv_spinbox_ext_t;\n\n\n/*Styles*/\nenum {\n    LV_SPINBOX_STYLE_BG,\n    LV_SPINBOX_STYLE_SB,\n    LV_SPINBOX_STYLE_CURSOR,\n};\ntypedef uint8_t lv_spinbox_style_t;\n\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a spinbox objects\n * @param par pointer to an object, it will be the parent of the new spinbox\n * @param copy pointer to a spinbox object, if not NULL then the new object will be copied from it\n * @return pointer to the created spinbox\n */\nlv_obj_t * lv_spinbox_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a style of a spinbox.\n * @param templ pointer to template object\n * @param type which style should be set\n * @param style pointer to a style\n */\nstatic inline void lv_spinbox_set_style(lv_obj_t * spinbox, lv_spinbox_style_t type, lv_style_t *style)\n{\n    lv_ta_set_style(spinbox, type, style);\n}\n\n/**\n * Set spinbox value\n * @param spinbox pointer to spinbox\n * @param i value to be set\n */\nvoid lv_spinbox_set_value(lv_obj_t * spinbox, int32_t i);\n\n/**\n * Set spinbox digit format (digit count and decimal format)\n * @param spinbox pointer to spinbox\n * @param digit_count number of digit excluding the decimal separator and the sign\n * @param separator_position number of digit before the decimal point. If 0, decimal point is not shown\n */\nvoid lv_spinbox_set_digit_format(lv_obj_t * spinbox, uint8_t digit_count, uint8_t separator_position);\n\n/**\n * Set spinbox step\n * @param spinbox pointer to spinbox\n * @param step steps on increment/decrement\n */\nvoid lv_spinbox_set_step(lv_obj_t * spinbox, uint32_t step);\n\n/**\n * Set spinbox value range\n * @param spinbox pointer to spinbox\n * @param range_min maximum value, inclusive\n * @param range_max minimum value, inclusive\n */\nvoid lv_spinbox_set_range(lv_obj_t * spinbox, int32_t range_min, int32_t range_max);\n\n/**\n * Set spinbox callback on calue change\n * @param spinbox pointer to spinbox\n * @param cb Callback function called on value change event\n */\nvoid lv_spinbox_set_value_changed_cb(lv_obj_t * spinbox, lv_spinbox_value_changed_cb_t cb);\n\n/**\n * Set spinbox left padding in digits count (added between sign and first digit)\n * @param spinbox pointer to spinbox\n * @param cb Callback function called on value change event\n */\nvoid lv_spinbox_set_padding_left(lv_obj_t * spinbox, uint8_t padding);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get style of a spinbox.\n * @param templ pointer to template object\n * @param type which style should be get\n * @return style pointer to the style\n */\nstatic inline lv_style_t * lv_spinbox_get_style(lv_obj_t * spinbox, lv_spinbox_style_t type)\n{\n    return lv_ta_get_style(spinbox, type);\n}\n\n/**\n * Get the spinbox numeral value (user has to convert to float according to its digit format)\n * @param spinbox pointer to spinbox\n * @return value integer value of the spinbox\n */\nint32_t lv_spinbox_get_value(lv_obj_t * spinbox);\n\n/*=====================\n * Other functions\n *====================*/\n\n/**\n * Select next lower digit for edition by dividing the step by 10\n * @param spinbox pointer to spinbox\n */\nvoid lv_spinbox_step_next(lv_obj_t * spinbox);\n\n/**\n * Select next higher digit for edition by multiplying the step by 10\n * @param spinbox pointer to spinbox\n */\nvoid lv_spinbox_step_previous(lv_obj_t * spinbox);\n\n/**\n * Increment spinbox value by one step\n * @param spinbox pointer to spinbox\n */\nvoid lv_spinbox_increment(lv_obj_t * spinbox);\n\n/**\n * Decrement spinbox value by one step\n * @param spinbox pointer to spinbox\n */\nvoid lv_spinbox_decrement(lv_obj_t * spinbox);\n\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_SPINBOX*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_SPINBOX_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_sw.c",
    "content": "/**\n * @file lv_sw.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_sw.h\"\n\n#if USE_LV_SW != 0\n\n/*Testing of dependencies*/\n#if USE_LV_SLIDER == 0\n#error \"lv_sw: lv_slider is required. Enable it in lv_conf.h (USE_LV_SLIDER  1) \"\n#endif\n\n#include \"../lv_themes/lv_theme.h\"\n#include \"../lv_misc/lv_math.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic lv_res_t lv_sw_signal(lv_obj_t * sw, lv_signal_t sign, void * param);\nstatic void lv_sw_anim_to_value(lv_obj_t * sw, int16_t value);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a switch objects\n * @param par pointer to an object, it will be the parent of the new switch\n * @param copy pointer to a switch object, if not NULL then the new object will be copied from it\n * @return pointer to the created switch\n */\nlv_obj_t * lv_sw_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"switch create started\");\n\n    /*Create the ancestor of switch*/\n    lv_obj_t * new_sw = lv_slider_create(par, copy);\n    lv_mem_assert(new_sw);\n    if(new_sw == NULL) return NULL;\n\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_sw);\n\n    /*Allocate the switch type specific extended data*/\n    lv_sw_ext_t * ext = lv_obj_allocate_ext_attr(new_sw, sizeof(lv_sw_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    /*Initialize the allocated 'ext' */\n    ext->changed = 0;\n#if USE_LV_ANIMATION\n    ext->anim_time = 0;\n#endif\n    ext->style_knob_off = ext->slider.style_knob;\n    ext->style_knob_on = ext->slider.style_knob;\n\n    /*The signal and design functions are not copied so set them here*/\n    lv_obj_set_signal_func(new_sw, lv_sw_signal);\n\n    /*Init the new switch switch*/\n    if(copy == NULL) {\n        lv_slider_set_range(new_sw, 0, 1);\n        lv_obj_set_size(new_sw, 2 * LV_DPI / 3, LV_DPI / 3);\n        lv_slider_set_knob_in(new_sw, true);\n        lv_slider_set_range(new_sw, 0, LV_SWITCH_SLIDER_ANIM_MAX);\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_sw_set_style(new_sw, LV_SW_STYLE_BG, th->sw.bg);\n            lv_sw_set_style(new_sw, LV_SW_STYLE_INDIC, th->sw.indic);\n            lv_sw_set_style(new_sw, LV_SW_STYLE_KNOB_OFF, th->sw.knob_off);\n            lv_sw_set_style(new_sw, LV_SW_STYLE_KNOB_ON, th->sw.knob_on);\n        } else {\n            /*Let the slider' style*/\n        }\n\n    }\n    /*Copy an existing switch*/\n    else {\n        lv_sw_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        ext->style_knob_off = copy_ext->style_knob_off;\n        ext->style_knob_on = copy_ext->style_knob_on;\n#if USE_LV_ANIMATION\n        ext->anim_time = copy_ext->anim_time;\n#endif\n\n        if(lv_sw_get_state(new_sw)) lv_slider_set_style(new_sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on);\n        else lv_slider_set_style(new_sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off);\n\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_sw);\n    }\n\n    LV_LOG_INFO(\"switch created\");\n\n    return new_sw;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Turn ON the switch\n * @param sw pointer to a switch object\n */\nvoid lv_sw_on(lv_obj_t * sw)\n{\n    lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw);\n    lv_slider_set_value(sw, LV_SWITCH_SLIDER_ANIM_MAX);\n\n    lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on);\n}\n\n/**\n * Turn OFF the switch\n * @param sw pointer to a switch object\n */\nvoid lv_sw_off(lv_obj_t * sw)\n{\n    lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw);\n    lv_slider_set_value(sw, 0);\n\n    lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off);\n}\n\n/**\n * Toggle the position of the switch\n * @param sw pointer to a switch object\n * @return resulting state of the switch.\n */\nbool lv_sw_toggle(lv_obj_t *sw) {\n    bool state = lv_sw_get_state(sw);\n    if(state) {\n        lv_sw_off(sw);\n    }\n    else {\n        lv_sw_on(sw);\n    }\n    return !state;\n}\n\n/**\n * Turn ON the switch with an animation\n * @param sw pointer to a switch object\n */\nvoid lv_sw_on_anim(lv_obj_t * sw)\n{\n    lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw);\n    if(lv_sw_get_anim_time(sw) > 0)lv_sw_anim_to_value(sw, LV_SWITCH_SLIDER_ANIM_MAX);\n    else lv_slider_set_value(sw, LV_SWITCH_SLIDER_ANIM_MAX);\n\n    lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on);\n}\n\n/**\n * Turn OFF the switch with an animation\n * @param sw pointer to a switch object\n */\nvoid lv_sw_off_anim(lv_obj_t * sw)\n{\n    lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw);\n    if(lv_sw_get_anim_time(sw) > 0)  lv_sw_anim_to_value(sw, 0);\n    else lv_slider_set_value(sw, 0);\n\n    lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off);\n}\n\n/**\n * Toggle the position of the switch with an animation\n * @param sw pointer to a switch object\n * @return resulting state of the switch.\n */\nbool lv_sw_toggle_anim(lv_obj_t *sw) {\n    bool state = lv_sw_get_state(sw);\n    if(state) {\n        lv_sw_off_anim(sw);\n    }\n    else {\n        lv_sw_on_anim(sw);\n    }\n    return !state;\n}\n\n/**\n * Set a style of a switch\n * @param sw pointer to a switch object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_sw_set_style(lv_obj_t * sw, lv_sw_style_t type, lv_style_t * style)\n{\n    lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw);\n\n    switch(type) {\n        case LV_SLIDER_STYLE_BG:\n            lv_slider_set_style(sw, LV_SLIDER_STYLE_BG, style);\n            break;\n        case LV_SLIDER_STYLE_INDIC:\n            lv_bar_set_style(sw, LV_SLIDER_STYLE_INDIC, style);\n            break;\n        case LV_SW_STYLE_KNOB_OFF:\n            ext->style_knob_off = style;\n            if(lv_sw_get_state(sw) == 0) lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, style);\n            break;\n        case LV_SW_STYLE_KNOB_ON:\n            ext->style_knob_on = style;\n            if(lv_sw_get_state(sw) != 0) lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, style);\n            break;\n    }\n}\n\nvoid lv_sw_set_anim_time(lv_obj_t *sw, uint16_t anim_time)\n{\n#if USE_LV_ANIMATION\n    lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw);\n    ext->anim_time = anim_time;\n#endif\n}\n\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get a style of a switch\n * @param sw pointer to a  switch object\n * @param type which style should be get\n * @return style pointer to a style\n */\nlv_style_t * lv_sw_get_style(const lv_obj_t * sw, lv_sw_style_t type)\n{\n    lv_style_t * style = NULL;\n    lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw);\n\n    switch(type) {\n        case LV_SW_STYLE_BG:\n            style = lv_slider_get_style(sw, LV_SLIDER_STYLE_BG);\n            break;\n        case LV_SW_STYLE_INDIC:\n            style = lv_slider_get_style(sw, LV_SLIDER_STYLE_INDIC);\n            break;\n        case LV_SW_STYLE_KNOB_OFF:\n            style = ext->style_knob_off;\n            break;\n        case LV_SW_STYLE_KNOB_ON:\n            style = ext->style_knob_on;\n            break;\n        default:\n            style = NULL;\n            break;\n    }\n\n    return style;\n}\n\nuint16_t lv_sw_get_anim_time(const lv_obj_t *sw)\n{\n\n#if USE_LV_ANIMATION\n\tlv_sw_ext_t * ext = lv_obj_get_ext_attr(sw);\n\treturn ext->anim_time;\n#else\n\treturn 0;\n#endif\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Signal function of the switch\n * @param sw pointer to a switch object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_sw_signal(lv_obj_t * sw, lv_signal_t sign, void * param)\n{\n    lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw);\n\n    /*Save the current (old) value before slider signal modifies it*/\n    int16_t old_val;\n\n    if(sign == LV_SIGNAL_PRESSING) old_val = ext->slider.drag_value;\n    else old_val = lv_slider_get_value(sw);\n\n    /*Do not let the slider to call the callback. The Switch will do it if required*/\n    lv_action_t slider_action = ext->slider.action;\n    ext->slider.action = NULL;\n\n    lv_res_t res;\n    /* Include the ancient signal function */\n    res = ancestor_signal(sw, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    if(sign == LV_SIGNAL_CLEANUP) {\n        /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/\n    }\n    else if(sign == LV_SIGNAL_PRESSED) {\n\n        /*Save the x coordinate of the pressed point to see if the switch was slid*/\n        lv_indev_t * indev = lv_indev_get_act();\n        if(indev) {\n            lv_point_t p;\n            lv_indev_get_point(indev,  &p);\n            ext->start_x = p.x;\n        }\n        ext->slided = 0;\n        ext->changed = 0;\n    }\n    else if(sign == LV_SIGNAL_PRESSING) {\n        /*See if the switch was slid*/\n        lv_indev_t * indev = lv_indev_get_act();\n        if(indev) {\n            lv_point_t p = {0,0};\n            lv_indev_get_point(indev,  &p);\n            if(LV_MATH_ABS(p.x - ext->start_x) > LV_INDEV_DRAG_LIMIT) ext->slided = 1;\n        }\n\n        /*If didn't slide then revert the min/max value. So click without slide won't move the switch as a slider*/\n        if(ext->slided == 0) {\n            if(lv_sw_get_state(sw)) ext->slider.drag_value = LV_SWITCH_SLIDER_ANIM_MAX;\n            else ext->slider.drag_value = 0;\n        }\n\n        /*If explicitly changed (by slide) don't need to be toggled on release*/\n        int16_t threshold  = LV_SWITCH_SLIDER_ANIM_MAX / 2;\n        if((old_val < threshold && ext->slider.drag_value > threshold) ||\n                (old_val > threshold && ext->slider.drag_value < threshold))\n        {\n            ext->changed = 1;\n        }\n    }\n    else if(sign == LV_SIGNAL_PRESS_LOST) {\n        if(lv_sw_get_state(sw)) {\n            lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on);\n#if USE_LV_ANIMATION\n            lv_sw_anim_to_value(sw, LV_SWITCH_SLIDER_ANIM_MAX);\n#endif\n        }\n        else {\n            lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off);\n#if USE_LV_ANIMATION\n            lv_sw_anim_to_value(sw, 0);\n#endif\n        }\n    }\n    else if(sign == LV_SIGNAL_RELEASED) {\n        /*If not dragged then toggle the switch*/\n        if(ext->changed == 0) {\n            if(lv_sw_get_state(sw)) lv_sw_off_anim(sw);\n            else lv_sw_on_anim(sw);\n\n            if(slider_action != NULL) res = slider_action(sw);\n        }\n        /*If the switch was dragged then calculate the new state based on the current position*/\n        else {\n            int16_t v = lv_slider_get_value(sw);\n            if(v > LV_SWITCH_SLIDER_ANIM_MAX / 2) lv_sw_on_anim(sw);\n            else lv_sw_off_anim(sw);\n\n            if(slider_action != NULL) res = slider_action(sw);\n        }\n\n    } else if(sign == LV_SIGNAL_CONTROLL) {\n\n        char c = *((char *)param);\n        if(c == LV_GROUP_KEY_ENTER) {\n            if(old_val) lv_sw_off_anim(sw);\n            else lv_sw_on_anim(sw);\n\n            if(slider_action) res = slider_action(sw);\n        } else if(c == LV_GROUP_KEY_UP || c == LV_GROUP_KEY_RIGHT) {\n            lv_sw_on_anim(sw);\n            if(slider_action) res = slider_action(sw);\n        } else if(c == LV_GROUP_KEY_DOWN || c == LV_GROUP_KEY_LEFT) {\n            lv_sw_off_anim(sw);\n            if(slider_action) res = slider_action(sw);\n        }\n    } else if(sign == LV_SIGNAL_GET_EDITABLE) {\n        bool * editable = (bool *)param;\n        *editable = false;          /*The ancestor slider is editable the switch is not*/\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_sw\";\n    }\n\n    /*Restore the callback*/\n    if(res == LV_RES_OK) ext->slider.action = slider_action;\n\n    return res;\n}\n\nstatic void lv_sw_anim_to_value(lv_obj_t * sw, int16_t value)\n{\n#if USE_LV_ANIMATION\n    lv_anim_t a;\n    lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw);\n    a.var = sw;\n    a.start = ext->slider.bar.cur_value;\n    a.end = value;\n    a.fp = (lv_anim_fp_t)lv_slider_set_value;\n    a.path = lv_anim_path_linear;\n    a.end_cb = NULL;\n    a.act_time = 0;\n    a.time = lv_sw_get_anim_time(sw);\n    a.playback = 0;\n    a.playback_pause = 0;\n    a.repeat = 0;\n    a.repeat_pause = 0;\n    lv_anim_create(&a);\n#endif\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_sw.h",
    "content": "/**\n * @file lv_sw.h\n *\n */\n\n#ifndef LV_SW_H\n#define LV_SW_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_SW != 0\n\n/*Testing of dependencies*/\n#if USE_LV_SLIDER == 0\n#error \"lv_sw: lv_slider is required. Enable it in lv_conf.h (USE_LV_SLIDER  1)\"\n#endif\n\n#include \"../lv_core/lv_obj.h\"\n#include \"lv_slider.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_SWITCH_SLIDER_ANIM_MAX 1000\n\n/**********************\n *      TYPEDEFS\n **********************/\n/*Data of switch*/\ntypedef struct\n{\n    lv_slider_ext_t slider;         /*Ext. of ancestor*/\n    /*New data for this type */\n    lv_style_t *style_knob_off;     /*Style of the knob when the switch is OFF*/\n    lv_style_t *style_knob_on;      /*Style of the knob when the switch is ON (NULL to use the same as OFF)*/\n    lv_coord_t start_x;\n    uint8_t changed   :1;           /*Indicates the switch state explicitly changed by drag*/\n    uint8_t slided  :1;\n#if USE_LV_ANIMATION\n    uint16_t anim_time;\t\t\t\t/*switch animation time */\n#endif\n} lv_sw_ext_t;\n\nenum {\n    LV_SW_STYLE_BG,\n    LV_SW_STYLE_INDIC,\n    LV_SW_STYLE_KNOB_OFF,\n    LV_SW_STYLE_KNOB_ON,\n};\ntypedef uint8_t lv_sw_style_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a switch objects\n * @param par pointer to an object, it will be the parent of the new switch\n * @param copy pointer to a switch object, if not NULL then the new object will be copied from it\n * @return pointer to the created switch\n */\nlv_obj_t * lv_sw_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Turn ON the switch\n * @param sw pointer to a switch object\n */\nvoid lv_sw_on(lv_obj_t *sw);\n\n/**\n * Turn OFF the switch\n * @param sw pointer to a switch object\n */\nvoid lv_sw_off(lv_obj_t *sw);\n\n/**\n * Toggle the position of the switch\n * @param sw pointer to a switch object\n * @return resulting state of the switch.\n */\nbool lv_sw_toggle(lv_obj_t *sw);\n\n/**\n * Turn ON the switch with an animation\n * @param sw pointer to a switch object\n */\nvoid lv_sw_on_anim(lv_obj_t * sw);\n\n/**\n * Turn OFF the switch with an animation\n * @param sw pointer to a switch object\n */\nvoid lv_sw_off_anim(lv_obj_t * sw);\n\n/**\n * Toggle the position of the switch with an animation\n * @param sw pointer to a switch object\n * @return resulting state of the switch.\n */\nbool lv_sw_toggle_anim(lv_obj_t *sw);\n\n/**\n * Set a function which will be called when the switch is toggled by the user\n * @param sw pointer to switch object\n * @param action a callback function\n */\nstatic inline void lv_sw_set_action(lv_obj_t * sw, lv_action_t action)\n{\n    lv_slider_set_action(sw, action);\n}\n\n/**\n * Set a style of a switch\n * @param sw pointer to a switch object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_sw_set_style(lv_obj_t *sw, lv_sw_style_t type, lv_style_t *style);\n\n#if USE_LV_ANIMATION\n/**\n * Set the animation time of the switch\n * @param sw pointer to a  switch object\n * @param anim_time animation time\n * @return style pointer to a style\n */\nvoid lv_sw_set_anim_time(lv_obj_t *sw, uint16_t anim_time);\n#endif\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the state of a switch\n * @param sw pointer to a switch object\n * @return false: OFF; true: ON\n */\nstatic inline bool lv_sw_get_state(const lv_obj_t *sw)\n{\n    return lv_bar_get_value(sw) < LV_SWITCH_SLIDER_ANIM_MAX / 2 ? false : true;\n}\n\n/**\n * Get the switch action function\n * @param slider pointer to a switch object\n * @return the callback function\n */\nstatic inline lv_action_t lv_sw_get_action(const lv_obj_t * slider)\n{\n    return lv_slider_get_action(slider);\n}\n\n/**\n * Get a style of a switch\n * @param sw pointer to a  switch object\n * @param type which style should be get\n * @return style pointer to a style\n */\nlv_style_t * lv_sw_get_style(const lv_obj_t *sw, lv_sw_style_t type);\n\n/**\n * Get the animation time of the switch\n * @param sw pointer to a  switch object\n * @return style pointer to a style\n */\nuint16_t lv_sw_get_anim_time(const lv_obj_t *sw);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_SW*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_SW_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_ta.c",
    "content": "/**\n * @file lv_ta.c\n *\n */\n\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_ta.h\"\n#if USE_LV_TA != 0\n\n#include \"../lv_core/lv_group.h\"\n#include \"../lv_core/lv_refr.h\"\n#include \"../lv_draw/lv_draw.h\"\n#include \"../lv_themes/lv_theme.h\"\n#include \"../lv_misc/lv_anim.h\"\n#include \"../lv_misc/lv_txt.h\"\n#include \"../lv_misc/lv_math.h\"\n\n/*********************\n *      DEFINES\n *********************/\n/*Test configuration*/\n\n#ifndef LV_TA_CURSOR_BLINK_TIME\n#define LV_TA_CURSOR_BLINK_TIME 400    /*ms*/\n#endif\n\n#ifndef LV_TA_PWD_SHOW_TIME\n#define LV_TA_PWD_SHOW_TIME 1500    /*ms*/\n#endif\n\n#define LV_TA_DEF_WIDTH     (2 * LV_DPI)\n#define LV_TA_DEF_HEIGHT    (1 * LV_DPI)\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool lv_ta_design(lv_obj_t * ta, const lv_area_t * mask, lv_design_mode_t mode);\nstatic bool lv_ta_scrollable_design(lv_obj_t * scrl, const lv_area_t * mask, lv_design_mode_t mode);\nstatic lv_res_t lv_ta_signal(lv_obj_t * ta, lv_signal_t sign, void * param);\nstatic lv_res_t lv_ta_scrollable_signal(lv_obj_t * scrl, lv_signal_t sign, void * param);\n#if USE_LV_ANIMATION\nstatic void cursor_blink_anim(lv_obj_t * ta, uint8_t show);\nstatic void pwd_char_hider_anim(lv_obj_t * ta, int32_t x);\n#endif\nstatic void pwd_char_hider(lv_obj_t * ta);\nstatic bool char_is_accepted(lv_obj_t * ta, uint32_t c);\nstatic void get_cursor_style(lv_obj_t * ta, lv_style_t * style_res);\nstatic void refr_cursor_area(lv_obj_t * ta);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_design_func_t ancestor_design;\nstatic lv_design_func_t scrl_design;\nstatic lv_signal_func_t ancestor_signal;\nstatic lv_signal_func_t scrl_signal;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a text area objects\n * @param par pointer to an object, it will be the parent of the new text area\n * @param copy pointer to a text area object, if not NULL then the new object will be copied from it\n * @return pointer to the created text area\n */\nlv_obj_t * lv_ta_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"text area create started\");\n\n    /*Create the ancestor object*/\n    lv_obj_t * new_ta = lv_page_create(par, copy);\n    lv_mem_assert(new_ta);\n    if(new_ta == NULL) return NULL;\n\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_ta);\n    if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_ta);\n    if(scrl_signal == NULL) scrl_signal = lv_obj_get_signal_func(lv_page_get_scrl(new_ta));\n    if(scrl_design == NULL) scrl_design = lv_obj_get_design_func(lv_page_get_scrl(new_ta));\n\n    /*Allocate the object type specific extended data*/\n    lv_ta_ext_t * ext = lv_obj_allocate_ext_attr(new_ta, sizeof(lv_ta_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    ext->cursor.state = 1;\n    ext->pwd_mode = 0;\n    ext->pwd_tmp = NULL;\n    ext->accapted_chars = NULL;\n    ext->max_length = 0;\n    ext->cursor.style = NULL;\n    ext->cursor.pos = 0;\n    ext->cursor.type = LV_CURSOR_LINE;\n    ext->cursor.valid_x = 0;\n    ext->one_line = 0;\n    ext->label = NULL;\n\n    lv_obj_set_signal_func(new_ta, lv_ta_signal);\n    lv_obj_set_signal_func(lv_page_get_scrl(new_ta), lv_ta_scrollable_signal);\n    lv_obj_set_design_func(new_ta, lv_ta_design);\n\n    /*Init the new text area object*/\n    if(copy == NULL) {\n        ext->label = lv_label_create(new_ta, NULL);\n\n        lv_obj_set_design_func(ext->page.scrl, lv_ta_scrollable_design);\n\n        lv_label_set_long_mode(ext->label, LV_LABEL_LONG_BREAK);\n        lv_label_set_text(ext->label, \"Text area\");\n        lv_obj_set_click(ext->label, false);\n        lv_obj_set_size(new_ta, LV_TA_DEF_WIDTH, LV_TA_DEF_HEIGHT);\n        lv_ta_set_sb_mode(new_ta, LV_SB_MODE_DRAG);\n        lv_page_set_style(new_ta, LV_PAGE_STYLE_SCRL, &lv_style_transp_tight);\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_ta_set_style(new_ta, LV_TA_STYLE_BG, th->ta.area);\n            lv_ta_set_style(new_ta, LV_TA_STYLE_SB, th->ta.sb);\n        } else {\n            lv_ta_set_style(new_ta, LV_TA_STYLE_BG, &lv_style_pretty);\n        }\n    }\n    /*Copy an existing object*/\n    else {\n        lv_obj_set_design_func(ext->page.scrl, lv_ta_scrollable_design);\n        lv_ta_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        ext->label = lv_label_create(new_ta, copy_ext->label);\n        ext->pwd_mode = copy_ext->pwd_mode;\n        ext->accapted_chars = copy_ext->accapted_chars;\n        ext->max_length = copy_ext->max_length;\n        ext->cursor.style = copy_ext->cursor.style;\n        ext->cursor.pos = copy_ext->cursor.pos;\n        ext->cursor.valid_x = copy_ext->cursor.valid_x;\n        ext->cursor.type = copy_ext->cursor.type;\n        if(copy_ext->one_line) lv_ta_set_one_line(new_ta, true);\n\n        lv_ta_set_style(new_ta, LV_TA_STYLE_CURSOR, lv_ta_get_style(copy, LV_TA_STYLE_CURSOR));\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_ta);\n    }\n\n#if USE_LV_ANIMATION\n    /*Create a cursor blinker animation*/\n    lv_anim_t a;\n    a.var = new_ta;\n    a.fp = (lv_anim_fp_t)cursor_blink_anim;\n    a.time = LV_TA_CURSOR_BLINK_TIME;\n    a.act_time = 0;\n    a.end_cb = NULL;\n    a.start = 1;\n    a.end = 0;\n    a.repeat = 1;\n    a.repeat_pause = 0;\n    a.playback = 1;\n    a.playback_pause = 0;\n    a.path = lv_anim_path_step;\n    lv_anim_create(&a);\n#endif\n\n    LV_LOG_INFO(\"text area created\");\n\n    return new_ta;\n}\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n/**\n * Insert a character to the current cursor position.\n * To add a wide char, e.g. 'Á' use `lv_txt_encoded_conv_wc('Á')`\n * @param ta pointer to a text area object\n * @param c a character (e.g. 'a')\n */\nvoid lv_ta_add_char(lv_obj_t * ta, uint32_t c)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n\n    if(ext->one_line && (c == '\\n' || c == '\\r')) {\n        LV_LOG_INFO(\"Text area: line break ignored in one-line mode\");\n        return;\n    }\n\n    uint32_t c_uni = lv_txt_encoded_next((const char *)&c, NULL);\n\n    if(char_is_accepted(ta, c_uni) == false) {\n        LV_LOG_INFO(\"Character is no accepted by the text area (too long text or not in the accepted list)\");\n        return;\n    }\n\n    /*Disable edge flash. If a new line was added it could show edge flash effect*/\n    bool edge_flash_en = lv_ta_get_edge_flash(ta);\n    lv_ta_set_edge_flash(ta, false);\n\n    if(ext->pwd_mode != 0) pwd_char_hider(ta);  /*Make sure all the current text contains only '*'*/\n    uint32_t letter_buf[2];\n    letter_buf[0] = c;\n    letter_buf[1] = '\\0';\n\n    lv_label_ins_text(ext->label, ext->cursor.pos, (const char *)letter_buf);    /*Insert the character*/\n\n    if(ext->pwd_mode != 0) {\n\n        ext->pwd_tmp = lv_mem_realloc(ext->pwd_tmp, strlen(ext->pwd_tmp) + 2);  /*+2: the new char + \\0 */\n        lv_mem_assert(ext->pwd_tmp);\n        if(ext->pwd_tmp == NULL) return;\n\n        lv_txt_ins(ext->pwd_tmp, ext->cursor.pos, (const char *)letter_buf);\n\n#if USE_LV_ANIMATION && LV_TA_PWD_SHOW_TIME > 0\n        /*Auto hide characters*/\n        lv_anim_t a;\n        a.var = ta;\n        a.fp = (lv_anim_fp_t)pwd_char_hider_anim;\n        a.time = LV_TA_PWD_SHOW_TIME;\n        a.act_time = 0;\n        a.end_cb = (lv_anim_cb_t)pwd_char_hider;\n        a.start = 0;\n        a.end = 1;\n        a.repeat = 0;\n        a.repeat_pause = 0;\n        a.playback = 0;\n        a.playback_pause = 0;\n        a.path = lv_anim_path_step;\n        lv_anim_create(&a);\n#else\n        pwd_char_hider(ta);\n#endif\n    }\n\n    /*Move the cursor after the new character*/\n    lv_ta_set_cursor_pos(ta, lv_ta_get_cursor_pos(ta) + 1);\n\n    /*Revert the original edge flash state*/\n    lv_ta_set_edge_flash(ta, edge_flash_en);\n}\n\n/**\n * Insert a text to the current cursor position\n * @param ta pointer to a text area object\n * @param txt a '\\0' terminated string to insert\n */\nvoid lv_ta_add_text(lv_obj_t * ta, const char * txt)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n\n    if(ext->pwd_mode != 0) pwd_char_hider(ta);  /*Make sure all the current text contains only '*'*/\n\n    /*Add the character one-by-one if not all characters are accepted or there is character limit.*/\n    if(lv_ta_get_accepted_chars(ta) || lv_ta_get_max_length(ta)) {\n        uint32_t i = 0;\n        while(txt[i] != '\\0') {\n            uint32_t c = lv_txt_encoded_next(txt, &i);\n            lv_ta_add_char(ta, lv_txt_unicode_to_encoded(c));\n        }\n        return;\n    }\n\n    /*Disable edge flash. If a new line was added it could show edge flash effect*/\n    bool edge_flash_en = lv_ta_get_edge_flash(ta);\n    lv_ta_set_edge_flash(ta, false);\n\n    /*Insert the text*/\n    lv_label_ins_text(ext->label, ext->cursor.pos, txt);\n\n    if(ext->pwd_mode != 0) {\n        ext->pwd_tmp = lv_mem_realloc(ext->pwd_tmp, strlen(ext->pwd_tmp) + strlen(txt) + 1);\n        lv_mem_assert(ext->pwd_tmp);\n        if(ext->pwd_tmp == NULL) return;\n\n        lv_txt_ins(ext->pwd_tmp, ext->cursor.pos, txt);\n\n#if USE_LV_ANIMATION && LV_TA_PWD_SHOW_TIME > 0\n        /*Auto hide characters*/\n        lv_anim_t a;\n        a.var = ta;\n        a.fp = (lv_anim_fp_t)pwd_char_hider_anim;\n        a.time = LV_TA_PWD_SHOW_TIME;\n        a.act_time = 0;\n        a.end_cb = (lv_anim_cb_t)pwd_char_hider;\n        a.start = 0;\n        a.end = 1;\n        a.repeat = 0;\n        a.repeat_pause = 0;\n        a.playback = 0;\n        a.playback_pause = 0;\n        a.path = lv_anim_path_step;\n        lv_anim_create(&a);\n#else\n        pwd_char_hider(ta);\n#endif\n    }\n\n    /*Move the cursor after the new text*/\n    lv_ta_set_cursor_pos(ta, lv_ta_get_cursor_pos(ta) + lv_txt_get_encoded_length(txt));\n\n    /*Revert the original edge flash state*/\n    lv_ta_set_edge_flash(ta, edge_flash_en);\n}\n\n/**\n * Delete a the left character from the current cursor position\n * @param ta pointer to a text area object\n */\nvoid lv_ta_del_char(lv_obj_t * ta)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n    uint16_t cur_pos = ext->cursor.pos;\n\n    if(cur_pos == 0) return;\n\n    char * label_txt = lv_label_get_text(ext->label);\n    /*Delete a character*/\n    lv_txt_cut(label_txt, ext->cursor.pos - 1, 1);\n    /*Refresh the label*/\n    lv_label_set_text(ext->label, label_txt);\n\n    /*Don't let 'width == 0' because cursor will not be visible*/\n    if(lv_obj_get_width(ext->label) == 0) {\n        lv_style_t * style = lv_obj_get_style(ext->label);\n        lv_obj_set_width(ext->label, style->line.width);\n    }\n\n    if(ext->pwd_mode != 0) {\n#if LV_TXT_UTF8 == 0\n        lv_txt_cut(ext->pwd_tmp, ext->cursor.pos - 1, 1);\n#else\n        uint32_t byte_pos = lv_txt_encoded_get_byte_id(ext->pwd_tmp, ext->cursor.pos - 1);\n        lv_txt_cut(ext->pwd_tmp, ext->cursor.pos - 1, lv_txt_encoded_size(&label_txt[byte_pos]));\n#endif\n        ext->pwd_tmp = lv_mem_realloc(ext->pwd_tmp, strlen(ext->pwd_tmp) + 1);\n        lv_mem_assert(ext->pwd_tmp);\n        if(ext->pwd_tmp == NULL) return;\n    }\n\n    /*Move the cursor to the place of the deleted character*/\n    lv_ta_set_cursor_pos(ta, ext->cursor.pos - 1);\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set the text of a text area\n * @param ta pointer to a text area\n * @param txt pointer to the text\n */\nvoid lv_ta_set_text(lv_obj_t * ta, const char * txt)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n\n    /*Add the character one-by-one if not all characters are accepted or there is character limit.*/\n    if(lv_ta_get_accepted_chars(ta) || lv_ta_get_max_length(ta)) {\n        lv_label_set_text(ext->label, \"\");\n        lv_ta_set_cursor_pos(ta, LV_TA_CURSOR_LAST);\n\n        uint32_t i = 0;\n        while(txt[i] != '\\0') {\n            uint32_t c = lv_txt_encoded_next(txt, &i);\n            lv_ta_add_char(ta, lv_txt_unicode_to_encoded(c));\n        }\n    } else {\n        lv_label_set_text(ext->label, txt);\n        lv_ta_set_cursor_pos(ta, LV_TA_CURSOR_LAST);\n    }\n\n    /*Don't let 'width == 0' because the cursor will not be visible*/\n    if(lv_obj_get_width(ext->label) == 0) {\n        lv_style_t * style = lv_obj_get_style(ext->label);\n        lv_obj_set_width(ext->label, lv_font_get_width(style->text.font, ' '));\n    }\n\n    if(ext->pwd_mode != 0) {\n        ext->pwd_tmp = lv_mem_realloc(ext->pwd_tmp, strlen(txt) + 1);\n        lv_mem_assert(ext->pwd_tmp);\n        if(ext->pwd_tmp == NULL) return;\n        strcpy(ext->pwd_tmp, txt);\n\n#if USE_LV_ANIMATION && LV_TA_PWD_SHOW_TIME > 0\n        /*Auto hide characters*/\n        lv_anim_t a;\n        a.var = ta;\n        a.fp = (lv_anim_fp_t)pwd_char_hider_anim;\n        a.time = LV_TA_PWD_SHOW_TIME;\n        a.act_time = 0;\n        a.end_cb = (lv_anim_cb_t)pwd_char_hider;\n        a.start = 0;\n        a.end = 1;\n        a.repeat = 0;\n        a.repeat_pause = 0;\n        a.playback = 0;\n        a.playback_pause = 0;\n        a.path = lv_anim_path_step;\n        lv_anim_create(&a);\n#else\n        pwd_char_hider(ta);\n#endif\n    }\n}\n\n/**\n * Set the cursor position\n * @param obj pointer to a text area object\n * @param pos the new cursor position in character index\n *             < 0 : index from the end of the text\n *             LV_TA_CURSOR_LAST: go after the last character\n */\nvoid lv_ta_set_cursor_pos(lv_obj_t * ta, int16_t pos)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n    if(ext->cursor.pos == pos) return;\n\n    uint16_t len = lv_txt_get_encoded_length(lv_label_get_text(ext->label));\n\n    if(pos < 0) pos = len + pos;\n\n    if(pos > len || pos == LV_TA_CURSOR_LAST) pos = len;\n\n    ext->cursor.pos = pos;\n\n    /*Position the label to make the cursor visible*/\n    lv_obj_t * label_par = lv_obj_get_parent(ext->label);\n    lv_point_t cur_pos;\n    lv_style_t * style = lv_obj_get_style(ta);\n    const lv_font_t * font_p = style->text.font;\n    lv_area_t label_cords;\n    lv_area_t ta_cords;\n    lv_label_get_letter_pos(ext->label, pos, &cur_pos);\n    lv_obj_get_coords(ta, &ta_cords);\n    lv_obj_get_coords(ext->label, &label_cords);\n\n    /*Check the top*/\n    lv_coord_t font_h = lv_font_get_height(font_p);\n    if(lv_obj_get_y(label_par) + cur_pos.y < 0) {\n        lv_obj_set_y(label_par, - cur_pos.y + style->body.padding.ver);\n    }\n\n    /*Check the bottom*/\n    if(label_cords.y1 + cur_pos.y + font_h + style->body.padding.ver > ta_cords.y2) {\n        lv_obj_set_y(label_par, -(cur_pos.y - lv_obj_get_height(ta) +\n                                  font_h + 2 * style->body.padding.ver));\n    }\n    /*Check the left (use the font_h as general unit)*/\n    if(lv_obj_get_x(label_par) + cur_pos.x < font_h) {\n        lv_obj_set_x(label_par, - cur_pos.x + font_h);\n    }\n\n    /*Check the right (use the font_h as general unit)*/\n    if(label_cords.x1 + cur_pos.x + font_h + style->body.padding.hor > ta_cords.x2) {\n        lv_obj_set_x(label_par, -(cur_pos.x - lv_obj_get_width(ta) +\n                                  font_h + 2 * style->body.padding.hor));\n    }\n\n    ext->cursor.valid_x = cur_pos.x;\n\n#if USE_LV_ANIMATION\n    /*Reset cursor blink animation*/\n    lv_anim_t a;\n    a.var = ta;\n    a.fp = (lv_anim_fp_t)cursor_blink_anim;\n    a.time = LV_TA_CURSOR_BLINK_TIME;\n    a.act_time = 0;\n    a.end_cb = NULL;\n    a.start = 1;\n    a.end = 0;\n    a.repeat = 1;\n    a.repeat_pause = 0;\n    a.playback = 1;\n    a.playback_pause = 0;\n    a.path = lv_anim_path_step;\n    lv_anim_create(&a);\n#endif\n\n    refr_cursor_area(ta);\n}\n\n/**\n * Set the cursor type.\n * @param ta pointer to a text area object\n * @param cur_type: element of 'lv_ta_cursor_type_t'\n */\nvoid lv_ta_set_cursor_type(lv_obj_t * ta, lv_cursor_type_t cur_type)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n    if(ext->cursor.type == cur_type) return;\n\n    ext->cursor.type = cur_type;\n\n    refr_cursor_area(ta);\n}\n\n/**\n * Enable/Disable password mode\n * @param ta pointer to a text area object\n * @param en true: enable, false: disable\n */\nvoid lv_ta_set_pwd_mode(lv_obj_t * ta, bool en)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n    if(ext->pwd_mode == en) return;\n\n    /*Pwd mode is now enabled*/\n    if(ext->pwd_mode == 0 && en != false) {\n        char * txt = lv_label_get_text(ext->label);\n        uint16_t len = strlen(txt);\n        ext->pwd_tmp = lv_mem_alloc(len + 1);\n        lv_mem_assert(ext->pwd_tmp);\n        if(ext->pwd_tmp == NULL) return;\n\n        strcpy(ext->pwd_tmp, txt);\n\n        uint16_t i;\n        for(i = 0; i < len; i++) {\n            txt[i] = '*';       /*All char to '*'*/\n        }\n        txt[i] = '\\0';\n\n        lv_label_set_text(ext->label, NULL);\n    }\n    /*Pwd mode is now disabled*/\n    else if(ext->pwd_mode == 1 && en == false) {\n        lv_label_set_text(ext->label, ext->pwd_tmp);\n        lv_mem_free(ext->pwd_tmp);\n        ext->pwd_tmp = NULL;\n    }\n\n    ext->pwd_mode = en == false ? 0 : 1;\n\n    refr_cursor_area(ta);\n}\n\n/**\n * Configure the text area to one line or back to normal\n * @param ta pointer to a Text area object\n * @param en true: one line, false: normal\n */\nvoid lv_ta_set_one_line(lv_obj_t * ta, bool en)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n    if(ext->one_line == en) return;\n\n    if(en) {\n        lv_style_t * style_ta = lv_obj_get_style(ta);\n        lv_style_t * style_scrl = lv_obj_get_style(lv_page_get_scrl(ta));\n        lv_style_t * style_label = lv_obj_get_style(ext->label);\n        lv_coord_t font_h =  lv_font_get_height(style_label->text.font);\n\n        ext->one_line = 1;\n        lv_page_set_scrl_fit(ta, true, true);\n        lv_obj_set_height(ta, font_h + (style_ta->body.padding.ver + style_scrl->body.padding.ver) * 2);\n        lv_label_set_long_mode(ext->label, LV_LABEL_LONG_EXPAND);\n        lv_obj_set_pos(lv_page_get_scrl(ta), style_ta->body.padding.hor, style_ta->body.padding.ver);\n    } else {\n        lv_style_t * style_ta = lv_obj_get_style(ta);\n\n        ext->one_line = 0;\n        lv_page_set_scrl_fit(ta, false, true);\n        lv_label_set_long_mode(ext->label, LV_LABEL_LONG_BREAK);\n        lv_obj_set_height(ta, LV_TA_DEF_HEIGHT);\n        lv_obj_set_pos(lv_page_get_scrl(ta), style_ta->body.padding.hor, style_ta->body.padding.ver);\n    }\n\n    refr_cursor_area(ta);\n}\n\n/**\n * Set the alignment of the text area.\n * In one line mode the text can be scrolled only with `LV_LABEL_ALIGN_LEFT`.\n * This function should be called if the size of text area changes.\n * @param ta pointer to a text are object\n * @param align the desired alignment from `lv_label_align_t`. (LV_LABEL_ALIGN_LEFT/CENTER/RIGHT)\n */\nvoid lv_ta_set_text_align(lv_obj_t * ta, lv_label_align_t align)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n    lv_obj_t * label = lv_ta_get_label(ta);\n    if(!ext->one_line) {\n        lv_label_set_align(label, align);\n    } else {\n        /*Normal left align. Just let the text expand*/\n        if(align == LV_LABEL_ALIGN_LEFT) {\n            lv_label_set_long_mode(label, LV_LABEL_LONG_EXPAND);\n            lv_page_set_scrl_fit(ta, true, false);\n            lv_label_set_align(label, align);\n\n        }\n        /*Else use fix label width equal to the Text area width*/\n        else {\n            lv_label_set_long_mode(label, LV_LABEL_LONG_CROP);\n            lv_page_set_scrl_fit(ta, false, false);\n            lv_page_set_scrl_width(ta, 1);      /*To refresh the scrollable's width*/\n            lv_label_set_align(label, align);\n\n            lv_style_t * bg_style = lv_ta_get_style(ta, LV_TA_STYLE_BG);\n            lv_obj_set_width(label, lv_obj_get_width(ta) - 2 * bg_style->body.padding.hor);\n        }\n    }\n\n    refr_cursor_area(ta);\n}\n\n/**\n * Set a list of characters. Only these characters will be accepted by the text area\n * @param ta pointer to  Text Area\n * @param list list of characters. Only the pointer is saved. E.g. \"+-.,0123456789\"\n */\nvoid lv_ta_set_accepted_chars(lv_obj_t * ta, const char * list)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n\n    ext->accapted_chars = list;\n}\n\n/**\n * Set max length of a Text Area.\n * @param ta pointer to  Text Area\n * @param num the maximal number of characters can be added (`lv_ta_set_text` ignores it)\n */\nvoid lv_ta_set_max_length(lv_obj_t * ta, uint16_t num)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n\n    ext->max_length = num;\n}\n\n/**\n * Set a style of a text area\n * @param ta pointer to a text area object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_ta_set_style(lv_obj_t * ta, lv_ta_style_t type, lv_style_t * style)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n\n    switch(type) {\n        case LV_TA_STYLE_BG:\n            lv_page_set_style(ta, LV_PAGE_STYLE_BG, style);\n            break;\n        case LV_TA_STYLE_SB:\n            lv_page_set_style(ta, LV_PAGE_STYLE_SB, style);\n            break;\n        case LV_TA_STYLE_EDGE_FLASH:\n            lv_page_set_style(ta, LV_PAGE_STYLE_EDGE_FLASH, style);\n            break;\n        case LV_TA_STYLE_CURSOR:\n            ext->cursor.style = style;\n            lv_obj_refresh_ext_size(lv_page_get_scrl(ta)); /*Refresh ext. size because of cursor drawing*/\n            refr_cursor_area(ta);\n            break;\n    }\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the text of a text area. In password mode it gives the real text (not '*'s).\n * @param ta pointer to a text area object\n * @return pointer to the text\n */\nconst char * lv_ta_get_text(const lv_obj_t * ta)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n\n    const char * txt;\n    if(ext->pwd_mode == 0) {\n        txt = lv_label_get_text(ext->label);\n    } else {\n        txt = ext->pwd_tmp;\n    }\n\n    return txt;\n}\n\n\n/**\n * Get the label of a text area\n * @param ta pointer to a text area object\n * @return pointer to the label object\n */\nlv_obj_t * lv_ta_get_label(const lv_obj_t * ta)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n    return ext->label;\n}\n\n\n/**\n * Get the current cursor position in character index\n * @param ta pointer to a text area object\n * @return the cursor position\n */\nuint16_t lv_ta_get_cursor_pos(const lv_obj_t * ta)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n    return ext->cursor.pos;\n}\n\n/**\n * Get the current cursor type.\n * @param ta pointer to a text area object\n * @return element of 'lv_ta_cursor_type_t'\n */\nlv_cursor_type_t lv_ta_get_cursor_type(const lv_obj_t * ta)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n    return ext->cursor.type;\n}\n\n/**\n * Get the password mode attribute\n * @param ta pointer to a text area object\n * @return true: password mode is enabled, false: disabled\n */\nbool lv_ta_get_pwd_mode(const lv_obj_t * ta)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n    return ext->pwd_mode == 0 ? false : true;\n}\n\n/**\n * Get the one line configuration attribute\n * @param ta pointer to a text area object\n * @return true: one line configuration is enabled, false: disabled\n */\nbool lv_ta_get_one_line(const lv_obj_t * ta)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n    return ext->one_line == 0 ? false : true;\n}\n\n/**\n * Get a list of accepted characters.\n * @param ta pointer to  Text Area\n * @return list of accented characters.\n */\nconst char * lv_ta_get_accepted_chars(lv_obj_t * ta)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n\n    return ext->accapted_chars;\n}\n\n/**\n * Set max length of a Text Area.\n * @param ta pointer to  Text Area\n * @return the maximal number of characters to be add\n */\nuint16_t lv_ta_get_max_length(lv_obj_t * ta)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n    return ext->max_length;\n}\n\n/**\n * Get a style of a text area\n * @param ta pointer to a text area object\n * @param type which style should be get\n * @return style pointer to a style\n */\nlv_style_t * lv_ta_get_style(const lv_obj_t * ta, lv_ta_style_t type)\n{\n    lv_style_t * style = NULL;\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n\n    switch(type) {\n        case LV_TA_STYLE_BG:\n            style = lv_page_get_style(ta, LV_PAGE_STYLE_BG);\n            break;\n        case LV_TA_STYLE_SB:\n            style = lv_page_get_style(ta, LV_PAGE_STYLE_SB);\n            break;\n        case LV_TA_STYLE_EDGE_FLASH:\n            style = lv_page_get_style(ta, LV_PAGE_STYLE_EDGE_FLASH);\n            break;\n        case LV_TA_STYLE_CURSOR:\n            style = ext->cursor.style;\n            break;\n        default:\n            style = NULL;\n            break;\n    }\n\n    return style;\n}\n\n/*=====================\n * Other functions\n *====================*/\n\n/**\n * Move the cursor one character right\n * @param ta pointer to a text area object\n */\nvoid lv_ta_cursor_right(lv_obj_t * ta)\n{\n    uint16_t cp = lv_ta_get_cursor_pos(ta);\n    cp++;\n    lv_ta_set_cursor_pos(ta, cp);\n}\n\n/**\n * Move the cursor one character left\n * @param ta pointer to a text area object\n */\nvoid lv_ta_cursor_left(lv_obj_t * ta)\n{\n    uint16_t cp = lv_ta_get_cursor_pos(ta);\n    if(cp > 0)  {\n        cp--;\n        lv_ta_set_cursor_pos(ta, cp);\n    }\n}\n\n/**\n * Move the cursor one line down\n * @param ta pointer to a text area object\n */\nvoid lv_ta_cursor_down(lv_obj_t * ta)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n    lv_point_t pos;\n\n    /*Get the position of the current letter*/\n    lv_label_get_letter_pos(ext->label, lv_ta_get_cursor_pos(ta), &pos);\n\n    /*Increment the y with one line and keep the valid x*/\n    lv_style_t * label_style = lv_obj_get_style(ext->label);\n    const lv_font_t * font_p = label_style->text.font;\n    lv_coord_t font_h = lv_font_get_height(font_p);\n    pos.y += font_h + label_style->text.line_space + 1;\n    pos.x = ext->cursor.valid_x;\n\n    /*Do not go below the last line*/\n    if(pos.y < lv_obj_get_height(ext->label)) {\n        /*Get the letter index on the new cursor position and set it*/\n        uint16_t new_cur_pos = lv_label_get_letter_on(ext->label, &pos);\n\n        lv_coord_t cur_valid_x_tmp = ext->cursor.valid_x;   /*Cursor position set overwrites the valid positon */\n        lv_ta_set_cursor_pos(ta, new_cur_pos);\n        ext->cursor.valid_x = cur_valid_x_tmp;\n    }\n}\n\n/**\n * Move the cursor one line up\n * @param ta pointer to a text area object\n */\nvoid lv_ta_cursor_up(lv_obj_t * ta)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n    lv_point_t pos;\n\n    /*Get the position of the current letter*/\n    lv_label_get_letter_pos(ext->label, lv_ta_get_cursor_pos(ta), &pos);\n\n    /*Decrement the y with one line and keep the valid x*/\n    lv_style_t * label_style = lv_obj_get_style(ext->label);\n    const lv_font_t * font = label_style->text.font;\n    lv_coord_t font_h = lv_font_get_height(font);\n    pos.y -= font_h + label_style->text.line_space - 1;\n    pos.x = ext->cursor.valid_x;\n\n\n    /*Get the letter index on the new cursor position and set it*/\n    uint16_t new_cur_pos = lv_label_get_letter_on(ext->label, &pos);\n    lv_coord_t cur_valid_x_tmp = ext->cursor.valid_x;   /*Cursor position set overwrites the valid positon */\n    lv_ta_set_cursor_pos(ta, new_cur_pos);\n    ext->cursor.valid_x = cur_valid_x_tmp;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Handle the drawing related tasks of the text areas\n * @param ta pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW_MAIN: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_ta_design(lv_obj_t * ta, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    if(mode == LV_DESIGN_COVER_CHK) {\n        /*Return false if the object is not covers the mask_p area*/\n        return ancestor_design(ta, mask, mode);\n    } else if(mode == LV_DESIGN_DRAW_MAIN) {\n        /*Draw the object*/\n        ancestor_design(ta, mask, mode);\n\n    } else if(mode == LV_DESIGN_DRAW_POST) {\n        ancestor_design(ta, mask, mode);\n    }\n    return true;\n}\n\n\n/**\n * An extended scrollable design of the page. Calls the normal design function and draws a cursor.\n * @param scrl pointer to the scrollable part of the Text area\n * @param mask  the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW_MAIN: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @return return true/false, depends on 'mode'\n */\nstatic bool lv_ta_scrollable_design(lv_obj_t * scrl, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    if(mode == LV_DESIGN_COVER_CHK) {\n        /*Return false if the object is not covers the mask_p area*/\n        return scrl_design(scrl, mask, mode);\n    } else if(mode == LV_DESIGN_DRAW_MAIN) {\n        /*Draw the object*/\n        scrl_design(scrl, mask, mode);\n    } else if(mode == LV_DESIGN_DRAW_POST) {\n        scrl_design(scrl, mask, mode);\n\n        /*Draw the cursor*/\n        lv_obj_t * ta = lv_obj_get_parent(scrl);\n        lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n\n        if(ext->cursor.type == LV_CURSOR_NONE ||\n                (ext->cursor.type & LV_CURSOR_HIDDEN) ||\n                ext->cursor.state == 0) {\n            return true;    /*The cursor is not visible now*/\n        }\n\n        lv_style_t cur_style;\n        get_cursor_style(ta, &cur_style);\n\n        const char * txt = lv_label_get_text(ext->label);\n\n        /*Draw he cursor according to the type*/\n        lv_area_t cur_area;\n        lv_area_copy(&cur_area, &ext->cursor.area);\n\n         cur_area.x1 += ext->label->coords.x1;\n         cur_area.y1 += ext->label->coords.y1;\n         cur_area.x2 += ext->label->coords.x1;\n         cur_area.y2 += ext->label->coords.y1;\n\n         lv_opa_t opa_scale = lv_obj_get_opa_scale(ta);\n\n        if(ext->cursor.type == LV_CURSOR_LINE) {\n            lv_draw_rect(&cur_area, mask, &cur_style, opa_scale);\n        } else if(ext->cursor.type == LV_CURSOR_BLOCK) {\n            lv_draw_rect(&cur_area, mask, &cur_style, opa_scale);\n\n#if LV_TXT_UTF8 == 0\n            char letter_buf[2];\n            letter_buf[0] = txt[ext->cursor.txt_byte_pos];\n            letter_buf[1] = '\\0';\n#else\n            char letter_buf[8] = {0};\n            memcpy(letter_buf, &txt[ext->cursor.txt_byte_pos], lv_txt_encoded_size(&txt[ext->cursor.txt_byte_pos]));\n#endif\n            cur_area.x1 += cur_style.body.padding.hor;\n            cur_area.y1 += cur_style.body.padding.ver;\n            lv_draw_label(&cur_area, mask, &cur_style, opa_scale, letter_buf, LV_TXT_FLAG_NONE, 0);\n\n        } else if(ext->cursor.type == LV_CURSOR_OUTLINE) {\n            cur_style.body.empty = 1;\n            if(cur_style.body.border.width == 0) cur_style.body.border.width = 1; /*Be sure the border will be drawn*/\n            lv_draw_rect(&cur_area, mask, &cur_style, opa_scale);\n        } else if(ext->cursor.type == LV_CURSOR_UNDERLINE) {\n            lv_draw_rect(&cur_area, mask, &cur_style, opa_scale);\n        }\n    }\n\n    return true;\n}\n\n/**\n * Signal function of the text area\n * @param ta pointer to a text area object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_ta_signal(lv_obj_t * ta, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(ta, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n    if(sign == LV_SIGNAL_CLEANUP) {\n        if(ext->pwd_tmp != NULL) lv_mem_free(ext->pwd_tmp);\n\n        /* (The created label will be deleted automatically) */\n    } else if(sign == LV_SIGNAL_STYLE_CHG) {\n        if(ext->label) {\n            lv_obj_t * scrl = lv_page_get_scrl(ta);\n            lv_style_t * style_ta = lv_obj_get_style(ta);\n            lv_style_t * style_scrl = lv_obj_get_style(scrl);\n            if(ext->one_line) {\n                /*In one line mode refresh the Text Area height because 'vpad' can modify it*/\n                lv_style_t * style_label = lv_obj_get_style(ext->label);\n                lv_coord_t font_h =  lv_font_get_height(style_label->text.font);\n                lv_obj_set_height(ta, font_h + (style_ta->body.padding.ver + style_scrl->body.padding.ver) * 2);\n            } else {\n                /*In not one line mode refresh the Label width because 'hpad' can modify it*/\n                lv_obj_set_width(ext->label, lv_obj_get_width(scrl) - 2 * style_scrl->body.padding.hor);\n                lv_obj_set_pos(ext->label, style_scrl->body.padding.hor, style_scrl->body.padding.ver);         /*Be sure the Label is in the correct position*/\n            }\n            lv_label_set_text(ext->label, NULL);\n\n        }\n    } else if(sign == LV_SIGNAL_CORD_CHG) {\n        /*Set the label width according to the text area width*/\n        if(ext->label) {\n            if(lv_obj_get_width(ta) != lv_area_get_width(param) ||\n                    lv_obj_get_height(ta) != lv_area_get_height(param)) {\n                lv_obj_t * scrl = lv_page_get_scrl(ta);\n                lv_style_t * style_scrl = lv_obj_get_style(scrl);\n                lv_obj_set_width(ext->label, lv_obj_get_width(scrl) - 2 * style_scrl->body.padding.hor);\n                lv_obj_set_pos(ext->label, style_scrl->body.padding.hor, style_scrl->body.padding.ver);\n                lv_label_set_text(ext->label, NULL);    /*Refresh the label*/\n\n                refr_cursor_area(ta);\n            }\n        }\n    } else if(sign == LV_SIGNAL_CONTROLL) {\n        uint32_t c = *((uint32_t *)param);      /*uint32_t because can be UTF-8*/\n        if(c == LV_GROUP_KEY_RIGHT)     lv_ta_cursor_right(ta);\n        else if(c == LV_GROUP_KEY_LEFT) lv_ta_cursor_left(ta);\n        else if(c == LV_GROUP_KEY_UP)   lv_ta_cursor_up(ta);\n        else if(c == LV_GROUP_KEY_DOWN) lv_ta_cursor_down(ta);\n        else if(c == LV_GROUP_KEY_BACKSPACE) lv_ta_del_char(ta);\n        else if(c == LV_GROUP_KEY_DEL)  {\n            uint16_t cp = lv_ta_get_cursor_pos(ta);\n            lv_ta_set_cursor_pos(ta, cp + 1);\n            if(cp != lv_ta_get_cursor_pos(ta)) lv_ta_del_char(ta);\n        }\n        else {\n            lv_ta_add_char(ta, c);\n        }\n    } else if(sign == LV_SIGNAL_GET_EDITABLE) {\n        bool * editable = (bool *)param;\n        *editable = true;\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_ta\";\n    } else if(sign == LV_SIGNAL_DEFOCUS) {\n        lv_cursor_type_t cur_type;\n        cur_type = lv_ta_get_cursor_type(ta);\n        lv_ta_set_cursor_type(ta, cur_type | LV_CURSOR_HIDDEN);\n    } else if(sign == LV_SIGNAL_FOCUS) {\n#if USE_LV_GROUP\n        lv_cursor_type_t cur_type;\n        cur_type = lv_ta_get_cursor_type(ta);\n        lv_group_t * g = lv_obj_get_group(ta);\n        bool editing = lv_group_get_editing(g);\n        lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act());\n\n        /*Encoders need special handling*/\n        if(indev_type == LV_INDEV_TYPE_ENCODER) {\n            if(editing) lv_ta_set_cursor_type(ta, cur_type & (~LV_CURSOR_HIDDEN));\n            else lv_ta_set_cursor_type(ta, cur_type | LV_CURSOR_HIDDEN);\n        }\n        else {\n            lv_ta_set_cursor_type(ta, cur_type & (~LV_CURSOR_HIDDEN));\n        }\n#endif\n    }\n    return res;\n}\n\n/**\n * Signal function of the scrollable part of the text area\n * @param scrl pointer to scrollable part of a text area object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_ta_scrollable_signal(lv_obj_t * scrl, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n    lv_obj_t * ta = lv_obj_get_parent(scrl);\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n\n    /* Include the ancient signal function */\n    res = scrl_signal(scrl, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    if(sign == LV_SIGNAL_REFR_EXT_SIZE) {\n        /*Set ext. size because the cursor might be out of this object*/\n        lv_style_t * style_label = lv_obj_get_style(ext->label);\n        lv_coord_t font_h = lv_font_get_height(style_label->text.font);\n        scrl->ext_size = LV_MATH_MAX(scrl->ext_size, style_label->text.line_space + font_h);\n    }\n#if 0\n    else if(sign == LV_SIGNAL_CORD_CHG) {\n        /*Set the label width according to the text area width*/\n        if(ext->label) {\n            if(lv_obj_get_width(ta) != lv_area_get_width(param) ||\n                    lv_obj_get_height(ta) != lv_area_get_height(param)) {\n                lv_obj_t * scrl = lv_page_get_scrl(ta);\n                lv_style_t * style_scrl = lv_obj_get_style(scrl);\n                lv_obj_set_width(ext->label, lv_obj_get_width(scrl) - 2 * style_scrl->body.padding.hor);\n                lv_obj_set_pos(ext->label, style_scrl->body.padding.hor, style_scrl->body.padding.ver);\n                lv_label_set_text(ext->label, NULL);    /*Refresh the label*/\n\n                refr_cursor_area(ta);\n            }\n        }\n    }\n#endif\n\n    return res;\n}\n\n#if USE_LV_ANIMATION\n\n/**\n * Called to blink the cursor\n * @param ta pointer to a text area\n * @param hide 1: hide the cursor, 0: show it\n */\nstatic void cursor_blink_anim(lv_obj_t * ta, uint8_t show)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n    if(show != ext->cursor.state) {\n        ext->cursor.state = show == 0 ? 0 : 1;\n        if(ext->cursor.type != LV_CURSOR_NONE &&\n                (ext->cursor.type & LV_CURSOR_HIDDEN) == 0)\n        {\n            lv_area_t area_tmp;\n            lv_area_copy(&area_tmp, &ext->cursor.area);\n            area_tmp.x1 += ext->label->coords.x1;\n            area_tmp.y1 += ext->label->coords.y1;\n            area_tmp.x2 += ext->label->coords.x1;\n            area_tmp.y2 += ext->label->coords.y1;\n            lv_inv_area(&area_tmp);\n        }\n    }\n}\n\n\n/**\n * Dummy function to animate char hiding in pwd mode.\n * Does nothing, but a function is required in car hiding anim.\n * (pwd_char_hider callback do the real job)\n * @param ta unused\n * @param x unused\n */\nstatic void pwd_char_hider_anim(lv_obj_t * ta, int32_t x)\n{\n    (void)ta;\n    (void)x;\n}\n\n#endif\n\n/**\n * Hide all characters (convert them to '*')\n * @param ta: pointer to text area object\n */\nstatic void pwd_char_hider(lv_obj_t * ta)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n    if(ext->pwd_mode != 0) {\n        char * txt = lv_label_get_text(ext->label);\n        int16_t len = lv_txt_get_encoded_length(txt);\n        bool refr = false;\n        uint16_t i;\n        for(i = 0; i < len; i++) {\n            txt[i] = '*';\n            refr = true;\n        }\n\n        txt[i] = '\\0';\n\n        if(refr != false) lv_label_set_text(ext->label, txt);\n    }\n}\n\n/**\n * Test an unicode character if it is accepted or not. Checks max length and accepted char list.\n * @param ta pointer to a test area object\n * @param c an unicode character\n * @return true: accapted; false: rejected\n */\nstatic bool char_is_accepted(lv_obj_t * ta, uint32_t c)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n\n    /*If no restriction accept it*/\n    if(ext->accapted_chars == NULL && ext->max_length == 0) return true;\n\n    /*Too many characters?*/\n    if(ext->max_length > 0 &&\n            lv_txt_get_encoded_length(lv_ta_get_text(ta)) >= ext->max_length) {\n        return false;\n    }\n\n    /*Accepted character?*/\n    if(ext->accapted_chars) {\n        uint32_t i = 0;\n        uint32_t a;\n        while(ext->accapted_chars[i] != '\\0') {\n            a = lv_txt_encoded_next(ext->accapted_chars, &i);\n            if(a == c) return true; /*Accepted*/\n        }\n\n        return false;   /*The character wasn't in the list*/\n    } else {\n        return true;    /*If the accepted char list in not specified the accept the character*/\n    }\n\n}\n\nstatic void get_cursor_style(lv_obj_t * ta, lv_style_t * style_res)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n    lv_style_t * label_style = lv_obj_get_style(ext->label);\n\n    if(ext->cursor.style) {\n        lv_style_copy(style_res, ext->cursor.style);\n    } else {\n        /*If cursor style is not specified then use the modified label style */\n        lv_style_copy(style_res, label_style);\n        lv_color_t clv_color_tmp = style_res->text.color;        /*Make letter color to cursor color*/\n        style_res->text.color = style_res->body.main_color;       /*In block mode the letter color will be current background color*/\n        style_res->body.main_color = clv_color_tmp;\n        style_res->body.grad_color = clv_color_tmp;\n        style_res->body.border.color = clv_color_tmp;\n        style_res->body.border.opa = LV_OPA_COVER;\n        style_res->body.border.width = 1;\n        style_res->body.shadow.width = 0;\n        style_res->body.radius = 0;\n        style_res->body.empty = 0;\n        style_res->body.padding.hor = 0;\n        style_res->body.padding.ver = 0;\n        style_res->line.width = 1;\n        style_res->body.opa = LV_OPA_COVER;\n    }\n\n}\n\nstatic void refr_cursor_area(lv_obj_t * ta)\n{\n    lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);\n    lv_style_t * label_style = lv_obj_get_style(ext->label);\n\n    lv_style_t cur_style;\n    get_cursor_style(ta, &cur_style);\n\n    uint16_t cur_pos = lv_ta_get_cursor_pos(ta);\n    const char * txt = lv_label_get_text(ext->label);\n    uint32_t byte_pos;\n#if LV_TXT_UTF8 != 0\n    byte_pos = lv_txt_encoded_get_byte_id(txt, cur_pos);\n    uint32_t letter = lv_txt_encoded_next(&txt[byte_pos], NULL);\n#else\n    byte_pos = cur_pos;\n    uint32_t letter = txt[byte_pos];\n#endif\n\n    lv_coord_t letter_h = lv_font_get_height(label_style->text.font);\n    /*Set letter_w (set not 0 on non printable but valid chars)*/\n    lv_coord_t letter_w;\n    if(letter == '\\0' || letter == '\\n' || letter == '\\r') {\n        letter_w = lv_font_get_width(label_style->text.font, ' ');\n    } else {\n        letter_w = lv_font_get_width(label_style->text.font, letter);\n    }\n\n    lv_point_t letter_pos;\n    lv_label_get_letter_pos(ext->label, cur_pos, &letter_pos);\n\n    /*If the cursor is out of the text (most right) draw it to the next line*/\n    if(letter_pos.x + ext->label->coords.x1 + letter_w > ext->label->coords.x2 && ext->one_line == 0 && lv_label_get_align(ext->label) != LV_LABEL_ALIGN_RIGHT) {\n        letter_pos.x = 0;\n        letter_pos.y += letter_h + label_style->text.line_space;\n\n        if(letter != '\\0') {\n            byte_pos += lv_txt_encoded_size(&txt[byte_pos]);\n            letter = lv_txt_encoded_next(&txt[byte_pos], NULL);\n        }\n\n        if(letter == '\\0' || letter == '\\n' || letter == '\\r') {\n            letter_w = lv_font_get_width(label_style->text.font, ' ');\n        } else {\n            letter_w = lv_font_get_width(label_style->text.font, letter);\n        }\n    }\n\n    /*Save the byte position. It is required to draw `LV_CURSOR_BLOCK`*/\n    ext->cursor.txt_byte_pos = byte_pos;\n\n    /*Draw he cursor according to the type*/\n    lv_area_t cur_area;\n\n    if(ext->cursor.type == LV_CURSOR_LINE) {\n        cur_area.x1 = letter_pos.x + cur_style.body.padding.hor - (cur_style.line.width >> 1) - (cur_style.line.width & 0x1);\n        cur_area.y1 = letter_pos.y + cur_style.body.padding.ver;\n        cur_area.x2 = letter_pos.x + cur_style.body.padding.hor + (cur_style.line.width >> 1);\n        cur_area.y2 = letter_pos.y + cur_style.body.padding.ver + letter_h;\n    } else if(ext->cursor.type == LV_CURSOR_BLOCK) {\n        cur_area.x1 = letter_pos.x - cur_style.body.padding.hor;\n        cur_area.y1 = letter_pos.y - cur_style.body.padding.ver;\n        cur_area.x2 = letter_pos.x + cur_style.body.padding.hor + letter_w;\n        cur_area.y2 = letter_pos.y + cur_style.body.padding.ver + letter_h;\n\n    } else if(ext->cursor.type == LV_CURSOR_OUTLINE) {\n        cur_area.x1 = letter_pos.x - cur_style.body.padding.hor;\n        cur_area.y1 = letter_pos.y - cur_style.body.padding.ver;\n        cur_area.x2 = letter_pos.x + cur_style.body.padding.hor + letter_w;\n        cur_area.y2 = letter_pos.y + cur_style.body.padding.ver + letter_h;\n    } else if(ext->cursor.type == LV_CURSOR_UNDERLINE) {\n        cur_area.x1 = letter_pos.x + cur_style.body.padding.hor;\n        cur_area.y1 = letter_pos.y + cur_style.body.padding.ver + letter_h - (cur_style.line.width >> 1);\n        cur_area.x2 = letter_pos.x + cur_style.body.padding.hor + letter_w;\n        cur_area.y2 = letter_pos.y + cur_style.body.padding.ver + letter_h + (cur_style.line.width >> 1) + (cur_style.line.width & 0x1);\n    }\n\n    /*Save the new area*/\n    lv_area_t area_tmp;\n    lv_area_copy(&area_tmp, &ext->cursor.area);\n    area_tmp.x1 += ext->label->coords.x1;\n    area_tmp.y1 += ext->label->coords.y1;\n    area_tmp.x2 += ext->label->coords.x1;\n    area_tmp.y2 += ext->label->coords.y1;\n    lv_inv_area(&area_tmp);\n\n    lv_area_copy(&ext->cursor.area, &cur_area);\n\n    lv_area_copy(&area_tmp, &ext->cursor.area);\n    area_tmp.x1 += ext->label->coords.x1;\n    area_tmp.y1 += ext->label->coords.y1;\n    area_tmp.x2 += ext->label->coords.x1;\n    area_tmp.y2 += ext->label->coords.y1;\n    lv_inv_area(&area_tmp);\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_ta.h",
    "content": "/**\n * @file lv_ta.h\n *\n */\n\n#ifndef LV_TA_H\n#define LV_TA_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_TA != 0\n\n/*Testing of dependencies*/\n#if USE_LV_PAGE == 0\n#error \"lv_ta: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE  1) \"\n#endif\n\n#if USE_LV_LABEL == 0\n#error \"lv_ta: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL  1) \"\n#endif\n\n#include \"../lv_core/lv_obj.h\"\n#include \"lv_page.h\"\n#include \"lv_label.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#define LV_TA_CURSOR_LAST (0x7FFF) /*Put the cursor after the last character*/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\nenum {\n    LV_CURSOR_NONE,\n    LV_CURSOR_LINE,\n    LV_CURSOR_BLOCK,\n    LV_CURSOR_OUTLINE,\n    LV_CURSOR_UNDERLINE,\n    LV_CURSOR_HIDDEN = 0x08,    /*Or it to any value to hide the cursor temporally*/\n};\ntypedef uint8_t lv_cursor_type_t;\n\n/*Data of text area*/\ntypedef struct\n{\n    lv_page_ext_t page; /*Ext. of ancestor*/\n    /*New data for this type */\n    lv_obj_t * label;           /*Label of the text area*/\n    char * pwd_tmp;             /*Used to store the original text in password mode*/\n    const char * accapted_chars;/*Only these characters will be accepted. NULL: accept all*/\n    uint16_t max_length;        /*The max. number of characters. 0: no limit*/\n    uint8_t pwd_mode :1;        /*Replace characters with '*' */\n    uint8_t one_line :1;        /*One line mode (ignore line breaks)*/\n    struct {\n        lv_style_t *style;      /*Style of the cursor (NULL to use label's style)*/\n        lv_coord_t valid_x;     /*Used when stepping up/down in text area when stepping to a shorter line. (Handled by the library)*/\n        uint16_t pos;           /*The current cursor position (0: before 1. letter; 1: before 2. letter etc.)*/\n        lv_area_t area;         /*Cursor area relative to the Text Area*/\n        uint16_t txt_byte_pos;  /*Byte index of the letter after (on) the cursor*/\n        lv_cursor_type_t type:4;  /*Shape of the cursor*/\n        uint8_t state :1;       /*Indicates that the cursor is visible now or not (Handled by the library)*/\n    } cursor;\n} lv_ta_ext_t;\n\nenum {\n    LV_TA_STYLE_BG,\n    LV_TA_STYLE_SB,\n    LV_TA_STYLE_EDGE_FLASH,\n    LV_TA_STYLE_CURSOR,\n};\ntypedef uint8_t lv_ta_style_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n\n/**\n * Create a text area objects\n * @param par pointer to an object, it will be the parent of the new text area\n * @param copy pointer to a text area object, if not NULL then the new object will be copied from it\n * @return pointer to the created text area\n */\nlv_obj_t * lv_ta_create(lv_obj_t * par, const lv_obj_t * copy);\n\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n/**\n * Insert a character to the current cursor position.\n * To add a wide char, e.g. 'Á' use `lv_txt_encoded_conv_wc('Á')`\n * @param ta pointer to a text area object\n * @param c a character (e.g. 'a')\n */\nvoid lv_ta_add_char(lv_obj_t * ta, uint32_t c);\n\n/**\n * Insert a text to the current cursor position\n * @param ta pointer to a text area object\n * @param txt a '\\0' terminated string to insert\n */\nvoid lv_ta_add_text(lv_obj_t * ta, const char * txt);\n\n/**\n * Delete a the left character from the current cursor position\n * @param ta pointer to a text area object\n */\nvoid lv_ta_del_char(lv_obj_t * ta);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set the text of a text area\n * @param ta pointer to a text area\n * @param txt pointer to the text\n */\nvoid lv_ta_set_text(lv_obj_t * ta, const char * txt);\n\n/**\n * Set the cursor position\n * @param obj pointer to a text area object\n * @param pos the new cursor position in character index\n *             < 0 : index from the end of the text\n *             LV_TA_CURSOR_LAST: go after the last character\n */\nvoid lv_ta_set_cursor_pos(lv_obj_t * ta, int16_t pos);\n\n/**\n * Set the cursor type.\n * @param ta pointer to a text area object\n * @param cur_type: element of 'lv_cursor_type_t'\n */\nvoid lv_ta_set_cursor_type(lv_obj_t * ta, lv_cursor_type_t cur_type);\n\n/**\n * Enable/Disable password mode\n * @param ta pointer to a text area object\n * @param en true: enable, false: disable\n */\nvoid lv_ta_set_pwd_mode(lv_obj_t * ta, bool en);\n\n/**\n * Configure the text area to one line or back to normal\n * @param ta pointer to a Text area object\n * @param en true: one line, false: normal\n */\nvoid lv_ta_set_one_line(lv_obj_t * ta, bool en);\n\n/**\n * Set the alignment of the text area.\n * In one line mode the text can be scrolled only with `LV_LABEL_ALIGN_LEFT`.\n * This function should be called if the size of text area changes.\n * @param ta pointer to a text are object\n * @param align the desired alignment from `lv_label_align_t`. (LV_LABEL_ALIGN_LEFT/CENTER/RIGHT)\n */\nvoid lv_ta_set_text_align(lv_obj_t * ta, lv_label_align_t align);\n\n/**\n * Set a list of characters. Only these characters will be accepted by the text area\n * @param ta pointer to  Text Area\n * @param list list of characters. Only the pointer is saved. E.g. \"+-.,0123456789\"\n */\nvoid lv_ta_set_accepted_chars(lv_obj_t * ta, const char * list);\n\n/**\n * Set max length of a Text Area.\n * @param ta pointer to  Text Area\n * @param num the maximal number of characters can be added (`lv_ta_set_text` ignores it)\n */\nvoid lv_ta_set_max_length(lv_obj_t * ta, uint16_t num);\n\n/**\n * Set an action to call when the Text area is clicked\n * @param ta pointer to a Text area\n * @param action a function pointer\n */\nstatic inline void lv_ta_set_action(lv_obj_t * ta, lv_action_t action)\n{\n    lv_page_set_rel_action(ta, action);\n}\n\n/**\n * Set the scroll bar mode of a text area\n * @param ta pointer to a text area object\n * @param sb_mode the new mode from 'lv_page_sb_mode_t' enum\n */\nstatic inline void lv_ta_set_sb_mode(lv_obj_t * ta, lv_sb_mode_t mode)\n{\n    lv_page_set_sb_mode(ta, mode);\n}\n\n/**\n * Enable the scroll propagation feature. If enabled then the Text area will move its parent if there is no more space to scroll.\n * @param ta pointer to a Text area\n * @param en true or false to enable/disable scroll propagation\n */\nstatic inline void lv_ta_set_scroll_propagation(lv_obj_t * ta, bool en)\n{\n    lv_page_set_scroll_propagation(ta, en);\n}\n\n/**\n * Enable the edge flash effect. (Show an arc when the an edge is reached)\n * @param page pointer to a Text Area\n * @param en true or false to enable/disable end flash\n */\nstatic inline void lv_ta_set_edge_flash(lv_obj_t * ta, bool en)\n{\n    lv_page_set_edge_flash(ta, en);\n}\n\n/**\n * Set a style of a text area\n * @param ta pointer to a text area object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_ta_set_style(lv_obj_t *ta, lv_ta_style_t type, lv_style_t *style);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the text of a text area. In password mode it gives the real text (not '*'s).\n * @param ta pointer to a text area object\n * @return pointer to the text\n */\nconst char * lv_ta_get_text(const lv_obj_t * ta);\n\n/**\n * Get the label of a text area\n * @param ta pointer to a text area object\n * @return pointer to the label object\n */\nlv_obj_t * lv_ta_get_label(const lv_obj_t * ta);\n\n/**\n * Get the current cursor position in character index\n * @param ta pointer to a text area object\n * @return the cursor position\n */\nuint16_t lv_ta_get_cursor_pos(const lv_obj_t * ta);\n\n/**\n * Get the current cursor visibility.\n * @param ta pointer to a text area object\n * @return true: the cursor is drawn, false: the cursor is hidden\n */\n//bool lv_ta_get_cursor_show(const lv_obj_t * ta);\n\n/**\n * Get the current cursor type.\n * @param ta pointer to a text area object\n * @return element of 'lv_cursor_type_t'\n */\nlv_cursor_type_t lv_ta_get_cursor_type(const lv_obj_t * ta);\n\n/**\n * Get the password mode attribute\n * @param ta pointer to a text area object\n * @return true: password mode is enabled, false: disabled\n */\nbool lv_ta_get_pwd_mode(const lv_obj_t * ta);\n\n/**\n * Get the one line configuration attribute\n * @param ta pointer to a text area object\n * @return true: one line configuration is enabled, false: disabled\n */\nbool lv_ta_get_one_line(const lv_obj_t * ta);\n\n/**\n * Get a list of accepted characters.\n * @param ta pointer to  Text Area\n * @return list of accented characters.\n */\nconst char * lv_ta_get_accepted_chars(lv_obj_t * ta);\n\n/**\n * Set max length of a Text Area.\n * @param ta pointer to  Text Area\n * @return the maximal number of characters to be add\n */\nuint16_t lv_ta_get_max_length(lv_obj_t * ta);\n\n/**\n * Set an action to call when the Text area is clicked\n * @param ta pointer to a Text area\n * @param action a function pointer\n */\nstatic inline lv_action_t lv_ta_get_action(lv_obj_t * ta)\n{\n    return lv_page_get_rel_action(ta);\n}\n\n/**\n * Get the scroll bar mode of a text area\n * @param ta pointer to a text area object\n * @return scrollbar mode from 'lv_page_sb_mode_t' enum\n */\nstatic inline lv_sb_mode_t lv_ta_get_sb_mode(const lv_obj_t * ta)\n{\n    return lv_page_get_sb_mode(ta);\n}\n\n/**\n * Get the scroll propagation property\n * @param ta pointer to a Text area\n * @return true or false\n */\nstatic inline bool lv_ta_get_scroll_propagation(lv_obj_t * ta)\n{\n    return lv_page_get_scroll_propagation(ta);\n}\n\n/**\n * Get the scroll propagation property\n * @param ta pointer to a Text area\n * @return true or false\n */\nstatic inline bool lv_ta_get_edge_flash(lv_obj_t * ta)\n{\n    return lv_page_get_edge_flash(ta);\n}\n\n/**\n * Get a style of a text area\n * @param ta pointer to a text area object\n * @param type which style should be get\n * @return style pointer to a style\n */\nlv_style_t * lv_ta_get_style(const lv_obj_t *ta, lv_ta_style_t type);\n\n/*=====================\n * Other functions\n *====================*/\n\n/**\n * Move the cursor one character right\n * @param ta pointer to a text area object\n */\nvoid lv_ta_cursor_right(lv_obj_t * ta);\n\n/**\n * Move the cursor one character left\n * @param ta pointer to a text area object\n */\nvoid lv_ta_cursor_left(lv_obj_t * ta);\n\n/**\n * Move the cursor one line down\n * @param ta pointer to a text area object\n */\nvoid lv_ta_cursor_down(lv_obj_t * ta);\n\n/**\n * Move the cursor one line up\n * @param ta pointer to a text area object\n */\nvoid lv_ta_cursor_up(lv_obj_t * ta);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_TA_H*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_TA_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_table.c",
    "content": "/**\n * @file lv_table.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_table.h\"\n#if USE_LV_TABLE != 0\n\n#include \"../lv_misc/lv_txt.h\"\n#include \"../lv_misc/lv_math.h\"\n#include \"../lv_draw/lv_draw_label.h\"\n#include \"../lv_themes/lv_theme.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic bool lv_table_design(lv_obj_t * table, const lv_area_t * mask, lv_design_mode_t mode);\nstatic lv_res_t lv_table_signal(lv_obj_t * table, lv_signal_t sign, void * param);\nstatic lv_coord_t get_row_height(lv_obj_t * table, uint16_t row_id);\nstatic void refr_size(lv_obj_t * table);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\nstatic lv_design_func_t ancestor_scrl_design;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a table object\n * @param par pointer to an object, it will be the parent of the new table\n * @param copy pointer to a table object, if not NULL then the new object will be copied from it\n * @return pointer to the created table\n */\nlv_obj_t * lv_table_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"table create started\");\n\n    /*Create the ancestor of table*/\n    lv_obj_t * new_table = lv_obj_create(par, copy);\n    lv_mem_assert(new_table);\n    if(new_table == NULL) return NULL;\n\n    /*Allocate the table type specific extended data*/\n    lv_table_ext_t * ext = lv_obj_allocate_ext_attr(new_table, sizeof(lv_table_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_table);\n    if(ancestor_scrl_design == NULL) ancestor_scrl_design = lv_obj_get_design_func(new_table);\n\n    /*Initialize the allocated 'ext' */\n    ext->cell_data = NULL;\n    ext->cell_style[0] = &lv_style_plain;\n    ext->cell_style[1] = &lv_style_plain;\n    ext->cell_style[2] = &lv_style_plain;\n    ext->cell_style[3] = &lv_style_plain;\n    ext->col_cnt = 0;\n    ext->row_cnt = 0;\n\n    uint16_t i;\n    for(i = 0; i < LV_TABLE_COL_MAX; i++) {\n        ext->col_w[i] = LV_DPI;\n    }\n\n    /*The signal and design functions are not copied so set them here*/\n    lv_obj_set_signal_func(new_table, lv_table_signal);\n    lv_obj_set_design_func(new_table, lv_table_design);\n\n    /*Init the new table table*/\n    if(copy == NULL) {\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_table_set_style(new_table, LV_TABLE_STYLE_BG, th->table.bg);\n            lv_table_set_style(new_table, LV_TABLE_STYLE_CELL1, th->table.cell);\n            lv_table_set_style(new_table, LV_TABLE_STYLE_CELL2, th->table.cell);\n            lv_table_set_style(new_table, LV_TABLE_STYLE_CELL3, th->table.cell);\n            lv_table_set_style(new_table, LV_TABLE_STYLE_CELL4, th->table.cell);\n        } else {\n            lv_table_set_style(new_table, LV_TABLE_STYLE_BG, &lv_style_plain_color);\n        }\n    }\n    /*Copy an existing table*/\n    else {\n        lv_table_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        ext->cell_style[0] = copy_ext->cell_style[0];\n        ext->cell_style[1] = copy_ext->cell_style[1];\n        ext->cell_style[2] = copy_ext->cell_style[2];\n        ext->cell_style[3] = copy_ext->cell_style[3];\n        ext->col_cnt = copy_ext->col_cnt;\n        ext->row_cnt = copy_ext->row_cnt;\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_table);\n    }\n\n    LV_LOG_INFO(\"table created\");\n\n    return new_table;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set the value of a cell.\n * @param table pointer to a Table object\n * @param row id of the row [0 .. row_cnt -1]\n * @param col id of the column [0 .. col_cnt -1]\n * @param txt text to display in the cell. It will be copied and saved so this variable is not required after this function call.\n */\nvoid lv_table_set_cell_value(lv_obj_t * table, uint16_t row, uint16_t col, const char * txt)\n{\n    lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n    if(row >= ext->row_cnt || col >= ext->col_cnt) {\n        LV_LOG_WARN(\"lv_table_set_cell_value: invalid row or column\");\n        return;\n    }\n    uint32_t cell = row * ext->col_cnt + col;\n    lv_table_cell_format_t format;\n\n    /*Save the format byte*/\n    if(ext->cell_data[cell]) {\n        format.format_byte = ext->cell_data[cell][0];\n    }\n    /*Initialize the format byte*/\n    else {\n        format.align = LV_LABEL_ALIGN_LEFT;\n        format.right_merge = 0;\n        format.type = 0;\n        format.crop = 0;\n    }\n\n\n    ext->cell_data[cell] = lv_mem_realloc(ext->cell_data[cell], strlen(txt) + 2);   /*+1: trailing '\\0; +1: format byte*/\n    strcpy(ext->cell_data[cell] + 1, txt);              /*Leave the format byte*/\n    ext->cell_data[cell][0] = format.format_byte;\n    refr_size(table);\n}\n\n/**\n * Set the number of rows\n * @param table table pointer to a Table object\n * @param row_cnt number of rows\n */\nvoid lv_table_set_row_cnt(lv_obj_t * table, uint16_t row_cnt)\n{\n    lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n    uint16_t old_row_cnt = ext->row_cnt;\n    ext->row_cnt = row_cnt;\n\n    if(ext->row_cnt > 0 && ext->col_cnt > 0) {\n        ext->cell_data = lv_mem_realloc(ext->cell_data, ext->row_cnt * ext->col_cnt * sizeof(char*));\n\n        /*Initilize the new fields*/\n        if(old_row_cnt < row_cnt) {\n\t\t\tuint16_t old_cell_cnt = old_row_cnt * ext->col_cnt;\n\t\t\tuint32_t new_cell_cnt = ext->col_cnt * ext->row_cnt;\n\t\t\tmemset(&ext->cell_data[old_cell_cnt], 0, (new_cell_cnt - old_cell_cnt) * sizeof(ext->cell_data[0]));\n        }\n    }\n    else {\n        lv_mem_free(ext->cell_data);\n        ext->cell_data = NULL;\n    }\n\n    refr_size(table);\n}\n\n/**\n * Set the number of columns\n * @param table table pointer to a Table object\n * @param col_cnt number of columns. Must be < LV_TABLE_COL_MAX\n */\nvoid lv_table_set_col_cnt(lv_obj_t * table, uint16_t col_cnt)\n{\n\n    if(col_cnt >= LV_TABLE_COL_MAX) {\n        LV_LOG_WARN(\"lv_table_set_col_cnt: too many columns. Must be < LV_TABLE_COL_MAX.\");\n        return;\n    }\n\n    lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n    uint16_t old_col_cnt = ext->col_cnt;\n    ext->col_cnt = col_cnt;\n\n    if(ext->row_cnt > 0 && ext->col_cnt > 0) {\n        ext->cell_data = lv_mem_realloc(ext->cell_data, ext->row_cnt * ext->col_cnt * sizeof(char*));\n        /*Initilize the new fields*/\n        if(old_col_cnt < col_cnt) {\n        \tuint16_t old_cell_cnt = old_col_cnt * ext->row_cnt;\n        \tuint32_t new_cell_cnt = ext->col_cnt * ext->row_cnt;\n        \tmemset(&ext->cell_data[old_cell_cnt], 0, (new_cell_cnt - old_cell_cnt) * sizeof(ext->cell_data[0]));\n        }\n\n    }\n    else {\n        lv_mem_free(ext->cell_data);\n        ext->cell_data = NULL;\n    }\n    refr_size(table);\n}\n\n/**\n * Set the width of a column\n * @param table table pointer to a Table object\n * @param col_id id of the column [0 .. LV_TABLE_COL_MAX -1]\n * @param w width of the column\n */\nvoid lv_table_set_col_width(lv_obj_t * table, uint16_t col_id, lv_coord_t w)\n{\n    if(col_id >= LV_TABLE_COL_MAX) {\n        LV_LOG_WARN(\"lv_table_set_col_width: too big 'col_id'. Must be < LV_TABLE_COL_MAX.\");\n        return;\n    }\n\n    lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n    ext->col_w[col_id] = w;\n    refr_size(table);\n}\n\n/**\n * Set the text align in a cell\n * @param table pointer to a Table object\n * @param row id of the row [0 .. row_cnt -1]\n * @param col id of the column [0 .. col_cnt -1]\n * @param align LV_LABEL_ALIGN_LEFT or LV_LABEL_ALIGN_CENTER or LV_LABEL_ALIGN_RIGHT\n */\nvoid lv_table_set_cell_align(lv_obj_t * table, uint16_t row, uint16_t col, lv_label_align_t align)\n{\n    lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n     if(row >= ext->row_cnt || col >= ext->col_cnt) {\n         LV_LOG_WARN(\"lv_table_set_cell_align: invalid row or column\");\n         return;\n     }\n     uint32_t cell = row * ext->col_cnt + col;\n\n     if(ext->cell_data[cell] == NULL) {\n         ext->cell_data[cell] = lv_mem_alloc(2);        /*+1: trailing '\\0; +1: format byte*/\n         ext->cell_data[cell][0] = 0;\n         ext->cell_data[cell][1] = '\\0';\n     }\n\n     lv_table_cell_format_t format;\n     format.format_byte = ext->cell_data[cell][0];\n     format.align = align;\n     ext->cell_data[cell][0] = format.format_byte;\n}\n\n/**\n * Set the type of a cell.\n * @param table pointer to a Table object\n * @param row id of the row [0 .. row_cnt -1]\n * @param col id of the column [0 .. col_cnt -1]\n * @param type 1,2,3 or 4. The cell style will be chosen accordingly.\n */\nvoid lv_table_set_cell_type(lv_obj_t * table, uint16_t row, uint16_t col, uint8_t type)\n{\n    lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n     if(row >= ext->row_cnt || col >= ext->col_cnt) {\n         LV_LOG_WARN(\"lv_table_set_cell_type: invalid row or column\");\n         return;\n     }\n     uint32_t cell = row * ext->col_cnt + col;\n\n     if(ext->cell_data[cell] == NULL) {\n         ext->cell_data[cell] = lv_mem_alloc(2);        /*+1: trailing '\\0; +1: format byte*/\n         ext->cell_data[cell][0] = 0;\n         ext->cell_data[cell][1] = '\\0';\n     }\n\n     if(type > 0) type--;   /*User gives 1,2,3,4 but easier to handle 0, 1, 2, 3*/\n     if(type >= LV_TABLE_CELL_STYLE_CNT) type = LV_TABLE_CELL_STYLE_CNT - 1;\n\n     lv_table_cell_format_t format;\n     format.format_byte = ext->cell_data[cell][0];\n     format.type = type;\n     ext->cell_data[cell][0] = format.format_byte;\n}\n\n/**\n * Set the cell crop. (Don't adjust the height of the cell according to its content)\n * @param table pointer to a Table object\n * @param row id of the row [0 .. row_cnt -1]\n * @param col id of the column [0 .. col_cnt -1]\n * @param crop true: crop the cell content; false: set the cell height to the content.\n */\nvoid lv_table_set_cell_crop(lv_obj_t * table, uint16_t row, uint16_t col, bool crop)\n{\n    lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n     if(row >= ext->row_cnt || col >= ext->col_cnt) {\n         LV_LOG_WARN(\"lv_table_set_cell_crop: invalid row or column\");\n         return;\n     }\n     uint32_t cell = row * ext->col_cnt + col;\n\n     if(ext->cell_data[cell] == NULL) {\n         ext->cell_data[cell] = lv_mem_alloc(2);        /*+1: trailing '\\0; +1: format byte*/\n         ext->cell_data[cell][0] = 0;\n         ext->cell_data[cell][1] = '\\0';\n     }\n\n     lv_table_cell_format_t format;\n     format.format_byte = ext->cell_data[cell][0];\n     format.crop = crop;\n     ext->cell_data[cell][0] = format.format_byte;\n}\n\n\n/**\n * Merge a cell with the right neighbor. The value of the cell to the right won't be displayed.\n * @param table table pointer to a Table object\n * @param row id of the row [0 .. row_cnt -1]\n * @param col id of the column [0 .. col_cnt -1]\n * @param en true: merge right; false: don't merge right\n */\nvoid lv_table_set_cell_merge_right(lv_obj_t * table, uint16_t row, uint16_t col, bool en)\n{\n    lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n    if(row >= ext->row_cnt || col >= ext->col_cnt) {\n        LV_LOG_WARN(\"lv_table_set_cell_merge_right: invalid row or column\");\n        return;\n    }\n\n    uint32_t cell = row * ext->col_cnt + col;\n\n    if(ext->cell_data[cell] == NULL) {\n        ext->cell_data[cell] = lv_mem_alloc(2);        /*+1: trailing '\\0; +1: format byte*/\n        ext->cell_data[cell][0] = 0;\n        ext->cell_data[cell][1] = '\\0';\n    }\n\n    lv_table_cell_format_t format;\n    format.format_byte = ext->cell_data[cell][0];\n    format.right_merge = en ? 1 : 0;\n    ext->cell_data[cell][0] = format.format_byte;\n    refr_size(table);\n}\n\n/**\n * Set a style of a table.\n * @param table pointer to table object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_table_set_style(lv_obj_t * table, lv_table_style_t type, lv_style_t * style)\n{\n    lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n\n    switch(type) {\n        case LV_TABLE_STYLE_BG:\n            lv_obj_set_style(table, style);\n            refr_size(table);\n            break;\n        case LV_TABLE_STYLE_CELL1:\n            ext->cell_style[0] = style;\n            refr_size(table);\n            break;\n        case LV_TABLE_STYLE_CELL2:\n            ext->cell_style[1] = style;\n            refr_size(table);\n            break;\n        case LV_TABLE_STYLE_CELL3:\n            ext->cell_style[2] = style;\n            refr_size(table);\n            break;\n        case LV_TABLE_STYLE_CELL4:\n            ext->cell_style[3] = style;\n            refr_size(table);\n            break;\n    }\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the value of a cell.\n * @param table pointer to a Table object\n * @param row id of the row [0 .. row_cnt -1]\n * @param col id of the column [0 .. col_cnt -1]\n * @return text in the cell\n */\nconst char * lv_table_get_cell_value(lv_obj_t * table, uint16_t row, uint16_t col)\n{\n    lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n    if(row >= ext->row_cnt || col >= ext->col_cnt) {\n        LV_LOG_WARN(\"lv_table_set_cell_value: invalid row or column\");\n        return \"\";\n    }\n    uint32_t cell = row * ext->col_cnt + col;\n\n    if(ext->cell_data[cell] == NULL) return \"\";\n\n    return &ext->cell_data[cell][1];    /*Skip the format byte*/\n}\n\n/**\n * Get the number of rows.\n * @param table table pointer to a Table object\n * @return number of rows.\n */\nuint16_t lv_table_get_row_cnt(lv_obj_t * table)\n{\n    lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n    return ext->row_cnt;\n}\n\n/**\n * Get the number of columns.\n * @param table table pointer to a Table object\n * @return number of columns.\n */\nuint16_t lv_table_get_col_cnt(lv_obj_t * table)\n{\n    lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n    return ext->col_cnt;\n}\n\n/**\n * Get the width of a column\n * @param table table pointer to a Table object\n * @param col_id id of the column [0 .. LV_TABLE_COL_MAX -1]\n * @return width of the column\n */\nlv_coord_t lv_table_get_col_width(lv_obj_t * table, uint16_t col_id)\n{\n    if(col_id >= LV_TABLE_COL_MAX) {\n        LV_LOG_WARN(\"lv_table_set_col_width: too big 'col_id'. Must be < LV_TABLE_COL_MAX.\");\n        return 0;\n    }\n\n    lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n    return ext->col_w[col_id];\n}\n\n/**\n * Get the text align of a cell\n * @param table pointer to a Table object\n * @param row id of the row [0 .. row_cnt -1]\n * @param col id of the column [0 .. col_cnt -1]\n * @return LV_LABEL_ALIGN_LEFT (default in case of error) or LV_LABEL_ALIGN_CENTER or LV_LABEL_ALIGN_RIGHT\n */\nlv_label_align_t lv_table_get_cell_align(lv_obj_t * table, uint16_t row, uint16_t col)\n{\n    lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n     if(row >= ext->row_cnt || col >= ext->col_cnt) {\n         LV_LOG_WARN(\"lv_table_set_cell_align: invalid row or column\");\n         return LV_LABEL_ALIGN_LEFT;    /*Just return with something*/\n     }\n     uint32_t cell = row * ext->col_cnt + col;\n\n     if(ext->cell_data[cell] == NULL) return LV_LABEL_ALIGN_LEFT;    /*Just return with something*/\n     else {\n         lv_table_cell_format_t format;\n         format.format_byte = ext->cell_data[cell][0];\n         return format.align;\n     }\n}\n\n/**\n * Get the type of a cell\n * @param table pointer to a Table object\n * @param row id of the row [0 .. row_cnt -1]\n * @param col id of the column [0 .. col_cnt -1]\n * @return 1,2,3 or 4\n */\nlv_label_align_t lv_table_get_cell_type(lv_obj_t * table, uint16_t row, uint16_t col)\n{\n    lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n     if(row >= ext->row_cnt || col >= ext->col_cnt) {\n         LV_LOG_WARN(\"lv_table_get_cell_type: invalid row or column\");\n         return 1;    /*Just return with something*/\n     }\n     uint32_t cell = row * ext->col_cnt + col;\n\n     if(ext->cell_data[cell] == NULL) return 1;    /*Just return with something*/\n     else {\n         lv_table_cell_format_t format;\n         format.format_byte = ext->cell_data[cell][0];\n         return format.type + 1;        /*0,1,2,3 is stored but user sees 1,2,3,4*/\n     }\n}\n\n/**\n * Get the crop property of a cell\n * @param table pointer to a Table object\n * @param row id of the row [0 .. row_cnt -1]\n * @param col id of the column [0 .. col_cnt -1]\n * @return true: text crop enabled; false: disabled\n */\nlv_label_align_t lv_table_get_cell_crop(lv_obj_t * table, uint16_t row, uint16_t col)\n{\n    lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n     if(row >= ext->row_cnt || col >= ext->col_cnt) {\n         LV_LOG_WARN(\"lv_table_get_cell_crop: invalid row or column\");\n         return false;    /*Just return with something*/\n     }\n     uint32_t cell = row * ext->col_cnt + col;\n\n     if(ext->cell_data[cell] == NULL) return false;    /*Just return with something*/\n     else {\n         lv_table_cell_format_t format;\n         format.format_byte = ext->cell_data[cell][0];\n         return format.crop;\n     }\n}\n\n/**\n * Get the cell merge attribute.\n * @param table table pointer to a Table object\n * @param row id of the row [0 .. row_cnt -1]\n * @param col id of the column [0 .. col_cnt -1]\n * @return true: merge right; false: don't merge right\n */\nbool lv_table_get_cell_merge_right(lv_obj_t * table, uint16_t row, uint16_t col)\n{\n    lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n    if(row >= ext->row_cnt || col >= ext->col_cnt) {\n        LV_LOG_WARN(\"lv_table_get_cell_merge_right: invalid row or column\");\n        return false;\n    }\n\n    uint32_t cell = row * ext->col_cnt + col;\n\n    if(ext->cell_data[cell] == NULL) return false;\n    else {\n        lv_table_cell_format_t format;\n        format.format_byte = ext->cell_data[cell][0];\n        return format.right_merge ? true : false;\n    }\n}\n\n/**\n * Get style of a table.\n * @param table pointer to table object\n * @param type which style should be get\n * @return style pointer to the style\n */\nlv_style_t * lv_table_get_style(const lv_obj_t * table, lv_table_style_t type)\n{\n    lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n    lv_style_t * style = NULL;\n\n    switch(type) {\n        case LV_TABLE_STYLE_BG:\n            style =  lv_obj_get_style(table);\n            break;\n        case LV_TABLE_STYLE_CELL1:\n            style = ext->cell_style[0];\n            break;\n        case LV_TABLE_STYLE_CELL2:\n            style = ext->cell_style[1];\n            break;\n        case LV_TABLE_STYLE_CELL3:\n            style = ext->cell_style[2];\n            break;\n        case LV_TABLE_STYLE_CELL4:\n            style = ext->cell_style[3];\n            break;\n        default:\n            return NULL;\n    }\n\n    return style;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Handle the drawing related tasks of the tables\n * @param table pointer to an object\n * @param mask the object will be drawn only in this area\n * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area\n *                                  (return 'true' if yes)\n *             LV_DESIGN_DRAW: draw the object (always return 'true')\n *             LV_DESIGN_DRAW_POST: drawing after every children are drawn\n * @param return true/false, depends on 'mode'\n */\nstatic bool lv_table_design(lv_obj_t * table, const lv_area_t * mask, lv_design_mode_t mode)\n{\n    /*Return false if the object is not covers the mask_p area*/\n    if(mode == LV_DESIGN_COVER_CHK) {\n        return false;\n    }\n    /*Draw the object*/\n    else if(mode == LV_DESIGN_DRAW_MAIN) {\n        ancestor_scrl_design(table, mask, mode);\n\n        lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n        lv_style_t * bg_style = lv_obj_get_style(table);\n        lv_style_t * cell_style;\n        lv_coord_t h_row;\n        lv_point_t txt_size;\n        lv_area_t cell_area;\n        lv_area_t txt_area;\n        lv_txt_flag_t txt_flags;\n        lv_opa_t opa_scale = lv_obj_get_opa_scale(table);\n\n        uint16_t col;\n        uint16_t row;\n        uint16_t cell = 0;\n\n        cell_area.y2 = table->coords.y1 + bg_style->body.padding.ver;\n        for(row = 0; row < ext->row_cnt; row++) {\n            h_row = get_row_height(table, row);\n\n            cell_area.y1 = cell_area.y2;\n            cell_area.y2 = cell_area.y1 + h_row;\n\n            cell_area.x2 = table->coords.x1 + bg_style->body.padding.hor;\n\n            for(col = 0; col < ext->col_cnt; col++) {\n\n                lv_table_cell_format_t format;\n                if(ext->cell_data[cell]) {\n                    format.format_byte = ext->cell_data[cell][0];\n                } else {\n                    format.right_merge = 0;\n                    format.align = LV_LABEL_ALIGN_LEFT;\n                    format.type = 0;\n                    format.crop = 1;\n                }\n\n                cell_style = ext->cell_style[format.type];\n                cell_area.x1 = cell_area.x2;\n                cell_area.x2 = cell_area.x1 + ext->col_w[col];\n\n                uint16_t col_merge = 0;\n                for(col_merge = 0; col_merge + col < ext->col_cnt - 1; col_merge ++) {\n\n                    if(ext->cell_data[cell + col_merge] != NULL) {\n                        format.format_byte = ext->cell_data[cell + col_merge][0];\n                        if(format.right_merge) cell_area.x2 += ext->col_w[col + col_merge + 1];\n                        else break;\n                    } else {\n                        break;\n                    }\n                }\n\n                lv_draw_rect(&cell_area, mask, cell_style, opa_scale);\n\n                if(ext->cell_data[cell]) {\n                    txt_area.x1 = cell_area.x1 + cell_style->body.padding.hor;\n                    txt_area.x2 = cell_area.x2 - cell_style->body.padding.hor;\n                    txt_area.y1 = cell_area.y1 + cell_style->body.padding.ver;\n                    txt_area.y2 = cell_area.y2 - cell_style->body.padding.ver;\n                    /*Align the content to the middle if not cropped*/\n                    if(format.crop == 0) {\n                        txt_flags = LV_TXT_FLAG_NONE;\n                    } else {\n                        txt_flags = LV_TXT_FLAG_EXPAND;\n                    }\n\n                    lv_txt_get_size(&txt_size, ext->cell_data[cell] + 1, cell_style->text.font,\n                                              cell_style->text.letter_space, cell_style->text.line_space, lv_area_get_width(&txt_area), txt_flags);\n\n                    /*Align the content to the middle if not cropped*/\n                    if(format.crop == 0) {\n                        txt_area.y1 = cell_area.y1 + h_row / 2 - txt_size.y / 2;\n                        txt_area.y2 = cell_area.y1 + h_row / 2 + txt_size.y / 2;\n                    }\n\n                    switch(format.align) {\n                    default:\n                    case LV_LABEL_ALIGN_LEFT:\n                        txt_flags |= LV_TXT_FLAG_NONE;\n                        break;\n                    case LV_LABEL_ALIGN_RIGHT:\n                        txt_flags |= LV_TXT_FLAG_RIGHT;\n                        break;\n                    case LV_LABEL_ALIGN_CENTER:\n                        txt_flags |= LV_TXT_FLAG_CENTER;\n                        break;\n                    }\n\n                    lv_area_t label_mask;\n                    bool label_mask_ok;\n                    label_mask_ok = lv_area_intersect(&label_mask, mask, &cell_area);\n                    if(label_mask_ok) {\n                        lv_draw_label(&txt_area, &label_mask, cell_style, opa_scale, ext->cell_data[cell] + 1, txt_flags, NULL);\n                    }\n                    /*Draw lines after '\\n's*/\n                    lv_point_t p1;\n                    lv_point_t p2;\n                    p1.x = cell_area.x1;\n                    p2.x = cell_area.x2;\n                    uint16_t i;\n                    for(i = 1; ext->cell_data[cell][i] != '\\0'; i++) {\n                        if(ext->cell_data[cell][i] == '\\n') {\n                            ext->cell_data[cell][i] = '\\0';\n                            lv_txt_get_size(&txt_size, ext->cell_data[cell] + 1, cell_style->text.font,\n                                                     cell_style->text.letter_space, cell_style->text.line_space, lv_area_get_width(&txt_area), txt_flags);\n\n                            p1.y = txt_area.y1 + txt_size.y + cell_style->text.line_space / 2;\n                            p2.y = txt_area.y1 + txt_size.y + cell_style->text.line_space / 2;\n                            lv_draw_line(&p1, &p2, mask, cell_style, opa_scale);\n\n                            ext->cell_data[cell][i] = '\\n';\n                        }\n                    }\n                }\n\n                cell += col_merge + 1;\n                col += col_merge;\n            }\n        }\n    }\n    /*Post draw when the children are drawn*/\n    else if(mode == LV_DESIGN_DRAW_POST) {\n\n    }\n\n    return true;\n}\n\n/**\n * Signal function of the table\n * @param table pointer to a table object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_table_signal(lv_obj_t * table, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(table, sign, param);\n    if(res != LV_RES_OK) return res;\n\n\n    if(sign == LV_SIGNAL_CLEANUP) {\n        /*Free the cell texts*/\n        lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n        uint16_t cell;\n        for(cell = 0; cell < ext->col_cnt * ext->row_cnt; cell++) {\n            if(ext->cell_data[cell]) {\n                lv_mem_free(ext->cell_data[cell]);\n                ext->cell_data[cell] = NULL;\n            }\n        }\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_table\";\n    }\n\n    return res;\n}\n\nstatic void refr_size(lv_obj_t * table)\n{\n    lv_coord_t h = 0;\n    lv_coord_t w = 0;\n\n    lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n\n    uint16_t i;\n    for(i= 0; i < ext->col_cnt; i++) {\n        w += ext->col_w[i];\n    }\n    for(i= 0; i < ext->row_cnt; i++) {\n        h += get_row_height(table, i);\n    }\n\n    lv_style_t * bg_style = lv_obj_get_style(table);\n\n    w += bg_style->body.padding.hor * 2;\n    h += bg_style->body.padding.ver * 2;\n\n    lv_obj_set_size(table, w + 1, h + 1);\n    lv_obj_invalidate(table);\n}\n\nstatic lv_coord_t get_row_height(lv_obj_t * table, uint16_t row_id)\n{\n    lv_table_ext_t * ext = lv_obj_get_ext_attr(table);\n    lv_point_t txt_size;\n    lv_coord_t txt_w;\n    lv_style_t * cell_style;\n\n    uint16_t row_start = row_id * ext->col_cnt;\n    uint16_t cell;\n    uint16_t col;\n    lv_coord_t h_max = lv_font_get_height(ext->cell_style[0]->text.font) + 2 * ext->cell_style[0]->body.padding.ver;\n\n    for(cell = row_start, col = 0; cell < row_start + ext->col_cnt; cell++, col ++) {\n        if(ext->cell_data[cell] != NULL) {\n\n            txt_w = ext->col_w[col];\n            uint16_t col_merge = 0;\n            for(col_merge = 0; col_merge + col < ext->col_cnt - 1; col_merge ++) {\n\n                if(ext->cell_data[cell + col_merge] != NULL) {\n                    lv_table_cell_format_t format;\n                    format.format_byte = ext->cell_data[cell + col_merge][0];\n                    if(format.right_merge) txt_w += ext->col_w[col + col_merge + 1];\n                    else break;\n                } else {\n                    break;\n                }\n            }\n\n            lv_table_cell_format_t format;\n            format.format_byte = ext->cell_data[cell][0];\n            cell_style = ext->cell_style[format.type];\n\n            /*With text crop assume 1 line*/\n            if(format.crop) {\n                h_max = LV_MATH_MAX(lv_font_get_height(cell_style->text.font) + 2 * cell_style->body.padding.ver, h_max);\n            }\n            /*Without text crop calculate the height of the text in the cell*/\n            else {\n                txt_w -= 2 * cell_style->body.padding.hor;\n\n                lv_txt_get_size(&txt_size, ext->cell_data[cell] + 1, cell_style->text.font,\n                        cell_style->text.letter_space, cell_style->text.line_space, txt_w, LV_TXT_FLAG_NONE);\n\n                h_max = LV_MATH_MAX(txt_size.y + 2 * cell_style->body.padding.ver, h_max);\n                cell += col_merge;\n                col += col_merge;\n            }\n        }\n    }\n\n    return h_max;\n}\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_table.h",
    "content": "/**\n * @file lv_table.h\n *\n */\n\n#ifndef LV_TABLE_H\n#define LV_TABLE_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_TABLE != 0\n\n/*Testing of dependencies*/\n#if USE_LV_LABEL == 0\n#error \"lv_table: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL  1) \"\n#endif\n\n#include \"../lv_core/lv_obj.h\"\n#include \"lv_label.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#ifndef LV_TABLE_COL_MAX\n#define LV_TABLE_COL_MAX    12\n#endif\n\n#define LV_TABLE_CELL_STYLE_CNT 4\n/**********************\n *      TYPEDEFS\n **********************/\n\ntypedef union {\n    struct {\n        uint8_t align:2;\n        uint8_t right_merge:1;\n        uint8_t type:2;\n        uint8_t crop:1;\n    };\n    uint8_t format_byte;\n}lv_table_cell_format_t;\n\n/*Data of table*/\ntypedef struct {\n    /*New data for this type */\n    uint16_t col_cnt;\n    uint16_t row_cnt;\n    char ** cell_data;\n    lv_style_t * cell_style[LV_TABLE_CELL_STYLE_CNT];\n    lv_coord_t col_w[LV_TABLE_COL_MAX];\n} lv_table_ext_t;\n\n\n/*Styles*/\nenum {\n    LV_TABLE_STYLE_BG,\n    LV_TABLE_STYLE_CELL1,\n    LV_TABLE_STYLE_CELL2,\n    LV_TABLE_STYLE_CELL3,\n    LV_TABLE_STYLE_CELL4,\n};\ntypedef uint8_t lv_table_style_t;\n\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a table object\n * @param par pointer to an object, it will be the parent of the new table\n * @param copy pointer to a table object, if not NULL then the new object will be copied from it\n * @return pointer to the created table\n */\nlv_obj_t * lv_table_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set the value of a cell.\n * @param table pointer to a Table object\n * @param row id of the row [0 .. row_cnt -1]\n * @param col id of the column [0 .. col_cnt -1]\n * @param txt text to display in the cell. It will be copied and saved so this variable is not required after this function call.\n */\nvoid lv_table_set_cell_value(lv_obj_t * table, uint16_t row, uint16_t col, const char * txt);\n\n/**\n * Set the number of rows\n * @param table table pointer to a Table object\n * @param row_cnt number of rows\n */\nvoid lv_table_set_row_cnt(lv_obj_t * table, uint16_t row_cnt);\n\n/**\n * Set the number of columns\n * @param table table pointer to a Table object\n * @param col_cnt number of columns. Must be < LV_TABLE_COL_MAX\n */\nvoid lv_table_set_col_cnt(lv_obj_t * table, uint16_t col_cnt);\n\n/**\n * Set the width of a column\n * @param table table pointer to a Table object\n * @param col_id id of the column [0 .. LV_TABLE_COL_MAX -1]\n * @param w width of the column\n */\nvoid lv_table_set_col_width(lv_obj_t * table, uint16_t col_id, lv_coord_t w);\n\n/**\n * Set the text align in a cell\n * @param table pointer to a Table object\n * @param row id of the row [0 .. row_cnt -1]\n * @param col id of the column [0 .. col_cnt -1]\n * @param align LV_LABEL_ALIGN_LEFT or LV_LABEL_ALIGN_CENTER or LV_LABEL_ALIGN_RIGHT\n */\nvoid lv_table_set_cell_align(lv_obj_t * table, uint16_t row, uint16_t col, lv_label_align_t align);\n\n/**\n * Set the type of a cell.\n * @param table pointer to a Table object\n * @param row id of the row [0 .. row_cnt -1]\n * @param col id of the column [0 .. col_cnt -1]\n * @param type 1,2,3 or 4. The cell style will be chosen accordingly.\n */\nvoid lv_table_set_cell_type(lv_obj_t * table, uint16_t row, uint16_t col, uint8_t type);\n\n/**\n * Set the cell crop. (Don't adjust the height of the cell according to its content)\n * @param table pointer to a Table object\n * @param row id of the row [0 .. row_cnt -1]\n * @param col id of the column [0 .. col_cnt -1]\n * @param crop true: crop the cell content; false: set the cell height to the content.\n */\nvoid lv_table_set_cell_crop(lv_obj_t * table, uint16_t row, uint16_t col, bool crop);\n\n/**\n * Merge a cell with the right neighbor. The value of the cell to the right won't be displayed.\n * @param table table pointer to a Table object\n * @param row id of the row [0 .. row_cnt -1]\n * @param col id of the column [0 .. col_cnt -1]\n * @param en true: merge right; false: don't merge right\n */\nvoid lv_table_set_cell_merge_right(lv_obj_t * table, uint16_t row, uint16_t col, bool en);\n\n/**\n * Set a style of a table.\n * @param table pointer to table object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_table_set_style(lv_obj_t * table, lv_table_style_t type, lv_style_t * style);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the value of a cell.\n * @param table pointer to a Table object\n * @param row id of the row [0 .. row_cnt -1]\n * @param col id of the column [0 .. col_cnt -1]\n * @return text in the cell\n */\nconst char * lv_table_get_cell_value(lv_obj_t * table, uint16_t row, uint16_t col);\n\n/**\n * Get the number of rows.\n * @param table table pointer to a Table object\n * @return number of rows.\n */\nuint16_t lv_table_get_row_cnt(lv_obj_t * table);\n\n/**\n * Get the number of columns.\n * @param table table pointer to a Table object\n * @return number of columns.\n */\nuint16_t lv_table_get_col_cnt(lv_obj_t * table);\n\n/**\n * Get the width of a column\n * @param table table pointer to a Table object\n * @param col_id id of the column [0 .. LV_TABLE_COL_MAX -1]\n * @return width of the column\n */\nlv_coord_t lv_table_get_col_width(lv_obj_t * table, uint16_t col_id);\n\n/**\n * Get the text align of a cell\n * @param table pointer to a Table object\n * @param row id of the row [0 .. row_cnt -1]\n * @param col id of the column [0 .. col_cnt -1]\n * @return LV_LABEL_ALIGN_LEFT (default in case of error) or LV_LABEL_ALIGN_CENTER or LV_LABEL_ALIGN_RIGHT\n */\nlv_label_align_t lv_table_get_cell_align(lv_obj_t * table, uint16_t row, uint16_t col);\n\n/**\n * Get the type of a cell\n * @param table pointer to a Table object\n * @param row id of the row [0 .. row_cnt -1]\n * @param col id of the column [0 .. col_cnt -1]\n * @return 1,2,3 or 4\n */\nlv_label_align_t lv_table_get_cell_type(lv_obj_t * table, uint16_t row, uint16_t col);\n\n\n/**\n * Get the crop property of a cell\n * @param table pointer to a Table object\n * @param row id of the row [0 .. row_cnt -1]\n * @param col id of the column [0 .. col_cnt -1]\n * @return true: text crop enabled; false: disabled\n */\nlv_label_align_t lv_table_get_cell_crop(lv_obj_t * table, uint16_t row, uint16_t col);\n\n/**\n * Get the cell merge attribute.\n * @param table table pointer to a Table object\n * @param row id of the row [0 .. row_cnt -1]\n * @param col id of the column [0 .. col_cnt -1]\n * @return true: merge right; false: don't merge right\n */\nbool lv_table_get_cell_merge_right(lv_obj_t * table, uint16_t row, uint16_t col);\n\n/**\n * Get style of a table.\n * @param table pointer to table object\n * @param type which style should be get\n * @return style pointer to the style\n */\nlv_style_t * lv_table_get_style(const lv_obj_t * table, lv_table_style_t type);\n\n/*=====================\n * Other functions\n *====================*/\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_TABLE*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_TABLE_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_tabview.c",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * @file lv_tab.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_tabview.h\"\n#if USE_LV_TABVIEW != 0\n\n#include \"lv_btnm.h\"\n#include \"../lv_themes/lv_theme.h\"\n#include \"../lv_misc/lv_anim.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#if USE_LV_ANIMATION\n#  ifndef LV_TABVIEW_ANIM_TIME\n#    define LV_TABVIEW_ANIM_TIME  300 /*Animation time of focusing to the a list element [ms] (0: no animation)  */\n#  endif\n#else\n#  undef  LV_TABVIEW_ANIM_TIME\n#  define LV_TABVIEW_ANIM_TIME  0   /*No animations*/\n#endif\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic lv_res_t lv_tabview_signal(lv_obj_t * tabview, lv_signal_t sign, void * param);\nstatic lv_res_t tabpage_signal(lv_obj_t * tab_page, lv_signal_t sign, void * param);\nstatic lv_res_t tabpage_scrl_signal(lv_obj_t * tab_scrl, lv_signal_t sign, void * param);\n\nstatic void tabpage_pressed_handler(lv_obj_t * tabview, lv_obj_t * tabpage);\nstatic void tabpage_pressing_handler(lv_obj_t * tabview, lv_obj_t * tabpage);\nstatic void tabpage_press_lost_handler(lv_obj_t * tabview, lv_obj_t * tabpage);\nstatic lv_res_t tab_btnm_action(lv_obj_t * tab_btnm, const char * tab_name);\nstatic void tabview_realign(lv_obj_t * tabview);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\nstatic lv_signal_func_t page_signal;\nstatic lv_signal_func_t page_scrl_signal;\nstatic const char * tab_def[] = {\"\"};\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a Tab view object\n * @param par pointer to an object, it will be the parent of the new tab\n * @param copy pointer to a tab object, if not NULL then the new object will be copied from it\n * @return pointer to the created tab\n */\nlv_obj_t * lv_tabview_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"tab view create started\");\n\n    /*Create the ancestor of tab*/\n    lv_obj_t * new_tabview = lv_obj_create(par, copy);\n    lv_mem_assert(new_tabview);\n    if(new_tabview == NULL) return NULL;\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_tabview);\n\n    /*Allocate the tab type specific extended data*/\n    lv_tabview_ext_t * ext = lv_obj_allocate_ext_attr(new_tabview, sizeof(lv_tabview_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    /*Initialize the allocated 'ext' */\n    ext->drag_hor = 0;\n    ext->draging = 0;\n    ext->slide_enable = 1;\n    ext->tab_cur = 0;\n    ext->point_last.x = 0;\n    ext->point_last.y = 0;\n    ext->content = NULL;\n    ext->indic = NULL;\n    ext->btns = NULL;\n    ext->tab_load_action = NULL;\n    ext->btns_pos = LV_TABVIEW_BTNS_POS_TOP;\n    ext->anim_time = LV_TABVIEW_ANIM_TIME;\n    ext->btns_hide = 0;\n\n\n    /*The signal and design functions are not copied so set them here*/\n    lv_obj_set_signal_func(new_tabview, lv_tabview_signal);\n\n    /*Init the new tab tab*/\n    if(copy == NULL) {\n        ext->tab_name_ptr = lv_mem_alloc(sizeof(char *));\n        lv_mem_assert(ext->tab_name_ptr);\n        if(ext->tab_name_ptr == NULL) return NULL;\n        ext->tab_name_ptr[0] = \"\";\n        ext->tab_cnt = 0;\n\n        lv_obj_set_size(new_tabview, LV_HOR_RES, LV_VER_RES);\n\n        ext->btns = lv_btnm_create(new_tabview, NULL);\n        lv_obj_set_height(ext->btns, 3 * LV_DPI / 4);\n        lv_btnm_set_map(ext->btns, tab_def);\n        lv_btnm_set_action(ext->btns, tab_btnm_action);\n        lv_btnm_set_toggle(ext->btns, true, 0);\n\n        ext->indic = lv_obj_create(ext->btns, NULL);\n        lv_obj_set_width(ext->indic, LV_DPI);\n        lv_obj_align(ext->indic, ext->btns, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);\n        lv_obj_set_click(ext->indic, false);\n\n        ext->content = lv_cont_create(new_tabview, NULL);\n        lv_cont_set_fit(ext->content, true, false);\n        lv_cont_set_layout(ext->content, LV_LAYOUT_ROW_T);\n        lv_cont_set_style(ext->content, &lv_style_transp_tight);\n        lv_obj_set_height(ext->content, LV_VER_RES - lv_obj_get_height(ext->btns));\n        lv_obj_align(ext->content, ext->btns, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BG, th->tabview.bg);\n            lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_INDIC, th->tabview.indic);\n            lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_BG, th->tabview.btn.bg);\n            lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_REL, th->tabview.btn.rel);\n            lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_PR, th->tabview.btn.pr);\n            lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_TGL_REL, th->tabview.btn.tgl_rel);\n            lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_TGL_PR, th->tabview.btn.tgl_pr);\n        } else {\n            lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BG, &lv_style_plain);\n            lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_BG, &lv_style_transp);\n            lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_INDIC, &lv_style_plain_color);\n        }\n    }\n    /*Copy an existing tab view*/\n    else {\n        lv_tabview_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        ext->point_last.x = 0;\n        ext->point_last.y = 0;\n        ext->btns = lv_btnm_create(new_tabview, copy_ext->btns);\n        ext->indic = lv_obj_create(ext->btns, copy_ext->indic);\n        ext->content = lv_cont_create(new_tabview, copy_ext->content);\n        ext->anim_time = copy_ext->anim_time;\n        ext->tab_load_action = copy_ext->tab_load_action;\n\n        ext->tab_name_ptr = lv_mem_alloc(sizeof(char *));\n        lv_mem_assert(ext->tab_name_ptr);\n        if(ext->tab_name_ptr == NULL) return NULL;\n        ext->tab_name_ptr[0] = \"\";\n        lv_btnm_set_map(ext->btns, ext->tab_name_ptr);\n\n        uint16_t i;\n        lv_obj_t * new_tab;\n        lv_obj_t * copy_tab;\n        for(i = 0; i < copy_ext->tab_cnt; i++) {\n            new_tab = lv_tabview_add_tab(new_tabview, copy_ext->tab_name_ptr[i]);\n            copy_tab = lv_tabview_get_tab(copy, i);\n            lv_page_set_style(new_tab, LV_PAGE_STYLE_BG, lv_page_get_style(copy_tab, LV_PAGE_STYLE_BG));\n            lv_page_set_style(new_tab, LV_PAGE_STYLE_SCRL, lv_page_get_style(copy_tab, LV_PAGE_STYLE_SCRL));\n            lv_page_set_style(new_tab, LV_PAGE_STYLE_SB, lv_page_get_style(copy_tab, LV_PAGE_STYLE_SB));\n        }\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_tabview);\n    }\n\n\n    LV_LOG_INFO(\"tab view created\");\n\n    return new_tabview;\n}\n\n/**\n * Delete all children of the scrl object, without deleting scrl child.\n * @param obj pointer to an object\n */\nvoid lv_tabview_clean(lv_obj_t * obj)\n{\n    lv_obj_t * scrl = lv_page_get_scrl(obj);\n    lv_obj_clean(scrl);\n}\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n/**\n * Add a new tab with the given name\n * @param tabview pointer to Tab view object where to ass the new tab\n * @param name the text on the tab button\n * @return pointer to the created page object (lv_page). You can create your content here\n */\nlv_obj_t * lv_tabview_add_tab(lv_obj_t * tabview, const char * name)\n{\n    lv_tabview_ext_t  * ext = lv_obj_get_ext_attr(tabview);\n\n    /*Create the container page*/\n    lv_obj_t * h = lv_page_create(ext->content, NULL);\n    lv_obj_set_size(h, lv_obj_get_width(tabview), lv_obj_get_height(ext->content));\n    lv_page_set_sb_mode(h, LV_SB_MODE_OFF); // Important!\n    lv_page_set_style(h, LV_PAGE_STYLE_BG, &lv_style_transp);\n    lv_page_set_style(h, LV_PAGE_STYLE_SCRL, &lv_style_transp);\n\n    if(page_signal == NULL) page_signal = lv_obj_get_signal_func(h);\n    if(page_scrl_signal == NULL) page_scrl_signal = lv_obj_get_signal_func(lv_page_get_scrl(h));\n    lv_obj_set_signal_func(h, tabpage_signal);\n    lv_obj_set_signal_func(lv_page_get_scrl(h), tabpage_scrl_signal);\n\n    /*Extend the button matrix map with the new name*/\n    char * name_dm;\n    if((name[0] & LV_BTNM_CTRL_MASK) == LV_BTNM_CTRL_CODE) { /*If control byte presented let is*/\n        name_dm = lv_mem_alloc(strlen(name) + 1); /*+1 for the the closing '\\0' */\n        lv_mem_assert(name_dm);\n        if(name_dm == NULL) return NULL;\n        strcpy(name_dm, name);\n    } else { /*Set a no long press control byte is not presented*/\n        name_dm = lv_mem_alloc(strlen(name) + 2); /*+1 for the the closing '\\0' and +1 for the control byte */\n        lv_mem_assert(name_dm);\n        if(name_dm == NULL) return NULL;\n        name_dm[0] = '\\221';\n        strcpy(&name_dm[1], name);\n    }\n\n    ext->tab_cnt++;\n    ext->tab_name_ptr = lv_mem_realloc(ext->tab_name_ptr, sizeof(char *) * (ext->tab_cnt + 1));\n    lv_mem_assert(ext->tab_name_ptr);\n    if(ext->tab_name_ptr == NULL) return NULL;\n\n    ext->tab_name_ptr[ext->tab_cnt - 1] = name_dm;\n    ext->tab_name_ptr[ext->tab_cnt] = \"\";\n\n    lv_btnm_set_map(ext->btns, ext->tab_name_ptr);\n\n    /*Modify the indicator size*/\n    lv_style_t * style_tabs = lv_obj_get_style(ext->btns);\n    lv_coord_t indic_width = (lv_obj_get_width(tabview) - style_tabs->body.padding.inner * (ext->tab_cnt - 1) - 2 * style_tabs->body.padding.hor) / ext->tab_cnt;\n    lv_obj_set_width(ext->indic, indic_width);\n    lv_obj_set_x(ext->indic, indic_width * ext->tab_cur + style_tabs->body.padding.inner * ext->tab_cur + style_tabs->body.padding.hor);\n\n    /*Set the first btn as active*/\n    if(ext->tab_cnt == 1) {\n        ext->tab_cur = 0;\n        lv_tabview_set_tab_act(tabview, 0, false);\n        tabview_realign(tabview);       /*To set the proper btns height*/\n    }\n\n    return h;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a new tab\n * @param tabview pointer to Tab view object\n * @param id index of a tab to load\n * @param anim_en true: set with sliding animation; false: set immediately\n */\nvoid lv_tabview_set_tab_act(lv_obj_t * tabview, uint16_t id, bool anim_en)\n{\n#if USE_LV_ANIMATION == 0\n    anim_en = false;\n#endif\n    lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview);\n\n    lv_style_t * style = lv_obj_get_style(ext->content);\n\n    lv_res_t res = LV_RES_OK;\n    if(id >= ext->tab_cnt) id = ext->tab_cnt - 1;\n    if(ext->tab_load_action && id != ext->tab_cur) res = ext->tab_load_action(tabview, id);\n    if(res != LV_RES_OK) return;        /*Prevent the tab loading*/\n\n    ext->tab_cur = id;\n\n    lv_coord_t cont_x = -(lv_obj_get_width(tabview) * id + style->body.padding.inner * id + style->body.padding.hor);\n    if(ext->anim_time == 0 || anim_en == false) {\n        lv_obj_set_x(ext->content, cont_x);\n    } else {\n#if USE_LV_ANIMATION\n        lv_anim_t a;\n        a.var = ext->content;\n        a.start = lv_obj_get_x(ext->content);\n        a.end = cont_x;\n        a.fp = (lv_anim_fp_t)lv_obj_set_x;\n        a.path = lv_anim_path_linear;\n        a.end_cb = NULL;\n        a.act_time = 0;\n        a.time = ext->anim_time;\n        a.playback = 0;\n        a.playback_pause = 0;\n        a.repeat = 0;\n        a.repeat_pause = 0;\n        lv_anim_create(&a);\n#endif\n    }\n\n    /*Move the indicator*/\n    lv_coord_t indic_width = lv_obj_get_width(ext->indic);\n    lv_style_t * tabs_style = lv_obj_get_style(ext->btns);\n    lv_coord_t indic_x = indic_width * id + tabs_style->body.padding.inner * id + tabs_style->body.padding.hor;\n\n    if(ext->anim_time == 0 || anim_en == false) {\n        lv_obj_set_x(ext->indic, indic_x);\n    } else {\n#if USE_LV_ANIMATION\n        lv_anim_t a;\n        a.var = ext->indic;\n        a.start = lv_obj_get_x(ext->indic);\n        a.end = indic_x;\n        a.fp = (lv_anim_fp_t)lv_obj_set_x;\n        a.path = lv_anim_path_linear;\n        a.end_cb = NULL;\n        a.act_time = 0;\n        a.time = ext->anim_time;\n        a.playback = 0;\n        a.playback_pause = 0;\n        a.repeat = 0;\n        a.repeat_pause = 0;\n        lv_anim_create(&a);\n#endif\n    }\n\n    lv_btnm_set_toggle(ext->btns, true, ext->tab_cur);\n}\n\n/**\n * Set an action to call when a tab is loaded (Good to create content only if required)\n * lv_tabview_get_act() still gives the current (old) tab (to remove content from here)\n * @param tabview pointer to a tabview object\n * @param action pointer to a function to call when a btn is loaded\n */\nvoid lv_tabview_set_tab_load_action(lv_obj_t * tabview, lv_tabview_action_t action)\n{\n    lv_tabview_ext_t  * ext = lv_obj_get_ext_attr(tabview);\n    ext->tab_load_action = action;\n}\n\n/**\n * Enable horizontal sliding with touch pad\n * @param tabview pointer to Tab view object\n * @param en true: enable sliding; false: disable sliding\n */\nvoid lv_tabview_set_sliding(lv_obj_t * tabview, bool en)\n{\n    lv_tabview_ext_t  * ext = lv_obj_get_ext_attr(tabview);\n    ext->slide_enable = en == false ? 0 : 1;\n}\n\n/**\n * Set the animation time of tab view when a new tab is loaded\n * @param tabview pointer to Tab view object\n * @param anim_time_ms time of animation in milliseconds\n */\nvoid lv_tabview_set_anim_time(lv_obj_t * tabview, uint16_t anim_time)\n{\n    lv_tabview_ext_t  * ext = lv_obj_get_ext_attr(tabview);\n#if USE_LV_ANIMATION == 0\n    anim_time = 0;\n#endif\n    ext->anim_time = anim_time;\n}\n\n/**\n * Set the style of a tab view\n * @param tabview pointer to a tan view object\n * @param type which style should be set\n * @param style pointer to the new style\n */\nvoid lv_tabview_set_style(lv_obj_t * tabview, lv_tabview_style_t type, lv_style_t * style)\n{\n    lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview);\n\n    switch(type) {\n        case LV_TABVIEW_STYLE_BG:\n            lv_obj_set_style(tabview, style);\n            break;\n        case LV_TABVIEW_STYLE_BTN_BG:\n            lv_btnm_set_style(ext->btns, LV_BTNM_STYLE_BG, style);\n            tabview_realign(tabview);\n            break;\n        case LV_TABVIEW_STYLE_BTN_REL:\n            lv_btnm_set_style(ext->btns, LV_BTNM_STYLE_BTN_REL, style);\n            tabview_realign(tabview);\n            break;\n        case LV_TABVIEW_STYLE_BTN_PR:\n            lv_btnm_set_style(ext->btns, LV_BTNM_STYLE_BTN_PR, style);\n            break;\n        case LV_TABVIEW_STYLE_BTN_TGL_REL:\n            lv_btnm_set_style(ext->btns, LV_BTNM_STYLE_BTN_TGL_REL, style);\n            break;\n        case LV_TABVIEW_STYLE_BTN_TGL_PR:\n            lv_btnm_set_style(ext->btns, LV_BTNM_STYLE_BTN_TGL_PR, style);\n            break;\n        case LV_TABVIEW_STYLE_INDIC:\n            lv_obj_set_style(ext->indic, style);\n            lv_obj_set_height(ext->indic, style->body.padding.inner);\n            tabview_realign(tabview);\n            break;\n    }\n}\n\n/**\n * Set the position of tab select buttons\n * @param tabview pointer to a tan view object\n * @param btns_pos which button position\n */\nvoid lv_tabview_set_btns_pos(lv_obj_t * tabview, lv_tabview_btns_pos_t btns_pos)\n{\n    lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview);\n\n    ext->btns_pos = btns_pos;\n    tabview_realign(tabview);\n}\n\n/**\n * Set whether tab buttons are hidden\n * @param tabview pointer to a tab view object\n * @param en whether tab buttons are hidden\n */\nvoid lv_tabview_set_btns_hidden(lv_obj_t *tabview, bool en)\n{\n\tlv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview);\n\n\text->btns_hide = en;\n\ttabview_realign(tabview);\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the index of the currently active tab\n * @param tabview pointer to Tab view object\n * @return the active btn index\n */\nuint16_t lv_tabview_get_tab_act(const lv_obj_t * tabview)\n{\n    lv_tabview_ext_t  * ext = lv_obj_get_ext_attr(tabview);\n    return ext->tab_cur;\n}\n\n/**\n * Get the number of tabs\n * @param tabview pointer to Tab view object\n * @return btn count\n */\nuint16_t lv_tabview_get_tab_count(const lv_obj_t * tabview)\n{\n    lv_tabview_ext_t  * ext = lv_obj_get_ext_attr(tabview);\n    return ext->tab_cnt;\n}\n\n/**\n * Get the page (content area) of a tab\n * @param tabview pointer to Tab view object\n * @param id index of the btn (>= 0)\n * @return pointer to page (lv_page) object\n */\nlv_obj_t * lv_tabview_get_tab(const lv_obj_t * tabview, uint16_t id)\n{\n    lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview);\n    uint16_t i = 0;\n    lv_obj_t * page = lv_obj_get_child_back(ext->content, NULL);\n\n    while(page != NULL && i != id) {\n        i++;\n        page = lv_obj_get_child_back(ext->content, page);\n    }\n\n    if(i == id) return page;\n\n    return NULL;\n}\n\n/**\n * Get the tab load action\n * @param tabview pointer to a tabview object\n * @param return the current btn load action\n */\nlv_tabview_action_t lv_tabview_get_tab_load_action(const lv_obj_t * tabview)\n{\n    lv_tabview_ext_t  * ext = lv_obj_get_ext_attr(tabview);\n    return ext->tab_load_action;\n}\n\n/**\n * Get horizontal sliding is enabled or not\n * @param tabview pointer to Tab view object\n * @return true: enable sliding; false: disable sliding\n */\nbool lv_tabview_get_sliding(const lv_obj_t * tabview)\n{\n    lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview);\n    return ext->slide_enable ? true : false;\n}\n\n/**\n * Get the animation time of tab view when a new tab is loaded\n * @param tabview pointer to Tab view object\n * @return time of animation in milliseconds\n */\nuint16_t lv_tabview_get_anim_time(const lv_obj_t * tabview)\n{\n    lv_tabview_ext_t  * ext = lv_obj_get_ext_attr(tabview);\n    return ext->anim_time;\n}\n\n/**\n * Get a style of a tab view\n * @param tabview pointer to a ab view object\n * @param type which style should be get\n * @return style pointer to a style\n */\nlv_style_t * lv_tabview_get_style(const lv_obj_t * tabview, lv_tabview_style_t type)\n{\n    lv_style_t * style = NULL;\n    lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview);\n\n    switch(type) {\n        case LV_TABVIEW_STYLE_BG:\n            style = lv_obj_get_style(tabview);\n            break;\n        case LV_TABVIEW_STYLE_BTN_BG:\n            style = lv_btnm_get_style(ext->btns, LV_BTNM_STYLE_BG);\n            break;\n        case LV_TABVIEW_STYLE_BTN_REL:\n            style = lv_btnm_get_style(ext->btns, LV_BTNM_STYLE_BTN_REL);\n            break;\n        case LV_TABVIEW_STYLE_BTN_PR:\n            style = lv_btnm_get_style(ext->btns, LV_BTNM_STYLE_BTN_PR);\n            break;\n        case LV_TABVIEW_STYLE_BTN_TGL_REL:\n            style = lv_btnm_get_style(ext->btns, LV_BTNM_STYLE_BTN_TGL_REL);\n            break;\n        case LV_TABVIEW_STYLE_BTN_TGL_PR:\n            style = lv_btnm_get_style(ext->btns, LV_BTNM_STYLE_BTN_TGL_PR);\n            break;\n        default:\n            style = NULL;\n            break;\n    }\n\n    return style;\n}\n\n/**\n * Get position of tab select buttons\n * @param tabview pointer to a ab view object\n */\nlv_tabview_btns_pos_t lv_tabview_get_btns_pos(const lv_obj_t * tabview)\n{\n    lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview);\n    return ext->btns_pos;\n}\n\n/**\n * Get whether tab buttons are hidden\n * @param tabview pointer to a tab view object\n * @return whether tab buttons are hidden\n */\nbool lv_tabview_get_btns_hidden(const lv_obj_t *tabview)\n{\n\tlv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview);\n\n\treturn ext->btns_hide;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Signal function of the Tab view\n * @param tabview pointer to a Tab view object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_tabview_signal(lv_obj_t * tabview, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(tabview, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview);\n    if(sign == LV_SIGNAL_CLEANUP) {\n        uint8_t i;\n        for(i = 0; ext->tab_name_ptr[i][0] != '\\0'; i++) lv_mem_free(ext->tab_name_ptr[i]);\n\n        lv_mem_free(ext->tab_name_ptr);\n        ext->tab_name_ptr = NULL;\n        ext->btns = NULL;     /*These objects were children so they are already invalid*/\n        ext->content = NULL;\n    } else if(sign == LV_SIGNAL_CORD_CHG) {\n        if(ext->content != NULL &&\n                (lv_obj_get_width(tabview) != lv_area_get_width(param) ||\n                 lv_obj_get_height(tabview) != lv_area_get_height(param))) {\n            tabview_realign(tabview);\n        }\n    } else if(sign == LV_SIGNAL_FOCUS || sign == LV_SIGNAL_DEFOCUS || sign == LV_SIGNAL_CONTROLL) {\n        /* The button matrix is not in a group (the tab view is in it) but it should handle the group signals.\n         * So propagate the related signals to the button matrix manually*/\n        if(ext->btns) {\n            ext->btns->signal_func(ext->btns, sign, param);\n        }\n        if(sign == LV_SIGNAL_FOCUS) {\n            lv_hal_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act());\n            /*With ENCODER select the first button only in edit mode*/\n            if(indev_type == LV_INDEV_TYPE_ENCODER) {\n#if USE_LV_GROUP\n                lv_group_t * g = lv_obj_get_group(tabview);\n                if(lv_group_get_editing(g)) {\n                    lv_btnm_ext_t * btnm_ext = lv_obj_get_ext_attr(ext->btns);\n                    btnm_ext->btn_id_pr = 0;\n                    lv_obj_invalidate(ext->btns);\n                }\n#endif\n            } else {\n                lv_btnm_ext_t * btnm_ext = lv_obj_get_ext_attr(ext->btns);\n                btnm_ext->btn_id_pr = 0;\n                lv_obj_invalidate(ext->btns);\n            }\n        }\n    } else if(sign == LV_SIGNAL_GET_EDITABLE) {\n        bool * editable = (bool *)param;\n        *editable = true;\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_tabview\";\n    }\n\n    return res;\n}\n\n\n/**\n * Signal function of a tab's page\n * @param tab pointer to a tab page object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t tabpage_signal(lv_obj_t * tab_page, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = page_signal(tab_page, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    lv_obj_t * cont = lv_obj_get_parent(tab_page);\n    lv_obj_t * tabview = lv_obj_get_parent(cont);\n\n    if(lv_tabview_get_sliding(tabview) == false) return res;\n\n    if(sign == LV_SIGNAL_PRESSED) {\n        tabpage_pressed_handler(tabview, tab_page);\n    } else if(sign == LV_SIGNAL_PRESSING) {\n        tabpage_pressing_handler(tabview, tab_page);\n    } else if(sign == LV_SIGNAL_RELEASED || sign == LV_SIGNAL_PRESS_LOST) {\n        tabpage_press_lost_handler(tabview, tab_page);\n    }\n\n    return res;\n}\n/**\n * Signal function of the tab page's scrollable object\n * @param tab_scrl pointer to a tab page's scrollable object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t tabpage_scrl_signal(lv_obj_t * tab_scrl, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = page_scrl_signal(tab_scrl, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    lv_obj_t * tab_page = lv_obj_get_parent(tab_scrl);\n    lv_obj_t * cont = lv_obj_get_parent(tab_page);\n    lv_obj_t * tabview = lv_obj_get_parent(cont);\n\n    if(lv_tabview_get_sliding(tabview) == false) return res;\n\n    if(sign == LV_SIGNAL_PRESSED) {\n        tabpage_pressed_handler(tabview, tab_page);\n    } else if(sign == LV_SIGNAL_PRESSING) {\n        tabpage_pressing_handler(tabview, tab_page);\n    } else if(sign == LV_SIGNAL_RELEASED || sign == LV_SIGNAL_PRESS_LOST) {\n        tabpage_press_lost_handler(tabview, tab_page);\n    }\n\n    return res;\n}\n\n/**\n * Called when a tab's page or scrollable object is pressed\n * @param tabview pointer to the btn view object\n * @param tabpage pointer to the page of a btn\n */\nstatic void tabpage_pressed_handler(lv_obj_t * tabview, lv_obj_t * tabpage)\n{\n    (void)tabpage;\n\n    lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview);\n    lv_indev_t * indev = lv_indev_get_act();\n    lv_indev_get_point(indev, &ext->point_last);\n}\n\n/**\n * Called when a tab's page or scrollable object is being pressed\n * @param tabview pointer to the btn view object\n * @param tabpage pointer to the page of a btn\n */\nstatic void tabpage_pressing_handler(lv_obj_t * tabview, lv_obj_t * tabpage)\n{\n    lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview);\n    lv_indev_t * indev = lv_indev_get_act();\n    lv_point_t point_act;\n    lv_indev_get_point(indev, &point_act);\n    lv_coord_t x_diff = point_act.x - ext->point_last.x;\n    lv_coord_t y_diff = point_act.y - ext->point_last.y;\n\n    if(ext->draging == 0) {\n        if(x_diff >= LV_INDEV_DRAG_LIMIT || x_diff <= -LV_INDEV_DRAG_LIMIT) {\n            ext->drag_hor = 1;\n            ext->draging = 1;\n            lv_obj_set_drag(lv_page_get_scrl(tabpage), false);\n        } else if(y_diff >= LV_INDEV_DRAG_LIMIT || y_diff <= -LV_INDEV_DRAG_LIMIT) {\n            ext->drag_hor = 0;\n            ext->draging = 1;\n        }\n    }\n    if(ext->drag_hor) {\n        lv_obj_set_x(ext->content, lv_obj_get_x(ext->content) + point_act.x - ext->point_last.x);\n        ext->point_last.x = point_act.x;\n        ext->point_last.y = point_act.y;\n\n        /*Move the indicator*/\n        lv_coord_t indic_width = lv_obj_get_width(ext->indic);\n        lv_style_t * tabs_style = lv_obj_get_style(ext->btns);\n        lv_style_t * indic_style = lv_obj_get_style(ext->indic);\n        lv_coord_t p = ((tabpage->coords.x1 - tabview->coords.x1) * (indic_width + tabs_style->body.padding.inner)) / lv_obj_get_width(tabview);\n\n        lv_obj_set_x(ext->indic, indic_width * ext->tab_cur + tabs_style->body.padding.inner * ext->tab_cur + indic_style->body.padding.hor - p);\n    }\n}\n\n/**\n * Called when a tab's page or scrollable object is released or the press id lost\n * @param tabview pointer to the btn view object\n * @param tabpage pointer to the page of a btn\n */\nstatic void tabpage_press_lost_handler(lv_obj_t * tabview, lv_obj_t * tabpage)\n{\n    lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview);\n    ext->drag_hor = 0;\n    ext->draging = 0;\n\n    lv_obj_set_drag(lv_page_get_scrl(tabpage), true);\n\n    lv_indev_t * indev = lv_indev_get_act();\n    lv_point_t point_act;\n    lv_indev_get_point(indev, &point_act);\n    lv_point_t vect;\n    lv_indev_get_vect(indev, &vect);\n    lv_coord_t x_predict = 0;\n\n    while(vect.x != 0)   {\n        x_predict += vect.x;\n        vect.x = vect.x * (100 - LV_INDEV_DRAG_THROW) / 100;\n    }\n\n    lv_coord_t page_x1 = tabpage->coords.x1 - tabview->coords.x1 + x_predict;\n    lv_coord_t page_x2 = page_x1 + lv_obj_get_width(tabpage);\n    lv_coord_t treshold = lv_obj_get_width(tabview) / 2;\n\n    uint16_t tab_cur = ext->tab_cur;\n    if(page_x1 > treshold) {\n        if(tab_cur != 0) tab_cur--;\n    } else if(page_x2 < treshold) {\n        if(tab_cur < ext->tab_cnt - 1) tab_cur++;\n    }\n\n    lv_tabview_set_tab_act(tabview, tab_cur, true);\n}\n\n/**\n * Called when a tab button is released\n * @param tab_btnm pointer to the tab's button matrix object\n * @param id the id of the tab (>= 0)\n * @return LV_ACTION_RES_OK because the button matrix in not deleted in the function\n */\nstatic lv_res_t tab_btnm_action(lv_obj_t * tab_btnm, const char * tab_name)\n{\n    lv_obj_t * tab = lv_obj_get_parent(tab_btnm);\n    const char ** tabs_map = lv_btnm_get_map(tab_btnm);\n\n    uint8_t i = 0;\n\n    while(tabs_map[i][0] != '\\0') {\n        if(strcmp(&tabs_map[i][1], tab_name) == 0) break;   /*[1] to skip the control byte*/\n        i++;\n    }\n\n    lv_tabview_set_tab_act(tab, i, true);\n\n    return LV_RES_OK;\n}\n\n/**\n * Realign and resize the elements of Tab view\n * @param tabview pointer to a Tab view object\n */\nstatic void tabview_realign(lv_obj_t * tabview)\n{\n    lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview);\n\n    lv_obj_set_width(ext->btns, lv_obj_get_width(tabview));\n\n    if(ext->btns_hide) {\n    \tlv_obj_set_hidden(ext->btns, true);\n    \tlv_obj_set_hidden(ext->indic, true);\n    \tlv_obj_set_height(ext->content, lv_obj_get_height(tabview));\n    \tlv_obj_align(ext->content, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0);\n    }\n    else if(ext->tab_cnt != 0) {\n    \tlv_obj_set_hidden(ext->btns, false);\n    \tlv_obj_set_hidden(ext->indic, false);\n\n        lv_style_t * style_btn_bg = lv_tabview_get_style(tabview, LV_TABVIEW_STYLE_BTN_BG);\n        lv_style_t * style_btn_rel = lv_tabview_get_style(tabview, LV_TABVIEW_STYLE_BTN_REL);\n\n        /*Set the indicator widths*/\n        lv_coord_t indic_width = (lv_obj_get_width(tabview) - style_btn_bg->body.padding.inner * (ext->tab_cnt - 1) -\n                                  2 * style_btn_bg->body.padding.hor) / ext->tab_cnt;\n        lv_obj_set_width(ext->indic, indic_width);\n\n        /*Set the tabs height*/\n        lv_coord_t btns_height = lv_font_get_height(style_btn_rel->text.font) +\n                                 2 * style_btn_rel->body.padding.ver +\n                                 2 * style_btn_bg->body.padding.ver;\n        lv_obj_set_height(ext->btns, btns_height);\n\n        lv_obj_set_height(ext->content, lv_obj_get_height(tabview) - lv_obj_get_height(ext->btns));\n\n        switch(ext->btns_pos) {\n\t\t\tcase LV_TABVIEW_BTNS_POS_TOP:\n\t\t\t\tlv_obj_align(ext->btns, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0);\n\t\t\t\tlv_obj_align(ext->content, ext->btns, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);\n\t\t\t\tbreak;\n\t\t\tcase LV_TABVIEW_BTNS_POS_BOTTOM:\n\t\t\t\tlv_obj_align(ext->content, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0);\n\t\t\t\tlv_obj_align(ext->btns, ext->content, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);\n\t\t\t\tbreak;\n\t\t}\n    }\n\n    lv_obj_t * pages = lv_obj_get_child(ext->content, NULL);\n    while(pages != NULL) {\n        if(lv_obj_get_signal_func(pages) == tabpage_signal) {  /*Be sure adjust only the pages (user can other things)*/\n            lv_obj_set_size(pages, lv_obj_get_width(tabview), lv_obj_get_height(ext->content));\n        }\n        pages = lv_obj_get_child(ext->content, pages);\n    }\n\n    if(!ext->btns_hide) {\n    \tlv_obj_align(ext->indic, ext->btns, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);\n    }\n\n    lv_tabview_set_tab_act(tabview, ext->tab_cur, false);\n}\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_tabview.h",
    "content": "/**\n * @file lv_tabview.h\n *\n */\n\n#ifndef LV_TABVIEW_H\n#define LV_TABVIEW_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_TABVIEW != 0\n\n/*Testing of dependencies*/\n#if USE_LV_BTNM == 0\n#error \"lv_tabview: lv_btnm is required. Enable it in lv_conf.h (USE_LV_BTNM  1) \"\n#endif\n\n#if USE_LV_PAGE == 0\n#error \"lv_tabview: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE  1) \"\n#endif\n\n#include \"../lv_core/lv_obj.h\"\n#include \"../lv_objx/lv_win.h\"\n#include \"../lv_objx/lv_page.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/* parametes: pointer to a tabview object, tab_id\n * return: LV_RES_INV: to prevent the loading of the tab;  LV_RES_OK: if everything is fine*/\ntypedef lv_res_t (*lv_tabview_action_t)(lv_obj_t *, uint16_t);\n\n\nenum {\n    LV_TABVIEW_BTNS_POS_TOP,\n    LV_TABVIEW_BTNS_POS_BOTTOM,\n};\ntypedef uint8_t lv_tabview_btns_pos_t;\n\n/*Data of tab*/\ntypedef struct\n{\n    /*Ext. of ancestor*/\n    /*New data for this type */\n    lv_obj_t * btns;\n    lv_obj_t * indic;\n    lv_obj_t * content;   /*A rectangle to show the current tab*/\n    const char ** tab_name_ptr;\n    lv_point_t point_last;\n    uint16_t tab_cur;\n    uint16_t tab_cnt;\n    uint16_t anim_time;\n    uint8_t slide_enable :1;    /*1: enable horizontal sliding by touch pad*/\n    uint8_t draging :1;\n    uint8_t drag_hor :1;\n    uint8_t btns_hide :1;\n    lv_tabview_btns_pos_t btns_pos :1;\n    lv_tabview_action_t tab_load_action;\n} lv_tabview_ext_t;\n\nenum {\n    LV_TABVIEW_STYLE_BG,\n    LV_TABVIEW_STYLE_INDIC,\n    LV_TABVIEW_STYLE_BTN_BG,\n    LV_TABVIEW_STYLE_BTN_REL,\n    LV_TABVIEW_STYLE_BTN_PR,\n    LV_TABVIEW_STYLE_BTN_TGL_REL,\n    LV_TABVIEW_STYLE_BTN_TGL_PR,\n};\ntypedef uint8_t lv_tabview_style_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n\n/**\n * Create a Tab view object\n * @param par pointer to an object, it will be the parent of the new tab\n * @param copy pointer to a tab object, if not NULL then the new object will be copied from it\n * @return pointer to the created tab\n */\nlv_obj_t * lv_tabview_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/**\n * Delete all children of the scrl object, without deleting scrl child.\n * @param obj pointer to an object\n */\nvoid lv_tabview_clean(lv_obj_t *obj);\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n/**\n * Add a new tab with the given name\n * @param tabview pointer to Tab view object where to ass the new tab\n * @param name the text on the tab button\n * @return pointer to the created page object (lv_page). You can create your content here\n */\nlv_obj_t * lv_tabview_add_tab(lv_obj_t * tabview, const char * name);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set a new tab\n * @param tabview pointer to Tab view object\n * @param id index of a tab to load\n * @param anim_en true: set with sliding animation; false: set immediately\n */\nvoid lv_tabview_set_tab_act(lv_obj_t * tabview, uint16_t id, bool anim_en);\n\n/**\n * Set an action to call when a tab is loaded (Good to create content only if required)\n * lv_tabview_get_act() still gives the current (old) tab (to remove content from here)\n * @param tabview pointer to a tabview object\n * @param action pointer to a function to call when a tab is loaded\n */\nvoid lv_tabview_set_tab_load_action(lv_obj_t *tabview, lv_tabview_action_t action);\n\n/**\n * Enable horizontal sliding with touch pad\n * @param tabview pointer to Tab view object\n * @param en true: enable sliding; false: disable sliding\n */\nvoid lv_tabview_set_sliding(lv_obj_t * tabview, bool en);\n\n/**\n * Set the animation time of tab view when a new tab is loaded\n * @param tabview pointer to Tab view object\n * @param anim_time time of animation in milliseconds\n */\nvoid lv_tabview_set_anim_time(lv_obj_t * tabview, uint16_t anim_time);\n\n/**\n * Set the style of a tab view\n * @param tabview pointer to a tan view object\n * @param type which style should be set\n * @param style pointer to the new style\n */\nvoid lv_tabview_set_style(lv_obj_t *tabview, lv_tabview_style_t type, lv_style_t *style);\n\n/**\n * Set the position of tab select buttons\n * @param tabview pointer to a tab view object\n * @param btns_pos which button position\n */\nvoid lv_tabview_set_btns_pos(lv_obj_t *tabview, lv_tabview_btns_pos_t btns_pos);\n\n/**\n * Set whether tab buttons are hidden\n * @param tabview pointer to a tab view object\n * @param en whether tab buttons are hidden\n */\nvoid lv_tabview_set_btns_hidden(lv_obj_t *tabview, bool en);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the index of the currently active tab\n * @param tabview pointer to Tab view object\n * @return the active tab index\n */\nuint16_t lv_tabview_get_tab_act(const lv_obj_t * tabview);\n\n/**\n * Get the number of tabs\n * @param tabview pointer to Tab view object\n * @return tab count\n */\nuint16_t lv_tabview_get_tab_count(const lv_obj_t * tabview);\n/**\n * Get the page (content area) of a tab\n * @param tabview pointer to Tab view object\n * @param id index of the tab (>= 0)\n * @return pointer to page (lv_page) object\n */\nlv_obj_t * lv_tabview_get_tab(const lv_obj_t * tabview, uint16_t id);\n\n/**\n * Get the tab load action\n * @param tabview pointer to a tabview object\n * @param return the current tab load action\n */\nlv_tabview_action_t lv_tabview_get_tab_load_action(const lv_obj_t *tabview);\n\n/**\n * Get horizontal sliding is enabled or not\n * @param tabview pointer to Tab view object\n * @return true: enable sliding; false: disable sliding\n */\nbool lv_tabview_get_sliding(const lv_obj_t * tabview);\n\n/**\n * Get the animation time of tab view when a new tab is loaded\n * @param tabview pointer to Tab view object\n * @return time of animation in milliseconds\n */\nuint16_t lv_tabview_get_anim_time(const lv_obj_t * tabview);\n\n/**\n * Get a style of a tab view\n * @param tabview pointer to a ab view object\n * @param type which style should be get\n * @return style pointer to a style\n */\nlv_style_t * lv_tabview_get_style(const lv_obj_t *tabview, lv_tabview_style_t type);\n\n/**\n * Get position of tab select buttons\n * @param tabview pointer to a ab view object\n */\nlv_tabview_btns_pos_t lv_tabview_get_btns_pos(const lv_obj_t *tabview);\n\n/**\n * Get whether tab buttons are hidden\n * @param tabview pointer to a tab view object\n * @return whether tab buttons are hidden\n */\nbool lv_tabview_get_btns_hidden(const lv_obj_t *tabview);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_TABVIEW*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_TABVIEW_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_tileview.c",
    "content": "/**\n * @file lv_tileview.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_tileview.h\"\n#if USE_LV_TILEVIEW != 0\n\n#include \"lv_cont.h\"\n#include \"../lv_themes/lv_theme.h\"\n\n/*********************\n *      DEFINES\n *********************/\n#if USE_LV_ANIMATION\n#  ifndef LV_TILEVIEW_ANIM_TIME\n#    define LV_TILEVIEW_ANIM_TIME  300 /*Animation time loading a tile [ms] (0: no animation)  */\n#  endif\n#else\n#  undef  LV_TILEVIEW_ANIM_TIME\n#  define LV_TILEVIEW_ANIM_TIME  0   /*No animations*/\n#endif\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic lv_res_t lv_tileview_signal(lv_obj_t * tileview, lv_signal_t sign, void * param);\nstatic lv_res_t lv_tileview_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void * param);\nstatic lv_res_t element_signal_func(lv_obj_t * element, lv_signal_t sign, void * param);\nstatic void drag_end_handler(lv_obj_t * tileview);\nstatic bool set_valid_drag_dirs(lv_obj_t * tileview);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\nstatic lv_signal_func_t ancestor_scrl_signal;\nstatic lv_design_func_t ancestor_design;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a tileview object\n * @param par pointer to an object, it will be the parent of the new tileview\n * @param copy pointer to a tileview object, if not NULL then the new object will be copied from it\n * @return pointer to the created tileview\n */\nlv_obj_t * lv_tileview_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"tileview create started\");\n\n    /*Create the ancestor of tileview*/\n    lv_obj_t * new_tileview = lv_page_create(par, copy);\n    lv_mem_assert(new_tileview);\n    if(new_tileview == NULL) return NULL;\n\n    /*Allocate the tileview type specific extended data*/\n    lv_tileview_ext_t * ext = lv_obj_allocate_ext_attr(new_tileview, sizeof(lv_tileview_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_tileview);\n    if(ancestor_scrl_signal == NULL) ancestor_scrl_signal = lv_obj_get_signal_func(lv_page_get_scrl(new_tileview));\n    if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_func(new_tileview);\n\n    /*Initialize the allocated 'ext' */\n    ext->anim_time = LV_TILEVIEW_ANIM_TIME;\n    ext->action = NULL;\n    ext->act_id.x = 0;\n    ext->act_id.y = 0;\n    ext->valid_pos = NULL;\n\n    /*The signal and design functions are not copied so set them here*/\n    lv_obj_set_signal_func(new_tileview, lv_tileview_signal);\n    lv_obj_set_signal_func(lv_page_get_scrl(new_tileview), lv_tileview_scrl_signal);\n\n    /*Init the new tileview*/\n    if(copy == NULL) {\n        lv_obj_set_size(new_tileview, LV_HOR_RES, LV_VER_RES);\n        lv_obj_set_drag_throw(lv_page_get_scrl(new_tileview), false);\n        lv_page_set_scrl_fit(new_tileview, true, true);\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_page_set_style(new_tileview, LV_PAGE_STYLE_BG, th->tileview.bg);\n            lv_page_set_style(new_tileview, LV_PAGE_STYLE_SCRL, th->tileview.scrl);\n            lv_page_set_style(new_tileview, LV_PAGE_STYLE_SB, th->tileview.sb);\n        } else {\n            lv_page_set_style(new_tileview, LV_PAGE_STYLE_BG, &lv_style_transp_tight);\n            lv_page_set_style(new_tileview, LV_PAGE_STYLE_SCRL, &lv_style_transp_tight);\n        }\n    }\n    /*Copy an existing tileview*/\n    else {\n        lv_tileview_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        ext->act_id.x = copy_ext->act_id.x;\n        ext->act_id.y = copy_ext->act_id.y;\n        ext->action = copy_ext->action;\n        ext->anim_time = copy_ext->anim_time;\n\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_tileview);\n    }\n\n    LV_LOG_INFO(\"tileview created\");\n\n    return new_tileview;\n}\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n/**\n * Register an object on the tileview. The register object will able to slide the tileview\n * @param element pointer to an object\n */\nvoid lv_tileview_add_element(lv_obj_t * element)\n{\n    lv_obj_set_free_ptr(element, lv_obj_get_signal_func(element));\n    lv_obj_set_signal_func(element, element_signal_func);\n    lv_obj_set_drag_parent(element, true);\n}\n\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * Set the valid position's indices. The scrolling will be possible only to these positions.\n * @param tileview pointer to a Tileview object\n * @param valid_pos array width the indices. E.g. `lv_point_t p[] = {{0,0}, {1,0}, {1,1}, {LV_COORD_MIN, LV_COORD_MIN}};`\n * Must be closed with `{LV_COORD_MIN, LV_COORD_MIN}`. Only the pointer is saved so can't be a local variable.\n */\nvoid lv_tileview_set_valid_positions(lv_obj_t * tileview, const lv_point_t * valid_pos)\n{\n    lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview);\n    ext->valid_pos = valid_pos;\n}\n\n/**\n * Set the tile to be shown\n * @param tileview pointer to a tileview object\n * @param x column id (0, 1, 2...)\n * @param y line id (0, 1, 2...)\n * @param anim_en true: move with animation\n */\nvoid lv_tileview_set_tile_act(lv_obj_t * tileview, lv_coord_t x, lv_coord_t y, bool anim_en)\n{\n#if USE_LV_ANIMATION == 0\n    anim_en = false;\n#endif\n\n    lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview);\n\n\n    uint16_t i;\n    bool valid = false;\n    for(i = 0; ext->valid_pos[i].x != LV_COORD_MIN; i++) {\n        if(ext->valid_pos[i].x == x && ext->valid_pos[i].y == y) {\n            valid = true;\n        }\n    }\n\n    if(valid == false) return;  /*Don't load not valid tiles*/\n\n    lv_res_t res = LV_RES_OK;\n    if(ext->action) res = ext->action(tileview, x, y);\n    if(res != LV_RES_OK) return;        /*Prevent the tile loading*/\n\n    ext->act_id.x = x;\n    ext->act_id.y = y;\n\n    lv_coord_t x_coord = -x * lv_obj_get_width(tileview);\n    lv_coord_t y_coord = -y * lv_obj_get_height(tileview);\n    lv_obj_t * scrl = lv_page_get_scrl(tileview);\n    if(anim_en) {\n#if USE_LV_ANIMATION\n        lv_coord_t x_act = lv_obj_get_x(scrl);\n        lv_coord_t y_act = lv_obj_get_y(scrl);\n\n        lv_anim_t a;\n        a.var = scrl;\n        a.fp = (lv_anim_fp_t)lv_obj_set_x;\n        a.path = lv_anim_path_linear;\n        a.end_cb = NULL;\n        a.act_time = 0;\n        a.time = ext->anim_time;\n        a.playback = 0;\n        a.playback_pause = 0;\n        a.repeat = 0;\n        a.repeat_pause = 0;\n\n        if(x_coord != x_act) {\n            a.start = x_act;\n            a.end = x_coord;\n            lv_anim_create(&a);\n        }\n\n        if(y_coord != y_act) {\n            a.start = y_act;\n            a.end = y_coord;\n            a.fp = (lv_anim_fp_t)lv_obj_set_y;\n            lv_anim_create(&a);\n        }\n#endif\n    } else {\n        lv_obj_set_pos(scrl, x_coord, y_coord);\n    }\n}\n\nvoid lv_tileview_set_tile_load_action(lv_obj_t * tileview, lv_tileview_action_t action)\n{\n    lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview);\n    ext->action = action;\n\n}\n\n/**\n * Set a style of a tileview.\n * @param tileview pointer to tileview object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_tileview_set_style(lv_obj_t * tileview, lv_tileview_style_t type, lv_style_t * style)\n{\n\n    switch(type) {\n        case LV_TILEVIEW_STYLE_BG:\n            lv_obj_set_style(tileview, style);\n            break;\n    }\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/*\n * New object specific \"get\" functions come here\n */\n\n/**\n * Get style of a tileview.\n * @param tileview pointer to tileview object\n * @param type which style should be get\n * @return style pointer to the style\n */\nlv_style_t * lv_tileview_get_style(const lv_obj_t * tileview, lv_tileview_style_t type)\n{\n    lv_style_t * style = NULL;\n    switch(type) {\n        case LV_TILEVIEW_STYLE_BG:\n            style = lv_obj_get_style(tileview);\n            break;\n        default:\n            style =  NULL;\n    }\n\n    return style;\n}\n\n/*=====================\n * Other functions\n *====================*/\n\n/*\n * New object specific \"other\" functions come here\n */\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Signal function of the tileview\n * @param tileview pointer to a tileview object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_tileview_signal(lv_obj_t * tileview, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(tileview, sign, param);\n    if(res != LV_RES_OK) return res;\n\n\n    if(sign == LV_SIGNAL_CLEANUP) {\n        /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_tileview\";\n    }\n\n    return res;\n}\n\n/**\n * Signal function of the tileview scrollable\n * @param tileview pointer to the scrollable part of the tileview object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_tileview_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void * param)\n{\n\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_scrl_signal(scrl, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    lv_obj_t * tileview = lv_obj_get_parent(scrl);\n    lv_style_t * style_bg = lv_tileview_get_style(tileview, LV_TILEVIEW_STYLE_BG);\n\n\n    /*Apply constraint on moving of the tileview*/\n    if(sign == LV_SIGNAL_CORD_CHG) {\n        lv_indev_t * indev = lv_indev_get_act();\n        if(indev) {\n            lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview);\n\n            /*Set horizontal drag constraint if no vertical constraint an dragged to valid x direction */\n            if(ext->drag_ver == 0 &&\n                    ((ext->drag_right_en && indev->proc.drag_sum.x <= -LV_INDEV_DRAG_LIMIT) ||\n                     (ext->drag_left_en  && indev->proc.drag_sum.x >= LV_INDEV_DRAG_LIMIT))) {\n                ext->drag_hor = 1;\n            }\n            /*Set vertical drag constraint if no horizontal constraint an dragged to valid y direction */\n            if(ext->drag_hor == 0 &&\n                    ((ext->drag_bottom_en && indev->proc.drag_sum.y <= -LV_INDEV_DRAG_LIMIT) ||\n                     (ext->drag_top_en && indev->proc.drag_sum.y >= LV_INDEV_DRAG_LIMIT))) {\n                ext->drag_ver = 1;\n            }\n\n            if(ext->drag_hor) {\n                ext->page.edge_flash.top_ip = 0;\n                ext->page.edge_flash.bottom_ip = 0;\n            }\n\n            if(ext->drag_ver) {\n                ext->page.edge_flash.right_ip = 0;\n                ext->page.edge_flash.left_ip = 0;\n            }\n\n            lv_coord_t x = lv_obj_get_x(scrl);\n            lv_coord_t y = lv_obj_get_y(scrl);\n            lv_coord_t h = lv_obj_get_height(tileview);\n            lv_coord_t w = lv_obj_get_width(tileview);\n            if(ext->drag_top_en == 0) {\n                if(y > -(ext->act_id.y * h) && indev->proc.vect.y > 0 && ext->drag_hor == 0) {\n                    if(ext->page.edge_flash.enabled &&\n                            ext->page.edge_flash.left_ip == 0 && ext->page.edge_flash.right_ip == 0 &&\n                            ext->page.edge_flash.top_ip == 0 && ext->page.edge_flash.bottom_ip == 0) {\n                        ext->page.edge_flash.top_ip = 1;\n                        lv_page_start_edge_flash(tileview);\n                    }\n\n                    lv_obj_set_y(scrl, -ext->act_id.y * h + style_bg->body.padding.ver);\n                }\n            }\n            if(ext->drag_bottom_en == 0 && indev->proc.vect.y < 0 && ext->drag_hor == 0) {\n                if(y < -(ext->act_id.y * h)) {\n                    if(ext->page.edge_flash.enabled &&\n                            ext->page.edge_flash.left_ip == 0 && ext->page.edge_flash.right_ip == 0 &&\n                            ext->page.edge_flash.top_ip == 0 && ext->page.edge_flash.bottom_ip == 0) {\n                        ext->page.edge_flash.bottom_ip = 1;\n                        lv_page_start_edge_flash(tileview);\n                    }\n                }\n\n                lv_obj_set_y(scrl, -ext->act_id.y * h + style_bg->body.padding.ver);\n            }\n            if(ext->drag_left_en == 0) {\n                if(x > -(ext->act_id.x * w) && indev->proc.vect.x > 0 && ext->drag_ver == 0) {\n                    if(ext->page.edge_flash.enabled &&\n                            ext->page.edge_flash.left_ip == 0 && ext->page.edge_flash.right_ip == 0 &&\n                            ext->page.edge_flash.top_ip == 0 && ext->page.edge_flash.bottom_ip == 0) {\n                        ext->page.edge_flash.left_ip = 1;\n                        lv_page_start_edge_flash(tileview);\n                    }\n\n                    lv_obj_set_x(scrl, -ext->act_id.x * w + style_bg->body.padding.hor);\n                }\n            }\n            if(ext->drag_right_en == 0 && indev->proc.vect.x < 0 && ext->drag_ver == 0) {\n                if(x < -(ext->act_id.x * w)) {\n                    if(ext->page.edge_flash.enabled &&\n                            ext->page.edge_flash.left_ip == 0 && ext->page.edge_flash.right_ip == 0 &&\n                            ext->page.edge_flash.top_ip == 0 && ext->page.edge_flash.bottom_ip == 0) {\n                        ext->page.edge_flash.right_ip = 1;\n                        lv_page_start_edge_flash(tileview);\n                    }\n                }\n\n                lv_obj_set_x(scrl, -ext->act_id.x * w + style_bg->body.padding.hor);\n            }\n\n            /*Apply the drag constraints*/\n            if(ext->drag_ver == 0) lv_obj_set_y(scrl, - ext->act_id.y * lv_obj_get_height(tileview) + style_bg->body.padding.ver);\n            if(ext->drag_hor == 0) lv_obj_set_x(scrl, - ext->act_id.x * lv_obj_get_width(tileview) + style_bg->body.padding.hor);\n        }\n    }\n\n    return res;\n\n}\n\n/**\n * This function is applied called for the elements of the tileview. Used when the element is\n * @param element\n * @param sign\n * @param param\n * @return\n */\nstatic lv_res_t element_signal_func(lv_obj_t * element, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    lv_signal_func_t sign_func = lv_obj_get_free_ptr(element);\n    res = sign_func(element, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    /*Initialize some variables on PRESS*/\n    if(sign == LV_SIGNAL_PRESSED) {\n        /*Get the tileview from the element*/\n        lv_obj_t * tileview = lv_obj_get_parent(element);\n        while(tileview) {\n            if(lv_obj_get_signal_func(tileview) != lv_tileview_signal) tileview = lv_obj_get_parent(tileview);\n            else break;\n        }\n\n        if(tileview) {\n            lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview);\n            ext->drag_hor = 0;\n            ext->drag_ver = 0;\n            set_valid_drag_dirs(tileview);\n        }\n    }\n\n    /*Animate the tabview to the correct location on RELEASE*/\n    else if(sign == LV_SIGNAL_PRESS_LOST || sign == LV_SIGNAL_RELEASED) {\n\n        /*Get the tileview from the element*/\n        lv_obj_t * tileview = lv_obj_get_parent(element);\n        while(tileview) {\n            if(lv_obj_get_signal_func(tileview) != lv_tileview_signal) tileview = lv_obj_get_parent(tileview);\n            else break;\n        }\n\n        if(tileview) {\n            /* If the element was dragged and it moved the tileview finish the drag manually to\n             * let the tileview to finish the move.*/\n            lv_indev_t * indev = lv_indev_get_act();\n            lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview);\n            if(indev->proc.drag_in_prog && (ext->drag_hor || ext->drag_ver)) {\n\n                lv_obj_t * drag_obj = element;\n                while(lv_obj_get_drag_parent(drag_obj)) {\n                    drag_obj = lv_obj_get_parent(drag_obj);\n                    if(drag_obj == NULL) break;\n                }\n                indev->proc.drag_in_prog = 0;\n                if(drag_obj) drag_obj->signal_func(drag_obj, LV_SIGNAL_DRAG_END, NULL);\n            }\n\n             drag_end_handler(tileview);\n        }\n    }\n\n    return res;\n}\n\n/**\n * Called when the user releases an element of the tileview after dragging it.\n * @param tileview pointer to a tileview object\n */\nstatic void drag_end_handler(lv_obj_t * tileview)\n{\n    lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview);\n    lv_indev_t * indev = lv_indev_get_act();\n    lv_point_t point_act;\n    lv_indev_get_point(indev, &point_act);\n    lv_obj_t * scrl = lv_page_get_scrl(tileview);\n    lv_point_t p;\n\n    p.x = - (scrl->coords.x1 - LV_HOR_RES / 2);\n    p.y = - (scrl->coords.y1 - LV_VER_RES / 2);\n\n    /*From the drag vector (drag throw) predict the end position*/\n    if(ext->drag_hor) {\n        lv_point_t vect;\n        lv_indev_get_vect(indev, &vect);\n        lv_coord_t predict = 0;\n\n        while(vect.x != 0) {\n            predict += vect.x;\n            vect.x = vect.x * (100 - LV_INDEV_DRAG_THROW) / 100;\n        }\n\n        p.x -= predict;\n    }\n    else if(ext->drag_ver) {\n        lv_point_t vect;\n        lv_indev_get_vect(indev, &vect);\n        lv_coord_t predict = 0;\n\n        while(vect.y != 0) {\n            predict += vect.y;\n            vect.y = vect.y * (100 - LV_INDEV_DRAG_THROW) / 100;\n        }\n\n        p.y -= predict;\n    }\n\n    /*Get the index of the tile*/\n    p.x = p.x / lv_obj_get_width(tileview);\n    p.y = p.y / lv_obj_get_height(tileview);\n\n    /*Max +- move*/\n    lv_coord_t x_move = p.x - ext->act_id.x;\n    lv_coord_t y_move = p.y - ext->act_id.y;\n    if(x_move < -1) x_move = -1;\n    if(x_move > 1)  x_move =  1;\n    if(y_move < -1) y_move = -1;\n    if(y_move > 1) y_move = 1;\n\n    /*Set the new tile*/\n    lv_tileview_set_tile_act(tileview, ext->act_id.x + x_move, ext->act_id.y + y_move,true);\n}\n\nstatic bool set_valid_drag_dirs(lv_obj_t * tileview)\n{\n\n    lv_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview);\n    if(ext->valid_pos == NULL) return false;\n\n    ext->drag_bottom_en = 0;\n    ext->drag_top_en = 0;\n    ext->drag_left_en = 0;\n    ext->drag_right_en = 0;\n\n    uint16_t i;\n    for(i = 0; ext->valid_pos[i].x != LV_COORD_MIN; i++) {\n        if(ext->valid_pos[i].x == ext->act_id.x && ext->valid_pos[i].y == ext->act_id.y - 1) ext->drag_top_en = 1;\n        if(ext->valid_pos[i].x == ext->act_id.x && ext->valid_pos[i].y == ext->act_id.y + 1) ext->drag_bottom_en = 1;\n        if(ext->valid_pos[i].x == ext->act_id.x - 1 && ext->valid_pos[i].y == ext->act_id.y) ext->drag_left_en = 1;\n        if(ext->valid_pos[i].x == ext->act_id.x + 1 && ext->valid_pos[i].y == ext->act_id.y) ext->drag_right_en = 1;\n    }\n\n    return true;\n}\n\n\n#endif\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_tileview.h",
    "content": "/**\n * @file lv_tileview.h\n *\n */\n\n\n#ifndef LV_TILEVIEW_H\n#define LV_TILEVIEW_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_TILEVIEW != 0\n\n#include \"../lv_objx/lv_page.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n\n\n/* parametes: pointer to a tileview object, x, y (tile coordinates to load)\n * return: LV_RES_INV: to prevent the loading of the tab;  LV_RES_OK: if everything is fine*/\ntypedef lv_res_t (*lv_tileview_action_t)(lv_obj_t *, lv_coord_t, lv_coord_t);\n\n/*Data of tileview*/\ntypedef struct {\n    lv_page_ext_t page;\n    /*New data for this type */\n    const lv_point_t * valid_pos;\n    uint16_t anim_time;\n    lv_tileview_action_t action;\n    lv_point_t act_id;\n    uint8_t drag_top_en     :1;\n    uint8_t drag_bottom_en  :1;\n    uint8_t drag_left_en    :1;\n    uint8_t drag_right_en   :1;\n    uint8_t drag_hor   :1;\n    uint8_t drag_ver   :1;\n} lv_tileview_ext_t;\n\n\n/*Styles*/\nenum {\n    LV_TILEVIEW_STYLE_BG,\n};\ntypedef uint8_t lv_tileview_style_t;\n\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a tileview objects\n * @param par pointer to an object, it will be the parent of the new tileview\n * @param copy pointer to a tileview object, if not NULL then the new object will be copied from it\n * @return pointer to the created tileview\n */\nlv_obj_t * lv_tileview_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n/**\n * Register an object on the tileview. The register object will able to slide the tileview\n * @param element pointer to an object\n */\nvoid lv_tileview_add_element(lv_obj_t * element);\n\n/*=====================\n * Setter functions\n *====================*/\n\n\n/**\n * Set the valid position's indices. The scrolling will be possible only to these positions.\n * @param tileview pointer to a Tileview object\n * @param valid_pos array width the indices. E.g. `lv_point_t p[] = {{0,0}, {1,0}, {1,1}, {LV_COORD_MIN, LV_COORD_MIN}};`\n * Must be closed with `{LV_COORD_MIN, LV_COORD_MIN}`. Only the pointer is saved so can't be a local variable.\n */\nvoid lv_tileview_set_valid_positions(lv_obj_t * tileview, const lv_point_t * valid_pos);\n\n/**\n * Set the tile to be shown\n * @param tileview pointer to a tileview object\n * @param x column id (0, 1, 2...)\n * @param y line id (0, 1, 2...)\n * @param anim_en true: move with animation\n */\nvoid lv_tileview_set_tile_act(lv_obj_t * tileview, lv_coord_t x, lv_coord_t y, bool anim_en);\n\n/**\n * Enable the edge flash effect. (Show an arc when the an edge is reached)\n * @param tileview pointer to a Tileview\n * @param en true or false to enable/disable end flash\n */\nstatic inline void lv_tileview_set_edge_flash(lv_obj_t * tileview, bool en)\n{\n    lv_page_set_edge_flash(tileview, en);\n}\n\n/**\n * Set a style of a tileview.\n * @param tileview pointer to tileview object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_tileview_set_style(lv_obj_t * tileview, lv_tileview_style_t type, lv_style_t *style);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the scroll propagation property\n * @param tileview pointer to a Tileview\n * @return true or false\n */\nstatic inline bool lv_tileview_get_edge_flash(lv_obj_t * tileview)\n{\n    return lv_page_get_edge_flash(tileview);\n}\n\n/**\n * Get style of a tileview.\n * @param tileview pointer to tileview object\n * @param type which style should be get\n * @return style pointer to the style\n */\nlv_style_t * lv_tileview_get_style(const lv_obj_t * tileview, lv_tileview_style_t type);\n\n/*=====================\n * Other functions\n *====================*/\n\n/**********************\n *      MACROS\n **********************/\n\n#endif  /*USE_LV_TILEVIEW*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif  /*LV_TILEVIEW_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_win.c",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * @file lv_win.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_win.h\"\n#if USE_LV_WIN != 0\n\n#include \"../lv_themes/lv_theme.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\nstatic lv_res_t lv_win_signal(lv_obj_t * win, lv_signal_t sign, void * param);\nstatic void lv_win_realign(lv_obj_t * win);\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_signal_func_t ancestor_signal;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Create a window objects\n * @param par pointer to an object, it will be the parent of the new window\n * @param copy pointer to a window object, if not NULL then the new object will be copied from it\n * @return pointer to the created window\n */\nlv_obj_t * lv_win_create(lv_obj_t * par, const lv_obj_t * copy)\n{\n    LV_LOG_TRACE(\"window create started\");\n\n    /*Create the ancestor object*/\n    lv_obj_t * new_win = lv_obj_create(par, copy);\n    lv_mem_assert(new_win);\n    if(new_win == NULL) return NULL;\n\n    if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_func(new_win);\n\n    /*Allocate the object type specific extended data*/\n    lv_win_ext_t * ext = lv_obj_allocate_ext_attr(new_win, sizeof(lv_win_ext_t));\n    lv_mem_assert(ext);\n    if(ext == NULL) return NULL;\n\n    ext->page = NULL;\n    ext->header = NULL;\n    ext->title = NULL;\n    ext->style_header = &lv_style_plain_color;\n    ext->style_btn_rel = &lv_style_btn_rel;\n    ext->style_btn_pr = &lv_style_btn_pr;\n    ext->btn_size = (LV_DPI) / 2;\n\n    /*Init the new window object*/\n    if(copy == NULL) {\n        lv_obj_set_size(new_win, LV_HOR_RES, LV_VER_RES);\n        lv_obj_set_pos(new_win, 0, 0);\n        lv_obj_set_style(new_win, &lv_style_pretty);\n\n        ext->page = lv_page_create(new_win, NULL);\n        lv_obj_set_protect(ext->page, LV_PROTECT_PARENT);\n        lv_page_set_sb_mode(ext->page, LV_SB_MODE_AUTO);\n        lv_page_set_arrow_scroll(ext->page, true);\n\n        /*Create a holder for the header*/\n        ext->header = lv_obj_create(new_win, NULL);\n        /*Move back the header because it is automatically moved to the scrollable */\n        lv_obj_set_protect(ext->header, LV_PROTECT_PARENT);\n        lv_obj_set_parent(ext->header, new_win);\n\t\tlv_obj_set_width(ext->header, LV_HOR_RES - 62);////\n\t\text->btn_size = lv_obj_get_height(ext->header) - 3;////\n\n        /*Create a title on the header*/\n        ext->title = lv_label_create(ext->header, NULL);\n        lv_label_set_text(ext->title, \"My title\");\n\n        /*Set the default styles*/\n        lv_theme_t * th = lv_theme_get_current();\n        if(th) {\n            lv_win_set_style(new_win, LV_WIN_STYLE_BG, th->win.bg);\n            lv_win_set_style(new_win, LV_WIN_STYLE_SB, th->win.sb);\n            lv_win_set_style(new_win, LV_WIN_STYLE_HEADER, th->win.header);\n            lv_win_set_style(new_win, LV_WIN_STYLE_CONTENT_BG, th->win.content.bg);\n            lv_win_set_style(new_win, LV_WIN_STYLE_CONTENT_SCRL, th->win.content.scrl);\n            lv_win_set_style(new_win, LV_WIN_STYLE_BTN_REL, th->win.btn.rel);\n            lv_win_set_style(new_win, LV_WIN_STYLE_BTN_PR, th->win.btn.pr);\n        } else {\n            lv_win_set_style(new_win, LV_WIN_STYLE_BG, &lv_style_plain);\n            lv_win_set_style(new_win, LV_WIN_STYLE_CONTENT_BG, &lv_style_plain);\n            lv_win_set_style(new_win, LV_WIN_STYLE_CONTENT_SCRL, &lv_style_transp);\n            lv_win_set_style(new_win, LV_WIN_STYLE_HEADER, &lv_style_plain_color);\n        }\n\n        lv_obj_set_signal_func(new_win, lv_win_signal);\n        lv_obj_set_size(new_win, LV_HOR_RES, LV_VER_RES);\n    }\n    /*Copy an existing object*/\n    else {\n        lv_win_ext_t * copy_ext = lv_obj_get_ext_attr(copy);\n        /*Create the objects*/\n        ext->header = lv_obj_create(new_win, copy_ext->header);\n        ext->title = lv_label_create(ext->header, copy_ext->title);\n        ext->page = lv_page_create(new_win, copy_ext->page);\n        ext->btn_size = copy_ext->btn_size;\n\n        /*Copy the control buttons*/\n        lv_obj_t * child;\n        lv_obj_t * cbtn;\n        child = lv_obj_get_child_back(copy_ext->header, NULL);\n        child = lv_obj_get_child_back(copy_ext->header, child); /*Sip the title*/\n        while(child != NULL) {\n            cbtn = lv_btn_create(ext->header, child);\n            lv_img_create(cbtn, lv_obj_get_child(child, NULL));\n            child = lv_obj_get_child_back(copy_ext->header, child);\n        }\n\n        lv_obj_set_signal_func(new_win, lv_win_signal);\n\n        /*Refresh the style with new signal function*/\n        lv_obj_refresh_style(new_win);\n    }\n\n    lv_win_realign(new_win);\n\n    LV_LOG_INFO(\"window created\");\n\n    return new_win;\n}\n\n/**\n * Delete all children of the scrl object, without deleting scrl child.\n * @param obj pointer to an object\n */\nvoid lv_win_clean(lv_obj_t * obj)\n{\n    lv_obj_t * scrl = lv_page_get_scrl(obj);\n    lv_obj_clean(scrl);\n}\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n/**\n * Add control button to the header of the window\n * @param win pointer to a window object\n * @param img_src an image source ('lv_img_t' variable, path to file or a symbol)\n * @param rel_action a function pointer to call when the button is released\n * @return pointer to the created button object\n */\nlv_obj_t * lv_win_add_btn(lv_obj_t * win, const void * img_src, const char * label_src, lv_action_t rel_action)\n{\n    lv_win_ext_t * ext = lv_obj_get_ext_attr(win);\n\n    lv_obj_t * btn = lv_btn_create(ext->header, NULL);\n    lv_btn_set_style(btn, LV_BTN_STYLE_REL, ext->style_btn_rel);\n    lv_btn_set_style(btn, LV_BTN_STYLE_PR, ext->style_btn_pr);\n\tlv_obj_set_size(btn, lv_obj_get_width(btn), ext->btn_size);\n\tlv_btn_set_fit(btn, true, false);\n    lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, rel_action);\n\n\tif (img_src)\n\t{\n\t\tlv_obj_t * img = lv_img_create(btn, NULL);\n\t\tlv_obj_set_click(img, false);\n\t\tlv_img_set_src(img, img_src);\n\t}\n\telse if (label_src)\n\t{\n\t\tlv_obj_t *label = lv_label_create(btn, NULL);\n        lv_label_set_recolor(label, true);\n\t\tlv_label_set_text(label, label_src);\n\t}\n\n    lv_win_realign(win);\n\n    return btn;\n}\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * A release action which can be assigned to a window control button to close it\n * @param btn pointer to the released button\n * @return always LV_ACTION_RES_INV because the button is deleted with the window\n */\nlv_res_t lv_win_close_action(lv_obj_t * btn)\n{\n    lv_obj_t * win = lv_win_get_from_btn(btn);\n\n    lv_obj_del(win);\n\n    return LV_RES_INV;\n}\n\n/**\n * Set the title of a window\n * @param win pointer to a window object\n * @param title string of the new title\n */\nvoid lv_win_set_title(lv_obj_t * win, const char * title)\n{\n    lv_win_ext_t * ext = lv_obj_get_ext_attr(win);\n\n    lv_label_set_text(ext->title, title);\n    lv_win_realign(win);\n}\n\n/**\n * Set the control button size of a window\n * @param win pointer to a window object\n * @param size control button size\n */\nvoid lv_win_set_btn_size(lv_obj_t * win, lv_coord_t size)\n{\n    lv_win_ext_t * ext = lv_obj_get_ext_attr(win);\n    if(ext->btn_size == size) return;\n\n    ext->btn_size = size;\n\n    lv_win_realign(win);\n}\n\n/**\n * Set the layout of the window\n * @param win pointer to a window object\n * @param layout the layout from 'lv_layout_t'\n */\nvoid lv_win_set_layout(lv_obj_t * win, lv_layout_t layout)\n{\n    lv_win_ext_t * ext = lv_obj_get_ext_attr(win);\n    lv_page_set_scrl_layout(ext->page, layout);\n}\n\n/**\n * Set the scroll bar mode of a window\n * @param win pointer to a window object\n * @param sb_mode the new scroll bar mode from  'lv_sb_mode_t'\n */\nvoid lv_win_set_sb_mode(lv_obj_t * win, lv_sb_mode_t sb_mode)\n{\n    lv_win_ext_t * ext = lv_obj_get_ext_attr(win);\n    lv_page_set_sb_mode(ext->page, sb_mode);\n}\n\n/**\n * Set a style of a window\n * @param win pointer to a window object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_win_set_style(lv_obj_t * win, lv_win_style_t type, lv_style_t * style)\n{\n    lv_win_ext_t * ext = lv_obj_get_ext_attr(win);\n\n    switch(type) {\n        case LV_WIN_STYLE_BG:\n            lv_obj_set_style(win, style);\n            lv_win_realign(win);\n            break;\n        case LV_WIN_STYLE_CONTENT_BG:\n            lv_page_set_style(ext->page, LV_PAGE_STYLE_BG, style);\n            break;\n        case LV_WIN_STYLE_CONTENT_SCRL:\n            lv_page_set_style(ext->page, LV_PAGE_STYLE_SCRL, style);\n            break;\n        case LV_WIN_STYLE_SB:\n            lv_page_set_style(ext->page, LV_PAGE_STYLE_SB, style);\n            break;\n        case LV_WIN_STYLE_HEADER:\n            lv_obj_set_style(ext->header, style);\n            lv_win_realign(win);\n            break;\n        case LV_WIN_STYLE_BTN_REL:\n            ext->style_btn_rel = style;\n            break;\n        case LV_WIN_STYLE_BTN_PR:\n            ext->style_btn_pr = style;\n            break;\n    }\n\n    /*Refresh the existing buttons*/\n    if(type == LV_WIN_STYLE_BTN_REL || type == LV_WIN_STYLE_BTN_PR) {\n        lv_obj_t * btn;\n        btn = lv_obj_get_child_back(ext->header, NULL);\n        btn = lv_obj_get_child_back(ext->header, btn);    /*Skip the title*/\n        while(btn != NULL) {\n            if(type == LV_WIN_STYLE_BTN_REL) lv_btn_set_style(btn, LV_BTN_STYLE_REL, style);\n            else lv_btn_set_style(btn, LV_BTN_STYLE_PR, style);\n            btn = lv_obj_get_child_back(ext->header, btn);\n        }\n    }\n}\n\n/**\n * Set drag status of a window. If set to 'true' window can be dragged like on a PC.\n * @param win pointer to a window object\n * @param en whether dragging is enabled\n */\nvoid lv_win_set_drag(lv_obj_t *win, bool en)\n{\n    lv_win_ext_t * ext = lv_obj_get_ext_attr(win);\n    lv_obj_t * win_header = ext->header;\n    lv_obj_set_drag_parent(win_header, en);\n    lv_obj_set_drag(win, en);\n}\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the title of a window\n * @param win pointer to a window object\n * @return title string of the window\n */\nconst char * lv_win_get_title(const lv_obj_t * win)\n{\n    lv_win_ext_t * ext = lv_obj_get_ext_attr(win);\n    return lv_label_get_text(ext->title);\n}\n\n/**\n* Get the content holder object of window (`lv_page`) to allow additional customization\n* @param win pointer to a window object\n* @return the Page object where the window's content is\n*/\nlv_obj_t * lv_win_get_content(const lv_obj_t * win)\n{\n    lv_win_ext_t * ext = lv_obj_get_ext_attr(win);\n    return ext->page;\n}\n\n/**\n * Get the control button size of a window\n * @param win pointer to a window object\n * @return control button size\n */\nlv_coord_t lv_win_get_btn_size(const lv_obj_t * win)\n{\n    lv_win_ext_t * ext = lv_obj_get_ext_attr(win);\n    return ext->btn_size;\n}\n\n/**\n * Get the pointer of a widow from one of  its control button.\n * It is useful in the action of the control buttons where only button is known.\n * @param ctrl_btn pointer to a control button of a window\n * @return pointer to the window of 'ctrl_btn'\n */\nlv_obj_t * lv_win_get_from_btn(const lv_obj_t * ctrl_btn)\n{\n    lv_obj_t * header = lv_obj_get_parent(ctrl_btn);\n    lv_obj_t * win = lv_obj_get_parent(header);\n\n    return win;\n}\n\n/**\n * Get the layout of a window\n * @param win pointer to a window object\n * @return the layout of the window (from 'lv_layout_t')\n */\nlv_layout_t lv_win_get_layout(lv_obj_t * win)\n{\n    lv_win_ext_t * ext = lv_obj_get_ext_attr(win);\n    return lv_page_get_scrl_layout(ext->page);\n}\n\n/**\n * Get the scroll bar mode of a window\n * @param win pointer to a window object\n * @return the scroll bar mode of the window (from 'lv_sb_mode_t')\n */\nlv_sb_mode_t lv_win_get_sb_mode(lv_obj_t * win)\n{\n    lv_win_ext_t * ext = lv_obj_get_ext_attr(win);\n    return lv_page_get_sb_mode(ext->page);\n}\n\n/**\n * Get width of the content area (page scrollable) of the window\n * @param win pointer to a window object\n * @return the width of the content_bg area\n */\nlv_coord_t lv_win_get_width(lv_obj_t * win)\n{\n    lv_win_ext_t * ext = lv_obj_get_ext_attr(win);\n    lv_obj_t * scrl = lv_page_get_scrl(ext->page);\n    lv_style_t * style_scrl = lv_obj_get_style(scrl);\n\n    return lv_obj_get_width(scrl) - 2 * style_scrl->body.padding.hor;\n}\n\n/**\n * Get a style of a window\n * @param win pointer to a button object\n * @param type which style window be get\n * @return style pointer to a style\n */\nlv_style_t * lv_win_get_style(const lv_obj_t * win, lv_win_style_t type)\n{\n    lv_style_t * style = NULL;\n    lv_win_ext_t * ext = lv_obj_get_ext_attr(win);\n\n    switch(type) {\n        case LV_WIN_STYLE_BG:\n            style = lv_obj_get_style(win);\n            break;\n        case LV_WIN_STYLE_CONTENT_BG:\n            style = lv_page_get_style(ext->page, LV_PAGE_STYLE_BG);\n            break;\n        case LV_WIN_STYLE_CONTENT_SCRL:\n            style = lv_page_get_style(ext->page, LV_PAGE_STYLE_SCRL);\n            break;\n        case LV_WIN_STYLE_SB:\n            style = lv_page_get_style(ext->page, LV_PAGE_STYLE_SB);\n            break;\n        case LV_WIN_STYLE_HEADER:\n            style = lv_obj_get_style(ext->header);\n            break;\n        case LV_WIN_STYLE_BTN_REL:\n            style = ext->style_btn_rel;\n            break;\n        case LV_WIN_STYLE_BTN_PR:\n            style = ext->style_btn_pr;\n            break;\n        default:\n            style = NULL;\n            break;\n    }\n\n    return style;\n}\n\n/*=====================\n * Other functions\n *====================*/\n\n/**\n * Focus on an object. It ensures that the object will be visible in the window.\n * @param win pointer to a window object\n * @param obj pointer to an object to focus (must be in the window)\n * @param anim_time scroll animation time in milliseconds (0: no animation)\n */\nvoid lv_win_focus(lv_obj_t * win, lv_obj_t * obj, uint16_t anim_time)\n{\n    lv_win_ext_t * ext = lv_obj_get_ext_attr(win);\n    lv_page_focus(ext->page, obj, anim_time);\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n/**\n * Signal function of the window\n * @param win pointer to a window object\n * @param sign a signal type from lv_signal_t enum\n * @param param pointer to a signal specific variable\n * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted\n */\nstatic lv_res_t lv_win_signal(lv_obj_t * win, lv_signal_t sign, void * param)\n{\n    lv_res_t res;\n\n    /* Include the ancient signal function */\n    res = ancestor_signal(win, sign, param);\n    if(res != LV_RES_OK) return res;\n\n    lv_win_ext_t * ext = lv_obj_get_ext_attr(win);\n    if(sign == LV_SIGNAL_CHILD_CHG) { /*Move children to the page*/\n        lv_obj_t * page = ext->page;\n        if(page != NULL) {\n            lv_obj_t * child;\n            child = lv_obj_get_child(win, NULL);\n            while(child != NULL) {\n                if(lv_obj_is_protected(child, LV_PROTECT_PARENT) == false) {\n                    lv_obj_t * tmp = child;\n                    child = lv_obj_get_child(win, child); /*Get the next child before move this*/\n                    lv_obj_set_parent(tmp, page);\n                } else {\n                    child = lv_obj_get_child(win, child);\n                }\n            }\n        }\n    } else if(sign == LV_SIGNAL_STYLE_CHG) {\n        lv_win_realign(win);\n    } else if(sign == LV_SIGNAL_CORD_CHG) {\n        /*If the size is changed refresh the window*/\n        if(lv_area_get_width(param) != lv_obj_get_width(win) ||\n                lv_area_get_height(param) != lv_obj_get_height(win)) {\n            lv_win_realign(win);\n        }\n    } else if(sign == LV_SIGNAL_CLEANUP) {\n        ext->header = NULL;     /*These objects were children so they are already invalid*/\n        ext->page = NULL;\n        ext->title = NULL;\n    } else if(sign == LV_SIGNAL_CONTROLL) {\n        /*Forward all the control signals to the page*/\n        ext->page->signal_func(ext->page, sign, param);\n    } else if(sign == LV_SIGNAL_GET_TYPE) {\n        lv_obj_type_t * buf = param;\n        uint8_t i;\n        for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) {  /*Find the last set data*/\n            if(buf->type[i] == NULL) break;\n        }\n        buf->type[i] = \"lv_win\";\n    }\n\n\n    return res;\n}\n\n/**\n * Realign the building elements of a window\n * @param win pointer to window objectker\n */\nstatic void lv_win_realign(lv_obj_t * win)\n{\n    lv_win_ext_t * ext = lv_obj_get_ext_attr(win);\n\n    if(ext->page == NULL || ext->header == NULL || ext->title == NULL) return;\n\n    lv_style_t * header_style = lv_win_get_style(win, LV_WIN_STYLE_HEADER);\n    lv_obj_set_size(ext->header, lv_obj_get_width(win) - 62, ext->btn_size + 2 * header_style->body.padding.ver);\n\n    bool first_btn = true;\n    lv_obj_t * btn;\n    lv_obj_t * btn_prev = NULL;\n    /*Refresh the size of all control buttons*/\n    btn = lv_obj_get_child_back(ext->header, NULL);\n    btn = lv_obj_get_child_back(ext->header, btn);    /*Skip the title*/\n    while(btn != NULL) {\n        lv_obj_set_size(btn, lv_obj_get_width(btn), ext->btn_size);\n        if(first_btn) {\n            lv_obj_align(btn, ext->header, LV_ALIGN_IN_RIGHT_MID, - header_style->body.padding.hor, 0);\n            first_btn = false;\n        } else {\n            lv_obj_align(btn, btn_prev, LV_ALIGN_OUT_LEFT_MID, - header_style->body.padding.inner, 0);\n        }\n        btn_prev = btn;\n        btn = lv_obj_get_child_back(ext->header, btn);\n    }\n\n\n    lv_obj_align(ext->title, NULL, LV_ALIGN_IN_LEFT_MID, ext->style_header->body.padding.hor, 0);\n\n    lv_obj_set_pos(ext->header, 31, 0);\n\n    lv_obj_set_size(ext->page, lv_obj_get_width(win), lv_obj_get_height(win) - lv_obj_get_height(ext->header));\n    lv_obj_align(ext->page, ext->header, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);\n}\n\n#endif\n\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_objx/lv_win.h",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * @file lv_win.h\n *\n */\n\n#ifndef LV_WIN_H\n#define LV_WIN_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_WIN != 0\n\n/*Testing of dependencies*/\n#if USE_LV_BTN == 0\n#error \"lv_win: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN  1) \"\n#endif\n\n#if USE_LV_LABEL == 0\n#error \"lv_win: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL  1) \"\n#endif\n\n#if USE_LV_IMG == 0\n#error \"lv_win: lv_img is required. Enable it in lv_conf.h (USE_LV_IMG  1) \"\n#endif\n\n\n#if USE_LV_PAGE == 0\n#error \"lv_win: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE  1) \"\n#endif\n\n#include \"../lv_core/lv_obj.h\"\n#include \"lv_cont.h\"\n#include \"lv_btn.h\"\n#include \"lv_label.h\"\n#include \"lv_img.h\"\n#include \"lv_page.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/*Data of window*/\ntypedef struct\n{\n    /*Ext. of ancestor*/\n    /*New data for this type */\n    lv_obj_t * page;                /*Pointer to a page which holds the content*/\n    lv_obj_t * header;              /*Pointer to the header container of the window*/\n    lv_obj_t * title;               /*Pointer to the title label of the window*/\n    lv_style_t * style_header;      /*Style of the header container*/\n    lv_style_t * style_btn_rel;    /*Control button releases style*/\n    lv_style_t * style_btn_pr;     /*Control button pressed style*/\n    lv_coord_t btn_size;               /*Size of the control buttons (square)*/\n} lv_win_ext_t;\n\nenum {\n    LV_WIN_STYLE_BG,\n    LV_WIN_STYLE_CONTENT_BG,\n    LV_WIN_STYLE_CONTENT_SCRL,\n    LV_WIN_STYLE_SB,\n    LV_WIN_STYLE_HEADER,\n    LV_WIN_STYLE_BTN_REL,\n    LV_WIN_STYLE_BTN_PR,\n};\ntypedef uint8_t lv_win_style_t;\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Create a window objects\n * @param par pointer to an object, it will be the parent of the new window\n * @param copy pointer to a window object, if not NULL then the new object will be copied from it\n * @return pointer to the created window\n */\nlv_obj_t * lv_win_create(lv_obj_t * par, const lv_obj_t * copy);\n\n/**\n * Delete all children of the scrl object, without deleting scrl child.\n * @param obj pointer to an object\n */\nvoid lv_win_clean(lv_obj_t *obj);\n\n/*======================\n * Add/remove functions\n *=====================*/\n\n/**\n * Add control button to the header of the window\n * @param win pointer to a window object\n * @param img_src an image source ('lv_img_t' variable, path to file or a symbol)\n * @param rel_action a function pointer to call when the button is released\n * @return pointer to the created button object\n */\nlv_obj_t * lv_win_add_btn(lv_obj_t * win, const void * img_src, const char * label_src, lv_action_t rel_action);\n\n/*=====================\n * Setter functions\n *====================*/\n\n/**\n * A release action which can be assigned to a window control button to close it\n * @param btn pointer to the released button\n * @return always LV_ACTION_RES_INV because the button is deleted with the window\n */\nlv_res_t lv_win_close_action(lv_obj_t * btn);\n\n/**\n * Set the title of a window\n * @param win pointer to a window object\n * @param title string of the new title\n */\nvoid lv_win_set_title(lv_obj_t * win, const char * title);\n\n/**\n * Set the control button size of a window\n * @param win pointer to a window object\n * @return control button size\n */\nvoid lv_win_set_btn_size(lv_obj_t * win, lv_coord_t size);\n\n/**\n * Set the layout of the window\n * @param win pointer to a window object\n * @param layout the layout from 'lv_layout_t'\n */\nvoid lv_win_set_layout(lv_obj_t *win, lv_layout_t layout);\n\n/**\n * Set the scroll bar mode of a window\n * @param win pointer to a window object\n * @param sb_mode the new scroll bar mode from  'lv_sb_mode_t'\n */\nvoid lv_win_set_sb_mode(lv_obj_t *win, lv_sb_mode_t sb_mode);\n\n/**\n * Set a style of a window\n * @param win pointer to a window object\n * @param type which style should be set\n * @param style pointer to a style\n */\nvoid lv_win_set_style(lv_obj_t *win, lv_win_style_t type, lv_style_t *style);\n\n/**\n * Set drag status of a window. If set to 'true' window can be dragged like on a PC.\n * @param win pointer to a window object\n * @param en whether dragging is enabled\n */\nvoid lv_win_set_drag(lv_obj_t *win, bool en);\n\n/*=====================\n * Getter functions\n *====================*/\n\n/**\n * Get the title of a window\n * @param win pointer to a window object\n * @return title string of the window\n */\nconst char * lv_win_get_title(const lv_obj_t * win);\n\n/**\n* Get the content holder object of window (`lv_page`) to allow additional customization\n* @param win pointer to a window object\n* @return the Page object where the window's content is\n*/\nlv_obj_t * lv_win_get_content(const lv_obj_t * win);\n\n/**\n * Get the control button size of a window\n * @param win pointer to a window object\n * @return control button size\n */\nlv_coord_t lv_win_get_btn_size(const lv_obj_t * win);\n\n/**\n * Get the pointer of a widow from one of  its control button.\n * It is useful in the action of the control buttons where only button is known.\n * @param ctrl_btn pointer to a control button of a window\n * @return pointer to the window of 'ctrl_btn'\n */\nlv_obj_t * lv_win_get_from_btn(const lv_obj_t * ctrl_btn);\n\n/**\n * Get the layout of a window\n * @param win pointer to a window object\n * @return the layout of the window (from 'lv_layout_t')\n */\nlv_layout_t lv_win_get_layout(lv_obj_t *win);\n\n/**\n * Get the scroll bar mode of a window\n * @param win pointer to a window object\n * @return the scroll bar mode of the window (from 'lv_sb_mode_t')\n */\nlv_sb_mode_t lv_win_get_sb_mode(lv_obj_t *win);\n\n/**\n * Get width of the content area (page scrollable) of the window\n * @param win pointer to a window object\n * @return the width of the content area\n */\nlv_coord_t lv_win_get_width(lv_obj_t * win);\n\n/**\n * Get a style of a window\n * @param win pointer to a button object\n * @param type which style window be get\n * @return style pointer to a style\n */\nlv_style_t * lv_win_get_style(const lv_obj_t *win, lv_win_style_t type);\n\n/**\n * Get drag status of a window. If set to 'true' window can be dragged like on a PC.\n * @param win pointer to a window object\n * @return whether window is draggable\n */\nstatic inline bool lv_win_get_drag(const lv_obj_t *win)\n{\n    return lv_obj_get_drag(win);\n}\n\n/*=====================\n * Other functions\n *====================*/\n\n/**\n * Focus on an object. It ensures that the object will be visible in the window.\n * @param win pointer to a window object\n * @param obj pointer to an object to focus (must be in the window)\n * @param anim_time scroll animation time in milliseconds (0: no animation)\n */\nvoid lv_win_focus(lv_obj_t * win, lv_obj_t * obj, uint16_t anim_time);\n\n/**\n * Scroll the window horizontally\n * @param win pointer to a window object\n * @param dist the distance to scroll (< 0: scroll right; > 0 scroll left)\n */\nstatic inline void lv_win_scroll_hor(lv_obj_t * win, lv_coord_t dist)\n{\n    lv_win_ext_t * ext = (lv_win_ext_t *)lv_obj_get_ext_attr(win);\n    lv_page_scroll_hor(ext->page, dist);\n}\n/**\n * Scroll the window vertically\n * @param win pointer to a window object\n * @param dist the distance to scroll (< 0: scroll down; > 0 scroll up)\n */\nstatic inline void lv_win_scroll_ver(lv_obj_t * win, lv_coord_t dist)\n{\n    lv_win_ext_t * ext = (lv_win_ext_t *)lv_obj_get_ext_attr(win);\n    lv_page_scroll_ver(ext->page, dist);\n}\n\n/**********************\n *      MACROS\n **********************/\n\n#endif /*USE_LV_WIN*/\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_WIN_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_themes/lv_theme.c",
    "content": "/**\n * @file lv_theme.c\n *\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_theme.h\"\n#include \"../lv_core/lv_obj.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n\n/**********************\n *  STATIC VARIABLES\n **********************/\n\n#if LV_THEME_LIVE_UPDATE == 0\nstatic lv_theme_t * current_theme;\n#else\n/* If live update is used then a big `lv_style_t` array is used to store the real styles of the theme not only pointers.\n * On `lv_theme_set_current` the styles of the theme are copied to this array.\n * The pointers in `current_theme` are initialized to point to the styles in the array.\n * This way the theme styles will always point to the same memory address even after theme is change.\n * (The pointers in the theme points to the styles declared by the theme itself) */\n\n/* Store the styles in this array.\n * Can't determine the size in compile time because sizeof is not evaluated (should be `sizeof(lv_theme_t) / sizeof(lv_style_t*)`).\n * Error will be generated in run time if too small.*/\nstatic lv_style_t th_styles[120];\nstatic bool inited = false;\nstatic lv_theme_t current_theme;\n#endif\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n/**\n * Set a theme for the system.\n * From now, all the created objects will use styles from this theme by default\n * @param th pointer to theme (return value of: 'lv_theme_init_xxx()')\n */\nvoid lv_theme_set_current(lv_theme_t * th)\n{\n#if LV_THEME_LIVE_UPDATE == 0\n    current_theme = th;\n#else\n    uint32_t style_num = sizeof(lv_theme_t) / sizeof(lv_style_t *);     /*Number of styles in a theme*/\n\n    if(!inited) {\n        /*It's not sure `th_styles` is big enough. Check it now!*/\n        if(style_num > sizeof(th_styles) / sizeof(lv_style_t)) {\n            LV_LOG_ERROR(\"Themes: th_styles array is too small. Increase it's size!\");\n            while(1);\n        }\n\n        /*Initialize the style pointers `current_theme` to point to the `th_styles` style array */\n        uint16_t i;\n        lv_style_t ** cur_th_style_p = (lv_style_t **) &current_theme;\n        for(i = 0; i < style_num; i++) {\n            uintptr_t adr = (uintptr_t)&th_styles[i];\n            memcpy(&cur_th_style_p[i], &adr, sizeof(lv_style_t *));\n        }\n        inited = true;\n    }\n\n\n    /*Copy the styles pointed by the new theme to the `th_styles` style array*/\n    uint16_t i;\n    lv_style_t ** th_style = (lv_style_t **) th;\n    for(i = 0; i < style_num; i++) {\n        uintptr_t s = (uintptr_t)th_style[i];\n        if(s) memcpy(&th_styles[i], (void *)s, sizeof(lv_style_t));\n    }\n\n    /*Let the object know their style might change*/\n    lv_obj_report_style_mod(NULL);\n#endif\n}\n\n/**\n * Get the current system theme.\n * @return pointer to the current system theme. NULL if not set.\n */\nlv_theme_t * lv_theme_get_current(void)\n{\n#if LV_THEME_LIVE_UPDATE == 0\n    return current_theme;\n#else\n    if(!inited) return NULL;\n    else return &current_theme;\n#endif\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_themes/lv_theme.h",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n *@file lv_themes.h\n *\n */\n\n#ifndef LV_THEMES_H\n#define LV_THEMES_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *    INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#include \"../lv_core/lv_style.h\"\n\n/*********************\n *    DEFINES\n *********************/\n\n/**********************\n *    TYPEDEFS\n **********************/\n\ntypedef struct {\n    lv_style_t *bg;\n    lv_style_t *panel;\n\n#if USE_LV_CONT != 0\n    lv_style_t *cont;\n#endif\n\n#if USE_LV_BTN != 0\n    struct {\n        lv_style_t *rel;\n        lv_style_t *pr;\n        lv_style_t *tgl_rel;\n        lv_style_t *tgl_pr;\n        lv_style_t *ina;\n    } btn;\n#endif\n\n\n#if USE_LV_IMGBTN != 0\n    struct {\n        lv_style_t *rel;\n        lv_style_t *pr;\n        lv_style_t *tgl_rel;\n        lv_style_t *tgl_pr;\n        lv_style_t *ina;\n    } imgbtn;\n#endif\n\n#if USE_LV_LABEL != 0\n    struct {\n        lv_style_t *prim;\n        lv_style_t *sec;\n        lv_style_t *hint;\n    } label;\n#endif\n\n#if USE_LV_LINE != 0\n    struct {\n        lv_style_t *decor;\n    } line;\n#endif\n\n#if USE_LV_LED != 0\n    lv_style_t *led;\n#endif\n\n#if USE_LV_BAR != 0\n    struct {\n        lv_style_t *bg;\n        lv_style_t *indic;\n    } bar;\n#endif\n\n#if USE_LV_SLIDER != 0\n    struct {\n        lv_style_t *bg;\n        lv_style_t *indic;\n        lv_style_t *knob;\n    } slider;\n#endif\n\n#if USE_LV_LMETER != 0\n    lv_style_t *lmeter;\n#endif\n\n#if USE_LV_GAUGE != 0\n    lv_style_t *gauge;\n#endif\n\n#if USE_LV_ARC != 0\n    lv_style_t *arc;\n#endif\n\n#if USE_LV_PRELOAD != 0\n    lv_style_t *preload;\n#endif\n\n#if USE_LV_SW != 0\n    struct {\n        lv_style_t *bg;\n        lv_style_t *indic;\n        lv_style_t *knob_off;\n        lv_style_t *knob_on;\n    } sw;\n#endif\n\n#if USE_LV_CHART != 0\n    lv_style_t *chart;\n#endif\n\n#if USE_LV_CALENDAR != 0\n    struct {\n        lv_style_t *bg;\n        lv_style_t *header;\n        lv_style_t *header_pr;\n        lv_style_t *day_names;\n        lv_style_t *highlighted_days;\n        lv_style_t *inactive_days;\n        lv_style_t *week_box;\n        lv_style_t *today_box;\n    } calendar;\n#endif\n\n#if USE_LV_CB != 0\n    struct {\n        lv_style_t *bg;\n        struct {\n            lv_style_t *rel;\n            lv_style_t *pr;\n            lv_style_t *tgl_rel;\n            lv_style_t *tgl_pr;\n            lv_style_t *ina;\n        } box;\n    } cb;\n#endif\n\n#if USE_LV_BTNM != 0\n    struct {\n        lv_style_t *bg;\n        struct {\n            lv_style_t *rel;\n            lv_style_t *pr;\n            lv_style_t *tgl_rel;\n            lv_style_t *tgl_pr;\n            lv_style_t *ina;\n        } btn;\n    } btnm;\n#endif\n\n#if USE_LV_KB != 0\n    struct {\n        lv_style_t *bg;\n        struct {\n            lv_style_t *rel;\n            lv_style_t *pr;\n            lv_style_t *tgl_rel;\n            lv_style_t *tgl_pr;\n            lv_style_t *ina;\n        } btn;\n    } kb;\n#endif\n\n#if USE_LV_MBOX != 0\n    struct {\n        lv_style_t *bg;\n        struct {\n            lv_style_t *bg;\n            lv_style_t *rel;\n            lv_style_t *pr;\n        } btn;\n    } mbox;\n#endif\n\n#if USE_LV_PAGE != 0\n    struct {\n        lv_style_t *bg;\n        lv_style_t *scrl;\n        lv_style_t *sb;\n    } page;\n#endif\n\n#if USE_LV_TA != 0\n    struct {\n        lv_style_t *area;\n        lv_style_t *oneline;\n        lv_style_t *cursor;\n        lv_style_t *sb;\n    } ta;\n#endif\n\n#if USE_LV_SPINBOX != 0\n    struct {\n        lv_style_t *bg;\n        lv_style_t *cursor;\n        lv_style_t *sb;\n    } spinbox;\n#endif\n\n#if USE_LV_LIST\n    struct {\n        lv_style_t *bg;\n        lv_style_t *scrl;\n        lv_style_t *sb;\n        struct {\n            lv_style_t *rel;\n            lv_style_t *pr;\n            lv_style_t *tgl_rel;\n            lv_style_t *tgl_pr;\n            lv_style_t *ina;\n        } btn;\n    } list;\n#endif\n\n#if USE_LV_DDLIST != 0\n    struct {\n        lv_style_t *bg;\n\t\tlv_style_t *bgo;\n\t\tlv_style_t *pr;\n        lv_style_t *sel;\n        lv_style_t *sb;\n    } ddlist;\n#endif\n\n#if USE_LV_ROLLER != 0\n    struct {\n        lv_style_t *bg;\n        lv_style_t *sel;\n    } roller;\n#endif\n\n#if USE_LV_TABVIEW != 0\n    struct {\n        lv_style_t *bg;\n        lv_style_t *indic;\n        struct {\n            lv_style_t *bg;\n            lv_style_t *rel;\n            lv_style_t *pr;\n            lv_style_t *tgl_rel;\n            lv_style_t *tgl_pr;\n        } btn;\n    } tabview;\n#endif\n\n#if USE_LV_TILEVIEW != 0\n    struct {\n        lv_style_t *bg;\n        lv_style_t *scrl;\n        lv_style_t *sb;\n    } tileview;\n#endif\n\n#if USE_LV_TABLE != 0\n    struct {\n        lv_style_t *bg;\n        lv_style_t *cell;\n    } table;\n#endif\n\n#if USE_LV_WIN != 0\n    struct {\n        lv_style_t *bg;\n        lv_style_t *sb;\n        lv_style_t *header;\n        struct {\n            lv_style_t *bg;\n            lv_style_t *scrl;\n        } content;\n        struct {\n            lv_style_t *rel;\n            lv_style_t *pr;\n        } btn;\n    } win;\n#endif\n} lv_theme_t;\n\n/**********************\n *  GLOBAL PROTOTYPES\n **********************/\n\n/**\n * Set a theme for the system.\n * From now, all the created objects will use styles from this theme by default\n * @param th pointer to theme (return value of: 'lv_theme_init_xxx()')\n */\nvoid lv_theme_set_current(lv_theme_t *th);\n\n/**\n * Get the current system theme.\n * @return pointer to the current system theme. NULL if not set.\n */\nlv_theme_t * lv_theme_get_current(void);\n\n/**********************\n *    MACROS\n **********************/\n\n/**********************\n *     POST INCLUDE\n *********************/\n#include \"lv_theme_hekate.h\"\n\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_THEMES_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_themes/lv_theme_hekate.c",
    "content": "/*\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/*********************\n *      INCLUDES\n *********************/\n#include \"lv_theme.h\"\n\n#if USE_LV_THEME_HEKATE\n\n/*********************\n *      DEFINES\n *********************/\n#define DEF_RADIUS             4\n\n#define COLOR_HOS_TURQUOISE    (_hue ? lv_color_hsv_to_rgb(_hue, 100, 100) : lv_color_hsv_to_rgb(53, 8, 90)) // 0x00FFC9\n#define COLOR_HOS_TEAL_LIGHTER (_hue ? lv_color_hsv_to_rgb(_hue, 100,  93) : lv_color_hsv_to_rgb(53, 8, 81)) // 0x00EDBA\n#define COLOR_HOS_TEAL_LIGHT   (_hue ? lv_color_hsv_to_rgb(_hue, 100,  72) : lv_color_hsv_to_rgb(53, 8, 65)) // 0x00B78F\n#define COLOR_HOS_TEAL         (_hue ? lv_color_hsv_to_rgb(_hue, 100,  64) : lv_color_hsv_to_rgb(53, 8, 58)) // 0x00A273\n#define COLOR_HOS_ORANGE       LV_COLOR_HEX(0xFF5500)\n#define COLOR_HOS_TXT_WHITE    LV_COLOR_HEX(0xFBFBFB)\n\n#define COLOR_BG_DARK          LV_COLOR_HEX(theme_bg_color ? (theme_bg_color - 0x0B0B0B) : 0x121212) // 0x222222.\n#define COLOR_BG               LV_COLOR_HEX(theme_bg_color)                                          // 0x2D2D2D.\n#define COLOR_BG_LIGHT         LV_COLOR_HEX(theme_bg_color ? (theme_bg_color + 0x101010) : 0x2D2D2D) // 0x3D3D3D.\n#define COLOR_BG_LIGHTER       LV_COLOR_HEX(theme_bg_color ? (theme_bg_color + 0x191919) : 0x363636) // 0x464646.\n\n#define COLOR_INACTIVE         LV_COLOR_HEX(theme_bg_color ? (theme_bg_color + 0x171717) : 0x343434) // 0x444444.\n#define COLOR_BAR              LV_COLOR_HEX(theme_bg_color ? (theme_bg_color + 0x202020) : 0x3D3D3D) // 0x4D4D4D.\n#define COLOR_PRESS            LV_COLOR_HEX(theme_bg_color ? (theme_bg_color + 0x232323) : 0x404040) // 0x505050.\n#define COLOR_LINE             LV_COLOR_HEX(theme_bg_color ? (theme_bg_color + 0x383838) : 0x555555) // 0x656565.\n\n#define COLOR_SHADOW_LIGHT     LV_COLOR_HEX(0xAAAAAA)\n#define COLOR_SHADOW           LV_COLOR_HEX(theme_bg_color ? theme_bg_color : 0x181818) // 0x2D2D2D.\n#define COLOR_SHADOW_DARK      LV_COLOR_HEX(theme_bg_color ? 0x1F1F1F : 0x0A0A0A)\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n *  STATIC PROTOTYPES\n **********************/\n\n/**********************\n *  STATIC VARIABLES\n **********************/\nstatic lv_theme_t theme;\nstatic lv_style_t def;\n\n/*Static style definitions*/\nstatic lv_style_t sb;\n\n/*Saved input parameters*/\nstatic uint16_t    _hue;\nstatic lv_font_t * _font;\nuint32_t theme_bg_color;\n\n/**********************\n *      MACROS\n **********************/\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\nstatic void basic_init(void)\n{\n\tstatic lv_style_t bg, panel;\n\n\tlv_style_copy(&def, &lv_style_plain); // Initialize the default style.\n\tdef.text.font = _font;\n\tdef.body.radius = DEF_RADIUS;\n\tdef.text.color = COLOR_HOS_TXT_WHITE;\n\t//def.image.color = COLOR_HOS_TXT_WHITE; //Needed if symbol image.\n\t//def.image.opa = LV_OPA_COVER;\n\n\tlv_style_copy(&bg, &def);\n\tbg.body.main_color = COLOR_BG;\n\tbg.body.grad_color = bg.body.main_color;\n\tbg.body.radius = 0;\n\tbg.body.empty = 1;\n\n\tlv_style_copy(&panel, &def);\n\tpanel.body.radius = DEF_RADIUS;\n\tpanel.body.main_color = COLOR_BG;\n\tpanel.body.grad_color = panel.body.main_color;\n\tpanel.body.border.width = 1;\n\tpanel.body.border.color = COLOR_BAR;\n\tpanel.body.border.opa = LV_OPA_COVER;\n\tpanel.body.shadow.color = COLOR_SHADOW_LIGHT;\n\tpanel.body.shadow.type = LV_SHADOW_BOTTOM;\n\tpanel.body.shadow.width = 4;\n\tpanel.body.padding.hor = LV_DPI / 8;\n\tpanel.body.padding.ver = LV_DPI / 8;\n\tpanel.body.padding.inner = LV_DPI / 12;\n\t//panel.text.color = COLOR_HOS_TXT_WHITE;\n\n\tlv_style_copy(&sb, &def);\n\tsb.body.main_color = LV_COLOR_BLACK;\n\tsb.body.grad_color = sb.body.grad_color;\n\tsb.body.opa = LV_OPA_40;\n\tsb.body.padding.hor = LV_DPI / 25;\n\n\ttheme.bg = &bg;\n\ttheme.panel = &panel;\n}\n\nstatic void cont_init(void)\n{\n#if USE_LV_CONT != 0\n\tstatic lv_style_t cont;\n\tlv_style_copy(&cont, theme.panel);\n\tcont.body.shadow.width = 0;\n\tcont.body.border.width = 0;\n\n\ttheme.cont = &cont;\n#endif\n}\n\nstatic void btn_init(void)\n{\n#if USE_LV_BTN != 0\n\tstatic lv_style_t rel, pr, tgl_rel, tgl_pr, ina;\n\n\tlv_style_copy(&rel, &def);\n\trel.body.main_color = COLOR_BG_LIGHT;\n\trel.body.grad_color = rel.body.main_color;\n\trel.body.radius = 6;\n\trel.body.padding.hor = LV_DPI / 3;\n\trel.body.padding.ver = LV_DPI / 6;\n\trel.body.padding.inner = LV_DPI / 10;\n\trel.body.shadow.color = COLOR_SHADOW_DARK;\n\trel.body.shadow.type = LV_SHADOW_BOTTOM;\n\trel.body.shadow.width = 6;\n\trel.body.border.width = 0;\n\trel.body.border.color = COLOR_BG_LIGHT;\n\trel.body.border.part = LV_BORDER_FULL;\n\t//rel.text.color = COLOR_HOS_TXT_WHITE;\n\n\tlv_style_copy(&pr, &rel);\n\tpr.body.main_color = COLOR_PRESS;\n\tpr.body.grad_color = pr.body.main_color;\n\tpr.body.shadow.width = 0;\n\tpr.body.border.color = COLOR_HOS_TEAL_LIGHTER;\n\tpr.text.color = COLOR_HOS_TURQUOISE;\n\tpr.body.border.width = 4;\n\n\tlv_style_copy(&tgl_rel, &rel);\n\ttgl_rel.body.border.color = COLOR_HOS_TEAL_LIGHTER;\n\ttgl_rel.body.border.width = 4;\n\n\tlv_style_copy(&tgl_pr, &tgl_rel);\n\ttgl_pr.body.main_color = COLOR_PRESS;\n\ttgl_pr.body.grad_color = tgl_pr.body.main_color;\n\ttgl_pr.text.color = COLOR_HOS_TURQUOISE;\n\ttgl_pr.body.shadow.width = 0;\n\n\tlv_style_copy(&ina, &rel);\n\tina.body.main_color = COLOR_BG_DARK;\n\tina.body.grad_color = ina.body.main_color;\n\t//ina.body.shadow.width = 0;\n\tina.text.color = LV_COLOR_HEX(0x888888);\n\tina.body.border.width = 4;\n\n\ttheme.btn.rel = &rel;\n\ttheme.btn.pr = &pr;\n\ttheme.btn.tgl_rel = &tgl_rel;\n\ttheme.btn.tgl_pr =  &tgl_pr;\n\ttheme.btn.ina =  &ina;\n#endif\n}\n\n\nstatic void label_init(void)\n{\n#if USE_LV_LABEL != 0\n\tstatic lv_style_t prim, sec, hint;\n\n\tlv_style_copy(&prim, &def);\n\tprim.text.font = _font;\n\tprim.text.color = COLOR_HOS_TXT_WHITE;\n\n\tlv_style_copy(&sec, &prim);\n\tsec.text.color = COLOR_HOS_ORANGE;\n\n\tlv_style_copy(&hint, &prim);\n\thint.text.color = LV_COLOR_HEX(0xCCCCCC);\n\n\ttheme.label.prim = &prim;\n\ttheme.label.sec = &sec;\n\ttheme.label.hint = &hint;\n#endif\n}\n\nstatic void line_init(void)\n{\n#if USE_LV_LINE != 0\n\tstatic lv_style_t line;\n\tlv_style_copy(&line, &def);\n\tline.line.color = COLOR_LINE;\n\ttheme.line.decor = &line;\n#endif\n}\n\nstatic void led_init(void)\n{\n#if USE_LV_LED != 0\n\tstatic lv_style_t led;\n\tlv_style_copy(&led, &def);\n\tled.body.shadow.width = LV_DPI / 10;\n\tled.body.radius = LV_RADIUS_CIRCLE;\n\tled.body.border.width = LV_DPI / 30;\n\tled.body.border.opa = LV_OPA_30;\n\tled.body.main_color = lv_color_hsv_to_rgb(_hue, 100, 100);\n\tled.body.grad_color = led.body.main_color;\n\tled.body.border.color = lv_color_hsv_to_rgb(_hue, 60, 60);\n\tled.body.shadow.color = lv_color_hsv_to_rgb(_hue, 100, 100);\n\n\ttheme.led = &led;\n#endif\n}\n\nstatic void bar_init(void)\n{\n#if USE_LV_BAR\n\tstatic lv_style_t bar_bg, bar_indic;\n\n\tlv_style_copy(&bar_bg, &def);\n\tbar_bg.body.main_color = COLOR_BAR;\n\tbar_bg.body.grad_color = bar_bg.body.main_color;\n\tbar_bg.body.radius = 3;\n\tbar_bg.body.border.width = 0;\n\tbar_bg.body.padding.hor = LV_DPI / 12;\n\tbar_bg.body.padding.ver = LV_DPI / 12;\n\n\tlv_style_copy(&bar_indic, &bar_bg);\n\tbar_indic.body.main_color = COLOR_HOS_TURQUOISE;\n\tbar_indic.body.grad_color = bar_indic.body.main_color;\n\tbar_indic.body.padding.hor = 0;\n\tbar_indic.body.padding.ver = 0;\n\n\ttheme.bar.bg = &bar_bg;\n\ttheme.bar.indic = &bar_indic;\n#endif\n}\n\nstatic void slider_init(void)\n{\n#if USE_LV_SLIDER != 0\n\tstatic lv_style_t knob;\n\tstatic lv_style_t slide_bar;\n\n\tlv_style_copy(&knob, &def);\n\tknob.body.radius = LV_RADIUS_CIRCLE;\n\tknob.body.border.width = 0;\n\tknob.body.main_color = theme.bar.indic->body.main_color;\n\tknob.body.grad_color = knob.body.main_color;\n\n\tlv_style_copy(&slide_bar, theme.bar.indic);\n\tslide_bar.body.main_color = COLOR_HOS_TEAL_LIGHT;\n\tslide_bar.body.grad_color = slide_bar.body.main_color;\n\n\ttheme.slider.bg = theme.bar.bg;\n\ttheme.slider.indic = &slide_bar;\n\ttheme.slider.knob = &knob;\n#endif\n}\n\nstatic void sw_init(void)\n{\n#if USE_LV_SW != 0\n\tstatic lv_style_t sw_bg, sw_indic, sw_knob_off, sw_knob_on;\n\tlv_style_copy(&sw_bg, theme.slider.bg);\n\tsw_bg.body.radius = LV_RADIUS_CIRCLE;\n\n\tlv_style_copy(&sw_indic, theme.slider.bg);\n\tsw_indic.body.radius = LV_RADIUS_CIRCLE;\n\n\tlv_style_copy(&sw_knob_on, theme.slider.knob);\n\n\tlv_style_copy(&sw_knob_off, &sw_knob_on);\n\tsw_knob_off.body.main_color = LV_COLOR_HEX(0xDADADA);\n\tsw_knob_off.body.grad_color = sw_knob_off.body.main_color;\n\tsw_knob_off.body.border.width = 1;\n\tsw_knob_off.body.border.color = LV_COLOR_HEX(0x999999);\n\tsw_knob_off.body.border.opa = LV_OPA_COVER;\n\n\ttheme.sw.bg = &sw_bg;\n\ttheme.sw.indic = &sw_indic;\n\ttheme.sw.knob_off = &sw_knob_off;\n\ttheme.sw.knob_on = &sw_knob_on;\n#endif\n}\n\n\nstatic void lmeter_init(void)\n{\n#if USE_LV_LMETER != 0\n\tstatic lv_style_t lmeter;\n\tlv_style_copy(&lmeter, &def);\n\tlmeter.body.main_color = lv_color_hsv_to_rgb(_hue, 75, 90);\n\tlmeter.body.grad_color = lmeter.body.main_color;\n\tlmeter.body.padding.hor = LV_DPI / 10; // Scale line length.\n\tlmeter.line.color = LV_COLOR_HEX(0x999999);\n\tlmeter.line.width = 2;\n\n\ttheme.lmeter = &lmeter;\n#endif\n}\n\nstatic void gauge_init(void)\n{\n#if USE_LV_GAUGE != 0\n\n\tstatic lv_style_t gauge;\n\tlv_style_copy(&gauge, &def);\n\tgauge.body.main_color = lv_color_hsv_to_rgb(_hue, 10, 60);\n\tgauge.body.grad_color = gauge.body.main_color;\n\tgauge.body.padding.hor = LV_DPI / 16; // Scale line length.\n\tgauge.body.padding.inner = LV_DPI / 8;\n\tgauge.body.border.color = LV_COLOR_HEX(0x999999);\n\tgauge.text.color = LV_COLOR_HEX(0xDDDDDD);\n\tgauge.line.width = 3;\n\tgauge.line.color = lv_color_hsv_to_rgb(_hue, 95, 70);\n\n\ttheme.gauge = &gauge;\n#endif\n}\n\nstatic void arc_init(void)\n{\n#if USE_LV_ARC != 0\n\n\tstatic lv_style_t arc;\n\tlv_style_copy(&arc, &def);\n\tarc.line.width = 10;\n\tarc.line.color = lv_color_hsv_to_rgb(_hue, 90, 90);\n\n\t/*For prelaoder*/\n\tarc.body.border.width = 10;\n\tarc.body.border.color = lv_color_hsv_to_rgb(_hue, 30, 90);\n\tarc.body.padding.hor = 0;\n\tarc.body.padding.ver = 0;\n\n\ttheme.arc = &arc;\n#endif\n}\n\nstatic void preload_init(void)\n{\n#if USE_LV_PRELOAD != 0\n\n\ttheme.preload = theme.arc;\n#endif\n}\n\nstatic void chart_init(void)\n{\n#if USE_LV_CHART\n\ttheme.chart = theme.panel;\n#endif\n}\n\nstatic void calendar_init(void)\n{\n#if USE_LV_CALENDAR\n\tstatic lv_style_t ina_days;\n\tlv_style_copy(&ina_days, &def);\n\tina_days.text.color = lv_color_hsv_to_rgb(_hue, 0, 70);\n\n\tstatic lv_style_t high_days;\n\tlv_style_copy(&high_days, &def);\n\thigh_days.text.color = lv_color_hsv_to_rgb(_hue, 80, 90);\n\n\tstatic lv_style_t week_box;\n\tlv_style_copy(&week_box, &def);\n\tweek_box.body.main_color = lv_color_hsv_to_rgb(_hue, 40, 100);\n\tweek_box.body.grad_color = week_box.body.main_color;\n\tweek_box.body.padding.ver = LV_DPI / 20;\n\tweek_box.body.padding.hor = theme.panel->body.padding.hor;\n\tweek_box.body.border.color = theme.panel->body.border.color;\n\tweek_box.body.border.width = theme.panel->body.border.width;\n\tweek_box.body.border.part = LV_BORDER_LEFT | LV_BORDER_RIGHT;\n\tweek_box.body.radius = 0;\n\n\tstatic lv_style_t today_box;\n\tlv_style_copy(&today_box, &def);\n\ttoday_box.body.main_color = LV_COLOR_WHITE;\n\ttoday_box.body.grad_color = today_box.body.main_color;\n\ttoday_box.body.padding.ver = LV_DPI / 20;\n\ttoday_box.body.radius = 0;\n\n\ttheme.calendar.bg = theme.panel;\n\ttheme.calendar.header = &lv_style_transp;\n\ttheme.calendar.inactive_days = &ina_days;\n\ttheme.calendar.highlighted_days = &high_days;\n\ttheme.calendar.week_box = &week_box;\n\ttheme.calendar.today_box = &today_box;\n#endif\n}\n\nstatic void cb_init(void)\n{\n#if USE_LV_CB != 0\n\tstatic lv_style_t rel, pr, tgl_rel, tgl_pr, ina;\n\tlv_style_copy(&rel, theme.panel);\n\trel.body.shadow.type = LV_SHADOW_FULL;\n\trel.body.shadow.width = 3;\n\n\tlv_style_copy(&pr, &rel);\n\tpr.body.main_color = LV_COLOR_HEX(0xCCCCCC);\n\tpr.body.grad_color = pr.body.main_color;\n\tpr.body.shadow.width = 3;\n\n\tlv_style_copy(&tgl_rel, &rel);\n\ttgl_rel.body.main_color = lv_color_hsv_to_rgb(_hue, 75, 85);\n\ttgl_rel.body.grad_color = tgl_rel.body.main_color;\n\ttgl_rel.body.shadow.width = 0;\n\n\tlv_style_copy(&tgl_pr, &tgl_rel);\n\ttgl_pr.body.main_color = lv_color_hsv_to_rgb(_hue, 75, 65);\n\ttgl_pr.body.grad_color = tgl_pr.body.main_color;\n\n\tlv_style_copy(&ina, theme.btn.ina);\n\n\ttheme.cb.bg = &lv_style_transp;\n\ttheme.cb.box.rel = &rel;\n\ttheme.cb.box.pr = &pr;\n\ttheme.cb.box.tgl_rel = &tgl_rel;\n\ttheme.cb.box.tgl_pr = &tgl_pr;\n\ttheme.cb.box.ina = &ina;\n#endif\n}\n\n\nstatic void btnm_init(void)\n{\n#if USE_LV_BTNM\n\tstatic lv_style_t bg, rel, pr, tgl_rel, tgl_pr, ina;\n\n\tlv_style_copy(&bg, theme.panel);\n\tbg.body.padding.hor = 0;\n\tbg.body.padding.ver = 0;\n\tbg.body.padding.inner = 0;\n\tbg.text.color = LV_COLOR_HEX(0x555555);\n\n\tlv_style_copy(&rel, theme.panel);\n\trel.body.border.part = LV_BORDER_FULL | LV_BORDER_INTERNAL;\n\trel.body.border.width = 1;\n\trel.body.border.color = LV_COLOR_HEX(0xBBBBBB);\n\trel.body.empty = 1;\n\trel.body.shadow.width = 0;\n\n\tlv_style_copy(&pr, &rel);\n\tpr.glass = 0;\n\tpr.body.main_color = LV_COLOR_HEX(0xDDDDDD);\n\tpr.body.grad_color = pr.body.main_color;\n\tpr.body.border.width = 0;\n\tpr.body.empty = 0;\n\n\tlv_style_copy(&tgl_rel, &pr);\n\ttgl_rel.body.main_color = lv_color_hsv_to_rgb(_hue, 90, 70);\n\ttgl_rel.body.grad_color = tgl_rel.body.main_color;\n\ttgl_rel.text.color = lv_color_hsv_to_rgb(_hue, 5, 95);\n\n\tlv_style_copy(&tgl_pr, &tgl_rel);\n\ttgl_pr.body.main_color = lv_color_hsv_to_rgb(_hue, 95, 65);\n\ttgl_pr.body.grad_color = tgl_pr.body.main_color;\n\ttgl_pr.body.border.width = 0;\n\n\tlv_style_copy(&ina, theme.btn.ina);\n\n\ttheme.btnm.bg = &bg;\n\ttheme.btnm.btn.rel = &rel;\n\ttheme.btnm.btn.pr = &pr;\n\ttheme.btnm.btn.tgl_rel = &tgl_rel;\n\ttheme.btnm.btn.tgl_pr = &tgl_pr;\n\ttheme.btnm.btn.ina = &ina;\n#endif\n}\n\nstatic void kb_init(void)\n{\n#if USE_LV_KB\n\n\tstatic lv_style_t bg, rel;\n\n\tlv_style_copy(&bg, theme.btnm.bg);\n\tbg.text.color = LV_COLOR_HEX(0xCCCCCC);\n\tbg.body.border.width = 0;\n\tbg.body.radius = 0;\n\tbg.body.shadow.color = COLOR_SHADOW_DARK;\n\tbg.body.shadow.type = LV_SHADOW_BOTTOM;\n\tbg.body.shadow.width = 4;\n\n\tlv_style_copy(&rel, &lv_style_transp);\n\trel.text.font = _font;\n\n\ttheme.kb.bg = &bg;\n\ttheme.kb.btn.rel = &rel;\n\ttheme.kb.btn.pr = theme.btnm.btn.pr;\n\ttheme.kb.btn.tgl_rel = theme.btnm.btn.tgl_rel;\n\ttheme.kb.btn.tgl_pr = theme.btnm.btn.tgl_pr;\n\ttheme.kb.btn.ina = theme.btnm.btn.ina;\n#endif\n\n}\n\nstatic void mbox_init(void)\n{\n#if USE_LV_MBOX\n\tstatic lv_style_t bg;\n\n\tlv_style_copy(&bg, theme.panel);\n\tbg.body.main_color = COLOR_BG_LIGHTER;\n\tbg.body.grad_color = bg.body.main_color;\n\tbg.body.shadow.color = COLOR_SHADOW;\n\tbg.body.shadow.type = LV_SHADOW_FULL;\n\tbg.body.shadow.width = 8;\n\n\tbg.body.padding.hor = LV_DPI * 3 / 6;\n\tbg.body.padding.ver = LV_DPI / 4;\n\tbg.body.padding.inner = LV_DPI / 3;\n\n\ttheme.mbox.bg = &bg;\n\ttheme.mbox.btn.bg = &lv_style_transp;\n\ttheme.mbox.btn.rel = theme.btn.rel;\n\ttheme.mbox.btn.pr = theme.btn.pr;\n#endif\n}\n\nstatic void page_init(void)\n{\n#if USE_LV_PAGE\n\ttheme.page.bg = theme.panel;\n\ttheme.page.scrl = &lv_style_transp;\n\ttheme.page.sb = &sb;\n#endif\n}\n\nstatic void ta_init(void)\n{\n#if USE_LV_TA\n\tstatic lv_style_t panel, oneline;\n\n\tlv_style_copy(&panel, theme.panel);\n\tpanel.body.border.width = 0;\n\tpanel.body.shadow.color = COLOR_SHADOW_DARK;\n\tpanel.body.shadow.type = LV_SHADOW_FULL;\n\tpanel.body.shadow.width = 3;\n\n\tlv_style_copy(&oneline, &def);\n\toneline.body.empty = 1;\n\toneline.body.radius = 0;\n\toneline.body.border.part = LV_BORDER_BOTTOM;\n\toneline.body.border.width = 3;\n\toneline.body.border.color = LV_COLOR_HEX(0x555555);\n\toneline.body.border.opa = LV_OPA_COVER;\n\toneline.text.color = LV_COLOR_HEX(0x888888);\n\n\ttheme.ta.area = &panel;\n\ttheme.ta.oneline = &oneline;\n\ttheme.ta.cursor = NULL; // Let library to calculate the cursor's style.\n\ttheme.ta.sb = &sb;\n#endif\n}\n\nstatic void spinbox_init(void)\n{\n#if USE_LV_SPINBOX\n\ttheme.spinbox.bg= theme.panel;\n\ttheme.spinbox.cursor = theme.ta.cursor;\n\ttheme.spinbox.sb = theme.ta.sb;\n#endif\n}\n\nstatic void list_init(void)\n{\n#if USE_LV_LIST != 0\n\n\tstatic lv_style_t list_bg, rel, pr, tgl_rel, tgl_pr, ina;\n\n\tlv_style_copy(&list_bg, theme.panel);\n\tlist_bg.body.padding.hor = 0;\n\tlist_bg.body.padding.ver = 0;\n\tlist_bg.body.padding.inner = 0;\n\tlist_bg.body.shadow.width = 0;\n\n\tlv_style_copy(&rel, &lv_style_transp);\n\trel.body.padding.hor = LV_DPI / 8;\n\trel.body.padding.ver = LV_DPI / 6;\n\trel.body.radius = 0;\n\trel.body.border.color = COLOR_INACTIVE;\n\trel.body.border.width = 1;\n\trel.body.border.part = LV_BORDER_BOTTOM;\n\n\tlv_style_copy(&pr, &rel);\n\tpr.glass = 0;\n\tpr.body.main_color = COLOR_PRESS;\n\tpr.body.grad_color = pr.body.main_color;\n\t//pr.body.border.width = 1;\n\tpr.body.empty = 0;\n\t//pr.body.radius = 0;\n   // pr.text.font = _font;\n\n\tlv_style_copy(&tgl_rel, &pr);\n\ttgl_rel.body.main_color = COLOR_BG_LIGHT;\n\ttgl_rel.body.grad_color = tgl_rel.body.main_color;\n\t//tgl_rel.text.color = lv_color_hsv_to_rgb(_hue, 5, 95);\n\ttgl_rel.text.color = COLOR_HOS_TEAL_LIGHTER;\n\n\tlv_style_copy(&tgl_pr, &tgl_rel);\n\ttgl_pr.body.main_color = COLOR_PRESS;\n\ttgl_pr.body.grad_color = tgl_pr.body.main_color;\n\ttgl_pr.body.border.width = 0;\n\n\tlv_style_copy(&ina, &pr);\n\tina.body.main_color = COLOR_BG_DARK;\n\tina.body.grad_color = ina.body.main_color;\n\n\ttheme.list.sb = &sb;\n\ttheme.list.bg = &list_bg;\n\ttheme.list.scrl = &lv_style_transp_tight;\n\ttheme.list.btn.rel = &rel;\n\ttheme.list.btn.pr = &pr;\n\ttheme.list.btn.tgl_rel = &tgl_rel;\n\ttheme.list.btn.tgl_pr = &tgl_pr;\n\ttheme.list.btn.ina = &ina;\n#endif\n}\n\nstatic void ddlist_init(void)\n{\n#if USE_LV_DDLIST != 0\n\tstatic lv_style_t bg, sel;\n\tlv_style_copy(&bg, theme.panel);\n\tbg.body.padding.hor = LV_DPI / 6;\n\t//bg.body.padding.ver = LV_DPI / 6;\n\tbg.body.radius = 0;\n\tbg.body.shadow.width = 0;\n\tbg.body.border.width = 0;\n\tbg.text.line_space = LV_DPI / 8;\n\tbg.text.color = COLOR_HOS_TURQUOISE;\n\n\tlv_style_copy(&sel, &bg);\n\tsel.body.main_color = COLOR_BG_LIGHT;\n\tsel.body.grad_color = sel.body.main_color;\n\n\ttheme.ddlist.bg = &bg;\n\ttheme.ddlist.bgo = &bg;\n\ttheme.ddlist.pr = &sel;\n\ttheme.ddlist.sel = &sel;\n\ttheme.ddlist.sb = &sb;\n#endif\n}\n\nstatic void roller_init(void)\n{\n#if USE_LV_ROLLER != 0\n\tstatic lv_style_t roller_bg, roller_sel;\n\n\tlv_style_copy(&roller_bg, &lv_style_transp);\n\troller_bg.body.padding.hor = LV_DPI / 6;\n\troller_bg.body.padding.ver = LV_DPI / 6;\n\troller_bg.text.line_space = LV_DPI / 8;\n\troller_bg.text.font = _font;\n\troller_bg.glass = 0;\n\troller_bg.text.color = COLOR_INACTIVE;\n\n\tlv_style_copy(&roller_sel, &roller_bg);\n\troller_sel.text.color = COLOR_HOS_TURQUOISE;\n\n\ttheme.roller.bg = &roller_bg;\n\ttheme.roller.sel = &roller_sel;\n#endif\n}\n\nstatic void tabview_init(void)\n{\n#if USE_LV_TABVIEW != 0\n\tstatic lv_style_t indic, btn_bg, rel, pr, tgl_rel, tgl_pr;\n\n\tlv_style_copy(&indic, &def);\n\tindic.body.main_color = COLOR_HOS_TURQUOISE;\n\tindic.body.grad_color = indic.body.main_color;\n\tindic.body.radius = 0;\n\tindic.body.border.width = 0;\n\tindic.body.padding.inner = LV_DPI / 20;\n\tindic.body.opa = LV_OPA_0;\n\n\tlv_style_copy(&btn_bg, &def);\n\tbtn_bg.body.main_color = COLOR_BG;\n\tbtn_bg.body.grad_color = btn_bg.body.main_color;\n\tbtn_bg.body.radius = 0;\n\tbtn_bg.body.empty = 1;\n\tbtn_bg.body.border.width = 0;\n\tbtn_bg.body.border.color = LV_COLOR_HEX(0xDDDDDD);\n\tbtn_bg.body.border.part = LV_BORDER_BOTTOM;\n\tbtn_bg.body.border.opa = LV_OPA_COVER;\n\tbtn_bg.body.shadow.width = 0;\n\tbtn_bg.body.shadow.color = COLOR_SHADOW_LIGHT;\n\tbtn_bg.body.shadow.type = LV_SHADOW_BOTTOM;\n\tbtn_bg.body.padding.inner = 0;\n\tbtn_bg.body.padding.hor = 0;\n\tbtn_bg.body.padding.ver = 0;\n\tbtn_bg.text.color = COLOR_HOS_TXT_WHITE;\n\n\tlv_style_copy(&rel, &lv_style_transp);\n\trel.body.padding.ver = LV_DPI * 4 / 23;\n\trel.text.font = _font;\n\n\tlv_style_copy(&pr, &def);\n\tpr.body.main_color = COLOR_BG_LIGHT;\n\tpr.body.grad_color = pr.body.main_color;\n\tpr.body.border.width = 0;\n\tpr.body.empty = 0;\n\tpr.body.radius = 0;\n\tpr.body.border.color = LV_COLOR_HEX(0x888888);\n\tpr.body.border.part = LV_BORDER_BOTTOM;\n\tpr.body.border.opa = LV_OPA_COVER;\n\tpr.text.color = COLOR_HOS_TURQUOISE;\n\n\tlv_style_copy(&tgl_rel, &lv_style_transp);\n\ttgl_rel.glass = 0;\n\ttgl_rel.text.font = _font;\n\ttgl_rel.text.color = COLOR_HOS_TURQUOISE;\n\n\tlv_style_copy(&tgl_pr, &def);\n\ttgl_pr.body.main_color = COLOR_BG_LIGHT;\n\ttgl_pr.body.grad_color = tgl_pr.body.main_color;\n\ttgl_pr.body.border.width = 0;\n\ttgl_pr.body.empty = 0;\n\ttgl_pr.body.radius = 0;\n\ttgl_pr.text.color = COLOR_HOS_TURQUOISE;\n\n\ttheme.tabview.bg = theme.bg;\n\ttheme.tabview.indic = &indic;\n\ttheme.tabview.btn.bg = &btn_bg;\n\ttheme.tabview.btn.rel = &rel;\n\ttheme.tabview.btn.pr = &pr;\n\ttheme.tabview.btn.tgl_rel = &tgl_rel;\n\ttheme.tabview.btn.tgl_pr = &tgl_pr;\n#endif\n}\n\nstatic void tileview_init(void)\n{\n#if USE_LV_TILEVIEW != 0\n\ttheme.tileview.bg = &lv_style_transp_tight;\n\ttheme.tileview.scrl = &lv_style_transp_tight;\n\ttheme.tileview.sb = theme.page.sb;\n#endif\n}\n\nstatic void table_init(void)\n{\n#if USE_LV_TABLE != 0\n\tstatic lv_style_t cell;\n\tlv_style_copy(&cell, theme.panel);\n\tcell.body.radius = 0;\n\tcell.body.border.width = 1;\n\tcell.body.padding.hor = LV_DPI / 12;\n\tcell.body.padding.ver = LV_DPI / 12;\n\n\ttheme.table.bg = &lv_style_transp_tight;\n\ttheme.table.cell = &cell;\n#endif\n}\n\nstatic void win_init(void)\n{\n#if USE_LV_WIN != 0\n\tstatic lv_style_t header, rel, pr;\n\n\tlv_style_copy(&header, &def);\n\theader.body.main_color = COLOR_BG;\n\theader.body.grad_color = header.body.main_color;\n\theader.body.radius = 0;\n\theader.body.border.width = 0;\n\theader.body.border.color = LV_COLOR_HEX(0xDDDDDD);\n\theader.body.border.part = LV_BORDER_BOTTOM;\n\theader.body.border.opa = LV_OPA_COVER;\n\theader.body.shadow.width = 0;\n\theader.body.shadow.color = COLOR_SHADOW_LIGHT;\n\theader.body.shadow.type = LV_SHADOW_BOTTOM;\n\theader.body.padding.inner = 0;\n\theader.body.padding.hor = 8;\n\theader.body.padding.ver = 0;\n\t//header.text.color = COLOR_HOS_TXT_WHITE;\n\n\tlv_style_copy(&rel, theme.btn.rel);\n\trel.body.radius = 0;\n\trel.body.opa = LV_OPA_0;\n\trel.body.border.width = 0;\n\n\tlv_style_copy(&pr, theme.btn.pr);\n\tpr.body.radius = 0;\n\tpr.body.border.width = 0;\n\n\ttheme.win.bg = theme.panel;\n\ttheme.win.sb = &sb;\n\ttheme.win.header = &header;\n\ttheme.win.content.bg = &lv_style_transp;\n\ttheme.win.content.scrl = &lv_style_transp;\n\ttheme.win.btn.rel = &rel;\n\ttheme.win.btn.pr = &pr;\n#endif\n}\n\n/**********************\n *   GLOBAL FUNCTIONS\n **********************/\n\n\n\n/**\n * Initialize the hekate theme\n * @param hue [0..360] hue value from HSV color space to define the theme's base color\n * @param font pointer to a font (NULL to use the default)\n * @return pointer to the initialized theme\n */\nlv_theme_t * lv_theme_hekate_init(uint32_t bg_color, uint16_t hue, lv_font_t * font)\n{\n\tif(font == NULL) font = LV_FONT_DEFAULT;\n\n\ttheme_bg_color = bg_color;\n\t_hue = hue;\n\t_font = font;\n\n\t/*For backward compatibility initialize all theme elements with a default style */\n\tuint16_t i;\n\tlv_style_t ** style_p = (lv_style_t **) &theme;\n\tfor(i = 0; i < sizeof(lv_theme_t) / sizeof(lv_style_t *); i++) {\n\t\t*style_p = &def;\n\t\tstyle_p++;\n\t}\n\n\tbasic_init();\n\tcont_init();\n\tbtn_init();\n\tlabel_init();\n\tline_init();\n\tled_init();\n\tbar_init();\n\tslider_init();\n\tsw_init();\n\tlmeter_init();\n\tgauge_init();\n\tchart_init();\n\tarc_init();\n\tpreload_init();\n\tcalendar_init();\n\tcb_init();\n\tbtnm_init();\n\tkb_init();\n\tmbox_init();\n\tpage_init();\n\tta_init();\n\tspinbox_init();\n\tlist_init();\n\tddlist_init();\n\troller_init();\n\ttabview_init();\n\ttileview_init();\n\ttable_init();\n\twin_init();\n\n\treturn &theme;\n}\n\n/**\n * Get a pointer to the theme\n * @return pointer to the theme\n */\nlv_theme_t * lv_theme_get_hekate(void)\n{\n\treturn &theme;\n}\n\n/**********************\n *   STATIC FUNCTIONS\n **********************/\n\n#endif\n\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_themes/lv_theme_hekate.h",
    "content": "/*\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef LV_THEME_HEKATE_H\n#define LV_THEME_HEKATE_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n#ifdef LV_CONF_INCLUDE_SIMPLE\n#include \"lv_conf.h\"\n#else\n#include \"../../lv_conf.h\"\n#endif\n\n#if USE_LV_THEME_HEKATE\n\n/*********************\n *      DEFINES\n *********************/\n#define COLOR_BG_BASE_MIN      0x0B0B0B\n#define COLOR_BG_BASE_MAX      0xC7C7C7\n\n#define COLOR_HOS_BG_DARKER    LV_COLOR_HEX(0x1B1B1B)\n#define COLOR_HOS_BG_DARK      LV_COLOR_HEX(0x222222)\n#define COLOR_HOS_BG           LV_COLOR_HEX(0x2D2D2D)\n#define COLOR_HOS_BG_RGB       0x2D2D2D\n#define COLOR_HOS_BG_LIGHT     LV_COLOR_HEX(0x3D3D3D)\n#define COLOR_HOS_BG_LIGHTER   LV_COLOR_HEX(0x4D4D4D)\n\n#define COLOR_HOS_TURQUOISE_EX(hue) (hue ? lv_color_hsv_to_rgb(hue, 100, 100) : lv_color_hsv_to_rgb(53, 8, 90)) // 0x00FFC9\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\nextern uint32_t theme_bg_color;\n\n/**\n * Initialize the material theme\n * @param hue [0..360] hue value from HSV color space to define the theme's base color\n * @param font pointer to a font (NULL to use the default)\n * @return pointer to the initialized theme\n */\nlv_theme_t * lv_theme_hekate_init(uint32_t bg_color, uint16_t hue, lv_font_t *font);\n\n/**\n * Get a pointer to the theme\n * @return pointer to the theme\n */\nlv_theme_t * lv_theme_get_hekate(void);\n\n/**********************\n *      MACROS\n **********************/\n\n#endif\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_THEME_MATERIAL_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_themes/lv_themes.mk",
    "content": "CSRCS += lv_theme.c\nCSRCS += lv_theme_default.c\nCSRCS += lv_theme_templ.c\nCSRCS += lv_theme_material.c\n\nDEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_themes\nVPATH += :$(LVGL_DIR)/lvgl/lv_themes\n\nCFLAGS += \"-I$(LVGL_DIR)/lvgl/lv_themes\"\n"
  },
  {
    "path": "bdk/libs/lvgl/lv_version.h",
    "content": "/**\n * @file lv_version.h\n *\n */\n\n#ifndef LV_VERSION_H\n#define LV_VERSION_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n/*Current version of LittlevGL*/\n#define LVGL_VERSION_MAJOR   5\n#define LVGL_VERSION_MINOR   3\n#define LVGL_VERSION_PATCH   0\n#define LVGL_VERSION_INFO    \"hekate\"\n\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**********************\n *      MACROS\n **********************/\n/* Gives 1 if the x.y.z version is supported in the current version\n * Usage:\n *\n * - Require v6\n * #if LV_VERSION_CHECK(6,0,0)\n *   new_func_in_v6();\n * #endif\n *\n *\n * - Require at least v5.3\n * #if LV_VERSION_CHECK(5,3,0)\n *   new_feature_from_v5_3();\n * #endif\n *\n *\n * - Require v5.3.2 bugfixes\n * #if LV_VERSION_CHECK(5,3,2)\n *   bugfix_in_v5_3_2();\n * #endif\n *\n * */\n#define LV_VERSION_CHECK(x,y,z) (x == LVGL_VERSION_MAJOR && (y < LVGL_VERSION_MINOR || (y == LVGL_VERSION_MINOR && z <= LVGL_VERSION_PATCH)))\n\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /*LV_VERSION_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lvgl.h",
    "content": "/**\n * @file lvgl.h\n * Include all LittleV GL related headers\n */\n\n#ifndef LVGL_H\n#define LVGL_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************\n *      INCLUDES\n *********************/\n\n#include \"lv_version.h\"\n\n#include \"lv_misc/lv_log.h\"\n#include \"lv_misc/lv_task.h\"\n\n#include \"lv_hal/lv_hal.h\"\n\n#include \"lv_core/lv_obj.h\"\n#include \"lv_core/lv_group.h\"\n#include \"lv_core/lv_lang.h\"\n#include \"lv_core/lv_vdb.h\"\n#include \"lv_core/lv_refr.h\"\n\n#include \"lv_themes/lv_theme.h\"\n\n#include \"lv_objx/lv_btn.h\"\n#include \"lv_objx/lv_imgbtn.h\"\n#include \"lv_objx/lv_img.h\"\n#include \"lv_objx/lv_label.h\"\n#include \"lv_objx/lv_line.h\"\n#include \"lv_objx/lv_page.h\"\n#include \"lv_objx/lv_cont.h\"\n#include \"lv_objx/lv_list.h\"\n#include \"lv_objx/lv_chart.h\"\n#include \"lv_objx/lv_table.h\"\n#include \"lv_objx/lv_cb.h\"\n#include \"lv_objx/lv_bar.h\"\n#include \"lv_objx/lv_slider.h\"\n#include \"lv_objx/lv_led.h\"\n#include \"lv_objx/lv_btnm.h\"\n#include \"lv_objx/lv_kb.h\"\n#include \"lv_objx/lv_ddlist.h\"\n#include \"lv_objx/lv_roller.h\"\n#include \"lv_objx/lv_ta.h\"\n#include \"lv_objx/lv_canvas.h\"\n#include \"lv_objx/lv_win.h\"\n#include \"lv_objx/lv_tabview.h\"\n#include \"lv_objx/lv_tileview.h\"\n#include \"lv_objx/lv_mbox.h\"\n#include \"lv_objx/lv_gauge.h\"\n#include \"lv_objx/lv_lmeter.h\"\n#include \"lv_objx/lv_sw.h\"\n#include \"lv_objx/lv_kb.h\"\n#include \"lv_objx/lv_arc.h\"\n#include \"lv_objx/lv_preload.h\"\n#include \"lv_objx/lv_calendar.h\"\n#include \"lv_objx/lv_spinbox.h\"\n\n/*********************\n *      DEFINES\n *********************/\n\n/**********************\n *      TYPEDEFS\n **********************/\n\n/**********************\n * GLOBAL PROTOTYPES\n **********************/\n\n/**********************\n *      MACROS\n **********************/\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /*LVGL_H*/\n"
  },
  {
    "path": "bdk/libs/lvgl/lvgl.mk",
    "content": "include $(LVGL_DIR)/lvgl/lv_core/lv_core.mk\ninclude $(LVGL_DIR)/lvgl/lv_hal/lv_hal.mk\ninclude $(LVGL_DIR)/lvgl/lv_objx/lv_objx.mk\ninclude $(LVGL_DIR)/lvgl/lv_fonts/lv_fonts.mk\ninclude $(LVGL_DIR)/lvgl/lv_misc/lv_misc.mk\ninclude $(LVGL_DIR)/lvgl/lv_themes/lv_themes.mk\ninclude $(LVGL_DIR)/lvgl/lv_draw/lv_draw.mk\n\n"
  },
  {
    "path": "bdk/mem/emc_t210.h",
    "content": "/*\n * Copyright (c) 2019-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _EMC_T210_H_\n#define _EMC_T210_H_\n\n/* External Memory Controller registers */\n#define EMC_INTSTATUS                                                0x0\n#define EMC_INTMASK                                                  0x4\n#define EMC_DBG                                                      0x8\n#define EMC_CFG                                                      0xC\n#define EMC_ADR_CFG                                                  0x10\n#define EMC_REFCTRL                                                  0x20\n#define EMC_PIN                                                      0x24\n#define EMC_TIMING_CONTROL                                           0x28\n#define EMC_RC                                                       0x2C\n#define EMC_RFC                                                      0x30\n#define EMC_RAS                                                      0x34\n#define EMC_RP                                                       0x38\n#define EMC_R2W                                                      0x3C\n#define EMC_W2R                                                      0x40\n#define EMC_R2P                                                      0x44\n#define EMC_W2P                                                      0x48\n#define EMC_RD_RCD                                                   0x4C\n#define EMC_WR_RCD                                                   0x50\n#define EMC_RRD                                                      0x54\n#define EMC_REXT                                                     0x58\n#define EMC_WDV                                                      0x5C\n#define EMC_QUSE                                                     0x60\n#define EMC_QRST                                                     0x64\n#define EMC_QSAFE                                                    0x68\n#define EMC_RDV                                                      0x6C\n#define EMC_REFRESH                                                  0x70\n#define EMC_BURST_REFRESH_NUM                                        0x74\n#define EMC_PDEX2WR                                                  0x78\n#define EMC_PDEX2RD                                                  0x7C\n#define EMC_PCHG2PDEN                                                0x80\n#define EMC_ACT2PDEN                                                 0x84\n#define EMC_AR2PDEN                                                  0x88\n#define EMC_RW2PDEN                                                  0x8C\n#define EMC_TXSR                                                     0x90\n#define EMC_TCKE                                                     0x94\n#define EMC_TFAW                                                     0x98\n#define EMC_TRPAB                                                    0x9C\n#define EMC_TCLKSTABLE                                               0xA0\n#define EMC_TCLKSTOP                                                 0xA4\n#define EMC_TREFBW                                                   0xA8\n#define EMC_TPPD                                                     0xAC\n#define EMC_ODT_WRITE                                                0xB0\n#define EMC_PDEX2MRR                                                 0xB4\n#define EMC_WEXT                                                     0xB8\n#define EMC_RFC_SLR                                                  0xC0\n#define EMC_MRS_WAIT_CNT2                                            0xC4\n#define EMC_MRS_WAIT_CNT                                             0xC8\n#define EMC_MRS                                                      0xCC\n#define EMC_EMRS                                                     0xD0\n#define EMC_REF                                                      0xD4\n#define EMC_PRE                                                      0xD8\n#define EMC_NOP                                                      0xDC\n#define EMC_SELF_REF                                                 0xE0\n#define EMC_DPD                                                      0xE4\n#define EMC_MRW                                                      0xE8\n#define EMC_MRR                                                      0xEC\n#define EMC_CMDQ                                                     0xF0\n#define EMC_MC2EMCQ                                                  0xF4\n#define EMC_FBIO_SPARE                                               0x100\n#define EMC_FBIO_CFG5                                                0x104\n#define EMC_PDEX2CKE                                                 0x118\n#define EMC_CKE2PDEN                                                 0x11C\n#define EMC_CFG_RSV                                                  0x120\n#define EMC_ACPD_CONTROL                                             0x124\n#define EMC_MPC                                                      0x128\n#define EMC_EMRS2                                                    0x12C\n#define EMC_EMRS3                                                    0x130\n#define EMC_MRW2                                                     0x134\n#define EMC_MRW3                                                     0x138\n#define EMC_MRW4                                                     0x13C\n#define EMC_CLKEN_OVERRIDE                                           0x140\n#define EMC_R2R                                                      0x144\n#define EMC_W2W                                                      0x148\n#define EMC_EINPUT                                                   0x14C\n#define EMC_EINPUT_DURATION                                          0x150\n#define EMC_PUTERM_EXTRA                                             0x154\n#define EMC_TCKESR                                                   0x158\n#define EMC_TPD                                                      0x15C\n#define EMC_STAT_CONTROL                                             0x160\n#define EMC_STAT_STATUS                                              0x164\n#define EMC_STAT_DRAM_CLOCK_LIMIT_LO                                 0x19C\n#define EMC_STAT_DRAM_CLOCK_LIMIT_HI                                 0x1A0\n#define EMC_STAT_DRAM_CLOCKS_LO                                      0x1A4\n#define EMC_STAT_DRAM_CLOCKS_HI                                      0x1A8\n#define EMC_STAT_DRAM_DEV0_ACTIVATE_CNT_LO                           0x1AC\n#define EMC_STAT_DRAM_DEV0_ACTIVATE_CNT_HI                           0x1B0\n#define EMC_STAT_DRAM_DEV0_READ_CNT_LO                               0x1B4\n#define EMC_STAT_DRAM_DEV0_READ_CNT_HI                               0x1B8\n#define EMC_STAT_DRAM_DEV0_READ8_CNT_LO                              0x1BC\n#define EMC_STAT_DRAM_DEV0_READ8_CNT_HI                              0x1C0\n#define EMC_STAT_DRAM_DEV0_WRITE_CNT_LO                              0x1C4\n#define EMC_STAT_DRAM_DEV0_WRITE_CNT_HI                              0x1C8\n#define EMC_STAT_DRAM_DEV0_WRITE8_CNT_LO                             0x1CC\n#define EMC_STAT_DRAM_DEV0_WRITE8_CNT_HI                             0x1D0\n#define EMC_STAT_DRAM_DEV0_REF_CNT_LO                                0x1D4\n#define EMC_STAT_DRAM_DEV0_REF_CNT_HI                                0x1D8\n#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO   0x1DC\n#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI   0x1E0\n#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO   0x1E4\n#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI   0x1E8\n#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO   0x1EC\n#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI   0x1F0\n#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO   0x1F4\n#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI   0x1F8\n#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 0x1FC\n#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 0x200\n#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 0x204\n#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 0x208\n#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 0x20C\n#define EMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0x210\n#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 0x214\n#define EMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0x218\n#define EMC_STAT_DRAM_DEV0_SR_CKE_EQ0_CLKS_LO                        0x21C\n#define EMC_STAT_DRAM_DEV0_SR_CKE_EQ0_CLKS_HI                        0x220\n#define EMC_STAT_DRAM_DEV0_DSR                                       0x224\n#define EMC_STAT_DRAM_DEV1_ACTIVATE_CNT_LO                           0x228\n#define EMC_STAT_DRAM_DEV1_ACTIVATE_CNT_HI                           0x22C\n#define EMC_STAT_DRAM_DEV1_READ_CNT_LO                               0x230\n#define EMC_STAT_DRAM_DEV1_READ_CNT_HI                               0x234\n#define EMC_STAT_DRAM_DEV1_READ8_CNT_LO                              0x238\n#define EMC_STAT_DRAM_DEV1_READ8_CNT_HI                              0x23C\n#define EMC_STAT_DRAM_DEV1_WRITE_CNT_LO                              0x240\n#define EMC_STAT_DRAM_DEV1_WRITE_CNT_HI                              0x244\n#define EMC_STAT_DRAM_DEV1_WRITE8_CNT_LO                             0x248\n#define EMC_STAT_DRAM_DEV1_WRITE8_CNT_HI                             0x24C\n#define EMC_STAT_DRAM_DEV1_REF_CNT_LO                                0x250\n#define EMC_STAT_DRAM_DEV1_REF_CNT_HI                                0x254\n#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO   0x258\n#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI   0x25C\n#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO   0x260\n#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI   0x264\n#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO   0x268\n#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI   0x26C\n#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO   0x270\n#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI   0x274\n#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 0x278\n#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 0x27C\n#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 0x280\n#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 0x284\n#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 0x288\n#define EMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0x28C\n#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 0x290\n#define EMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 0x294\n#define EMC_STAT_DRAM_DEV1_SR_CKE_EQ0_CLKS_LO                        0x298\n#define EMC_STAT_DRAM_DEV1_SR_CKE_EQ0_CLKS_HI                        0x29C\n#define EMC_STAT_DRAM_DEV1_DSR                                       0x2A0\n#define EMC_AUTO_CAL_CONFIG                                          0x2A4\n#define EMC_AUTO_CAL_INTERVAL                                        0x2A8\n#define EMC_AUTO_CAL_STATUS                                          0x2AC\n#define EMC_REQ_CTRL                                                 0x2B0\n#define EMC_EMC_STATUS                                               0x2B4\n#define  EMC_STATUS_MRR_DIVLD                                         BIT(20)\n#define EMC_CFG_2                                                    0x2B8\n#define EMC_CFG_DIG_DLL                                              0x2BC\n#define EMC_CFG_DIG_DLL_PERIOD                                       0x2C0\n#define EMC_DIG_DLL_STATUS                                           0x2C4\n#define EMC_CFG_DIG_DLL_1                                            0x2C8\n#define EMC_RDV_MASK                                                 0x2CC\n#define EMC_WDV_MASK                                                 0x2D0\n#define EMC_RDV_EARLY_MASK                                           0x2D4\n#define EMC_RDV_EARLY                                                0x2D8\n#define EMC_AUTO_CAL_CONFIG8                                         0x2DC\n#define EMC_ZCAL_INTERVAL                                            0x2E0\n#define EMC_ZCAL_WAIT_CNT                                            0x2E4\n#define EMC_ZCAL_MRW_CMD                                             0x2E8\n#define EMC_ZQ_CAL                                                   0x2EC\n#define EMC_XM2COMPPADCTRL3                                          0x2F4\n#define EMC_AUTO_CAL_VREF_SEL_0                                      0x2F8\n#define EMC_AUTO_CAL_VREF_SEL_1                                      0x300\n#define EMC_XM2COMPPADCTRL                                           0x30C\n#define EMC_FDPD_CTRL_DQ                                             0x310\n#define EMC_FDPD_CTRL_CMD                                            0x314\n#define EMC_PMACRO_CMD_BRICK_CTRL_FDPD                               0x318\n#define EMC_PMACRO_DATA_BRICK_CTRL_FDPD                              0x31C\n#define EMC_SCRATCH0                                                 0x324\n#define EMC_PMACRO_BRICK_CTRL_RFU1                                   0x330\n#define EMC_PMACRO_BRICK_CTRL_RFU2                                   0x334\n#define EMC_CMD_MAPPING_CMD0_0                                       0x380\n#define EMC_CMD_MAPPING_CMD0_1                                       0x384\n#define EMC_CMD_MAPPING_CMD0_2                                       0x388\n#define EMC_CMD_MAPPING_CMD1_0                                       0x38C\n#define EMC_CMD_MAPPING_CMD1_1                                       0x390\n#define EMC_CMD_MAPPING_CMD1_2                                       0x394\n#define EMC_CMD_MAPPING_CMD2_0                                       0x398\n#define EMC_CMD_MAPPING_CMD2_1                                       0x39C\n#define EMC_CMD_MAPPING_CMD2_2                                       0x3A0\n#define EMC_CMD_MAPPING_CMD3_0                                       0x3A4\n#define EMC_CMD_MAPPING_CMD3_1                                       0x3A8\n#define EMC_CMD_MAPPING_CMD3_2                                       0x3AC\n#define EMC_CMD_MAPPING_BYTE                                         0x3B0\n#define EMC_TR_TIMING_0                                              0x3B4\n#define EMC_TR_CTRL_0                                                0x3B8\n#define EMC_TR_CTRL_1                                                0x3BC\n#define EMC_SWITCH_BACK_CTRL                                         0x3C0\n#define EMC_TR_RDV                                                   0x3C4\n#define EMC_STALL_THEN_EXE_BEFORE_CLKCHANGE                          0x3C8\n#define EMC_STALL_THEN_EXE_AFTER_CLKCHANGE                           0x3CC\n#define EMC_UNSTALL_RW_AFTER_CLKCHANGE                               0x3D0\n#define EMC_AUTO_CAL_STATUS2                                         0x3D4\n#define EMC_SEL_DPD_CTRL                                             0x3D8\n#define EMC_PRE_REFRESH_REQ_CNT                                      0x3DC\n#define EMC_DYN_SELF_REF_CONTROL                                     0x3E0\n#define EMC_TXSRDLL                                                  0x3E4\n#define EMC_CCFIFO_ADDR                                              0x3E8\n#define EMC_CCFIFO_DATA                                              0x3EC\n#define EMC_CCFIFO_STATUS                                            0x3F0\n#define EMC_TR_QPOP                                                  0x3F4\n#define EMC_TR_RDV_MASK                                              0x3F8\n#define EMC_TR_QSAFE                                                 0x3FC\n#define EMC_TR_QRST                                                  0x400\n#define EMC_SWIZZLE_RANK0_BYTE0                                      0x404\n#define EMC_SWIZZLE_RANK0_BYTE1                                      0x408\n#define EMC_SWIZZLE_RANK0_BYTE2                                      0x40C\n#define EMC_SWIZZLE_RANK0_BYTE3                                      0x410\n#define EMC_SWIZZLE_RANK1_BYTE0                                      0x418\n#define EMC_SWIZZLE_RANK1_BYTE1                                      0x41C\n#define EMC_SWIZZLE_RANK1_BYTE2                                      0x420\n#define EMC_SWIZZLE_RANK1_BYTE3                                      0x424\n#define EMC_ISSUE_QRST                                               0x428\n#define EMC_PMC_SCRATCH1                                             0x440\n#define EMC_PMC_SCRATCH2                                             0x444\n#define EMC_PMC_SCRATCH3                                             0x448\n#define EMC_AUTO_CAL_CONFIG2                                         0x458\n#define EMC_AUTO_CAL_CONFIG3                                         0x45C\n#define EMC_TR_DVFS                                                  0x460\n#define EMC_AUTO_CAL_CHANNEL                                         0x464\n#define EMC_IBDLY                                                    0x468\n#define EMC_OBDLY                                                    0x46C\n#define EMC_TXDSRVTTGEN                                              0x480\n#define EMC_WE_DURATION                                              0x48C\n#define EMC_WS_DURATION                                              0x490\n#define EMC_WEV                                                      0x494\n#define EMC_WSV                                                      0x498\n#define EMC_CFG_3                                                    0x49C\n#define EMC_MRW5                                                     0x4A0\n#define EMC_MRW6                                                     0x4A4\n#define EMC_MRW7                                                     0x4A8\n#define EMC_MRW8                                                     0x4AC\n#define EMC_MRW9                                                     0x4B0\n#define EMC_MRW10                                                    0x4B4\n#define EMC_MRW11                                                    0x4B8\n#define EMC_MRW12                                                    0x4BC\n#define EMC_MRW13                                                    0x4C0\n#define EMC_MRW14                                                    0x4C4\n#define EMC_MRW15                                                    0x4D0\n#define EMC_CFG_SYNC                                                 0x4D4\n#define EMC_FDPD_CTRL_CMD_NO_RAMP                                    0x4D8\n#define EMC_WDV_CHK                                                  0x4E0\n#define EMC_CFG_PIPE_2                                               0x554\n#define EMC_CFG_PIPE_CLK                                             0x558\n#define EMC_CFG_PIPE_1                                               0x55C\n#define EMC_CFG_PIPE                                                 0x560\n#define EMC_QPOP                                                     0x564\n#define EMC_QUSE_WIDTH                                               0x568\n#define EMC_PUTERM_WIDTH                                             0x56C\n#define EMC_AUTO_CAL_CONFIG7                                         0x574\n#define EMC_XM2COMPPADCTRL2                                          0x578\n#define EMC_COMP_PAD_SW_CTRL                                         0x57C\n#define EMC_REFCTRL2                                                 0x580\n#define EMC_FBIO_CFG7                                                0x584\n#define EMC_DATA_BRLSHFT_0                                           0x588\n#define EMC_DATA_BRLSHFT_1                                           0x58C\n#define EMC_RFCPB                                                    0x590\n#define EMC_DQS_BRLSHFT_0                                            0x594\n#define EMC_DQS_BRLSHFT_1                                            0x598\n#define EMC_CMD_BRLSHFT_0                                            0x59C\n#define EMC_CMD_BRLSHFT_1                                            0x5A0\n#define EMC_CMD_BRLSHFT_2                                            0x5A4\n#define EMC_CMD_BRLSHFT_3                                            0x5A8\n#define EMC_QUSE_BRLSHFT_0                                           0x5AC\n#define EMC_AUTO_CAL_CONFIG4                                         0x5B0\n#define EMC_AUTO_CAL_CONFIG5                                         0x5B4\n#define EMC_QUSE_BRLSHFT_1                                           0x5B8\n#define EMC_QUSE_BRLSHFT_2                                           0x5BC\n#define EMC_CCDMW                                                    0x5C0\n#define EMC_QUSE_BRLSHFT_3                                           0x5C4\n#define EMC_FBIO_CFG8                                                0x5C8\n#define EMC_AUTO_CAL_CONFIG6                                         0x5CC\n#define EMC_PROTOBIST_CONFIG_ADR_1                                   0x5D0\n#define EMC_PROTOBIST_CONFIG_ADR_2                                   0x5D4\n#define EMC_PROTOBIST_MISC                                           0x5D8\n#define EMC_PROTOBIST_WDATA_LOWER                                    0x5DC\n#define EMC_PROTOBIST_WDATA_UPPER                                    0x5E0\n#define EMC_DLL_CFG_0                                                0x5E4\n#define EMC_DLL_CFG_1                                                0x5E8\n#define EMC_PROTOBIST_RDATA                                          0x5EC\n#define EMC_CONFIG_SAMPLE_DELAY                                      0x5F0\n#define EMC_CFG_UPDATE                                               0x5F4\n#define EMC_PMACRO_QUSE_DDLL_RANK0_0                                 0x600\n#define EMC_PMACRO_QUSE_DDLL_RANK0_1                                 0x604\n#define EMC_PMACRO_QUSE_DDLL_RANK0_2                                 0x608\n#define EMC_PMACRO_QUSE_DDLL_RANK0_3                                 0x60C\n#define EMC_PMACRO_QUSE_DDLL_RANK0_4                                 0x610\n#define EMC_PMACRO_QUSE_DDLL_RANK0_5                                 0x614\n#define EMC_PMACRO_QUSE_DDLL_RANK1_0                                 0x620\n#define EMC_PMACRO_QUSE_DDLL_RANK1_1                                 0x624\n#define EMC_PMACRO_QUSE_DDLL_RANK1_2                                 0x628\n#define EMC_PMACRO_QUSE_DDLL_RANK1_3                                 0x62C\n#define EMC_PMACRO_QUSE_DDLL_RANK1_4                                 0x630\n#define EMC_PMACRO_QUSE_DDLL_RANK1_5                                 0x634\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0                           0x640\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1                           0x644\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2                           0x648\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3                           0x64C\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4                           0x650\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5                           0x654\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0                           0x660\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1                           0x664\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2                           0x668\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3                           0x66C\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4                           0x670\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5                           0x674\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0                          0x680\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1                          0x684\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2                          0x688\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3                          0x68C\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4                          0x690\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5                          0x694\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0                          0x6A0\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1                          0x6A4\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2                          0x6A8\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3                          0x6AC\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4                          0x6B0\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5                          0x6B4\n#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0                          0x6C0\n#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1                          0x6C4\n#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2                          0x6C8\n#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3                          0x6CC\n#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_4                          0x6D0\n#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_5                          0x6D4\n#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0                          0x6E0\n#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1                          0x6E4\n#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2                          0x6E8\n#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3                          0x6EC\n#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_4                          0x6F0\n#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_5                          0x6F4\n#define EMC_PMACRO_AUTOCAL_CFG_0                                     0x700\n#define EMC_PMACRO_AUTOCAL_CFG_1                                     0x704\n#define EMC_PMACRO_AUTOCAL_CFG_2                                     0x708\n#define EMC_PMACRO_TX_PWRD_0                                         0x720\n#define EMC_PMACRO_TX_PWRD_1                                         0x724\n#define EMC_PMACRO_TX_PWRD_2                                         0x728\n#define EMC_PMACRO_TX_PWRD_3                                         0x72C\n#define EMC_PMACRO_TX_PWRD_4                                         0x730\n#define EMC_PMACRO_TX_PWRD_5                                         0x734\n#define EMC_PMACRO_TX_SEL_CLK_SRC_0                                  0x740\n#define EMC_PMACRO_TX_SEL_CLK_SRC_1                                  0x744\n#define EMC_PMACRO_TX_SEL_CLK_SRC_2                                  0x748\n#define EMC_PMACRO_TX_SEL_CLK_SRC_3                                  0x74C\n#define EMC_PMACRO_TX_SEL_CLK_SRC_4                                  0x750\n#define EMC_PMACRO_TX_SEL_CLK_SRC_5                                  0x754\n#define EMC_PMACRO_DDLL_BYPASS                                       0x760\n#define EMC_PMACRO_DDLL_PWRD_0                                       0x770\n#define EMC_PMACRO_DDLL_PWRD_1                                       0x774\n#define EMC_PMACRO_DDLL_PWRD_2                                       0x778\n#define EMC_PMACRO_CMD_CTRL_0                                        0x780\n#define EMC_PMACRO_CMD_CTRL_1                                        0x784\n#define EMC_PMACRO_CMD_CTRL_2                                        0x788\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0                    0x800\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1                    0x804\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2                    0x808\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_3                    0x80C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0                    0x810\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1                    0x814\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2                    0x818\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_3                    0x81C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0                    0x820\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1                    0x824\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2                    0x828\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_3                    0x82C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0                    0x830\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1                    0x834\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2                    0x838\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_3                    0x83C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0                    0x840\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1                    0x844\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2                    0x848\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_3                    0x84C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0                    0x850\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1                    0x854\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2                    0x858\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_3                    0x85C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0                    0x860\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1                    0x864\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2                    0x868\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_3                    0x86C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0                    0x870\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1                    0x874\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2                    0x878\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_3                    0x87C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0                     0x880\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1                     0x884\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2                     0x888\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_3                     0x88C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0                     0x890\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1                     0x894\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2                     0x898\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_3                     0x89C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0                     0x8A0\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1                     0x8A4\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2                     0x8A8\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_3                     0x8AC\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0                     0x8B0\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1                     0x8B4\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2                     0x8B8\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_3                     0x8BC\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0                    0x900\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1                    0x904\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2                    0x908\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_3                    0x90C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0                    0x910\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1                    0x914\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2                    0x918\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_3                    0x91C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0                    0x920\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1                    0x924\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2                    0x928\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_3                    0x92C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0                    0x930\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1                    0x934\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2                    0x938\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_3                    0x93C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0                    0x940\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1                    0x944\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2                    0x948\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_3                    0x94C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0                    0x950\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1                    0x954\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2                    0x958\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_3                    0x95C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0                    0x960\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1                    0x964\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2                    0x968\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_3                    0x96C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0                    0x970\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1                    0x974\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2                    0x978\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_3                    0x97C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_0                     0x980\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_1                     0x984\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_2                     0x988\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_3                     0x98C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_0                     0x990\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_1                     0x994\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_2                     0x998\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_3                     0x99C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_0                     0x9A0\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_1                     0x9A4\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_2                     0x9A8\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_3                     0x9AC\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_0                     0x9B0\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_1                     0x9B4\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_2                     0x9B8\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_3                     0x9BC\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0                    0xA00\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1                    0xA04\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2                    0xA08\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0                    0xA10\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1                    0xA14\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2                    0xA18\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0                    0xA20\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1                    0xA24\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2                    0xA28\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0                    0xA30\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1                    0xA34\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2                    0xA38\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0                    0xA40\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1                    0xA44\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2                    0xA48\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0                    0xA50\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1                    0xA54\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2                    0xA58\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0                    0xA60\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1                    0xA64\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2                    0xA68\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0                    0xA70\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1                    0xA74\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2                    0xA78\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_0                     0xA80\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_1                     0xA84\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_2                     0xA88\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_0                     0xA90\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_1                     0xA94\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_2                     0xA98\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_0                     0xAA0\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_1                     0xAA4\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_2                     0xAA8\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_0                     0xAB0\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_1                     0xAB4\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_2                     0xAB8\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0                    0xB00\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1                    0xB04\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2                    0xB08\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0                    0xB10\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1                    0xB14\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2                    0xB18\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0                    0xB20\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1                    0xB24\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2                    0xB28\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0                    0xB30\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1                    0xB34\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2                    0xB38\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0                    0xB40\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1                    0xB44\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2                    0xB48\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0                    0xB50\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1                    0xB54\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2                    0xB58\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0                    0xB60\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1                    0xB64\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2                    0xB68\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0                    0xB70\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1                    0xB74\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2                    0xB78\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_0                     0xB80\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_1                     0xB84\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_2                     0xB88\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_0                     0xB90\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_1                     0xB94\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_2                     0xB98\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_0                     0xBA0\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_1                     0xBA4\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_2                     0xBA8\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_0                     0xBB0\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_1                     0xBB4\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_2                     0xBB8\n#define EMC_PMACRO_IB_VREF_DQ_0                                      0xBE0\n#define EMC_PMACRO_IB_VREF_DQ_1                                      0xBE4\n#define EMC_PMACRO_IB_VREF_DQ_2                                      0xBE8\n#define EMC_PMACRO_IB_VREF_DQS_0                                     0xBF0\n#define EMC_PMACRO_IB_VREF_DQS_1                                     0xBF4\n#define EMC_PMACRO_IB_VREF_DQS_2                                     0xBF8\n#define EMC_PMACRO_DDLL_LONG_CMD_0                                   0xC00\n#define EMC_PMACRO_DDLL_LONG_CMD_1                                   0xC04\n#define EMC_PMACRO_DDLL_LONG_CMD_2                                   0xC08\n#define EMC_PMACRO_DDLL_LONG_CMD_3                                   0xC0C\n#define EMC_PMACRO_DDLL_LONG_CMD_4                                   0xC10\n#define EMC_PMACRO_DDLL_LONG_CMD_5                                   0xC14\n#define EMC_PMACRO_DDLL_SHORT_CMD_0                                  0xC20\n#define EMC_PMACRO_DDLL_SHORT_CMD_1                                  0xC24\n#define EMC_PMACRO_DDLL_SHORT_CMD_2                                  0xC28\n#define EMC_PMACRO_CFG_PM_GLOBAL_0                                   0xC30\n#define EMC_PMACRO_VTTGEN_CTRL_0                                     0xC34\n#define EMC_PMACRO_VTTGEN_CTRL_1                                     0xC38\n#define EMC_PMACRO_BG_BIAS_CTRL_0                                    0xC3C\n#define EMC_PMACRO_PAD_CFG_CTRL                                      0xC40\n#define EMC_PMACRO_ZCTRL                                             0xC44\n#define EMC_PMACRO_RX_TERM                                           0xC48\n#define EMC_PMACRO_CMD_TX_DRV                                        0xC4C\n#define EMC_PMACRO_CMD_PAD_RX_CTRL                                   0xC50\n#define EMC_PMACRO_DATA_PAD_RX_CTRL                                  0xC54\n#define EMC_PMACRO_CMD_RX_TERM_MODE                                  0xC58\n#define EMC_PMACRO_DATA_RX_TERM_MODE                                 0xC5C\n#define EMC_PMACRO_CMD_PAD_TX_CTRL                                   0xC60\n#define EMC_PMACRO_DATA_PAD_TX_CTRL                                  0xC64\n#define EMC_PMACRO_COMMON_PAD_TX_CTRL                                0xC68 // Only in T210.\n#define EMC_PMACRO_DQ_TX_DRV                                         0xC70\n#define EMC_PMACRO_CA_TX_DRV                                         0xC74\n#define EMC_PMACRO_AUTOCAL_CFG_COMMON                                0xC78\n#define EMC_PMACRO_BRICK_MAPPING_0                                   0xC80\n#define EMC_PMACRO_BRICK_MAPPING_1                                   0xC84\n#define EMC_PMACRO_BRICK_MAPPING_2                                   0xC88\n#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO     0xC8C\n#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI     0xC90\n#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO     0xC94\n#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI     0xC98\n#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO     0xC9C\n#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI     0xCA0\n#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO     0xCA4\n#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI     0xCA8\n#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO   0xCAC\n#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI   0xCB0\n#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO   0xCB4\n#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI   0xCB8\n#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO   0xCBC\n#define EMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI   0xCC0\n#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO   0xCC4\n#define EMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI   0xCC8\n#define EMC_STAT_DRAM_IO_SR_CKE_EQ0_CLKS_LO                          0xCCC\n#define EMC_STAT_DRAM_IO_SR_CKE_EQ0_CLKS_HI                          0xCD0\n#define EMC_STAT_DRAM_IO_DSR                                         0xCD4\n#define EMC_PMACRO_DDLLCAL_CAL                                       0xCE0 // Only in T210.\n#define EMC_PMACRO_DDLL_OFFSET                                       0xCE4\n#define EMC_PMACRO_DDLL_PERIODIC_OFFSET                              0xCE8\n#define EMC_PMACRO_VTTGEN_CTRL_2                                     0xCF0\n#define EMC_PMACRO_IB_RXRT                                           0xCF4\n#define EMC_PMACRO_TRAINING_CTRL_0                                   0xCF8\n#define EMC_PMACRO_TRAINING_CTRL_1                                   0xCFC\n#define EMC_TRAINING_CMD                                             0xE00\n#define EMC_TRAINING_CTRL                                            0xE04\n#define EMC_TRAINING_STATUS                                          0xE08\n#define EMC_TRAINING_QUSE_CORS_CTRL                                  0xE0C\n#define EMC_TRAINING_QUSE_FINE_CTRL                                  0xE10\n#define EMC_TRAINING_QUSE_CTRL_MISC                                  0xE14\n#define EMC_TRAINING_WRITE_FINE_CTRL                                 0xE18\n#define EMC_TRAINING_WRITE_CTRL_MISC                                 0xE1C\n#define EMC_TRAINING_WRITE_VREF_CTRL                                 0xE20\n#define EMC_TRAINING_READ_FINE_CTRL                                  0xE24\n#define EMC_TRAINING_READ_CTRL_MISC                                  0xE28\n#define EMC_TRAINING_READ_VREF_CTRL                                  0xE2C\n#define EMC_TRAINING_CA_FINE_CTRL                                    0xE30\n#define EMC_TRAINING_CA_CTRL_MISC                                    0xE34\n#define EMC_TRAINING_CA_CTRL_MISC1                                   0xE38\n#define EMC_TRAINING_CA_VREF_CTRL                                    0xE3C\n#define EMC_TRAINING_CA_TADR_CTRL                                    0xE40\n#define EMC_TRAINING_SETTLE                                          0xE44\n#define EMC_TRAINING_DEBUG_CTRL                                      0xE48\n#define EMC_TRAINING_DEBUG_DQ0                                       0xE4C\n#define EMC_TRAINING_DEBUG_DQ1                                       0xE50\n#define EMC_TRAINING_DEBUG_DQ2                                       0xE54\n#define EMC_TRAINING_DEBUG_DQ3                                       0xE58\n#define EMC_TRAINING_MPC                                             0xE5C\n#define EMC_TRAINING_PATRAM_CTRL                                     0xE60\n#define EMC_TRAINING_PATRAM_DQ                                       0xE64\n#define EMC_TRAINING_PATRAM_DMI                                      0xE68\n#define EMC_TRAINING_VREF_SETTLE                                     0xE6C\n#define EMC_TRAINING_RW_EYE_CENTER_IB_BYTE0                          0xE70\n#define EMC_TRAINING_RW_EYE_CENTER_IB_BYTE1                          0xE74\n#define EMC_TRAINING_RW_EYE_CENTER_IB_BYTE2                          0xE78\n#define EMC_TRAINING_RW_EYE_CENTER_IB_BYTE3                          0xE7C\n#define EMC_TRAINING_RW_EYE_CENTER_IB_MISC                           0xE80\n#define EMC_TRAINING_RW_EYE_CENTER_OB_BYTE0                          0xE84\n#define EMC_TRAINING_RW_EYE_CENTER_OB_BYTE1                          0xE88\n#define EMC_TRAINING_RW_EYE_CENTER_OB_BYTE2                          0xE8C\n#define EMC_TRAINING_RW_EYE_CENTER_OB_BYTE3                          0xE90\n#define EMC_TRAINING_RW_EYE_CENTER_OB_MISC                           0xE94\n#define EMC_TRAINING_RW_OFFSET_IB_BYTE0                              0xE98\n#define EMC_TRAINING_RW_OFFSET_IB_BYTE1                              0xE9C\n#define EMC_TRAINING_RW_OFFSET_IB_BYTE2                              0xEA0\n#define EMC_TRAINING_RW_OFFSET_IB_BYTE3                              0xEA4\n#define EMC_TRAINING_RW_OFFSET_IB_MISC                               0xEA8\n#define EMC_TRAINING_RW_OFFSET_OB_BYTE0                              0xEAC\n#define EMC_TRAINING_RW_OFFSET_OB_BYTE1                              0xEB0\n#define EMC_TRAINING_RW_OFFSET_OB_BYTE2                              0xEB4\n#define EMC_TRAINING_RW_OFFSET_OB_BYTE3                              0xEB8\n#define EMC_TRAINING_RW_OFFSET_OB_MISC                               0xEBC\n#define EMC_TRAINING_OPT_CA_VREF                                     0xEC0\n#define EMC_TRAINING_OPT_DQ_OB_VREF                                  0xEC4\n#define EMC_TRAINING_OPT_DQ_IB_VREF_RANK0                            0xEC8\n#define EMC_TRAINING_OPT_DQ_IB_VREF_RANK1                            0xECC\n#define EMC_TRAINING_QUSE_VREF_CTRL                                  0xED0\n#define EMC_TRAINING_OPT_DQS_IB_VREF_RANK0                           0xED4\n#define EMC_TRAINING_OPT_DQS_IB_VREF_RANK1                           0xED8\n#define EMC_TRAINING_DRAMC_TIMING                                    0xEDC\n\n/* T210B01 only registers */\n#define EMC_TRTM_B01                                                 0xBC\n#define EMC_TWTM_B01                                                 0xF8\n#define EMC_TRATM_B01                                                0xFC\n#define EMC_TWATM_B01                                                0x108\n#define EMC_TR2REF_B01                                               0x10C\n#define EMC_PMACRO_DATA_PI_CTRL_B01                                  0x110\n#define EMC_PMACRO_CMD_PI_CTRL_B01                                   0x114\n#define EMC_PMACRO_PMU_CTRL_B01                                      0x304\n#define EMC_PMACRO_XM2COMP_PMU_CTRL_B01                              0x308\n#define EMC_AUTO_CAL_CONFIG9_B01                                     0x42C\n#define EMC_PMACRO_DDLLCAL_EN_B01                                    0x44C\n#define EMC_PMACRO_DLL_CFG_0_B01                                     0x5E4\n#define EMC_PMACRO_DLL_CFG_1_B01                                     0x5E8\n#define EMC_PMACRO_DLL_CFG_2_B01                                     0x5F8\n#define EMC_PMACRO_DSR_VTTGEN_CTRL_0_B01                             0xC6C\n#define EMC_PMACRO_DDLLCAL_CAL_0_B01                                 0xD00\n#define EMC_PMACRO_DDLLCAL_CAL_1_B01                                 0xD04\n#define EMC_PMACRO_DDLLCAL_CAL_2_B01                                 0xD08\n#define EMC_PMACRO_DDLLCAL_CAL_3_B01                                 0xD0C\n#define EMC_PMACRO_DDLLCAL_CAL_4_B01                                 0xD10\n#define EMC_PMACRO_DDLLCAL_CAL_5_B01                                 0xD14\n#define EMC_PMACRO_DIG_DLL_STATUS_0_B01                              0xD20\n#define EMC_PMACRO_DIG_DLL_STATUS_1_B01                              0xD24\n#define EMC_PMACRO_DIG_DLL_STATUS_2_B01                              0xD28\n#define EMC_PMACRO_DIG_DLL_STATUS_3_B01                              0xD2C\n#define EMC_PMACRO_DIG_DLL_STATUS_4_B01                              0xD30\n#define EMC_PMACRO_DIG_DLL_STATUS_5_B01                              0xD34\n#define EMC_PMACRO_PERBIT_FGCG_CTRL_0_B01                            0xD40\n#define EMC_PMACRO_PERBIT_FGCG_CTRL_1_B01                            0xD44\n#define EMC_PMACRO_PERBIT_FGCG_CTRL_2_B01                            0xD48\n#define EMC_PMACRO_PERBIT_FGCG_CTRL_3_B01                            0xD4C\n#define EMC_PMACRO_PERBIT_FGCG_CTRL_4_B01                            0xD50\n#define EMC_PMACRO_PERBIT_FGCG_CTRL_5_B01                            0xD54\n#define EMC_PMACRO_PERBIT_RFU_CTRL_0_B01                             0xD60\n#define EMC_PMACRO_PERBIT_RFU_CTRL_1_B01                             0xD64\n#define EMC_PMACRO_PERBIT_RFU_CTRL_2_B01                             0xD68\n#define EMC_PMACRO_PERBIT_RFU_CTRL_3_B01                             0xD6C\n#define EMC_PMACRO_PERBIT_RFU_CTRL_4_B01                             0xD70\n#define EMC_PMACRO_PERBIT_RFU_CTRL_5_B01                             0xD74\n#define EMC_PMACRO_PERBIT_RFU1_CTRL_0_B01                            0xD80\n#define EMC_PMACRO_PERBIT_RFU1_CTRL_1_B01                            0xD84\n#define EMC_PMACRO_PERBIT_RFU1_CTRL_2_B01                            0xD88\n#define EMC_PMACRO_PERBIT_RFU1_CTRL_3_B01                            0xD8C\n#define EMC_PMACRO_PERBIT_RFU1_CTRL_4_B01                            0xD90\n#define EMC_PMACRO_PERBIT_RFU1_CTRL_5_B01                            0xD94\n#define EMC_PMACRO_PMU_OUT_EOFF1_0_B01                               0xDA0\n#define EMC_PMACRO_PMU_OUT_EOFF1_1_B01                               0xDA4\n#define EMC_PMACRO_PMU_OUT_EOFF1_2_B01                               0xDA8\n#define EMC_PMACRO_PMU_OUT_EOFF1_3_B01                               0xDAC\n#define EMC_PMACRO_PMU_OUT_EOFF1_4_B01                               0xDB0\n#define EMC_PMACRO_PMU_OUT_EOFF1_5_B01                               0xDB4\n#define EMC_PMACRO_COMP_PMU_OUT_B01                                  0xDC0\n\n#define EMC_STATUS_UPDATE_TIMEOUT 1000\n\ntypedef enum _emc_mr_t\n{\n\tMR0_FEAT    = 0,\n\tMR4_TEMP    = 4,\n\tMR5_MAN_ID  = 5,\n\tMR6_REV_ID1 = 6,\n\tMR7_REV_ID2 = 7,\n\tMR8_DENSITY = 8,\n} emc_mr_t;\n\nenum\n{\n\tEMC_CHAN0 = 0,\n\tEMC_CHAN1 = 1\n};\n\ntypedef struct _emc_mr_chip_data_t\n{\n\t// Device 0.\n\tu8 rank0_ch0;\n\tu8 rank0_ch1;\n\n\t// Device 1.\n\tu8 rank1_ch0;\n\tu8 rank1_ch1;\n} emc_mr_chip_data_t;\n\ntypedef struct _emc_mr_data_t\n{\n\temc_mr_chip_data_t chip0;\n\temc_mr_chip_data_t chip1;\n} emc_mr_data_t;\n\ntypedef struct _emc_regs_t210_t {\n/* 0x000 */\tu32 emc_intstatus;\n/* 0x004 */\tu32 emc_intmask;\n/* 0x008 */\tu32 emc_dbg;\n/* 0x00c */\tu32 emc_cfg;\n/* 0x010 */\tu32 emc_adr_cfg;\n/* 0x014 */\tu32 rsvd_014[3];\n/* 0x020 */\tu32 emc_refctrl;\n/* 0x024 */\tu32 emc_pin;\n/* 0x028 */\tu32 emc_timing_control;\n/* 0x02c */\tu32 emc_rc;\n/* 0x030 */\tu32 emc_rfc;\n/* 0x034 */\tu32 emc_ras;\n/* 0x038 */\tu32 emc_rp;\n/* 0x03c */\tu32 emc_r2w;\n/* 0x040 */\tu32 emc_w2r;\n/* 0x044 */\tu32 emc_r2p;\n/* 0x048 */\tu32 emc_w2p;\n/* 0x04c */\tu32 emc_rd_rcd;\n/* 0x050 */\tu32 emc_wr_rcd;\n/* 0x054 */\tu32 emc_rrd;\n/* 0x058 */\tu32 emc_rext;\n/* 0x05c */\tu32 emc_wdv;\n/* 0x060 */\tu32 emc_quse;\n/* 0x064 */\tu32 emc_qrst;\n/* 0x068 */\tu32 emc_qsafe;\n/* 0x06c */\tu32 emc_rdv;\n/* 0x070 */\tu32 emc_refresh;\n/* 0x074 */\tu32 emc_burst_refresh_num;\n/* 0x078 */\tu32 emc_pdex2wr;\n/* 0x07c */\tu32 emc_pdex2rd;\n/* 0x080 */\tu32 emc_pchg2pden;\n/* 0x084 */\tu32 emc_act2pden;\n/* 0x088 */\tu32 emc_ar2pden;\n/* 0x08c */\tu32 emc_rw2pden;\n/* 0x090 */\tu32 emc_txsr;\n/* 0x094 */\tu32 emc_tcke;\n/* 0x098 */\tu32 emc_tfaw;\n/* 0x09c */\tu32 emc_trpab;\n/* 0x0a0 */\tu32 emc_tclkstable;\n/* 0x0a4 */\tu32 emc_tclkstop;\n/* 0x0a8 */\tu32 emc_trefbw;\n/* 0x0ac */\tu32 emc_tppd;\n/* 0x0b0 */\tu32 emc_odt_write;\n/* 0x0b4 */\tu32 emc_pdex2mrr;\n/* 0x0b8 */\tu32 emc_wext;\n/* 0x0bc */\tu32 emc_trtm_b01;\n/* 0x0c0 */\tu32 emc_rfc_slr;\n/* 0x0c4 */\tu32 emc_mrs_wait_cnt2;\n/* 0x0c8 */\tu32 emc_mrs_wait_cnt;\n/* 0x0cc */\tu32 emc_mrs;\n/* 0x0d0 */\tu32 emc_emrs;\n/* 0x0d4 */\tu32 emc_ref;\n/* 0x0d8 */\tu32 emc_pre;\n/* 0x0dc */\tu32 emc_nop;\n/* 0x0e0 */\tu32 emc_self_ref;\n/* 0x0e4 */\tu32 emc_dpd;\n/* 0x0e8 */\tu32 emc_mrw;\n/* 0x0ec */\tu32 emc_mrr;\n/* 0x0f0 */\tu32 emc_cmdq;\n/* 0x0f4 */\tu32 emc_mc2emcq;\n/* 0x0f8 */\tu32 emc_twtm_b01;\n/* 0x0fc */\tu32 emc_tratm_b01;\n/* 0x100 */\tu32 emc_fbio_spare;\n/* 0x104 */\tu32 emc_fbio_cfg5;\n/* 0x108 */\tu32 emc_twatm_b01;\n/* 0x10c */\tu32 emc_tr2ref_b01;\n/* 0x110 */\tu32 emc_pmacro_data_pi_ctrl_b01;\n/* 0x114 */\tu32 emc_pmacro_cmd_pi_ctrl_b01;\n/* 0x118 */\tu32 emc_pdex2cke;\n/* 0x11c */\tu32 emc_cke2pden;\n/* 0x120 */\tu32 emc_cfg_rsv;\n/* 0x124 */\tu32 emc_acpd_control;\n/* 0x128 */\tu32 emc_mpc;\n/* 0x12c */\tu32 emc_emrs2;\n/* 0x130 */\tu32 emc_emrs3;\n/* 0x134 */\tu32 emc_mrw2;\n/* 0x138 */\tu32 emc_mrw3;\n/* 0x13c */\tu32 emc_mrw4;\n/* 0x140 */\tu32 emc_clken_override;\n/* 0x144 */\tu32 emc_r2r;\n/* 0x148 */\tu32 emc_w2w;\n/* 0x14c */\tu32 emc_einput;\n/* 0x150 */\tu32 emc_einput_duration;\n/* 0x154 */\tu32 emc_puterm_extra;\n/* 0x158 */\tu32 emc_tckesr;\n/* 0x15c */\tu32 emc_tpd;\n/* 0x160 */\tu32 emc_stat_control;\n/* 0x164 */\tu32 emc_stat_status;\n/* 0x168 */\tu32 rsvd_168[13];\n/* 0x19c */\tu32 emc_stat_dram_clock_limit_lo;\n/* 0x1a0 */\tu32 emc_stat_dram_clock_limit_hi;\n/* 0x1a4 */\tu32 emc_stat_dram_clocks_lo;\n/* 0x1a8 */\tu32 emc_stat_dram_clocks_hi;\n/* 0x1ac */\tu32 emc_stat_dram_dev0_activate_cnt_lo;\n/* 0x1b0 */\tu32 emc_stat_dram_dev0_activate_cnt_hi;\n/* 0x1b4 */\tu32 emc_stat_dram_dev0_read_cnt_lo;\n/* 0x1b8 */\tu32 emc_stat_dram_dev0_read_cnt_hi;\n/* 0x1bc */\tu32 emc_stat_dram_dev0_read8_cnt_lo;\n/* 0x1c0 */\tu32 emc_stat_dram_dev0_read8_cnt_hi;\n/* 0x1c4 */\tu32 emc_stat_dram_dev0_write_cnt_lo;\n/* 0x1c8 */\tu32 emc_stat_dram_dev0_write_cnt_hi;\n/* 0x1cc */\tu32 emc_stat_dram_dev0_write8_cnt_lo;\n/* 0x1d0 */\tu32 emc_stat_dram_dev0_write8_cnt_hi;\n/* 0x1d4 */\tu32 emc_stat_dram_dev0_ref_cnt_lo;\n/* 0x1d8 */\tu32 emc_stat_dram_dev0_ref_cnt_hi;\n/* 0x1dc */\tu32 emc_stat_dram_dev0_extclks_cke_eq0_no_banks_active_clks_lo;\n/* 0x1e0 */\tu32 emc_stat_dram_dev0_extclks_cke_eq0_no_banks_active_clks_hi;\n/* 0x1e4 */\tu32 emc_stat_dram_dev0_clkstop_cke_eq0_no_banks_active_clks_lo;\n/* 0x1e8 */\tu32 emc_stat_dram_dev0_clkstop_cke_eq0_no_banks_active_clks_hi;\n/* 0x1ec */\tu32 emc_stat_dram_dev0_extclks_cke_eq1_no_banks_active_clks_lo;\n/* 0x1f0 */\tu32 emc_stat_dram_dev0_extclks_cke_eq1_no_banks_active_clks_hi;\n/* 0x1f4 */\tu32 emc_stat_dram_dev0_clkstop_cke_eq1_no_banks_active_clks_lo;\n/* 0x1f8 */\tu32 emc_stat_dram_dev0_clkstop_cke_eq1_no_banks_active_clks_hi;\n/* 0x1fc */\tu32 emc_stat_dram_dev0_extclks_cke_eq0_some_banks_active_clks_lo;\n/* 0x200 */\tu32 emc_stat_dram_dev0_extclks_cke_eq0_some_banks_active_clks_hi;\n/* 0x204 */\tu32 emc_stat_dram_dev0_clkstop_cke_eq0_some_banks_active_clks_lo;\n/* 0x208 */\tu32 emc_stat_dram_dev0_clkstop_cke_eq0_some_banks_active_clks_hi;\n/* 0x20c */\tu32 emc_stat_dram_dev0_extclks_cke_eq1_some_banks_active_clks_lo;\n/* 0x210 */\tu32 emc_stat_dram_dev0_extclks_cke_eq1_some_banks_active_clks_hi;\n/* 0x214 */\tu32 emc_stat_dram_dev0_clkstop_cke_eq1_some_banks_active_clks_lo;\n/* 0x218 */\tu32 emc_stat_dram_dev0_clkstop_cke_eq1_some_banks_active_clks_hi;\n/* 0x21c */\tu32 emc_stat_dram_dev0_sr_cke_eq0_clks_lo;\n/* 0x220 */\tu32 emc_stat_dram_dev0_sr_cke_eq0_clks_hi;\n/* 0x224 */\tu32 emc_stat_dram_dev0_dsr;\n/* 0x228 */\tu32 emc_stat_dram_dev1_activate_cnt_lo;\n/* 0x22c */\tu32 emc_stat_dram_dev1_activate_cnt_hi;\n/* 0x230 */\tu32 emc_stat_dram_dev1_read_cnt_lo;\n/* 0x234 */\tu32 emc_stat_dram_dev1_read_cnt_hi;\n/* 0x238 */\tu32 emc_stat_dram_dev1_read8_cnt_lo;\n/* 0x23c */\tu32 emc_stat_dram_dev1_read8_cnt_hi;\n/* 0x240 */\tu32 emc_stat_dram_dev1_write_cnt_lo;\n/* 0x244 */\tu32 emc_stat_dram_dev1_write_cnt_hi;\n/* 0x248 */\tu32 emc_stat_dram_dev1_write8_cnt_lo;\n/* 0x24c */\tu32 emc_stat_dram_dev1_write8_cnt_hi;\n/* 0x250 */\tu32 emc_stat_dram_dev1_ref_cnt_lo;\n/* 0x254 */\tu32 emc_stat_dram_dev1_ref_cnt_hi;\n/* 0x258 */\tu32 emc_stat_dram_dev1_extclks_cke_eq0_no_banks_active_clks_lo;\n/* 0x25c */\tu32 emc_stat_dram_dev1_extclks_cke_eq0_no_banks_active_clks_hi;\n/* 0x260 */\tu32 emc_stat_dram_dev1_clkstop_cke_eq0_no_banks_active_clks_lo;\n/* 0x264 */\tu32 emc_stat_dram_dev1_clkstop_cke_eq0_no_banks_active_clks_hi;\n/* 0x268 */\tu32 emc_stat_dram_dev1_extclks_cke_eq1_no_banks_active_clks_lo;\n/* 0x26c */\tu32 emc_stat_dram_dev1_extclks_cke_eq1_no_banks_active_clks_hi;\n/* 0x270 */\tu32 emc_stat_dram_dev1_clkstop_cke_eq1_no_banks_active_clks_lo;\n/* 0x274 */\tu32 emc_stat_dram_dev1_clkstop_cke_eq1_no_banks_active_clks_hi;\n/* 0x278 */\tu32 emc_stat_dram_dev1_extclks_cke_eq0_some_banks_active_clks_lo;\n/* 0x27c */\tu32 emc_stat_dram_dev1_extclks_cke_eq0_some_banks_active_clks_hi;\n/* 0x280 */\tu32 emc_stat_dram_dev1_clkstop_cke_eq0_some_banks_active_clks_lo;\n/* 0x284 */\tu32 emc_stat_dram_dev1_clkstop_cke_eq0_some_banks_active_clks_hi;\n/* 0x288 */\tu32 emc_stat_dram_dev1_extclks_cke_eq1_some_banks_active_clks_lo;\n/* 0x28c */\tu32 emc_stat_dram_dev1_extclks_cke_eq1_some_banks_active_clks_hi;\n/* 0x290 */\tu32 emc_stat_dram_dev1_clkstop_cke_eq1_some_banks_active_clks_lo;\n/* 0x294 */\tu32 emc_stat_dram_dev1_clkstop_cke_eq1_some_banks_active_clks_hi;\n/* 0x298 */\tu32 emc_stat_dram_dev1_sr_cke_eq0_clks_lo;\n/* 0x29c */\tu32 emc_stat_dram_dev1_sr_cke_eq0_clks_hi;\n/* 0x2a0 */\tu32 emc_stat_dram_dev1_dsr;\n/* 0x2a4 */\tu32 emc_auto_cal_config;\n/* 0x2a8 */\tu32 emc_auto_cal_interval;\n/* 0x2ac */\tu32 emc_auto_cal_status;\n/* 0x2b0 */\tu32 emc_req_ctrl;\n/* 0x2b4 */\tu32 emc_emc_status;\n/* 0x2b8 */\tu32 emc_cfg_2;\n/* 0x2bc */\tu32 emc_cfg_dig_dll;\n/* 0x2c0 */\tu32 emc_cfg_dig_dll_period;\n/* 0x2c4 */\tu32 emc_dig_dll_status;\n/* 0x2c8 */\tu32 emc_cfg_dig_dll_1;\n/* 0x2cc */\tu32 emc_rdv_mask;\n/* 0x2d0 */\tu32 emc_wdv_mask;\n/* 0x2d4 */\tu32 emc_rdv_early_mask;\n/* 0x2d8 */\tu32 emc_rdv_early;\n/* 0x2dc */\tu32 emc_auto_cal_config8;\n/* 0x2e0 */\tu32 emc_zcal_interval;\n/* 0x2e4 */\tu32 emc_zcal_wait_cnt;\n/* 0x2e8 */\tu32 emc_zcal_mrw_cmd;\n/* 0x2ec */\tu32 emc_zq_cal;\n/* 0x2f0 */\tu32 rsvd_2f0;\n/* 0x2f4 */\tu32 emc_xm2comppadctrl3;\n/* 0x2f8 */\tu32 emc_auto_cal_vref_sel_0;\n/* 0x2fc */\tu32 rsvd_2fc;\n/* 0x300 */\tu32 emc_auto_cal_vref_sel_1;\n/* 0x304 */\tu32 emc_pmacro_pmu_ctrl_b01;\n/* 0x308 */\tu32 emc_pmacro_xm2comp_pmu_ctrl_b01;\n/* 0x30c */\tu32 emc_xm2comppadctrl;\n/* 0x310 */\tu32 emc_fdpd_ctrl_dq;\n/* 0x314 */\tu32 emc_fdpd_ctrl_cmd;\n/* 0x318 */\tu32 emc_pmacro_cmd_brick_ctrl_fdpd;\n/* 0x31c */\tu32 emc_pmacro_data_brick_ctrl_fdpd;\n/* 0x320 */\tu32 rsvd_320;\n/* 0x324 */\tu32 emc_scratch0;\n/* 0x328 */\tu32 rsvd_328[2];\n/* 0x330 */\tu32 emc_pmacro_brick_ctrl_rfu1;\n/* 0x334 */\tu32 emc_pmacro_brick_ctrl_rfu2;\n/* 0x338 */\tu32 rsvd_338[18];\n/* 0x380 */\tu32 emc_cmd_mapping_cmd0_0;\n/* 0x384 */\tu32 emc_cmd_mapping_cmd0_1;\n/* 0x388 */\tu32 emc_cmd_mapping_cmd0_2;\n/* 0x38c */\tu32 emc_cmd_mapping_cmd1_0;\n/* 0x390 */\tu32 emc_cmd_mapping_cmd1_1;\n/* 0x394 */\tu32 emc_cmd_mapping_cmd1_2;\n/* 0x398 */\tu32 emc_cmd_mapping_cmd2_0;\n/* 0x39c */\tu32 emc_cmd_mapping_cmd2_1;\n/* 0x3a0 */\tu32 emc_cmd_mapping_cmd2_2;\n/* 0x3a4 */\tu32 emc_cmd_mapping_cmd3_0;\n/* 0x3a8 */\tu32 emc_cmd_mapping_cmd3_1;\n/* 0x3ac */\tu32 emc_cmd_mapping_cmd3_2;\n/* 0x3b0 */\tu32 emc_cmd_mapping_byte;\n/* 0x3b4 */\tu32 emc_tr_timing_0;\n/* 0x3b8 */\tu32 emc_tr_ctrl_0;\n/* 0x3bc */\tu32 emc_tr_ctrl_1;\n/* 0x3c0 */\tu32 emc_switch_back_ctrl;\n/* 0x3c4 */\tu32 emc_tr_rdv;\n/* 0x3c8 */\tu32 emc_stall_then_exe_before_clkchange;\n/* 0x3cc */\tu32 emc_stall_then_exe_after_clkchange;\n/* 0x3d0 */\tu32 emc_unstall_rw_after_clkchange;\n/* 0x3d4 */\tu32 emc_auto_cal_status2;\n/* 0x3d8 */\tu32 emc_sel_dpd_ctrl;\n/* 0x3dc */\tu32 emc_pre_refresh_req_cnt;\n/* 0x3e0 */\tu32 emc_dyn_self_ref_control;\n/* 0x3e4 */\tu32 emc_txsrdll;\n/* 0x3e8 */\tu32 emc_ccfifo_addr;\n/* 0x3ec */\tu32 emc_ccfifo_data;\n/* 0x3f0 */\tu32 emc_ccfifo_status;\n/* 0x3f4 */\tu32 emc_tr_qpop;\n/* 0x3f8 */\tu32 emc_tr_rdv_mask;\n/* 0x3fc */\tu32 emc_tr_qsafe;\n/* 0x400 */\tu32 emc_tr_qrst;\n/* 0x404 */\tu32 emc_swizzle_rank0_byte0;\n/* 0x408 */\tu32 emc_swizzle_rank0_byte1;\n/* 0x40c */\tu32 emc_swizzle_rank0_byte2;\n/* 0x410 */\tu32 emc_swizzle_rank0_byte3;\n/* 0x414 */\tu32 rsvd_414;\n/* 0x418 */\tu32 emc_swizzle_rank1_byte0;\n/* 0x41c */\tu32 emc_swizzle_rank1_byte1;\n/* 0x420 */\tu32 emc_swizzle_rank1_byte2;\n/* 0x424 */\tu32 emc_swizzle_rank1_byte3;\n/* 0x428 */\tu32 emc_issue_qrst;\n/* 0x42c */\tu32 emc_auto_cal_config9_b01;\n/* 0x430 */\tu32 rsvd_430[4];\n/* 0x440 */\tu32 emc_pmc_scratch1;\n/* 0x444 */\tu32 emc_pmc_scratch2;\n/* 0x448 */\tu32 emc_pmc_scratch3;\n/* 0x44c */\tu32 emc_pmacro_ddllcal_en_b01;\n/* 0x450 */\tu32 rsvd_450[2];\n/* 0x458 */\tu32 emc_auto_cal_config2;\n/* 0x45c */\tu32 emc_auto_cal_config3;\n/* 0x460 */\tu32 emc_tr_dvfs;\n/* 0x464 */\tu32 emc_auto_cal_channel;\n/* 0x468 */\tu32 emc_ibdly;\n/* 0x46c */\tu32 emc_obdly;\n/* 0x470 */\tu32 rsvd_470[4];\n/* 0x480 */\tu32 emc_txdsrvttgen;\n/* 0x484 */\tu32 rsvd_484[2];\n/* 0x48c */\tu32 emc_we_duration;\n/* 0x490 */\tu32 emc_ws_duration;\n/* 0x494 */\tu32 emc_wev;\n/* 0x498 */\tu32 emc_wsv;\n/* 0x49c */\tu32 emc_cfg_3;\n/* 0x4a0 */\tu32 emc_mrw5;\n/* 0x4a4 */\tu32 emc_mrw6;\n/* 0x4a8 */\tu32 emc_mrw7;\n/* 0x4ac */\tu32 emc_mrw8;\n/* 0x4b0 */\tu32 emc_mrw9;\n/* 0x4b4 */\tu32 emc_mrw10;\n/* 0x4b8 */\tu32 emc_mrw11;\n/* 0x4bc */\tu32 emc_mrw12;\n/* 0x4c0 */\tu32 emc_mrw13;\n/* 0x4c4 */\tu32 emc_mrw14;\n/* 0x4c8 */\tu32 rsvd_4c8[2];\n/* 0x4d0 */\tu32 emc_mrw15;\n/* 0x4d4 */\tu32 emc_cfg_sync;\n/* 0x4d8 */\tu32 emc_fdpd_ctrl_cmd_no_ramp;\n/* 0x4dc */\tu32 rsvd_4dc;\n/* 0x4e0 */\tu32 emc_wdv_chk;\n/* 0x4e4 */\tu32 rsvd_4e4[28];\n/* 0x554 */\tu32 emc_cfg_pipe_2;\n/* 0x558 */\tu32 emc_cfg_pipe_clk;\n/* 0x55c */\tu32 emc_cfg_pipe_1;\n/* 0x560 */\tu32 emc_cfg_pipe;\n/* 0x564 */\tu32 emc_qpop;\n/* 0x568 */\tu32 emc_quse_width;\n/* 0x56c */\tu32 emc_puterm_width;\n/* 0x570 */\tu32 rsvd_570;\n/* 0x574 */\tu32 emc_auto_cal_config7;\n/* 0x578 */\tu32 emc_xm2comppadctrl2;\n/* 0x57c */\tu32 emc_comp_pad_sw_ctrl;\n/* 0x580 */\tu32 emc_refctrl2;\n/* 0x584 */\tu32 emc_fbio_cfg7;\n/* 0x588 */\tu32 emc_data_brlshft_0;\n/* 0x58c */\tu32 emc_data_brlshft_1;\n/* 0x590 */\tu32 emc_rfcpb;\n/* 0x594 */\tu32 emc_dqs_brlshft_0;\n/* 0x598 */\tu32 emc_dqs_brlshft_1;\n/* 0x59c */\tu32 emc_cmd_brlshft_0;\n/* 0x5a0 */\tu32 emc_cmd_brlshft_1;\n/* 0x5a4 */\tu32 emc_cmd_brlshft_2;\n/* 0x5a8 */\tu32 emc_cmd_brlshft_3;\n/* 0x5ac */\tu32 emc_quse_brlshft_0;\n/* 0x5b0 */\tu32 emc_auto_cal_config4;\n/* 0x5b4 */\tu32 emc_auto_cal_config5;\n/* 0x5b8 */\tu32 emc_quse_brlshft_1;\n/* 0x5bc */\tu32 emc_quse_brlshft_2;\n/* 0x5c0 */\tu32 emc_ccdmw;\n/* 0x5c4 */\tu32 emc_quse_brlshft_3;\n/* 0x5c8 */\tu32 emc_fbio_cfg8;\n/* 0x5cc */\tu32 emc_auto_cal_config6;\n/* 0x5d0 */\tu32 emc_protobist_config_adr_1;\n/* 0x5d4 */\tu32 emc_protobist_config_adr_2;\n/* 0x5d8 */\tu32 emc_protobist_misc;\n/* 0x5dc */\tu32 emc_protobist_wdata_lower;\n/* 0x5e0 */\tu32 emc_protobist_wdata_upper;\n\tunion {\n/* 0x5e4 */\tu32 emc_dll_cfg_0;\n/* 0x5e4 */\tu32 emc_pmacro_dll_cfg_0_b01;\n\t};\n\tunion {\n/* 0x5e8 */\tu32 emc_dll_cfg_1;\n/* 0x5e8 */\tu32 emc_pmacro_dll_cfg_1_b01;\n\t};\n/* 0x5ec */\tu32 emc_protobist_rdata;\n/* 0x5f0 */\tu32 emc_config_sample_delay;\n/* 0x5f4 */\tu32 emc_cfg_update;\n/* 0x5f8 */\tu32 emc_pmacro_dll_cfg_2_b01;\n/* 0x5fc */\tu32 rsvd_5fc;\n/* 0x600 */\tu32 emc_pmacro_quse_ddll_rank0_0;\n/* 0x604 */\tu32 emc_pmacro_quse_ddll_rank0_1;\n/* 0x608 */\tu32 emc_pmacro_quse_ddll_rank0_2;\n/* 0x60c */\tu32 emc_pmacro_quse_ddll_rank0_3;\n/* 0x610 */\tu32 emc_pmacro_quse_ddll_rank0_4;\n/* 0x614 */\tu32 emc_pmacro_quse_ddll_rank0_5;\n/* 0x618 */\tu32 rsvd_618[2];\n/* 0x620 */\tu32 emc_pmacro_quse_ddll_rank1_0;\n/* 0x624 */\tu32 emc_pmacro_quse_ddll_rank1_1;\n/* 0x628 */\tu32 emc_pmacro_quse_ddll_rank1_2;\n/* 0x62c */\tu32 emc_pmacro_quse_ddll_rank1_3;\n/* 0x630 */\tu32 emc_pmacro_quse_ddll_rank1_4;\n/* 0x634 */\tu32 emc_pmacro_quse_ddll_rank1_5;\n/* 0x638 */\tu32 rsvd_638[2];\n/* 0x640 */\tu32 emc_pmacro_ob_ddll_long_dq_rank0_0;\n/* 0x644 */\tu32 emc_pmacro_ob_ddll_long_dq_rank0_1;\n/* 0x648 */\tu32 emc_pmacro_ob_ddll_long_dq_rank0_2;\n/* 0x64c */\tu32 emc_pmacro_ob_ddll_long_dq_rank0_3;\n/* 0x650 */\tu32 emc_pmacro_ob_ddll_long_dq_rank0_4;\n/* 0x654 */\tu32 emc_pmacro_ob_ddll_long_dq_rank0_5;\n/* 0x658 */\tu32 rsvd_658[2];\n/* 0x660 */\tu32 emc_pmacro_ob_ddll_long_dq_rank1_0;\n/* 0x664 */\tu32 emc_pmacro_ob_ddll_long_dq_rank1_1;\n/* 0x668 */\tu32 emc_pmacro_ob_ddll_long_dq_rank1_2;\n/* 0x66c */\tu32 emc_pmacro_ob_ddll_long_dq_rank1_3;\n/* 0x670 */\tu32 emc_pmacro_ob_ddll_long_dq_rank1_4;\n/* 0x674 */\tu32 emc_pmacro_ob_ddll_long_dq_rank1_5;\n/* 0x678 */\tu32 rsvd_678[2];\n/* 0x680 */\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_0;\n/* 0x684 */\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_1;\n/* 0x688 */\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_2;\n/* 0x68c */\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_3;\n/* 0x690 */\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_4;\n/* 0x694 */\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_5;\n/* 0x698 */\tu32 rsvd_698[2];\n/* 0x6a0 */\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_0;\n/* 0x6a4 */\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_1;\n/* 0x6a8 */\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_2;\n/* 0x6ac */\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_3;\n/* 0x6b0 */\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_4;\n/* 0x6b4 */\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_5;\n/* 0x6b8 */\tu32 rsvd_6b8[2];\n/* 0x6c0 */\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_0;\n/* 0x6c4 */\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_1;\n/* 0x6c8 */\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_2;\n/* 0x6cc */\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_3;\n/* 0x6d0 */\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_4;\n/* 0x6d4 */\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_5;\n/* 0x6d8 */\tu32 rsvd_6d8[2];\n/* 0x6e0 */\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_0;\n/* 0x6e4 */\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_1;\n/* 0x6e8 */\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_2;\n/* 0x6ec */\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_3;\n/* 0x6f0 */\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_4;\n/* 0x6f4 */\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_5;\n/* 0x6f8 */\tu32 rsvd_6f8[2];\n/* 0x700 */\tu32 emc_pmacro_autocal_cfg_0;\n/* 0x704 */\tu32 emc_pmacro_autocal_cfg_1;\n/* 0x708 */\tu32 emc_pmacro_autocal_cfg_2;\n/* 0x70c */\tu32 rsvd_70c[5];\n/* 0x720 */\tu32 emc_pmacro_tx_pwrd_0;\n/* 0x724 */\tu32 emc_pmacro_tx_pwrd_1;\n/* 0x728 */\tu32 emc_pmacro_tx_pwrd_2;\n/* 0x72c */\tu32 emc_pmacro_tx_pwrd_3;\n/* 0x730 */\tu32 emc_pmacro_tx_pwrd_4;\n/* 0x734 */\tu32 emc_pmacro_tx_pwrd_5;\n/* 0x738 */\tu32 rsvd_738[2];\n/* 0x740 */\tu32 emc_pmacro_tx_sel_clk_src_0;\n/* 0x744 */\tu32 emc_pmacro_tx_sel_clk_src_1;\n/* 0x748 */\tu32 emc_pmacro_tx_sel_clk_src_2;\n/* 0x74c */\tu32 emc_pmacro_tx_sel_clk_src_3;\n/* 0x750 */\tu32 emc_pmacro_tx_sel_clk_src_4;\n/* 0x754 */\tu32 emc_pmacro_tx_sel_clk_src_5;\n/* 0x758 */\tu32 rsvd_758[2];\n/* 0x760 */\tu32 emc_pmacro_ddll_bypass;\n/* 0x764 */\tu32 rsvd_764[3];\n/* 0x770 */\tu32 emc_pmacro_ddll_pwrd_0;\n/* 0x774 */\tu32 emc_pmacro_ddll_pwrd_1;\n/* 0x778 */\tu32 emc_pmacro_ddll_pwrd_2;\n/* 0x77c */\tu32 rsvd_77c;\n/* 0x780 */\tu32 emc_pmacro_cmd_ctrl_0;\n/* 0x784 */\tu32 emc_pmacro_cmd_ctrl_1;\n/* 0x788 */\tu32 emc_pmacro_cmd_ctrl_2;\n/* 0x78c */\tu32 rsvd_78c[29];\n/* 0x800 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_0;\n/* 0x804 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_1;\n/* 0x808 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_2;\n/* 0x80c */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_3;\n/* 0x810 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_0;\n/* 0x814 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_1;\n/* 0x818 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_2;\n/* 0x81c */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_3;\n/* 0x820 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_0;\n/* 0x824 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_1;\n/* 0x828 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_2;\n/* 0x82c */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_3;\n/* 0x830 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_0;\n/* 0x834 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_1;\n/* 0x838 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_2;\n/* 0x83c */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_3;\n/* 0x840 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_0;\n/* 0x844 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_1;\n/* 0x848 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_2;\n/* 0x84c */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_3;\n/* 0x850 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_0;\n/* 0x854 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_1;\n/* 0x858 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_2;\n/* 0x85c */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_3;\n/* 0x860 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_0;\n/* 0x864 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_1;\n/* 0x868 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_2;\n/* 0x86c */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_3;\n/* 0x870 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_0;\n/* 0x874 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_1;\n/* 0x878 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_2;\n/* 0x87c */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_3;\n/* 0x880 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_0;\n/* 0x884 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_1;\n/* 0x888 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_2;\n/* 0x88c */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_3;\n/* 0x890 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_0;\n/* 0x894 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_1;\n/* 0x898 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_2;\n/* 0x89c */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_3;\n/* 0x8a0 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_0;\n/* 0x8a4 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_1;\n/* 0x8a8 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_2;\n/* 0x8ac */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_3;\n/* 0x8b0 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_0;\n/* 0x8b4 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_1;\n/* 0x8b8 */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_2;\n/* 0x8bc */\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_3;\n/* 0x8c0 */\tu32 rsvd_8c0[16];\n/* 0x900 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_0;\n/* 0x904 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_1;\n/* 0x908 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_2;\n/* 0x90c */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_3;\n/* 0x910 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_0;\n/* 0x914 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_1;\n/* 0x918 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_2;\n/* 0x91c */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_3;\n/* 0x920 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_0;\n/* 0x924 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_1;\n/* 0x928 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_2;\n/* 0x92c */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_3;\n/* 0x930 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_0;\n/* 0x934 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_1;\n/* 0x938 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_2;\n/* 0x93c */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_3;\n/* 0x940 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_0;\n/* 0x944 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_1;\n/* 0x948 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_2;\n/* 0x94c */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_3;\n/* 0x950 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_0;\n/* 0x954 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_1;\n/* 0x958 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_2;\n/* 0x95c */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_3;\n/* 0x960 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_0;\n/* 0x964 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_1;\n/* 0x968 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_2;\n/* 0x96c */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_3;\n/* 0x970 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_0;\n/* 0x974 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_1;\n/* 0x978 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_2;\n/* 0x97c */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_3;\n/* 0x980 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_0;\n/* 0x984 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_1;\n/* 0x988 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_2;\n/* 0x98c */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_3;\n/* 0x990 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_0;\n/* 0x994 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_1;\n/* 0x998 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_2;\n/* 0x99c */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_3;\n/* 0x9a0 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_0;\n/* 0x9a4 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_1;\n/* 0x9a8 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_2;\n/* 0x9ac */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_3;\n/* 0x9b0 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_0;\n/* 0x9b4 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_1;\n/* 0x9b8 */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_2;\n/* 0x9bc */\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_3;\n/* 0x9c0 */\tu32 rsvd_9c0[16];\n/* 0xa00 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_0;\n/* 0xa04 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_1;\n/* 0xa08 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_2;\n/* 0xa0c */\tu32 rsvd_a0c;\n/* 0xa10 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_0;\n/* 0xa14 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_1;\n/* 0xa18 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_2;\n/* 0xa1c */\tu32 rsvd_a1c;\n/* 0xa20 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_0;\n/* 0xa24 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_1;\n/* 0xa28 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_2;\n/* 0xa2c */\tu32 rsvd_a2c;\n/* 0xa30 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_0;\n/* 0xa34 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_1;\n/* 0xa38 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_2;\n/* 0xa3c */\tu32 rsvd_a3c;\n/* 0xa40 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_0;\n/* 0xa44 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_1;\n/* 0xa48 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_2;\n/* 0xa4c */\tu32 rsvd_a4c;\n/* 0xa50 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_0;\n/* 0xa54 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_1;\n/* 0xa58 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_2;\n/* 0xa5c */\tu32 rsvd_a5c;\n/* 0xa60 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_0;\n/* 0xa64 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_1;\n/* 0xa68 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_2;\n/* 0xa6c */\tu32 rsvd_a6c;\n/* 0xa70 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_0;\n/* 0xa74 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_1;\n/* 0xa78 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_2;\n/* 0xa7c */\tu32 rsvd_a7c;\n/* 0xa80 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_cmd0_0;\n/* 0xa84 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_cmd0_1;\n/* 0xa88 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_cmd0_2;\n/* 0xa8c */\tu32 rsvd_a8c;\n/* 0xa90 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_cmd1_0;\n/* 0xa94 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_cmd1_1;\n/* 0xa98 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_cmd1_2;\n/* 0xa9c */\tu32 rsvd_a9c;\n/* 0xaa0 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_cmd2_0;\n/* 0xaa4 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_cmd2_1;\n/* 0xaa8 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_cmd2_2;\n/* 0xaac */\tu32 rsvd_aac;\n/* 0xab0 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_cmd3_0;\n/* 0xab4 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_cmd3_1;\n/* 0xab8 */\tu32 emc_pmacro_ib_ddll_short_dq_rank0_cmd3_2;\n/* 0xabc */\tu32 rsvd_abc[17];\n/* 0xb00 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_0;\n/* 0xb04 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_1;\n/* 0xb08 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_2;\n/* 0xb0c */\tu32 rsvd_b0c;\n/* 0xb10 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_0;\n/* 0xb14 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_1;\n/* 0xb18 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_2;\n/* 0xb1c */\tu32 rsvd_b1c;\n/* 0xb20 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_0;\n/* 0xb24 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_1;\n/* 0xb28 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_2;\n/* 0xb2c */\tu32 rsvd_b2c;\n/* 0xb30 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_0;\n/* 0xb34 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_1;\n/* 0xb38 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_2;\n/* 0xb3c */\tu32 rsvd_b3c;\n/* 0xb40 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_0;\n/* 0xb44 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_1;\n/* 0xb48 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_2;\n/* 0xb4c */\tu32 rsvd_b4c;\n/* 0xb50 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_0;\n/* 0xb54 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_1;\n/* 0xb58 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_2;\n/* 0xb5c */\tu32 rsvd_b5c;\n/* 0xb60 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_0;\n/* 0xb64 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_1;\n/* 0xb68 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_2;\n/* 0xb6c */\tu32 rsvd_b6c;\n/* 0xb70 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_0;\n/* 0xb74 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_1;\n/* 0xb78 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_2;\n/* 0xb7c */\tu32 rsvd_b7c;\n/* 0xb80 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_cmd0_0;\n/* 0xb84 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_cmd0_1;\n/* 0xb88 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_cmd0_2;\n/* 0xb8c */\tu32 rsvd_b8c;\n/* 0xb90 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_cmd1_0;\n/* 0xb94 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_cmd1_1;\n/* 0xb98 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_cmd1_2;\n/* 0xb9c */\tu32 rsvd_b9c;\n/* 0xba0 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_cmd2_0;\n/* 0xba4 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_cmd2_1;\n/* 0xba8 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_cmd2_2;\n/* 0xbac */\tu32 rsvd_bac;\n/* 0xbb0 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_cmd3_0;\n/* 0xbb4 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_cmd3_1;\n/* 0xbb8 */\tu32 emc_pmacro_ib_ddll_short_dq_rank1_cmd3_2;\n/* 0xbbc */\tu32 rsvd_bbc[9];\n/* 0xbe0 */\tu32 emc_pmacro_ib_vref_dq_0;\n/* 0xbe4 */\tu32 emc_pmacro_ib_vref_dq_1;\n/* 0xbe8 */\tu32 emc_pmacro_ib_vref_dq_2;\n/* 0xbec */\tu32 rsvd_bec;\n/* 0xbf0 */\tu32 emc_pmacro_ib_vref_dqs_0;\n/* 0xbf4 */\tu32 emc_pmacro_ib_vref_dqs_1;\n/* 0xbf8 */\tu32 emc_pmacro_ib_vref_dqs_2;\n/* 0xbfc */\tu32 rsvd_bfc;\n/* 0xc00 */\tu32 emc_pmacro_ddll_long_cmd_0;\n/* 0xc04 */\tu32 emc_pmacro_ddll_long_cmd_1;\n/* 0xc08 */\tu32 emc_pmacro_ddll_long_cmd_2;\n/* 0xc0c */\tu32 emc_pmacro_ddll_long_cmd_3;\n/* 0xc10 */\tu32 emc_pmacro_ddll_long_cmd_4;\n/* 0xc14 */\tu32 emc_pmacro_ddll_long_cmd_5;\n/* 0xc18 */\tu32 rsvd_c18[2];\n/* 0xc20 */\tu32 emc_pmacro_ddll_short_cmd_0;\n/* 0xc24 */\tu32 emc_pmacro_ddll_short_cmd_1;\n/* 0xc28 */\tu32 emc_pmacro_ddll_short_cmd_2;\n/* 0xc2c */\tu32 rsvd_c2c;\n/* 0xc30 */\tu32 emc_pmacro_cfg_pm_global_0;\n/* 0xc34 */\tu32 emc_pmacro_vttgen_ctrl_0;\n/* 0xc38 */\tu32 emc_pmacro_vttgen_ctrl_1;\n/* 0xc3c */\tu32 emc_pmacro_bg_bias_ctrl_0;\n/* 0xc40 */\tu32 emc_pmacro_pad_cfg_ctrl;\n/* 0xc44 */\tu32 emc_pmacro_zctrl;\n/* 0xc48 */\tu32 emc_pmacro_rx_term;\n/* 0xc4c */\tu32 emc_pmacro_cmd_tx_drv;\n/* 0xc50 */\tu32 emc_pmacro_cmd_pad_rx_ctrl;\n/* 0xc54 */\tu32 emc_pmacro_data_pad_rx_ctrl;\n/* 0xc58 */\tu32 emc_pmacro_cmd_rx_term_mode;\n/* 0xc5c */\tu32 emc_pmacro_data_rx_term_mode;\n/* 0xc60 */\tu32 emc_pmacro_cmd_pad_tx_ctrl;\n/* 0xc64 */\tu32 emc_pmacro_data_pad_tx_ctrl;\n/* 0xc68 */\tu32 emc_pmacro_common_pad_tx_ctrl_t210;\n/* 0xc6c */\tu32 emc_pmacro_dsr_vttgen_ctrl_0_b01;\n/* 0xc70 */\tu32 emc_pmacro_dq_tx_drv;\n/* 0xc74 */\tu32 emc_pmacro_ca_tx_drv;\n/* 0xc78 */\tu32 emc_pmacro_autocal_cfg_common;\n/* 0xc7c */\tu32 rsvd_c7c;\n/* 0xc80 */\tu32 emc_pmacro_brick_mapping_0;\n/* 0xc84 */\tu32 emc_pmacro_brick_mapping_1;\n/* 0xc88 */\tu32 emc_pmacro_brick_mapping_2;\n/* 0xc8c */\tu32 emc_stat_dram_io_extclks_cke_eq0_no_banks_active_clks_lo;\n/* 0xc90 */\tu32 emc_stat_dram_io_extclks_cke_eq0_no_banks_active_clks_hi;\n/* 0xc94 */\tu32 emc_stat_dram_io_clkstop_cke_eq0_no_banks_active_clks_lo;\n/* 0xc98 */\tu32 emc_stat_dram_io_clkstop_cke_eq0_no_banks_active_clks_hi;\n/* 0xc9c */\tu32 emc_stat_dram_io_extclks_cke_eq1_no_banks_active_clks_lo;\n/* 0xca0 */\tu32 emc_stat_dram_io_extclks_cke_eq1_no_banks_active_clks_hi;\n/* 0xca4 */\tu32 emc_stat_dram_io_clkstop_cke_eq1_no_banks_active_clks_lo;\n/* 0xca8 */\tu32 emc_stat_dram_io_clkstop_cke_eq1_no_banks_active_clks_hi;\n/* 0xcac */\tu32 emc_stat_dram_io_extclks_cke_eq0_some_banks_active_clks_lo;\n/* 0xcb0 */\tu32 emc_stat_dram_io_extclks_cke_eq0_some_banks_active_clks_hi;\n/* 0xcb4 */\tu32 emc_stat_dram_io_clkstop_cke_eq0_some_banks_active_clks_lo;\n/* 0xcb8 */\tu32 emc_stat_dram_io_clkstop_cke_eq0_some_banks_active_clks_hi;\n/* 0xcbc */\tu32 emc_stat_dram_io_extclks_cke_eq1_some_banks_active_clks_lo;\n/* 0xcc0 */\tu32 emc_stat_dram_io_extclks_cke_eq1_some_banks_active_clks_hi;\n/* 0xcc4 */\tu32 emc_stat_dram_io_clkstop_cke_eq1_some_banks_active_clks_lo;\n/* 0xcc8 */\tu32 emc_stat_dram_io_clkstop_cke_eq1_some_banks_active_clks_hi;\n/* 0xccc */\tu32 emc_stat_dram_io_sr_cke_eq0_clks_lo;\n/* 0xcd0 */\tu32 emc_stat_dram_io_sr_cke_eq0_clks_hi;\n/* 0xcd4 */\tu32 emc_stat_dram_io_dsr;\n/* 0xcd8 */\tu32 rsvd_cd8[2];\n/* 0xce0 */\tu32 emc_pmacro_ddllcal_cal_t210;\n/* 0xce4 */\tu32 emc_pmacro_ddll_offset;\n/* 0xce8 */\tu32 emc_pmacro_ddll_periodic_offset;\n/* 0xcec */\tu32 rsvd_cec;\n/* 0xcf0 */\tu32 emc_pmacro_vttgen_ctrl_2;\n/* 0xcf4 */\tu32 emc_pmacro_ib_rxrt;\n/* 0xcf8 */\tu32 emc_pmacro_training_ctrl_0;\n/* 0xcfc */\tu32 emc_pmacro_training_ctrl_1;\n/* 0xd00 */\tu32 emc_pmacro_ddllcal_cal_0_b01;\n/* 0xd04 */\tu32 emc_pmacro_ddllcal_cal_1_b01;\n/* 0xd08 */\tu32 emc_pmacro_ddllcal_cal_2_b01;\n/* 0xd0c */\tu32 emc_pmacro_ddllcal_cal_3_b01;\n/* 0xd10 */\tu32 emc_pmacro_ddllcal_cal_4_b01;\n/* 0xd14 */\tu32 emc_pmacro_ddllcal_cal_5_b01;\n/* 0xd18 */\tu32 rsvd_d18[2];\n/* 0xd20 */\tu32 emc_pmacro_dig_dll_status_0_b01;\n/* 0xd24 */\tu32 emc_pmacro_dig_dll_status_1_b01;\n/* 0xd28 */\tu32 emc_pmacro_dig_dll_status_2_b01;\n/* 0xd2c */\tu32 emc_pmacro_dig_dll_status_3_b01;\n/* 0xd30 */\tu32 emc_pmacro_dig_dll_status_4_b01;\n/* 0xd34 */\tu32 emc_pmacro_dig_dll_status_5_b01;\n/* 0xd38 */\tu32 rsvd_d38[2];\n/* 0xd40 */\tu32 emc_pmacro_perbit_fgcg_ctrl_0_b01;\n/* 0xd44 */\tu32 emc_pmacro_perbit_fgcg_ctrl_1_b01;\n/* 0xd48 */\tu32 emc_pmacro_perbit_fgcg_ctrl_2_b01;\n/* 0xd4c */\tu32 emc_pmacro_perbit_fgcg_ctrl_3_b01;\n/* 0xd50 */\tu32 emc_pmacro_perbit_fgcg_ctrl_4_b01;\n/* 0xd54 */\tu32 emc_pmacro_perbit_fgcg_ctrl_5_b01;\n/* 0xd58 */\tu32 rsvd_d58[2];\n/* 0xd60 */\tu32 emc_pmacro_perbit_rfu_ctrl_0_b01;\n/* 0xd64 */\tu32 emc_pmacro_perbit_rfu_ctrl_1_b01;\n/* 0xd68 */\tu32 emc_pmacro_perbit_rfu_ctrl_2_b01;\n/* 0xd6c */\tu32 emc_pmacro_perbit_rfu_ctrl_3_b01;\n/* 0xd70 */\tu32 emc_pmacro_perbit_rfu_ctrl_4_b01;\n/* 0xd74 */\tu32 emc_pmacro_perbit_rfu_ctrl_5_b01;\n/* 0xd78 */\tu32 rsvd_d78[2];\n/* 0xd80 */\tu32 emc_pmacro_perbit_rfu1_ctrl_0_b01;\n/* 0xd84 */\tu32 emc_pmacro_perbit_rfu1_ctrl_1_b01;\n/* 0xd88 */\tu32 emc_pmacro_perbit_rfu1_ctrl_2_b01;\n/* 0xd8c */\tu32 emc_pmacro_perbit_rfu1_ctrl_3_b01;\n/* 0xd90 */\tu32 emc_pmacro_perbit_rfu1_ctrl_4_b01;\n/* 0xd94 */\tu32 emc_pmacro_perbit_rfu1_ctrl_5_b01;\n/* 0xd98 */\tu32 rsvd_d98[2];\n/* 0xda0 */\tu32 emc_pmacro_pmu_out_eoff1_0_b01;\n/* 0xda4 */\tu32 emc_pmacro_pmu_out_eoff1_1_b01;\n/* 0xda8 */\tu32 emc_pmacro_pmu_out_eoff1_2_b01;\n/* 0xdac */\tu32 emc_pmacro_pmu_out_eoff1_3_b01;\n/* 0xdb0 */\tu32 emc_pmacro_pmu_out_eoff1_4_b01;\n/* 0xdb4 */\tu32 emc_pmacro_pmu_out_eoff1_5_b01;\n/* 0xdb8 */\tu32 rsvd_db8[2];\n/* 0xdc0 */\tu32 emc_pmacro_comp_pmu_out_b01;\n/* 0xdc4 */\tu32 rsvd_dc4[15];\n/* 0xe00 */\tu32 emc_training_cmd;\n/* 0xe04 */\tu32 emc_training_ctrl;\n/* 0xe08 */\tu32 emc_training_status;\n/* 0xe0c */\tu32 emc_training_quse_cors_ctrl;\n/* 0xe10 */\tu32 emc_training_quse_fine_ctrl;\n/* 0xe14 */\tu32 emc_training_quse_ctrl_misc;\n/* 0xe18 */\tu32 emc_training_write_fine_ctrl;\n/* 0xe1c */\tu32 emc_training_write_ctrl_misc;\n/* 0xe20 */\tu32 emc_training_write_vref_ctrl;\n/* 0xe24 */\tu32 emc_training_read_fine_ctrl;\n/* 0xe28 */\tu32 emc_training_read_ctrl_misc;\n/* 0xe2c */\tu32 emc_training_read_vref_ctrl;\n/* 0xe30 */\tu32 emc_training_ca_fine_ctrl;\n/* 0xe34 */\tu32 emc_training_ca_ctrl_misc;\n/* 0xe38 */\tu32 emc_training_ca_ctrl_misc1;\n/* 0xe3c */\tu32 emc_training_ca_vref_ctrl;\n/* 0xe40 */\tu32 emc_training_ca_tadr_ctrl;\n/* 0xe44 */\tu32 emc_training_settle;\n/* 0xe48 */\tu32 emc_training_debug_ctrl;\n/* 0xe4c */\tu32 emc_training_debug_dq0;\n/* 0xe50 */\tu32 emc_training_debug_dq1;\n/* 0xe54 */\tu32 emc_training_debug_dq2;\n/* 0xe58 */\tu32 emc_training_debug_dq3;\n/* 0xe5c */\tu32 emc_training_mpc;\n/* 0xe60 */\tu32 emc_training_patram_ctrl;\n/* 0xe64 */\tu32 emc_training_patram_dq;\n/* 0xe68 */\tu32 emc_training_patram_dmi;\n/* 0xe6c */\tu32 emc_training_vref_settle;\n/* 0xe70 */\tu32 emc_training_rw_eye_center_ib_byte0;\n/* 0xe74 */\tu32 emc_training_rw_eye_center_ib_byte1;\n/* 0xe78 */\tu32 emc_training_rw_eye_center_ib_byte2;\n/* 0xe7c */\tu32 emc_training_rw_eye_center_ib_byte3;\n/* 0xe80 */\tu32 emc_training_rw_eye_center_ib_misc;\n/* 0xe84 */\tu32 emc_training_rw_eye_center_ob_byte0;\n/* 0xe88 */\tu32 emc_training_rw_eye_center_ob_byte1;\n/* 0xe8c */\tu32 emc_training_rw_eye_center_ob_byte2;\n/* 0xe90 */\tu32 emc_training_rw_eye_center_ob_byte3;\n/* 0xe94 */\tu32 emc_training_rw_eye_center_ob_misc;\n/* 0xe98 */\tu32 emc_training_rw_offset_ib_byte0;\n/* 0xe9c */\tu32 emc_training_rw_offset_ib_byte1;\n/* 0xea0 */\tu32 emc_training_rw_offset_ib_byte2;\n/* 0xea4 */\tu32 emc_training_rw_offset_ib_byte3;\n/* 0xea8 */\tu32 emc_training_rw_offset_ib_misc;\n/* 0xeac */\tu32 emc_training_rw_offset_ob_byte0;\n/* 0xeb0 */\tu32 emc_training_rw_offset_ob_byte1;\n/* 0xeb4 */\tu32 emc_training_rw_offset_ob_byte2;\n/* 0xeb8 */\tu32 emc_training_rw_offset_ob_byte3;\n/* 0xebc */\tu32 emc_training_rw_offset_ob_misc;\n/* 0xec0 */\tu32 emc_training_opt_ca_vref;\n/* 0xec4 */\tu32 emc_training_opt_dq_ob_vref;\n/* 0xec8 */\tu32 emc_training_opt_dq_ib_vref_rank0;\n/* 0xecc */\tu32 emc_training_opt_dq_ib_vref_rank1;\n/* 0xed0 */\tu32 emc_training_quse_vref_ctrl;\n/* 0xed4 */\tu32 emc_training_opt_dqs_ib_vref_rank0;\n/* 0xed8 */\tu32 emc_training_opt_dqs_ib_vref_rank1;\n/* 0xedc */\tu32 emc_training_dramc_timing;\n} emc_regs_t210_t;\n\n#endif\n"
  },
  {
    "path": "bdk/mem/heap.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n#include \"heap.h\"\n#include <gfx_utils.h>\n\n#define HEAP_USED_MAGIC 0x50414548 // \"HEAP\".\n\nheap_t _heap;\n\nstatic void _heap_create(void *start)\n{\n\t_heap.start = start;\n\t_heap.first = NULL;\n\t_heap.last  = NULL;\n}\n\n// Node info is before node address.\nstatic void *_heap_alloc(u32 size)\n{\n\thnode_t *node, *new_node;\n\n\t// Align to cache line size.\n\tsize = ALIGN(size, sizeof(hnode_t));\n\n\t// First allocation.\n\tif (!_heap.first)\n\t{\n\t\tnode = (hnode_t *)_heap.start;\n\t\tnode->used = HEAP_USED_MAGIC;\n\t\tnode->size = size;\n\t\tnode->prev = NULL;\n\t\tnode->next = NULL;\n\n\t\t_heap.first = node;\n\t\t_heap.last = node;\n\n\t\treturn (void *)node + sizeof(hnode_t);\n\t}\n\n#ifdef BDK_MALLOC_NO_DEFRAG\n\t// Get the last allocated block.\n\tnode = _heap.last;\n#else\n\t// Get first block and find the first available one.\n\tnode = _heap.first;\n\twhile (true)\n\t{\n\t\t// Check if there's available unused node.\n\t\tif (!node->used && (size <= node->size))\n\t\t{\n\t\t\t// Size and offset of the new unused node.\n\t\t\tu32 new_size = node->size - size;\n\t\t\tnew_node = (hnode_t *)((void *)node + sizeof(hnode_t) + size);\n\n\t\t\t// If there's aligned unused space from the old node,\n\t\t\t// create a new one and set the leftover size.\n\t\t\tif (new_size >= (sizeof(hnode_t) << 2))\n\t\t\t{\n\t\t\t\tnew_node->used = 0;\n\t\t\t\tnew_node->size = new_size - sizeof(hnode_t);\n\t\t\t\tnew_node->next = node->next;\n\n\t\t\t\t// Check that we are not on first node.\n\t\t\t\tif (new_node->next)\n\t\t\t\t\tnew_node->next->prev = new_node;\n\n\t\t\t\tnew_node->prev = node;\n\t\t\t\tnode->next = new_node;\n\t\t\t}\n\t\t\telse // Unused node size is just enough.\n\t\t\t\tsize += new_size;\n\n\t\t\tnode->size = size;\n\t\t\tnode->used = HEAP_USED_MAGIC;\n\n\t\t\treturn (void *)node + sizeof(hnode_t);\n\t\t}\n\n\t\t// No unused node found, try the next one.\n\t\tif (node->next)\n\t\t\tnode = node->next;\n\t\telse\n\t\t\tbreak;\n\t}\n#endif\n\n\t// No unused node found, create a new one.\n\tnew_node = (hnode_t *)((void *)node + sizeof(hnode_t) + node->size);\n\tnew_node->used = HEAP_USED_MAGIC;\n\tnew_node->size = size;\n\tnew_node->prev = node;\n\tnew_node->next = NULL;\n\n\tnode->next = new_node;\n\t_heap.last = new_node;\n\n\treturn (void *)new_node + sizeof(hnode_t);\n}\n\nstatic void _heap_free(void *addr)\n{\n\thnode_t *node = (hnode_t *)(addr - sizeof(hnode_t));\n\n\t// Check if heap owns this address.\n\tif (addr < _heap.start || node->used != HEAP_USED_MAGIC)\n\t{\n\t\t//! BUGPRINTF(\"free error: addr %08p, used %08X!\\n\");\n\t\treturn;\n\t}\n\n\tnode->used = 0;\n\n#ifndef BDK_MALLOC_NO_DEFRAG\n\t// Merge with previous node if empty.\n\thnode_t *prev = node->prev;\n\tif (prev && !prev->used)\n\t{\n\t\tprev->size += node->size + sizeof(hnode_t);\n\t\tprev->next  = node->next;\n\n\t\tif (node->next)\n\t\t\tnode->next->prev = prev;\n\n\t\t// Set node to resized one.\n\t\tnode = prev;\n\t}\n\n\t// Merge with next node if empty.\n\thnode_t *next = node->next;\n\tif (next && !next->used)\n\t{\n\t\tnode->size += next->size + sizeof(hnode_t);\n\t\tnode->next  = next->next;\n\n\t\tif (next->next)\n\t\t\tnext->next->prev = node;\n\t}\n#endif\n}\n\nvoid heap_init(void *base)\n{\n\t_heap_create(base);\n}\n\nvoid heap_set(heap_t *heap)\n{\n\tmemcpy(&_heap, heap, sizeof(heap_t));\n}\n\nvoid *malloc(u32 size)\n{\n\treturn _heap_alloc(size);\n}\n\nvoid *zalloc(u32 size)\n{\n\tvoid *buf = (void *)_heap_alloc(size);\n\tmemset(buf, 0, ALIGN(size, sizeof(hnode_t))); // Clear the aligned size.\n\treturn buf;\n}\n\nvoid *calloc(u32 num, u32 size)\n{\n\treturn zalloc(num * size);\n}\n\nvoid free(void *buf)\n{\n\t_heap_free(buf);\n}\n\nvoid heap_monitor(heap_monitor_t *mon, bool print_node_stats)\n{\n\tu32 count = 0;\n\tmemset(mon, 0, sizeof(heap_monitor_t));\n\n\thnode_t *node = _heap.first;\n\twhile (true)\n\t{\n\t\tif (node->used)\n\t\t{\n\t\t\tmon->nodes_used++;\n\t\t\tmon->used += node->size + sizeof(hnode_t);\n\t\t}\n\t\telse\n\t\t\tmon->total += node->size + sizeof(hnode_t);\n\n\t\tif (print_node_stats)\n\t\t\tgfx_printf(\"%3d - %d, addr: 0x%08X, size: 0x%X\\n\",\n\t\t\t\tcount, node->used, (u32)node + sizeof(hnode_t), node->size);\n\n\t\tcount++;\n\n\t\tif (node->next)\n\t\t\tnode = node->next;\n\t\telse\n\t\t\tbreak;\n\t}\n\tmon->total += mon->used;\n\tmon->nodes_total = count;\n}\n"
  },
  {
    "path": "bdk/mem/heap.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2024 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _HEAP_H_\n#define _HEAP_H_\n\n#include <utils/types.h>\n\ntypedef struct _hnode\n{\n\tint used;\n\tu32 size;\n\tstruct _hnode *prev;\n\tstruct _hnode *next;\n\tu32 align[4]; // Align to arch cache line size.\n} hnode_t;\n\ntypedef struct _heap\n{\n\tvoid *start;\n\thnode_t *first;\n\thnode_t *last;\n} heap_t;\n\ntypedef struct\n{\n\tu32 total;\n\tu32 used;\n\tu32 nodes_total;\n\tu32 nodes_used;\n} heap_monitor_t;\n\nvoid heap_init(void *base);\nvoid heap_set(heap_t *heap);\nvoid *malloc(u32 size);\nvoid *calloc(u32 num, u32 size);\nvoid *zalloc(u32 size);\nvoid free(void *buf);\nvoid heap_monitor(heap_monitor_t *mon, bool print_node_stats);\n\n#endif\n"
  },
  {
    "path": "bdk/mem/mc.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <memory_map.h>\n#include <mem/mc.h>\n#include <soc/bpmp.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n#include <soc/clock.h>\n\n#define HOS_WPR1_BASE 0x80020000\n\nvoid mc_config_carveout_hos()\n{\n\t// Enable ACR GSR3 and flush data to ram.\n\t*(u32 *)(HOS_WPR1_BASE + SZ_256K - sizeof(u32)) = ACR_GSC3_ENABLE_MAGIC;\n\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);\n\n\t// Set VPR CYA TRUSTED DEFAULT.\n\tMC(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) = VPR_OVR0_CYA_TRUST_DEFAULT;\n\tMC(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) = 0;\n\n\t// Disable VPR carveout.\n\tMC(MC_VIDEO_PROTECT_BOM)      = 0;\n\tMC(MC_VIDEO_PROTECT_SIZE_MB)  = 0;\n\tMC(MC_VIDEO_PROTECT_REG_CTRL) = VPR_CTRL_LOCKED;\n\n\t// Disable TZDRAM carveout.\n\tMC(MC_SEC_CARVEOUT_BOM)      = 0;\n\tMC(MC_SEC_CARVEOUT_SIZE_MB)  = 0;\n\tMC(MC_SEC_CARVEOUT_REG_CTRL) = BIT(0);\n\n\t// Disable CPU FW carveout.\n\tMC(MC_MTS_CARVEOUT_BOM)      = 0;\n\tMC(MC_MTS_CARVEOUT_SIZE_MB)  = 0;\n\tMC(MC_MTS_CARVEOUT_REG_CTRL) = BIT(0);\n\n\t// Disable GEN1 carveout.\n\tMC(MC_SECURITY_CARVEOUT1_SIZE_128KB) = 0;\n\tMC(MC_SECURITY_CARVEOUT1_CFG0) = SEC_CARVEOUT_CFG_LOCKED            |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_APERTURE_ID(0)    |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH;\n\n\t// Enable GEN2 carveout as WPR1.\n\tMC(MC_SECURITY_CARVEOUT2_BOM)        = HOS_WPR1_BASE;\n\tMC(MC_SECURITY_CARVEOUT2_SIZE_128KB) = SZ_256K / SZ_128K;\n\tMC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2) = SEC_CARVEOUT_CA2_R_GPU  | SEC_CARVEOUT_CA2_W_GPU | SEC_CARVEOUT_CA2_R_TSEC;\n\tMC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4) = SEC_CARVEOUT_CA4_R_GPU2 | SEC_CARVEOUT_CA4_W_GPU2;\n\tMC(MC_SECURITY_CARVEOUT2_CFG0) = SEC_CARVEOUT_CFG_LOCKED            |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_NS             |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_SEC            |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_FALCON_LS      |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_FALCON_HS      |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_WR_FALCON_LS      |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_WR_FALCON_HS      |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_APERTURE_ID(2)    |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_SEND_CFG_TO_GPU   |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH;\n\n\t// Prepare GEN3 carveout as WPR2.\n\tMC(MC_SECURITY_CARVEOUT3_SIZE_128KB) = 0;\n\tMC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2) = SEC_CARVEOUT_CA2_R_GPU  | SEC_CARVEOUT_CA2_W_GPU;\n\tMC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4) = SEC_CARVEOUT_CA4_R_GPU2 | SEC_CARVEOUT_CA4_W_GPU2;\n\tMC(MC_SECURITY_CARVEOUT3_CFG0) = SEC_CARVEOUT_CFG_LOCKED            |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_NS             |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_SEC            |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_FALCON_LS      |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_FALCON_HS      |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_WR_FALCON_LS      |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_WR_FALCON_HS      |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_APERTURE_ID(3)    |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_SEND_CFG_TO_GPU   |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH;\n\n\t// Disable GEN4 carveout.\n\tMC(MC_SECURITY_CARVEOUT4_SIZE_128KB) = 0;\n\tMC(MC_SECURITY_CARVEOUT4_CFG0) = SEC_CARVEOUT_CFG_TZ_SECURE         |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_LOCKED            |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_NS             |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_WR_NS;\n\n\t// Disable GEN5 carveout.\n\tMC(MC_SECURITY_CARVEOUT5_SIZE_128KB) = 0;\n\tMC(MC_SECURITY_CARVEOUT5_CFG0) = SEC_CARVEOUT_CFG_TZ_SECURE         |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_LOCKED            |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_NS             |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_WR_NS;\n}\n\n// SDMMC, TSEC, XUSB and probably more need it to access < DRAM_START.\nvoid mc_enable_ahb_redirect(u32 offset)\n{\n\t// Bypass ARC clock gating.\n\tCLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) |= BIT(19);\n\t//MC(MC_IRAM_REG_CTRL) &= ~BIT(0);\n\tMC(MC_IRAM_BOM) = IRAM_BASE;\n\tMC(MC_IRAM_TOM) = DRAM_START - offset; // Default is only IRAM: 0x4003F000.\n}\n\nvoid mc_disable_ahb_redirect()\n{\n\tMC(MC_IRAM_BOM) = 0xFFFFF000;\n\tMC(MC_IRAM_TOM) = 0;\n\t// Disable IRAM_CFG_WRITE_ACCESS (sticky).\n\t//MC(MC_IRAM_REG_CTRL) |= BIT(0);\n\t// Set ARC clock gating to automatic.\n\tCLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) &= ~BIT(19);\n}\n\nbool mc_client_has_access(void *address)\n{\n\t// Check if address is in DRAM or if arbitration for IRAM is enabled.\n\tif ((u32)address >= DRAM_START)\n\t\treturn true; // Access by default.\n\telse if ((u32)address >= IRAM_BASE && MC(MC_IRAM_BOM) == IRAM_BASE)\n\t\treturn true; // Access by AHB arbitration.\n\n\t// No access to address space.\n\treturn false;\n}\n\nvoid mc_enable()\n{\n\t// Reset EMC source to PLLP.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF) | (2 << 29u);\n\n\t// Enable and clear reset for memory clocks.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = BIT(CLK_H_EMC) | BIT(CLK_H_MEM);\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = BIT(CLK_X_EMC_DLL);\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = BIT(CLK_H_EMC) | BIT(CLK_H_MEM);\n\tusleep(5);\n\n\t// Enable redirection by default.\n\tmc_enable_ahb_redirect(1);\n}\n"
  },
  {
    "path": "bdk/mem/mc.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _MC_H_\n#define _MC_H_\n\n#include <utils/types.h>\n#include <mem/mc_t210.h>\n\nvoid mc_config_tsec_carveout(u32 bom, u32 size1mb, bool lock);\nvoid mc_config_carveout_hos();\nvoid mc_enable_ahb_redirect(u32 offset);\nvoid mc_disable_ahb_redirect();\nbool mc_client_has_access(void *address);\nvoid mc_enable();\n\n#endif\n"
  },
  {
    "path": "bdk/mem/mc_t210.h",
    "content": "/*\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _MC_T210_H_\n#define _MC_T210_H_\n\n/* Memory Controller registers */\n#define MC_INTSTATUS                                        0x0\n#define MC_INTMASK                                          0x4\n#define MC_ERR_STATUS                                       0x8\n#define MC_ERR_ADR                                          0xC\n#define MC_SMMU_CONFIG                                      0x10\n#define MC_SMMU_TLB_CONFIG                                  0x14\n#define MC_SMMU_PTC_CONFIG                                  0x18\n#define MC_SMMU_PTB_ASID                                    0x1C\n#define MC_SMMU_PTB_DATA                                    0x20\n#define MC_SMMU_TLB_FLUSH                                   0x30\n#define MC_SMMU_PTC_FLUSH                                   0x34\n#define MC_SMMU_ASID_SECURITY                               0x38\n#define MC_SMMU_ASID_SECURITY_1                             0x3C\n#define MC_SMMU_CLIENT_CONFIG0                              0x40\n#define MC_SMMU_CLIENT_CONFIG1                              0x44\n#define MC_SMMU_CLIENT_CONFIG2                              0x48\n#define MC_SMMU_CLIENT_CONFIG3                              0x4C\n#define MC_EMEM_CFG                                         0x50\n#define MC_EMEM_ADR_CFG                                     0x54\n#define MC_EMEM_ADR_CFG_DEV0                                0x58\n#define MC_EMEM_ADR_CFG_DEV1                                0x5C\n#define MC_EMEM_ADR_CFG_CHANNEL_MASK                        0x60\n#define MC_EMEM_ADR_CFG_BANK_MASK_0                         0x64\n#define MC_EMEM_ADR_CFG_BANK_MASK_1                         0x68\n#define MC_EMEM_ADR_CFG_BANK_MASK_2                         0x6C\n#define MC_SECURITY_CFG0                                    0x70\n#define MC_SECURITY_CFG1                                    0x74\n#define MC_SECURITY_RSV                                     0x7C\n#define MC_EMEM_ARB_CFG                                     0x90\n#define MC_EMEM_ARB_OUTSTANDING_REQ                         0x94\n#define MC_EMEM_ARB_TIMING_RCD                              0x98\n#define MC_EMEM_ARB_TIMING_RP                               0x9C\n#define MC_EMEM_ARB_TIMING_RC                               0xA0\n#define MC_EMEM_ARB_TIMING_RAS                              0xA4\n#define MC_EMEM_ARB_TIMING_FAW                              0xA8\n#define MC_EMEM_ARB_TIMING_RRD                              0xAC\n#define MC_EMEM_ARB_TIMING_RAP2PRE                          0xB0\n#define MC_EMEM_ARB_TIMING_WAP2PRE                          0xB4\n#define MC_EMEM_ARB_TIMING_R2R                              0xB8\n#define MC_EMEM_ARB_TIMING_W2W                              0xBC\n#define MC_EMEM_ARB_TIMING_R2W                              0xC0\n#define MC_EMEM_ARB_TIMING_W2R                              0xC4\n#define MC_EMEM_ARB_MISC2                                   0xC8\n#define MC_EMEM_ARB_DA_TURNS                                0xD0\n#define MC_EMEM_ARB_DA_COVERS                               0xD4\n#define MC_EMEM_ARB_MISC0                                   0xD8\n#define MC_EMEM_ARB_MISC1                                   0xDC\n#define MC_EMEM_ARB_RING1_THROTTLE                          0xE0\n#define MC_EMEM_ARB_RING3_THROTTLE                          0xE4\n#define MC_EMEM_ARB_OVERRIDE                                0xE8\n#define MC_EMEM_ARB_RSV                                     0xEC\n#define MC_CLKEN_OVERRIDE                                   0xF4\n#define MC_TIMING_CONTROL_DBG                               0xF8\n#define MC_TIMING_CONTROL                                   0xFC\n#define MC_STAT_CONTROL                                     0x100\n#define MC_STAT_STATUS                                      0x104\n#define MC_STAT_EMC_CLOCK_LIMIT                             0x108\n#define MC_STAT_EMC_CLOCK_LIMIT_MSBS                        0x10C\n#define MC_STAT_EMC_CLOCKS                                  0x110\n#define MC_STAT_EMC_CLOCKS_MSBS                             0x114\n#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_LO                0x118\n#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_HI                0x11C\n#define MC_STAT_EMC_FILTER_SET0_SLACK_LIMIT                 0x120\n#define MC_STAT_EMC_FILTER_SET0_CLIENT_0                    0x128\n#define MC_STAT_EMC_FILTER_SET0_CLIENT_1                    0x12C\n#define MC_STAT_EMC_FILTER_SET0_CLIENT_2                    0x130\n#define MC_STAT_EMC_FILTER_SET0_CLIENT_3                    0x134\n#define MC_STAT_EMC_SET0_COUNT                              0x138\n#define MC_STAT_EMC_SET0_COUNT_MSBS                         0x13C\n#define MC_STAT_EMC_SET0_SLACK_ACCUM                        0x140\n#define MC_STAT_EMC_SET0_SLACK_ACCUM_MSBS                   0x144\n#define MC_STAT_EMC_SET0_HISTO_COUNT                        0x148\n#define MC_STAT_EMC_SET0_HISTO_COUNT_MSBS                   0x14C\n#define MC_STAT_EMC_SET0_MINIMUM_SLACK_OBSERVED             0x150\n#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_LO                0x158\n#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_HI                0x15C\n#define MC_STAT_EMC_FILTER_SET1_SLACK_LIMIT                 0x160\n#define MC_STAT_EMC_FILTER_SET1_CLIENT_0                    0x168\n#define MC_STAT_EMC_FILTER_SET1_CLIENT_1                    0x16C\n#define MC_STAT_EMC_FILTER_SET1_CLIENT_2                    0x170\n#define MC_STAT_EMC_FILTER_SET1_CLIENT_3                    0x174\n#define MC_STAT_EMC_SET1_COUNT                              0x178\n#define MC_STAT_EMC_SET1_COUNT_MSBS                         0x17C\n#define MC_STAT_EMC_SET1_SLACK_ACCUM                        0x180\n#define MC_STAT_EMC_SET1_SLACK_ACCUM_MSBS                   0x184\n#define MC_STAT_EMC_SET1_HISTO_COUNT                        0x188\n#define MC_STAT_EMC_SET1_HISTO_COUNT_MSBS                   0x18C\n#define MC_STAT_EMC_SET1_MINIMUM_SLACK_OBSERVED             0x190\n#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_LO        0x198\n#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_HI        0x19C\n#define MC_STAT_EMC_FILTER_SET0_ASID                        0x1A0\n#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_LO        0x1A8\n#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_HI        0x1AC\n#define MC_STAT_EMC_FILTER_SET1_ASID                        0x1B0\n#define MC_STAT_EMC_SET0_IDLE_CYCLE_COUNT                   0x1B8\n#define MC_STAT_EMC_SET0_IDLE_CYCLE_COUNT_MSBS              0x1BC\n#define MC_STAT_EMC_SET0_IDLE_CYCLE_PARTITION_SELECT        0x1C0\n#define MC_STAT_EMC_SET1_IDLE_CYCLE_COUNT                   0x1C8\n#define MC_STAT_EMC_SET1_IDLE_CYCLE_COUNT_MSBS              0x1CC\n#define MC_STAT_EMC_SET1_IDLE_CYCLE_PARTITION_SELECT        0x1D0\n#define MC_SMMU_STATS_TLB_HIT_MISS_SOURCE                   0x1EC\n#define MC_SMMU_STATS_TLB_HIT_COUNT                         0x1F0\n#define MC_SMMU_STATS_TLB_MISS_COUNT                        0x1F4\n#define MC_SMMU_STATS_PTC_HIT_COUNT                         0x1F8\n#define MC_SMMU_STATS_PTC_MISS_COUNT                        0x1FC\n#define MC_CLIENT_HOTRESET_CTRL                             0x200\n#define MC_CLIENT_HOTRESET_STATUS                           0x204\n#define MC_EMEM_ARB_ISOCHRONOUS_0                           0x208\n#define MC_EMEM_ARB_ISOCHRONOUS_1                           0x20C\n#define MC_EMEM_ARB_ISOCHRONOUS_2                           0x210\n#define MC_EMEM_ARB_ISOCHRONOUS_3                           0x214\n#define MC_EMEM_ARB_HYSTERESIS_0                            0x218\n#define MC_EMEM_ARB_HYSTERESIS_1                            0x21C\n#define MC_EMEM_ARB_HYSTERESIS_2                            0x220\n#define MC_EMEM_ARB_HYSTERESIS_3                            0x224\n#define MC_SMMU_TRANSLATION_ENABLE_0                        0x228\n#define MC_SMMU_TRANSLATION_ENABLE_1                        0x22C\n#define MC_SMMU_TRANSLATION_ENABLE_2                        0x230\n#define MC_SMMU_TRANSLATION_ENABLE_3                        0x234\n#define MC_SMMU_AFI_ASID                                    0x238\n#define MC_SMMU_AVPC_ASID                                   0x23C\n#define MC_SMMU_DC_ASID                                     0x240\n#define MC_SMMU_DCB_ASID                                    0x244\n#define MC_SMMU_HC_ASID                                     0x250\n#define MC_SMMU_HDA_ASID                                    0x254\n#define MC_SMMU_ISP2_ASID                                   0x258\n#define MC_SMMU_NVENC_ASID                                  0x264\n#define MC_SMMU_PPCS_ASID                                   0x270\n#define MC_SMMU_SATA_ASID                                   0x274\n#define MC_SMMU_VI_ASID                                     0x280\n#define MC_SMMU_VIC_ASID                                    0x284\n#define MC_SMMU_XUSB_HOST_ASID                              0x288\n#define MC_SMMU_XUSB_DEV_ASID                               0x28C\n#define MC_SMMU_A9AVP_ASID                                  0x290\n#define MC_SMMU_TSEC_ASID                                   0x294\n#define MC_SMMU_PPCS1_ASID                                  0x298\n#define MC_AHB_EXTRA_SNAP_LEVELS                            0x2A0\n#define MC_APB_EXTRA_SNAP_LEVELS                            0x2A4\n#define MC_AVP_EXTRA_SNAP_LEVELS                            0x2A8\n#define MC_DIS_EXTRA_SNAP_LEVELS                            0x2AC\n#define MC_PCX_EXTRA_SNAP_LEVELS                            0x2B8\n#define MC_FTOP_EXTRA_SNAP_LEVELS                           0x2BC\n#define MC_SAX_EXTRA_SNAP_LEVELS                            0x2C0\n#define MC_VE_EXTRA_SNAP_LEVELS                             0x2D8\n#define MC_LATENCY_ALLOWANCE_AFI_0                          0x2E0\n#define MC_LATENCY_ALLOWANCE_AVPC_0                         0x2E4\n#define MC_LATENCY_ALLOWANCE_DC_0                           0x2E8\n#define MC_LATENCY_ALLOWANCE_DC_1                           0x2EC\n#define MC_LATENCY_ALLOWANCE_DC_2                           0x2F0\n#define MC_LATENCY_ALLOWANCE_DCB_0                          0x2F4\n#define MC_LATENCY_ALLOWANCE_DCB_1                          0x2F8\n#define MC_LATENCY_ALLOWANCE_DCB_2                          0x2FC\n#define MC_LATENCY_ALLOWANCE_HC_0                           0x310\n#define MC_LATENCY_ALLOWANCE_HC_1                           0x314\n#define MC_LATENCY_ALLOWANCE_HDA_0                          0x318\n#define MC_LATENCY_ALLOWANCE_MPCORE_0                       0x320\n#define MC_LATENCY_ALLOWANCE_NVENC_0                        0x328\n#define MC_LATENCY_ALLOWANCE_PPCS_0                         0x344\n#define MC_LATENCY_ALLOWANCE_PPCS_1                         0x348\n#define MC_LATENCY_ALLOWANCE_PTC_0                          0x34C\n#define MC_LATENCY_ALLOWANCE_SATA_0                         0x350\n#define MC_LATENCY_ALLOWANCE_ISP2_0                         0x370\n#define MC_LATENCY_ALLOWANCE_ISP2_1                         0x374\n#define MC_LATENCY_ALLOWANCE_XUSB_0                         0x37C\n#define MC_LATENCY_ALLOWANCE_XUSB_1                         0x380\n#define MC_LATENCY_ALLOWANCE_ISP2B_0                        0x384\n#define MC_LATENCY_ALLOWANCE_ISP2B_1                        0x388\n#define MC_LATENCY_ALLOWANCE_TSEC_0                         0x390\n#define MC_LATENCY_ALLOWANCE_VIC_0                          0x394\n#define MC_LATENCY_ALLOWANCE_VI2_0                          0x398\n#define MC_LATENCY_ALLOWANCE_AXIAP_0                        0x3A0\n#define MC_LATENCY_ALLOWANCE_A9AVP_0                        0x3A4\n#define MC_LATENCY_ALLOWANCE_GPU_0                          0x3AC\n#define MC_LATENCY_ALLOWANCE_SDMMCA_0                       0x3B8\n#define MC_LATENCY_ALLOWANCE_SDMMCAA_0                      0x3BC\n#define MC_LATENCY_ALLOWANCE_SDMMC_0                        0x3C0\n#define MC_LATENCY_ALLOWANCE_SDMMCAB_0                      0x3C4\n#define MC_LATENCY_ALLOWANCE_DC_3                           0x3C8\n#define MC_LATENCY_ALLOWANCE_NVDEC_0                        0x3D8\n#define MC_LATENCY_ALLOWANCE_APE_0                          0x3DC\n#define MC_LATENCY_ALLOWANCE_SE_0                           0x3E0\n#define MC_LATENCY_ALLOWANCE_NVJPG_0                        0x3E4\n#define MC_LATENCY_ALLOWANCE_GPU2_0                         0x3E8\n#define MC_LATENCY_ALLOWANCE_ETR_0                          0x3EC\n#define MC_LATENCY_ALLOWANCE_TSECB_0                        0x3F0\n#define MC_RESERVED_RSV                                     0x3FC\n#define MC_USBX_EXTRA_SNAP_LEVELS                           0x404\n#define MC_DISB_EXTRA_SNAP_LEVELS                           0x408\n#define MC_MSE_EXTRA_SNAP_LEVELS                            0x40C\n#define MC_VE2_EXTRA_SNAP_LEVELS                            0x410\n#define MC_A9AVPPC_EXTRA_SNAP_LEVELS                        0x414\n#define MC_VIDEO_PROTECT_VPR_OVERRIDE                       0x418\n#define MC_DIS_PTSA_RATE                                    0x41C\n#define MC_DIS_PTSA_MIN                                     0x420\n#define MC_DIS_PTSA_MAX                                     0x424\n#define MC_DISB_PTSA_RATE                                   0x428\n#define MC_DISB_PTSA_MIN                                    0x42C\n#define MC_DISB_PTSA_MAX                                    0x430\n#define MC_VE_PTSA_RATE                                     0x434\n#define MC_VE_PTSA_MIN                                      0x438\n#define MC_VE_PTSA_MAX                                      0x43C\n#define MC_RING2_PTSA_RATE                                  0x440\n#define MC_RING2_PTSA_MIN                                   0x444\n#define MC_RING2_PTSA_MAX                                   0x448\n#define MC_MLL_MPCORER_PTSA_RATE                            0x44C\n#define MC_MLL_MPCORER_PTSA_MIN                             0x450\n#define MC_MLL_MPCORER_PTSA_MAX                             0x454\n#define MC_SMMU_SMMU_PTSA_RATE                              0x458\n#define MC_SMMU_SMMU_PTSA_MIN                               0x45C\n#define MC_SMMU_SMMU_PTSA_MAX                               0x460\n#define MC_RING1_PTSA_RATE                                  0x47C\n#define MC_RING1_PTSA_MIN                                   0x480\n#define MC_RING1_PTSA_MAX                                   0x484\n#define MC_A9AVPPC_PTSA_RATE                                0x488\n#define MC_A9AVPPC_PTSA_MIN                                 0x48C\n#define MC_A9AVPPC_PTSA_MAX                                 0x490\n#define MC_VE2_PTSA_RATE                                    0x494\n#define MC_VE2_PTSA_MIN                                     0x498\n#define MC_VE2_PTSA_MAX                                     0x49C\n#define MC_ISP_PTSA_RATE                                    0x4A0\n#define MC_ISP_PTSA_MIN                                     0x4A4\n#define MC_ISP_PTSA_MAX                                     0x4A8\n#define MC_PCX_PTSA_RATE                                    0x4AC\n#define MC_PCX_PTSA_MIN                                     0x4B0\n#define MC_PCX_PTSA_MAX                                     0x4B4\n#define MC_SAX_PTSA_RATE                                    0x4B8\n#define MC_SAX_PTSA_MIN                                     0x4BC\n#define MC_SAX_PTSA_MAX                                     0x4C0\n#define MC_MSE_PTSA_RATE                                    0x4C4\n#define MC_MSE_PTSA_MIN                                     0x4C8\n#define MC_MSE_PTSA_MAX                                     0x4CC\n#define MC_SD_PTSA_RATE                                     0x4D0\n#define MC_SD_PTSA_MIN                                      0x4D4\n#define MC_SD_PTSA_MAX                                      0x4D8\n#define MC_AHB_PTSA_RATE                                    0x4DC\n#define MC_AHB_PTSA_MIN                                     0x4E0\n#define MC_AHB_PTSA_MAX                                     0x4E4\n#define MC_APB_PTSA_RATE                                    0x4E8\n#define MC_APB_PTSA_MIN                                     0x4EC\n#define MC_APB_PTSA_MAX                                     0x4F0\n#define MC_AVP_PTSA_RATE                                    0x4F4\n#define MC_AVP_PTSA_MIN                                     0x4F8\n#define MC_AVP_PTSA_MAX                                     0x4FC\n#define MC_FTOP_PTSA_RATE                                   0x50C\n#define MC_FTOP_PTSA_MIN                                    0x510\n#define MC_FTOP_PTSA_MAX                                    0x514\n#define MC_HOST_PTSA_RATE                                   0x518\n#define MC_HOST_PTSA_MIN                                    0x51C\n#define MC_HOST_PTSA_MAX                                    0x520\n#define MC_USBX_PTSA_RATE                                   0x524\n#define MC_USBX_PTSA_MIN                                    0x528\n#define MC_USBX_PTSA_MAX                                    0x52C\n#define MC_USBD_PTSA_RATE                                   0x530\n#define MC_USBD_PTSA_MIN                                    0x534\n#define MC_USBD_PTSA_MAX                                    0x538\n#define MC_GK_PTSA_RATE                                     0x53C\n#define MC_GK_PTSA_MIN                                      0x540\n#define MC_GK_PTSA_MAX                                      0x544\n#define MC_AUD_PTSA_RATE                                    0x548\n#define MC_AUD_PTSA_MIN                                     0x54C\n#define MC_AUD_PTSA_MAX                                     0x550\n#define MC_VICPC_PTSA_RATE                                  0x554\n#define MC_VICPC_PTSA_MIN                                   0x558\n#define MC_VICPC_PTSA_MAX                                   0x55C\n#define MC_JPG_PTSA_RATE                                    0x584\n#define MC_JPG_PTSA_MIN                                     0x588\n#define MC_JPG_PTSA_MAX                                     0x58C\n#define MC_VIDEO_PROTECT_VPR_OVERRIDE1                      0x590\n#define MC_SMMU_TLB_SET_SELECTION_MASK_0                    0x600\n#define MC_GK2_PTSA_RATE                                    0x610\n#define MC_GK2_PTSA_MIN                                     0x614\n#define MC_GK2_PTSA_MAX                                     0x618\n#define MC_SDM_PTSA_RATE                                    0x61C\n#define MC_SDM_PTSA_MIN                                     0x620\n#define MC_SDM_PTSA_MAX                                     0x624\n#define MC_HDAPC_PTSA_RATE                                  0x628\n#define MC_HDAPC_PTSA_MIN                                   0x62C\n#define MC_HDAPC_PTSA_MAX                                   0x630\n#define MC_DFD_PTSA_RATE                                    0x634\n#define MC_DFD_PTSA_MIN                                     0x638\n#define MC_DFD_PTSA_MAX                                     0x63C\n#define MC_VIDEO_PROTECT_BOM                                0x648\n#define MC_VIDEO_PROTECT_SIZE_MB                            0x64C\n#define MC_VIDEO_PROTECT_REG_CTRL                           0x650\n#define MC_ERR_VPR_STATUS                                   0x654\n#define MC_ERR_VPR_ADR                                      0x658\n#define MC_IRAM_BOM                                         0x65C\n#define MC_IRAM_TOM                                         0x660\n#define MC_EMEM_CFG_ACCESS_CTRL                             0x664\n#define MC_TZ_SECURITY_CTRL                                 0x668\n#define  TZ_SEC_CTRL_CPU_STRICT_TZ_APERTURE_CHECK                BIT(0)\n#define MC_EMEM_ARB_OUTSTANDING_REQ_RING3                   0x66C\n#define MC_SEC_CARVEOUT_BOM                                 0x670\n#define MC_SEC_CARVEOUT_SIZE_MB                             0x674\n#define MC_SEC_CARVEOUT_REG_CTRL                            0x678\n#define MC_ERR_SEC_STATUS                                   0x67C\n#define MC_ERR_SEC_ADR                                      0x680\n#define MC_PC_IDLE_CLOCK_GATE_CONFIG                        0x684\n#define MC_STUTTER_CONTROL                                  0x688\n#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A               0x690\n#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB              0x694\n#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B               0x698\n#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB              0x69C\n#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C               0x6A0\n#define MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB              0x6A4\n#define MC_EMEM_ARB_NISO_THROTTLE                           0x6B0\n#define MC_EMEM_ARB_OUTSTANDING_REQ_NISO                    0x6B4\n#define MC_EMEM_ARB_NISO_THROTTLE_MASK                      0x6B8\n#define MC_EMEM_ARB_RING0_THROTTLE_MASK                     0x6BC\n#define MC_EMEM_ARB_TIMING_RFCPB                            0x6C0\n#define MC_EMEM_ARB_TIMING_CCDMW                            0x6C4\n#define MC_EMEM_ARB_REFPB_HP_CTRL                           0x6F0\n#define MC_EMEM_ARB_REFPB_BANK_CTRL                         0x6F4\n#define MC_MIN_LENGTH_AFI_0                                 0x88C\n#define MC_MIN_LENGTH_AVPC_0                                0x890\n#define MC_MIN_LENGTH_DC_0                                  0x894\n#define MC_MIN_LENGTH_DC_1                                  0x898\n#define MC_MIN_LENGTH_DC_2                                  0x89C\n#define MC_MIN_LENGTH_DCB_0                                 0x8A0\n#define MC_MIN_LENGTH_DCB_1                                 0x8A4\n#define MC_MIN_LENGTH_DCB_2                                 0x8A8\n#define MC_MIN_LENGTH_HC_0                                  0x8BC\n#define MC_MIN_LENGTH_HC_1                                  0x8C0\n#define MC_MIN_LENGTH_HDA_0                                 0x8C4\n#define MC_MIN_LENGTH_MPCORE_0                              0x8CC\n#define MC_MIN_LENGTH_NVENC_0                               0x8D4\n#define MC_MIN_LENGTH_PPCS_0                                0x8F0\n#define MC_MIN_LENGTH_PPCS_1                                0x8F4\n#define MC_MIN_LENGTH_PTC_0                                 0x8F8\n#define MC_MIN_LENGTH_SATA_0                                0x8FC\n#define MC_MIN_LENGTH_ISP2_0                                0x91C\n#define MC_MIN_LENGTH_ISP2_1                                0x920\n#define MC_MIN_LENGTH_XUSB_0                                0x928\n#define MC_MIN_LENGTH_XUSB_1                                0x92C\n#define MC_MIN_LENGTH_ISP2B_0                               0x930\n#define MC_MIN_LENGTH_ISP2B_1                               0x934\n#define MC_MIN_LENGTH_TSEC_0                                0x93C\n#define MC_MIN_LENGTH_VIC_0                                 0x940\n#define MC_MIN_LENGTH_VI2_0                                 0x944\n#define MC_MIN_LENGTH_AXIAP_0                               0x94C\n#define MC_MIN_LENGTH_A9AVP_0                               0x950\n#define MC_RESERVED_RSV_1                                   0x958\n#define MC_DVFS_PIPE_SELECT                                 0x95C\n#define MC_PTSA_GRANT_DECREMENT                             0x960\n#define MC_IRAM_REG_CTRL                                    0x964\n#define MC_EMEM_ARB_OVERRIDE_1                              0x968\n#define MC_CLIENT_HOTRESET_CTRL_1                           0x970\n#define MC_CLIENT_HOTRESET_STATUS_1                         0x974\n#define MC_VIDEO_PROTECT_BOM_ADR_HI                         0x978\n#define MC_IRAM_ADR_HI                                      0x980\n#define MC_VIDEO_PROTECT_GPU_OVERRIDE_0                     0x984\n#define MC_VIDEO_PROTECT_GPU_OVERRIDE_1                     0x988\n#define MC_EMEM_ARB_STATS_0                                 0x990\n#define MC_EMEM_ARB_STATS_1                                 0x994\n#define MC_MTS_CARVEOUT_BOM                                 0x9A0\n#define MC_MTS_CARVEOUT_SIZE_MB                             0x9A4\n#define MC_MTS_CARVEOUT_ADR_HI                              0x9A8\n#define MC_MTS_CARVEOUT_REG_CTRL                            0x9AC\n#define MC_ERR_MTS_STATUS                                   0x9B0\n#define MC_ERR_MTS_ADR                                      0x9B4\n#define MC_SMMU_PTC_FLUSH_1                                 0x9B8\n#define MC_SECURITY_CFG3                                    0x9BC\n#define MC_ERR_APB_ASID_UPDATE_STATUS                       0x9D0\n#define MC_SEC_CARVEOUT_ADR_HI                              0x9D4\n#define MC_DA_CONFIG0                                       0x9DC\n#define MC_SMMU_ASID_SECURITY_2                             0x9E0\n#define MC_SMMU_ASID_SECURITY_3                             0x9E4\n#define MC_SMMU_ASID_SECURITY_4                             0x9E8\n#define MC_SMMU_ASID_SECURITY_5                             0x9EC\n#define MC_SMMU_ASID_SECURITY_6                             0x9F0\n#define MC_SMMU_ASID_SECURITY_7                             0x9F4\n#define MC_GK_EXTRA_SNAP_LEVELS                             0xA00\n#define MC_SD_EXTRA_SNAP_LEVELS                             0xA04\n#define MC_ISP_EXTRA_SNAP_LEVELS                            0xA08\n#define MC_AUD_EXTRA_SNAP_LEVELS                            0xA10\n#define MC_HOST_EXTRA_SNAP_LEVELS                           0xA14\n#define MC_USBD_EXTRA_SNAP_LEVELS                           0xA18\n#define MC_VICPC_EXTRA_SNAP_LEVELS                          0xA1C\n#define MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_UPPER             0xA20\n#define MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_UPPER             0xA24\n#define MC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_UPPER     0xA28\n#define MC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_UPPER     0xA2C\n#define MC_JPG_EXTRA_SNAP_LEVELS                            0xA3C\n#define MC_GK2_EXTRA_SNAP_LEVELS                            0xA40\n#define MC_SDM_EXTRA_SNAP_LEVELS                            0xA44\n#define MC_HDAPC_EXTRA_SNAP_LEVELS                          0xA48\n#define MC_DFD_EXTRA_SNAP_LEVELS                            0xA4C\n#define MC_SMMU_DC1_ASID                                    0xA88\n#define MC_SMMU_SDMMC1A_ASID                                0xA94\n#define MC_SMMU_SDMMC2A_ASID                                0xA98\n#define MC_SMMU_SDMMC3A_ASID                                0xA9C\n#define MC_SMMU_SDMMC4A_ASID                                0xAA0\n#define MC_SMMU_ISP2B_ASID                                  0xAA4\n#define MC_SMMU_GPU_ASID                                    0xAA8\n#define MC_SMMU_GPUB_ASID                                   0xAAC\n#define MC_SMMU_PPCS2_ASID                                  0xAB0\n#define MC_SMMU_NVDEC_ASID                                  0xAB4\n#define MC_SMMU_APE_ASID                                    0xAB8\n#define MC_SMMU_SE_ASID                                     0xABC\n#define MC_SMMU_NVJPG_ASID                                  0xAC0\n#define MC_SMMU_HC1_ASID                                    0xAC4\n#define MC_SMMU_SE1_ASID                                    0xAC8\n#define MC_SMMU_AXIAP_ASID                                  0xACC\n#define MC_SMMU_ETR_ASID                                    0xAD0\n#define MC_SMMU_TSECB_ASID                                  0xAD4\n#define MC_SMMU_TSEC1_ASID                                  0xAD8\n#define MC_SMMU_TSECB1_ASID                                 0xADC\n#define MC_SMMU_NVDEC1_ASID                                 0xAE0\n#define MC_MIN_LENGTH_GPU_0                                 0xB04\n#define MC_MIN_LENGTH_SDMMCA_0                              0xB10\n#define MC_MIN_LENGTH_SDMMCAA_0                             0xB14\n#define MC_MIN_LENGTH_SDMMC_0                               0xB18\n#define MC_MIN_LENGTH_SDMMCAB_0                             0xB1C\n#define MC_MIN_LENGTH_DC_3                                  0xB20\n#define MC_MIN_LENGTH_NVDEC_0                               0xB30\n#define MC_MIN_LENGTH_APE_0                                 0xB34\n#define MC_MIN_LENGTH_SE_0                                  0xB38\n#define MC_MIN_LENGTH_NVJPG_0                               0xB3C\n#define MC_MIN_LENGTH_GPU2_0                                0xB40\n#define MC_MIN_LENGTH_ETR_0                                 0xB44\n#define MC_MIN_LENGTH_TSECB_0                               0xB48\n#define MC_EMEM_ARB_NISO_THROTTLE_MASK_1                    0xB80\n#define MC_EMEM_ARB_HYSTERESIS_4                            0xB84\n#define MC_STAT_EMC_FILTER_SET0_CLIENT_4                    0xB88\n#define MC_STAT_EMC_FILTER_SET1_CLIENT_4                    0xB8C\n#define MC_EMEM_ARB_ISOCHRONOUS_4                           0xB94\n#define MC_SMMU_TRANSLATION_ENABLE_4                        0xB98\n#define MC_SMMU_CLIENT_CONFIG4                              0xB9C\n#define MC_EMEM_ARB_DHYSTERESIS_0                           0xBB0\n#define MC_EMEM_ARB_DHYSTERESIS_1                           0xBB4\n#define MC_EMEM_ARB_DHYSTERESIS_2                           0xBB8\n#define MC_EMEM_ARB_DHYSTERESIS_3                           0xBBC\n#define MC_EMEM_ARB_DHYSTERESIS_4                           0xBC0\n#define MC_EMEM_ARB_DHYST_CTRL                              0xBCC\n#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0                    0xBD0\n#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1                    0xBD4\n#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2                    0xBD8\n#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3                    0xBDC\n#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4                    0xBE0\n#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5                    0xBE4\n#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6                    0xBE8\n#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7                    0xBEC\n#define MC_ERR_GENERALIZED_CARVEOUT_STATUS                  0xC00\n#define MC_ERR_GENERALIZED_CARVEOUT_ADR                     0xC04\n#define MC_SECURITY_CARVEOUT1_CFG0                          0xC08\n#define MC_SECURITY_CARVEOUT1_BOM                           0xC0C\n#define MC_SECURITY_CARVEOUT1_BOM_HI                        0xC10\n#define MC_SECURITY_CARVEOUT1_SIZE_128KB                    0xC14\n#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0                0xC18\n#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1                0xC1C\n#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2                0xC20\n#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3                0xC24\n#define MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4                0xC28\n#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0 0xC2C\n#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1 0xC30\n#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2 0xC34\n#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3 0xC38\n#define MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4 0xC3C\n#define MC_SECURITY_CARVEOUT2_CFG0                          0xC58\n#define MC_SECURITY_CARVEOUT2_BOM                           0xC5C\n#define MC_SECURITY_CARVEOUT2_BOM_HI                        0xC60\n#define MC_SECURITY_CARVEOUT2_SIZE_128KB                    0xC64\n#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0                0xC68\n#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1                0xC6C\n#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2                0xC70\n#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3                0xC74\n#define MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4                0xC78\n#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0 0xC7C\n#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1 0xC80\n#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2 0xC84\n#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3 0xC88\n#define MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4 0xC8C\n#define MC_SECURITY_CARVEOUT3_CFG0                          0xCA8\n#define MC_SECURITY_CARVEOUT3_BOM                           0xCAC\n#define MC_SECURITY_CARVEOUT3_BOM_HI                        0xCB0\n#define MC_SECURITY_CARVEOUT3_SIZE_128KB                    0xCB4\n#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0                0xCB8\n#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1                0xCBC\n#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2                0xCC0\n#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3                0xCC4\n#define MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4                0xCC8\n#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0 0xCCC\n#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1 0xCD0\n#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2 0xCD4\n#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3 0xCD8\n#define MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4 0xCDC\n#define MC_SECURITY_CARVEOUT4_CFG0                          0xCF8\n#define MC_SECURITY_CARVEOUT4_BOM                           0xCFC\n#define MC_SECURITY_CARVEOUT4_BOM_HI                        0xD00\n#define MC_SECURITY_CARVEOUT4_SIZE_128KB                    0xD04\n#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0                0xD08\n#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1                0xD0C\n#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2                0xD10\n#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3                0xD14\n#define MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4                0xD18\n#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0 0xD1C\n#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1 0xD20\n#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2 0xD24\n#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3 0xD28\n#define MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4 0xD2C\n#define MC_SECURITY_CARVEOUT5_CFG0                          0xD48\n#define MC_SECURITY_CARVEOUT5_BOM                           0xD4C\n#define MC_SECURITY_CARVEOUT5_BOM_HI                        0xD50\n#define MC_SECURITY_CARVEOUT5_SIZE_128KB                    0xD54\n#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0                0xD58\n#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1                0xD5C\n#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2                0xD60\n#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3                0xD64\n#define MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4                0xD68\n#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0 0xD6C\n#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1 0xD70\n#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2 0xD74\n#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3 0xD78\n#define MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4 0xD7C\n#define MC_PCFIFO_CLIENT_CONFIG0                            0xDD0\n#define MC_PCFIFO_CLIENT_CONFIG1                            0xDD4\n#define MC_PCFIFO_CLIENT_CONFIG2                            0xDD8\n#define MC_PCFIFO_CLIENT_CONFIG3                            0xDDC\n#define MC_PCFIFO_CLIENT_CONFIG4                            0xDE0\n\n/* T210B01 only registers */\n#define MC_SMMU_ISP21_ASID_B01                              0x804\n#define MC_SMMU_ISP2B1_ASID_B01                             0x808\n#define MC_UNTRANSLATED_REGION_CHECK_B01                    0x948\n\n/*! MC_SECURITY_CARVEOUTX_CLIENT_ACCESS/CLIENT_FORCE_INTERNAL_ACCESS0 */\n#define SEC_CARVEOUT_CA0_R_PTCR       BIT(0)\n#define SEC_CARVEOUT_CA0_R_DISPLAY0A  BIT(1)\n#define SEC_CARVEOUT_CA0_R_DISPLAY0AB BIT(2)\n#define SEC_CARVEOUT_CA0_R_DISPLAY0B  BIT(3)\n#define SEC_CARVEOUT_CA0_R_DISPLAY0BB BIT(4)\n#define SEC_CARVEOUT_CA0_R_DISPLAY0C  BIT(5)\n#define SEC_CARVEOUT_CA0_R_DISPLAY0CB BIT(6)\n#define SEC_CARVEOUT_CA0_R_AFI        BIT(14)\n#define SEC_CARVEOUT_CA0_R_BPMP_C     BIT(15)\n#define SEC_CARVEOUT_CA0_R_DISPLAYHC  BIT(16)\n#define SEC_CARVEOUT_CA0_R_DISPLAYHCB BIT(17)\n#define SEC_CARVEOUT_CA0_R_HDA        BIT(21)\n#define SEC_CARVEOUT_CA0_R_HOST1XDMA  BIT(22)\n#define SEC_CARVEOUT_CA0_R_HOST1X     BIT(23)\n#define SEC_CARVEOUT_CA0_R_NVENC      BIT(28)\n#define SEC_CARVEOUT_CA0_R_PPCSAHBDMA BIT(29)\n#define SEC_CARVEOUT_CA0_R_PPCSAHBSLV BIT(30)\n#define SEC_CARVEOUT_CA0_R_SATAR      BIT(31)\n\n/*! MC_SECURITY_CARVEOUTX_CLIENT_ACCESS/CLIENT_FORCE_INTERNAL_ACCESS1 */\n#define SEC_CARVEOUT_CA1_R_VDEBSEV    BIT(2)\n#define SEC_CARVEOUT_CA1_R_VDEMBE     BIT(3)\n#define SEC_CARVEOUT_CA1_R_VDEMCE     BIT(4)\n#define SEC_CARVEOUT_CA1_R_VDETPE     BIT(5)\n#define SEC_CARVEOUT_CA1_R_CCPLEXLP_C BIT(6)\n#define SEC_CARVEOUT_CA1_R_CCPLEX_C   BIT(7)\n#define SEC_CARVEOUT_CA1_W_NVENC      BIT(11)\n#define SEC_CARVEOUT_CA1_W_AFI        BIT(17)\n#define SEC_CARVEOUT_CA1_W_BPMP_C     BIT(18)\n#define SEC_CARVEOUT_CA1_W_HDA        BIT(21)\n#define SEC_CARVEOUT_CA1_W_HOST1X     BIT(22)\n#define SEC_CARVEOUT_CA1_W_CCPLEXLP_C BIT(24)\n#define SEC_CARVEOUT_CA1_W_CCPLEX_C   BIT(25)\n#define SEC_CARVEOUT_CA1_W_PPCSAHBDMA BIT(27)\n#define SEC_CARVEOUT_CA1_W_PPCSAHBSLV BIT(28)\n#define SEC_CARVEOUT_CA1_W_SATA       BIT(29)\n#define SEC_CARVEOUT_CA1_W_VDEBSEV    BIT(30)\n#define SEC_CARVEOUT_CA1_W_VDEDBG     BIT(31)\n\n/*! MC_SECURITY_CARVEOUTX_CLIENT_ACCESS/CLIENT_FORCE_INTERNAL_ACCESS2 */\n#define SEC_CARVEOUT_CA2_W_VDEMBE    BIT(0)\n#define SEC_CARVEOUT_CA2_W_VDETPM    BIT(1)\n#define SEC_CARVEOUT_CA2_R_ISPRA     BIT(4)\n#define SEC_CARVEOUT_CA2_W_ISPWA     BIT(6)\n#define SEC_CARVEOUT_CA2_W_ISPWB     BIT(7)\n#define SEC_CARVEOUT_CA2_R_XUSB_HOST BIT(10)\n#define SEC_CARVEOUT_CA2_W_XUSB_HOST BIT(11)\n#define SEC_CARVEOUT_CA2_R_XUSB_DEV  BIT(12)\n#define SEC_CARVEOUT_CA2_W_XUSB_DEV  BIT(13)\n#define SEC_CARVEOUT_CA2_R_SE2       BIT(14)\n#define SEC_CARVEOUT_CA2_W_SE2       BIT(16)\n#define SEC_CARVEOUT_CA2_R_TSEC      BIT(20)\n#define SEC_CARVEOUT_CA2_W_TSEC      BIT(21)\n#define SEC_CARVEOUT_CA2_R_ADSP_SC   BIT(22)\n#define SEC_CARVEOUT_CA2_W_ADSP_SC   BIT(23)\n#define SEC_CARVEOUT_CA2_R_GPU       BIT(24)\n#define SEC_CARVEOUT_CA2_W_GPU       BIT(25)\n#define SEC_CARVEOUT_CA2_R_DISPLAYT  BIT(26)\n\n/*! MC_SECURITY_CARVEOUTX_CLIENT_ACCESS/CLIENT_FORCE_INTERNAL_ACCESS3 */\n#define SEC_CARVEOUT_CA3_R_SDMMCA   BIT(0)\n#define SEC_CARVEOUT_CA3_R_SDMMCAA  BIT(1)\n#define SEC_CARVEOUT_CA3_R_SDMMC    BIT(2)\n#define SEC_CARVEOUT_CA3_R_SDMMCAB  BIT(3)\n#define SEC_CARVEOUT_CA3_W_SDMMCA   BIT(4)\n#define SEC_CARVEOUT_CA3_W_SDMMCAA  BIT(5)\n#define SEC_CARVEOUT_CA3_W_SDMMC    BIT(6)\n#define SEC_CARVEOUT_CA3_W_SDMMCAB  BIT(7)\n#define SEC_CARVEOUT_CA3_R_VIC      BIT(12)\n#define SEC_CARVEOUT_CA3_W_VIC      BIT(13)\n#define SEC_CARVEOUT_CA3_W_VIW      BIT(18)\n#define SEC_CARVEOUT_CA3_R_DISPLAYD BIT(19)\n#define SEC_CARVEOUT_CA3_R_NVDEC    BIT(24)\n#define SEC_CARVEOUT_CA3_W_NVDEC    BIT(25)\n#define SEC_CARVEOUT_CA3_R_APE      BIT(26)\n#define SEC_CARVEOUT_CA3_W_APE      BIT(27)\n#define SEC_CARVEOUT_CA3_R_NVJPG    BIT(30)\n#define SEC_CARVEOUT_CA3_W_NVJPG    BIT(31)\n\n/*! MC_SECURITY_CARVEOUTX_CLIENT_ACCESS/CLIENT_FORCE_INTERNAL_ACCESS4 */\n#define SEC_CARVEOUT_CA4_R_SE    BIT(0)\n#define SEC_CARVEOUT_CA4_W_SE    BIT(1)\n#define SEC_CARVEOUT_CA4_R_AXIAP BIT(2)\n#define SEC_CARVEOUT_CA4_W_AXIAP BIT(3)\n#define SEC_CARVEOUT_CA4_R_ETR   BIT(4)\n#define SEC_CARVEOUT_CA4_W_ETR   BIT(5)\n#define SEC_CARVEOUT_CA4_R_TSECB BIT(6)\n#define SEC_CARVEOUT_CA4_W_TSECB BIT(7)\n#define SEC_CARVEOUT_CA4_R_GPU2  BIT(8)\n#define SEC_CARVEOUT_CA4_W_GPU2  BIT(9)\n\n/*! MC_VIDEO_PROTECT_REG_CTRL */\n#define VPR_LOCK_MODE_SHIFT 0\n#define VPR_CTRL_UNLOCKED  (0 << VPR_LOCK_MODE_SHIFT)\n#define VPR_CTRL_LOCKED    (1 << VPR_LOCK_MODE_SHIFT)\n#define VPR_PROTECT_MODE_SHIFT 1\n#define SEC_CTRL_SECURE    (0 << VPR_PROTECT_MODE_SHIFT)\n#define VPR_CTRL_TZ_SECURE (1 << VPR_PROTECT_MODE_SHIFT)\n\n/*! MC_SECURITY_CARVEOUTX_CFG0 */\n// Mode of LOCK_MODE.\n#define PROTECT_MODE_SHIFT 0\n#define SEC_CARVEOUT_CFG_ALL_SECURE (0 << PROTECT_MODE_SHIFT)\n#define SEC_CARVEOUT_CFG_TZ_SECURE  (1 << PROTECT_MODE_SHIFT)\n// Enables PROTECT_MODE.\n#define LOCK_MODE_SHIFT 1\n#define SEC_CARVEOUT_CFG_UNLOCKED (0 << LOCK_MODE_SHIFT)\n#define SEC_CARVEOUT_CFG_LOCKED   (1 << LOCK_MODE_SHIFT)\n\n#define ADDRESS_TYPE_SHIFT 2\n#define SEC_CARVEOUT_CFG_ANY_ADDRESS       (0 << ADDRESS_TYPE_SHIFT)\n#define SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY (1 << ADDRESS_TYPE_SHIFT)\n\n#define READ_ACCESS_LEVEL_SHIFT 3\n#define SEC_CARVEOUT_CFG_RD_NS        (1 << READ_ACCESS_LEVEL_SHIFT)\n#define SEC_CARVEOUT_CFG_RD_SEC       (2 << READ_ACCESS_LEVEL_SHIFT)\n#define SEC_CARVEOUT_CFG_RD_FALCON_LS (4 << READ_ACCESS_LEVEL_SHIFT)\n#define SEC_CARVEOUT_CFG_RD_FALCON_HS (8 << READ_ACCESS_LEVEL_SHIFT)\n\n#define WRITE_ACCESS_LEVEL_SHIFT 7\n#define SEC_CARVEOUT_CFG_WR_NS        (1 << WRITE_ACCESS_LEVEL_SHIFT)\n#define SEC_CARVEOUT_CFG_WR_SEC       (2 << WRITE_ACCESS_LEVEL_SHIFT)\n#define SEC_CARVEOUT_CFG_WR_FALCON_LS (4 << WRITE_ACCESS_LEVEL_SHIFT)\n#define SEC_CARVEOUT_CFG_WR_FALCON_HS (8 << WRITE_ACCESS_LEVEL_SHIFT)\n\n#define SEC_CARVEOUT_CFG_APERTURE_ID_MASK (3 << 11)\n#define SEC_CARVEOUT_CFG_APERTURE_ID(id) ((id) << 11)\n\n#define DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT 14\n#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_NS (1 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT)\n#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_SEC (2 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT)\n#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_FLCN_LS (4 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT)\n#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_FLCN_HS (8 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT)\n\n#define DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT 18\n#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_NS (1 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT)\n#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_SEC (2 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT)\n#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_FLCN_LS (4 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT)\n#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_FLCN_HS (8 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT)\n\n#define SEC_CARVEOUT_CFG_SEND_CFG_TO_GPU BIT(22)\n\n#define SEC_CARVEOUT_CFG_TZ_GLOBAL_WR_EN_BYPASS_CHECK BIT(23)\n#define SEC_CARVEOUT_CFG_TZ_GLOBAL_RD_EN_BYPASS_CHECK BIT(24)\n\n#define SEC_CARVEOUT_CFG_ALLOW_APERTURE_ID_MISMATCH BIT(25)\n#define SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH    BIT(26)\n\n#define SEC_CARVEOUT_CFG_IS_WPR BIT(27)\n\n// WPR1 magic to enable WPR2.\n#define ACR_GSC3_ENABLE_MAGIC 0xC0EDBBCC\n\n/*! MC_VIDEO_PROTECT_GPU_OVERRIDE_0 */\n// VPR CYA. Parsed as (vpr_gpu_ovr1 << 32 | vpr_gpu_ovr0) << 5.\n#define VPR_TRUST_UNTRUSTED  0\n#define VPR_TRUST_GRAPHICS   1\n#define VPR_TRUST_QUARANTINE 2\n#define VPR_TRUST_TRUSTED    3\n// VPR CYA LO.\n// Setting VPR_OVR0_CYA_TRUST_DEFAULT disables the overrides.\n// Defaults: PD, SCC, SKED, L1, TEX, PE, RASTER, GCC and PROP as GRAPHICS. The rest UNTRUSTED.\n#define VPR_OVR0_CYA_TRUST_OVERRIDE   0\n#define VPR_OVR0_CYA_TRUST_DEFAULT    BIT(0)\n#define VPR_OVR0_CYA_TRUST_CPU(t)     ((t) <<  1u) // HOST CPU.\n#define VPR_OVR0_CYA_TRUST_HOST(t)    ((t) <<  3u)\n#define VPR_OVR0_CYA_TRUST_PERF(t)    ((t) <<  5u)\n#define VPR_OVR0_CYA_TRUST_PMU(t)     ((t) <<  7u)\n#define VPR_OVR0_CYA_TRUST_CE2(t)     ((t) <<  9u) // GRCOPY.\n#define VPR_OVR0_CYA_TRUST_SEC(t)     ((t) << 11u)\n#define VPR_OVR0_CYA_TRUST_FE(t)      ((t) << 13u)\n#define VPR_OVR0_CYA_TRUST_PD(t)      ((t) << 15u)\n#define VPR_OVR0_CYA_TRUST_SCC(t)     ((t) << 17u)\n#define VPR_OVR0_CYA_TRUST_SKED(t)    ((t) << 19u)\n#define VPR_OVR0_CYA_TRUST_L1(t)      ((t) << 21u)\n#define VPR_OVR0_CYA_TRUST_TEX(t)     ((t) << 23u)\n#define VPR_OVR0_CYA_TRUST_PE(t)      ((t) << 25u)\n// VPR CYA HI.\n#define VPR_OVR0_CYA_TRUST_RASTER(t)  ((t) << 27u)\n#define VPR_OVR0_CYA_TRUST_GCC(t)     ((t) << 29u)\n// Setting GPCCS to anything other than untrusted, causes a hang.\n#define VPR_OVR0_CYA_TRUST_GPCCS(t)   (((t) & 1) << 31u)\n\n/*! MC_VIDEO_PROTECT_GPU_OVERRIDE_1 */\n// VPR CYA HI.\n#define VPR_OVR1_CYA_TRUST_GPCCS(t)   ((t) >> 1)\n#define VPR_OVR1_CYA_TRUST_PROP(t)    ((t) <<  1u)\n#define VPR_OVR1_CYA_TRUST_PROP_READ  BIT(3)\n#define VPR_OVR1_CYA_TRUST_PROP_WRITE BIT(4)\n#define VPR_OVR1_CYA_TRUST_DNISO(t)   ((t) <<  5u)\n#define VPR_OVR1_CYA_TRUST_CE0(t)     VPR_OVR1_CYA_TRUST_DNISO(t)\n#define VPR_OVR1_CYA_TRUST_CE1(t)     VPR_OVR1_CYA_TRUST_DNISO(t)\n#define VPR_OVR1_CYA_TRUST_NVENC(t)   ((t) <<  7u) // Unused?\n#define VPR_OVR1_CYA_TRUST_NVDEC(t)   ((t) <<  9u) // Unused?\n#define VPR_OVR1_CYA_TRUST_MSPPP(t)   ((t) << 11u) // Unused? VIC/JPG?\n#define VPR_OVR1_CYA_TRUST_MSVLD(t)   ((t) << 13u) // Unused? SEC2?\n\ntypedef struct _mc_regs_t210_t {\n/* 0x000 */\tu32 mc_intstatus;\n/* 0x004 */\tu32 mc_intmask;\n/* 0x008 */\tu32 mc_err_status;\n/* 0x00c */\tu32 mc_err_adr;\n/* 0x010 */\tu32 mc_smmu_config;\n/* 0x014 */\tu32 mc_smmu_tlb_config;\n/* 0x018 */\tu32 mc_smmu_ptc_config;\n/* 0x01c */\tu32 mc_smmu_ptb_asid;\n/* 0x020 */\tu32 mc_smmu_ptb_data;\n/* 0x024 */\tu32 rsvd_024[3];\n/* 0x030 */\tu32 mc_smmu_tlb_flush;\n/* 0x034 */\tu32 mc_smmu_ptc_flush;\n/* 0x038 */\tu32 mc_smmu_asid_security;\n/* 0x03c */\tu32 mc_smmu_asid_security_1;\n/* 0x040 */\tu32 mc_smmu_client_config0;\n/* 0x044 */\tu32 mc_smmu_client_config1;\n/* 0x048 */\tu32 mc_smmu_client_config2;\n/* 0x04c */\tu32 mc_smmu_client_config3;\n/* 0x050 */\tu32 mc_emem_cfg;\n/* 0x054 */\tu32 mc_emem_adr_cfg;\n/* 0x058 */\tu32 mc_emem_adr_cfg_dev0;\n/* 0x05c */\tu32 mc_emem_adr_cfg_dev1;\n/* 0x060 */\tu32 mc_emem_adr_cfg_channel_mask;\n/* 0x064 */\tu32 mc_emem_adr_cfg_bank_mask_0;\n/* 0x068 */\tu32 mc_emem_adr_cfg_bank_mask_1;\n/* 0x06c */\tu32 mc_emem_adr_cfg_bank_mask_2;\n/* 0x070 */\tu32 mc_security_cfg0;\n/* 0x074 */\tu32 mc_security_cfg1;\n/* 0x078 */\tu32 rsvd_078;\n/* 0x07c */\tu32 mc_security_rsv;\n/* 0x080 */\tu32 rsvd_080[4];\n/* 0x090 */\tu32 mc_emem_arb_cfg;\n/* 0x094 */\tu32 mc_emem_arb_outstanding_req;\n/* 0x098 */\tu32 mc_emem_arb_timing_rcd;\n/* 0x09c */\tu32 mc_emem_arb_timing_rp;\n/* 0x0a0 */\tu32 mc_emem_arb_timing_rc;\n/* 0x0a4 */\tu32 mc_emem_arb_timing_ras;\n/* 0x0a8 */\tu32 mc_emem_arb_timing_faw;\n/* 0x0ac */\tu32 mc_emem_arb_timing_rrd;\n/* 0x0b0 */\tu32 mc_emem_arb_timing_rap2pre;\n/* 0x0b4 */\tu32 mc_emem_arb_timing_wap2pre;\n/* 0x0b8 */\tu32 mc_emem_arb_timing_r2r;\n/* 0x0bc */\tu32 mc_emem_arb_timing_w2w;\n/* 0x0c0 */\tu32 mc_emem_arb_timing_r2w;\n/* 0x0c4 */\tu32 mc_emem_arb_timing_w2r;\n/* 0x0c8 */\tu32 mc_emem_arb_misc2;\n/* 0x0cc */\tu32 rsvd_0cc;\n/* 0x0d0 */\tu32 mc_emem_arb_da_turns;\n/* 0x0d4 */\tu32 mc_emem_arb_da_covers;\n/* 0x0d8 */\tu32 mc_emem_arb_misc0;\n/* 0x0dc */\tu32 mc_emem_arb_misc1;\n/* 0x0e0 */\tu32 mc_emem_arb_ring1_throttle;\n/* 0x0e4 */\tu32 mc_emem_arb_ring3_throttle;\n/* 0x0e8 */\tu32 mc_emem_arb_override;\n/* 0x0ec */\tu32 mc_emem_arb_rsv;\n/* 0x0f0 */\tu32 rsvd_0f0;\n/* 0x0f4 */\tu32 mc_clken_override;\n/* 0x0f8 */\tu32 mc_timing_control_dbg;\n/* 0x0fc */\tu32 mc_timing_control;\n/* 0x100 */\tu32 mc_stat_control;\n/* 0x104 */\tu32 mc_stat_status;\n/* 0x108 */\tu32 mc_stat_emc_clock_limit;\n/* 0x10c */\tu32 mc_stat_emc_clock_limit_msbs;\n/* 0x110 */\tu32 mc_stat_emc_clocks;\n/* 0x114 */\tu32 mc_stat_emc_clocks_msbs;\n/* 0x118 */\tu32 mc_stat_emc_filter_set0_adr_limit_lo;\n/* 0x11c */\tu32 mc_stat_emc_filter_set0_adr_limit_hi;\n/* 0x120 */\tu32 mc_stat_emc_filter_set0_slack_limit;\n/* 0x124 */\tu32 rsvd_124;\n/* 0x128 */\tu32 mc_stat_emc_filter_set0_client_0;\n/* 0x12c */\tu32 mc_stat_emc_filter_set0_client_1;\n/* 0x130 */\tu32 mc_stat_emc_filter_set0_client_2;\n/* 0x134 */\tu32 mc_stat_emc_filter_set0_client_3;\n/* 0x138 */\tu32 mc_stat_emc_set0_count;\n/* 0x13c */\tu32 mc_stat_emc_set0_count_msbs;\n/* 0x140 */\tu32 mc_stat_emc_set0_slack_accum;\n/* 0x144 */\tu32 mc_stat_emc_set0_slack_accum_msbs;\n/* 0x148 */\tu32 mc_stat_emc_set0_histo_count;\n/* 0x14c */\tu32 mc_stat_emc_set0_histo_count_msbs;\n/* 0x150 */\tu32 mc_stat_emc_set0_minimum_slack_observed;\n/* 0x154 */\tu32 rsvd_154;\n/* 0x158 */\tu32 mc_stat_emc_filter_set1_adr_limit_lo;\n/* 0x15c */\tu32 mc_stat_emc_filter_set1_adr_limit_hi;\n/* 0x160 */\tu32 mc_stat_emc_filter_set1_slack_limit;\n/* 0x164 */\tu32 rsvd_164;\n/* 0x168 */\tu32 mc_stat_emc_filter_set1_client_0;\n/* 0x16c */\tu32 mc_stat_emc_filter_set1_client_1;\n/* 0x170 */\tu32 mc_stat_emc_filter_set1_client_2;\n/* 0x174 */\tu32 mc_stat_emc_filter_set1_client_3;\n/* 0x178 */\tu32 mc_stat_emc_set1_count;\n/* 0x17c */\tu32 mc_stat_emc_set1_count_msbs;\n/* 0x180 */\tu32 mc_stat_emc_set1_slack_accum;\n/* 0x184 */\tu32 mc_stat_emc_set1_slack_accum_msbs;\n/* 0x188 */\tu32 mc_stat_emc_set1_histo_count;\n/* 0x18c */\tu32 mc_stat_emc_set1_histo_count_msbs;\n/* 0x190 */\tu32 mc_stat_emc_set1_minimum_slack_observed;\n/* 0x194 */\tu32 rsvd_194;\n/* 0x198 */\tu32 mc_stat_emc_filter_set0_virtual_adr_limit_lo;\n/* 0x19c */\tu32 mc_stat_emc_filter_set0_virtual_adr_limit_hi;\n/* 0x1a0 */\tu32 mc_stat_emc_filter_set0_asid;\n/* 0x1a4 */\tu32 rsvd_1a4;\n/* 0x1a8 */\tu32 mc_stat_emc_filter_set1_virtual_adr_limit_lo;\n/* 0x1ac */\tu32 mc_stat_emc_filter_set1_virtual_adr_limit_hi;\n/* 0x1b0 */\tu32 mc_stat_emc_filter_set1_asid;\n/* 0x1b4 */\tu32 rsvd_1b4;\n/* 0x1b8 */\tu32 mc_stat_emc_set0_idle_cycle_count;\n/* 0x1bc */\tu32 mc_stat_emc_set0_idle_cycle_count_msbs;\n/* 0x1c0 */\tu32 mc_stat_emc_set0_idle_cycle_partition_select;\n/* 0x1c4 */\tu32 rsvd_1c4;\n/* 0x1c8 */\tu32 mc_stat_emc_set1_idle_cycle_count;\n/* 0x1cc */\tu32 mc_stat_emc_set1_idle_cycle_count_msbs;\n/* 0x1d0 */\tu32 mc_stat_emc_set1_idle_cycle_partition_select;\n/* 0x1d4 */\tu32 rsvd_1d4[6];\n/* 0x1ec */\tu32 mc_smmu_stats_tlb_hit_miss_source;\n/* 0x1f0 */\tu32 mc_smmu_stats_tlb_hit_count;\n/* 0x1f4 */\tu32 mc_smmu_stats_tlb_miss_count;\n/* 0x1f8 */\tu32 mc_smmu_stats_ptc_hit_count;\n/* 0x1fc */\tu32 mc_smmu_stats_ptc_miss_count;\n/* 0x200 */\tu32 mc_client_hotreset_ctrl;\n/* 0x204 */\tu32 mc_client_hotreset_status;\n/* 0x208 */\tu32 mc_emem_arb_isochronous_0;\n/* 0x20c */\tu32 mc_emem_arb_isochronous_1;\n/* 0x210 */\tu32 mc_emem_arb_isochronous_2;\n/* 0x214 */\tu32 mc_emem_arb_isochronous_3;\n/* 0x218 */\tu32 mc_emem_arb_hysteresis_0;\n/* 0x21c */\tu32 mc_emem_arb_hysteresis_1;\n/* 0x220 */\tu32 mc_emem_arb_hysteresis_2;\n/* 0x224 */\tu32 mc_emem_arb_hysteresis_3;\n/* 0x228 */\tu32 mc_smmu_translation_enable_0;\n/* 0x22c */\tu32 mc_smmu_translation_enable_1;\n/* 0x230 */\tu32 mc_smmu_translation_enable_2;\n/* 0x234 */\tu32 mc_smmu_translation_enable_3;\n/* 0x238 */\tu32 mc_smmu_afi_asid;\n/* 0x23c */\tu32 mc_smmu_avpc_asid;\n/* 0x240 */\tu32 mc_smmu_dc_asid;\n/* 0x244 */\tu32 mc_smmu_dcb_asid;\n/* 0x248 */\tu32 rsvd_248[2];\n/* 0x250 */\tu32 mc_smmu_hc_asid;\n/* 0x254 */\tu32 mc_smmu_hda_asid;\n/* 0x258 */\tu32 mc_smmu_isp2_asid;\n/* 0x25c */\tu32 rsvd_25c[2];\n/* 0x264 */\tu32 mc_smmu_nvenc_asid;\n/* 0x268 */\tu32 rsvd_268[2];\n/* 0x270 */\tu32 mc_smmu_ppcs_asid;\n/* 0x274 */\tu32 mc_smmu_sata_asid;\n/* 0x278 */\tu32 rsvd_278[2];\n/* 0x280 */\tu32 mc_smmu_vi_asid;\n/* 0x284 */\tu32 mc_smmu_vic_asid;\n/* 0x288 */\tu32 mc_smmu_xusb_host_asid;\n/* 0x28c */\tu32 mc_smmu_xusb_dev_asid;\n/* 0x290 */\tu32 mc_smmu_a9avp_asid;\n/* 0x294 */\tu32 mc_smmu_tsec_asid;\n/* 0x298 */\tu32 mc_smmu_ppcs1_asid;\n/* 0x29c */\tu32 rsvd_29c;\n/* 0x2a0 */\tu32 mc_ahb_extra_snap_levels;\n/* 0x2a4 */\tu32 mc_apb_extra_snap_levels;\n/* 0x2a8 */\tu32 mc_avp_extra_snap_levels;\n/* 0x2ac */\tu32 mc_dis_extra_snap_levels;\n/* 0x2b0 */\tu32 rsvd_2b0[2];\n/* 0x2b8 */\tu32 mc_pcx_extra_snap_levels;\n/* 0x2bc */\tu32 mc_ftop_extra_snap_levels;\n/* 0x2c0 */\tu32 mc_sax_extra_snap_levels;\n/* 0x2c4 */\tu32 rsvd_2c4[5];\n/* 0x2d8 */\tu32 mc_ve_extra_snap_levels;\n/* 0x2dc */\tu32 rsvd_2dc;\n/* 0x2e0 */\tu32 mc_latency_allowance_afi_0;\n/* 0x2e4 */\tu32 mc_latency_allowance_avpc_0;\n/* 0x2e8 */\tu32 mc_latency_allowance_dc_0;\n/* 0x2ec */\tu32 mc_latency_allowance_dc_1;\n/* 0x2f0 */\tu32 mc_latency_allowance_dc_2;\n/* 0x2f4 */\tu32 mc_latency_allowance_dcb_0;\n/* 0x2f8 */\tu32 mc_latency_allowance_dcb_1;\n/* 0x2fc */\tu32 mc_latency_allowance_dcb_2;\n/* 0x300 */\tu32 rsvd_300[4];\n/* 0x310 */\tu32 mc_latency_allowance_hc_0;\n/* 0x314 */\tu32 mc_latency_allowance_hc_1;\n/* 0x318 */\tu32 mc_latency_allowance_hda_0;\n/* 0x31c */\tu32 rsvd_31c;\n/* 0x320 */\tu32 mc_latency_allowance_mpcore_0;\n/* 0x324 */\tu32 rsvd_324;\n/* 0x328 */\tu32 mc_latency_allowance_nvenc_0;\n/* 0x32c */\tu32 rsvd_32c[6];\n/* 0x344 */\tu32 mc_latency_allowance_ppcs_0;\n/* 0x348 */\tu32 mc_latency_allowance_ppcs_1;\n/* 0x34c */\tu32 mc_latency_allowance_ptc_0;\n/* 0x350 */\tu32 mc_latency_allowance_sata_0;\n/* 0x354 */\tu32 rsvd_354[7];\n/* 0x370 */\tu32 mc_latency_allowance_isp2_0;\n/* 0x374 */\tu32 mc_latency_allowance_isp2_1;\n/* 0x378 */\tu32 rsvd_378;\n/* 0x37c */\tu32 mc_latency_allowance_xusb_0;\n/* 0x380 */\tu32 mc_latency_allowance_xusb_1;\n/* 0x384 */\tu32 mc_latency_allowance_isp2b_0;\n/* 0x388 */\tu32 mc_latency_allowance_isp2b_1;\n/* 0x38c */\tu32 rsvd_38c;\n/* 0x390 */\tu32 mc_latency_allowance_tsec_0;\n/* 0x394 */\tu32 mc_latency_allowance_vic_0;\n/* 0x398 */\tu32 mc_latency_allowance_vi2_0;\n/* 0x39c */\tu32 rsvd_39c;\n/* 0x3a0 */\tu32 mc_latency_allowance_axiap_0;\n/* 0x3a4 */\tu32 mc_latency_allowance_a9avp_0;\n/* 0x3a8 */\tu32 rsvd_3a8;\n/* 0x3ac */\tu32 mc_latency_allowance_gpu_0;\n/* 0x3b0 */\tu32 rsvd_3b0[2];\n/* 0x3b8 */\tu32 mc_latency_allowance_sdmmca_0;\n/* 0x3bc */\tu32 mc_latency_allowance_sdmmcaa_0;\n/* 0x3c0 */\tu32 mc_latency_allowance_sdmmc_0;\n/* 0x3c4 */\tu32 mc_latency_allowance_sdmmcab_0;\n/* 0x3c8 */\tu32 mc_latency_allowance_dc_3;\n/* 0x3cc */\tu32 rsvd_3cc[3];\n/* 0x3d8 */\tu32 mc_latency_allowance_nvdec_0;\n/* 0x3dc */\tu32 mc_latency_allowance_ape_0;\n/* 0x3e0 */\tu32 mc_latency_allowance_se_0;\n/* 0x3e4 */\tu32 mc_latency_allowance_nvjpg_0;\n/* 0x3e8 */\tu32 mc_latency_allowance_gpu2_0;\n/* 0x3ec */\tu32 mc_latency_allowance_etr_0;\n/* 0x3f0 */\tu32 mc_latency_allowance_tsecb_0;\n/* 0x3f4 */\tu32 rsvd_3f4[2];\n/* 0x3fc */\tu32 mc_reserved_rsv;\n/* 0x400 */\tu32 rsvd_400;\n/* 0x404 */\tu32 mc_usbx_extra_snap_levels;\n/* 0x408 */\tu32 mc_disb_extra_snap_levels;\n/* 0x40c */\tu32 mc_mse_extra_snap_levels;\n/* 0x410 */\tu32 mc_ve2_extra_snap_levels;\n/* 0x414 */\tu32 mc_a9avppc_extra_snap_levels;\n/* 0x418 */\tu32 mc_video_protect_vpr_override;\n/* 0x41c */\tu32 mc_dis_ptsa_rate;\n/* 0x420 */\tu32 mc_dis_ptsa_min;\n/* 0x424 */\tu32 mc_dis_ptsa_max;\n/* 0x428 */\tu32 mc_disb_ptsa_rate;\n/* 0x42c */\tu32 mc_disb_ptsa_min;\n/* 0x430 */\tu32 mc_disb_ptsa_max;\n/* 0x434 */\tu32 mc_ve_ptsa_rate;\n/* 0x438 */\tu32 mc_ve_ptsa_min;\n/* 0x43c */\tu32 mc_ve_ptsa_max;\n/* 0x440 */\tu32 mc_ring2_ptsa_rate;\n/* 0x444 */\tu32 mc_ring2_ptsa_min;\n/* 0x448 */\tu32 mc_ring2_ptsa_max;\n/* 0x44c */\tu32 mc_mll_mpcorer_ptsa_rate;\n/* 0x450 */\tu32 mc_mll_mpcorer_ptsa_min;\n/* 0x454 */\tu32 mc_mll_mpcorer_ptsa_max;\n/* 0x458 */\tu32 mc_smmu_smmu_ptsa_rate;\n/* 0x45c */\tu32 mc_smmu_smmu_ptsa_min;\n/* 0x460 */\tu32 mc_smmu_smmu_ptsa_max;\n/* 0x464 */\tu32 rsvd_464[6];\n/* 0x47c */\tu32 mc_ring1_ptsa_rate;\n/* 0x480 */\tu32 mc_ring1_ptsa_min;\n/* 0x484 */\tu32 mc_ring1_ptsa_max;\n/* 0x488 */\tu32 mc_a9avppc_ptsa_rate;\n/* 0x48c */\tu32 mc_a9avppc_ptsa_min;\n/* 0x490 */\tu32 mc_a9avppc_ptsa_max;\n/* 0x494 */\tu32 mc_ve2_ptsa_rate;\n/* 0x498 */\tu32 mc_ve2_ptsa_min;\n/* 0x49c */\tu32 mc_ve2_ptsa_max;\n/* 0x4a0 */\tu32 mc_isp_ptsa_rate;\n/* 0x4a4 */\tu32 mc_isp_ptsa_min;\n/* 0x4a8 */\tu32 mc_isp_ptsa_max;\n/* 0x4ac */\tu32 mc_pcx_ptsa_rate;\n/* 0x4b0 */\tu32 mc_pcx_ptsa_min;\n/* 0x4b4 */\tu32 mc_pcx_ptsa_max;\n/* 0x4b8 */\tu32 mc_sax_ptsa_rate;\n/* 0x4bc */\tu32 mc_sax_ptsa_min;\n/* 0x4c0 */\tu32 mc_sax_ptsa_max;\n/* 0x4c4 */\tu32 mc_mse_ptsa_rate;\n/* 0x4c8 */\tu32 mc_mse_ptsa_min;\n/* 0x4cc */\tu32 mc_mse_ptsa_max;\n/* 0x4d0 */\tu32 mc_sd_ptsa_rate;\n/* 0x4d4 */\tu32 mc_sd_ptsa_min;\n/* 0x4d8 */\tu32 mc_sd_ptsa_max;\n/* 0x4dc */\tu32 mc_ahb_ptsa_rate;\n/* 0x4e0 */\tu32 mc_ahb_ptsa_min;\n/* 0x4e4 */\tu32 mc_ahb_ptsa_max;\n/* 0x4e8 */\tu32 mc_apb_ptsa_rate;\n/* 0x4ec */\tu32 mc_apb_ptsa_min;\n/* 0x4f0 */\tu32 mc_apb_ptsa_max;\n/* 0x4f4 */\tu32 mc_avp_ptsa_rate;\n/* 0x4f8 */\tu32 mc_avp_ptsa_min;\n/* 0x4fc */\tu32 mc_avp_ptsa_max;\n/* 0x500 */\tu32 rsvd_500[3];\n/* 0x50c */\tu32 mc_ftop_ptsa_rate;\n/* 0x510 */\tu32 mc_ftop_ptsa_min;\n/* 0x514 */\tu32 mc_ftop_ptsa_max;\n/* 0x518 */\tu32 mc_host_ptsa_rate;\n/* 0x51c */\tu32 mc_host_ptsa_min;\n/* 0x520 */\tu32 mc_host_ptsa_max;\n/* 0x524 */\tu32 mc_usbx_ptsa_rate;\n/* 0x528 */\tu32 mc_usbx_ptsa_min;\n/* 0x52c */\tu32 mc_usbx_ptsa_max;\n/* 0x530 */\tu32 mc_usbd_ptsa_rate;\n/* 0x534 */\tu32 mc_usbd_ptsa_min;\n/* 0x538 */\tu32 mc_usbd_ptsa_max;\n/* 0x53c */\tu32 mc_gk_ptsa_rate;\n/* 0x540 */\tu32 mc_gk_ptsa_min;\n/* 0x544 */\tu32 mc_gk_ptsa_max;\n/* 0x548 */\tu32 mc_aud_ptsa_rate;\n/* 0x54c */\tu32 mc_aud_ptsa_min;\n/* 0x550 */\tu32 mc_aud_ptsa_max;\n/* 0x554 */\tu32 mc_vicpc_ptsa_rate;\n/* 0x558 */\tu32 mc_vicpc_ptsa_min;\n/* 0x55c */\tu32 mc_vicpc_ptsa_max;\n/* 0x560 */\tu32 rsvd_560[9];\n/* 0x584 */\tu32 mc_jpg_ptsa_rate;\n/* 0x588 */\tu32 mc_jpg_ptsa_min;\n/* 0x58c */\tu32 mc_jpg_ptsa_max;\n/* 0x590 */\tu32 mc_video_protect_vpr_override1;\n/* 0x594 */\tu32 rsvd_594[27];\n/* 0x600 */\tu32 mc_smmu_tlb_set_selection_mask_0;\n/* 0x604 */\tu32 rsvd_604[3];\n/* 0x610 */\tu32 mc_gk2_ptsa_rate;\n/* 0x614 */\tu32 mc_gk2_ptsa_min;\n/* 0x618 */\tu32 mc_gk2_ptsa_max;\n/* 0x61c */\tu32 mc_sdm_ptsa_rate;\n/* 0x620 */\tu32 mc_sdm_ptsa_min;\n/* 0x624 */\tu32 mc_sdm_ptsa_max;\n/* 0x628 */\tu32 mc_hdapc_ptsa_rate;\n/* 0x62c */\tu32 mc_hdapc_ptsa_min;\n/* 0x630 */\tu32 mc_hdapc_ptsa_max;\n/* 0x634 */\tu32 mc_dfd_ptsa_rate;\n/* 0x638 */\tu32 mc_dfd_ptsa_min;\n/* 0x63c */\tu32 mc_dfd_ptsa_max;\n/* 0x640 */\tu32 rsvd_640[2];\n/* 0x648 */\tu32 mc_video_protect_bom;\n/* 0x64c */\tu32 mc_video_protect_size_mb;\n/* 0x650 */\tu32 mc_video_protect_reg_ctrl;\n/* 0x654 */\tu32 mc_err_vpr_status;\n/* 0x658 */\tu32 mc_err_vpr_adr;\n/* 0x65c */\tu32 mc_iram_bom;\n/* 0x660 */\tu32 mc_iram_tom;\n/* 0x664 */\tu32 mc_emem_cfg_access_ctrl;\n/* 0x668 */\tu32 mc_tz_security_ctrl;\n/* 0x66c */\tu32 mc_emem_arb_outstanding_req_ring3;\n/* 0x670 */\tu32 mc_sec_carveout_bom;\n/* 0x674 */\tu32 mc_sec_carveout_size_mb;\n/* 0x678 */\tu32 mc_sec_carveout_reg_ctrl;\n/* 0x67c */\tu32 mc_err_sec_status;\n/* 0x680 */\tu32 mc_err_sec_adr;\n/* 0x684 */\tu32 mc_pc_idle_clock_gate_config;\n/* 0x688 */\tu32 mc_stutter_control;\n/* 0x68c */\tu32 rsvd_68c;\n/* 0x690 */\tu32 mc_scaled_latency_allowance_display0a;\n/* 0x694 */\tu32 mc_scaled_latency_allowance_display0ab;\n/* 0x698 */\tu32 mc_scaled_latency_allowance_display0b;\n/* 0x69c */\tu32 mc_scaled_latency_allowance_display0bb;\n/* 0x6a0 */\tu32 mc_scaled_latency_allowance_display0c;\n/* 0x6a4 */\tu32 mc_scaled_latency_allowance_display0cb;\n/* 0x6a8 */\tu32 rsvd_6a8[2];\n/* 0x6b0 */\tu32 mc_emem_arb_niso_throttle;\n/* 0x6b4 */\tu32 mc_emem_arb_outstanding_req_niso;\n/* 0x6b8 */\tu32 mc_emem_arb_niso_throttle_mask;\n/* 0x6bc */\tu32 mc_emem_arb_ring0_throttle_mask;\n/* 0x6c0 */\tu32 mc_emem_arb_timing_rfcpb;\n/* 0x6c4 */\tu32 mc_emem_arb_timing_ccdmw;\n/* 0x6c8 */\tu32 rsvd_6c8[10];\n/* 0x6f0 */\tu32 mc_emem_arb_refpb_hp_ctrl;\n/* 0x6f4 */\tu32 mc_emem_arb_refpb_bank_ctrl;\n/* 0x6f8 */\tu32 rsvd_6f8[67];\n/* 0x804 */\tu32 mc_smmu_isp21_asid_b01;\n/* 0x808 */\tu32 mc_smmu_isp2b1_asid_b01;\n/* 0x80c */\tu32 rsvd_80c[32];\n/* 0x88c */\tu32 mc_min_length_afi_0;\n/* 0x890 */\tu32 mc_min_length_avpc_0;\n/* 0x894 */\tu32 mc_min_length_dc_0;\n/* 0x898 */\tu32 mc_min_length_dc_1;\n/* 0x89c */\tu32 mc_min_length_dc_2;\n/* 0x8a0 */\tu32 mc_min_length_dcb_0;\n/* 0x8a4 */\tu32 mc_min_length_dcb_1;\n/* 0x8a8 */\tu32 mc_min_length_dcb_2;\n/* 0x8ac */\tu32 rsvd_8ac[4];\n/* 0x8bc */\tu32 mc_min_length_hc_0;\n/* 0x8c0 */\tu32 mc_min_length_hc_1;\n/* 0x8c4 */\tu32 mc_min_length_hda_0;\n/* 0x8c8 */\tu32 rsvd_8c8;\n/* 0x8cc */\tu32 mc_min_length_mpcore_0;\n/* 0x8d0 */\tu32 rsvd_8d0;\n/* 0x8d4 */\tu32 mc_min_length_nvenc_0;\n/* 0x8d8 */\tu32 rsvd_8d8[6];\n/* 0x8f0 */\tu32 mc_min_length_ppcs_0;\n/* 0x8f4 */\tu32 mc_min_length_ppcs_1;\n/* 0x8f8 */\tu32 mc_min_length_ptc_0;\n/* 0x8fc */\tu32 mc_min_length_sata_0;\n/* 0x900 */\tu32 rsvd_900[7];\n/* 0x91c */\tu32 mc_min_length_isp2_0;\n/* 0x920 */\tu32 mc_min_length_isp2_1;\n/* 0x924 */\tu32 rsvd_924;\n/* 0x928 */\tu32 mc_min_length_xusb_0;\n/* 0x92c */\tu32 mc_min_length_xusb_1;\n/* 0x930 */\tu32 mc_min_length_isp2b_0;\n/* 0x934 */\tu32 mc_min_length_isp2b_1;\n/* 0x938 */\tu32 rsvd_938;\n/* 0x93c */\tu32 mc_min_length_tsec_0;\n/* 0x940 */\tu32 mc_min_length_vic_0;\n/* 0x944 */\tu32 mc_min_length_vi2_0;\n/* 0x948 */\tu32 mc_untranslated_region_check_b01;\n/* 0x94c */\tu32 mc_min_length_axiap_0;\n/* 0x950 */\tu32 mc_min_length_a9avp_0;\n/* 0x954 */\tu32 rsvd_954;\n/* 0x958 */\tu32 mc_reserved_rsv_1;\n/* 0x95c */\tu32 mc_dvfs_pipe_select;\n/* 0x960 */\tu32 mc_ptsa_grant_decrement;\n/* 0x964 */\tu32 mc_iram_reg_ctrl;\n/* 0x968 */\tu32 mc_emem_arb_override_1;\n/* 0x96c */\tu32 rsvd_96c;\n/* 0x970 */\tu32 mc_client_hotreset_ctrl_1;\n/* 0x974 */\tu32 mc_client_hotreset_status_1;\n/* 0x978 */\tu32 mc_video_protect_bom_adr_hi;\n/* 0x97c */\tu32 rsvd_97c;\n/* 0x980 */\tu32 mc_iram_adr_hi;\n/* 0x984 */\tu32 mc_video_protect_gpu_override_0;\n/* 0x988 */\tu32 mc_video_protect_gpu_override_1;\n/* 0x98c */\tu32 rsvd_98c;\n/* 0x990 */\tu32 mc_emem_arb_stats_0;\n/* 0x994 */\tu32 mc_emem_arb_stats_1;\n/* 0x998 */\tu32 rsvd_998[2];\n/* 0x9a0 */\tu32 mc_mts_carveout_bom;\n/* 0x9a4 */\tu32 mc_mts_carveout_size_mb;\n/* 0x9a8 */\tu32 mc_mts_carveout_adr_hi;\n/* 0x9ac */\tu32 mc_mts_carveout_reg_ctrl;\n/* 0x9b0 */\tu32 mc_err_mts_status;\n/* 0x9b4 */\tu32 mc_err_mts_adr;\n/* 0x9b8 */\tu32 mc_smmu_ptc_flush_1;\n/* 0x9bc */\tu32 mc_security_cfg3;\n/* 0x9c0 */\tu32 rsvd_9c0[4];\n/* 0x9d0 */\tu32 mc_err_apb_asid_update_status;\n/* 0x9d4 */\tu32 mc_sec_carveout_adr_hi;\n/* 0x9d8 */\tu32 rsvd_9d8;\n/* 0x9dc */\tu32 mc_da_config0;\n/* 0x9e0 */\tu32 mc_smmu_asid_security_2;\n/* 0x9e4 */\tu32 mc_smmu_asid_security_3;\n/* 0x9e8 */\tu32 mc_smmu_asid_security_4;\n/* 0x9ec */\tu32 mc_smmu_asid_security_5;\n/* 0x9f0 */\tu32 mc_smmu_asid_security_6;\n/* 0x9f4 */\tu32 mc_smmu_asid_security_7;\n/* 0x9f8 */\tu32 rsvd_9f8[2];\n/* 0xa00 */\tu32 mc_gk_extra_snap_levels;\n/* 0xa04 */\tu32 mc_sd_extra_snap_levels;\n/* 0xa08 */\tu32 mc_isp_extra_snap_levels;\n/* 0xa0c */\tu32 rsvd_a0c;\n/* 0xa10 */\tu32 mc_aud_extra_snap_levels;\n/* 0xa14 */\tu32 mc_host_extra_snap_levels;\n/* 0xa18 */\tu32 mc_usbd_extra_snap_levels;\n/* 0xa1c */\tu32 mc_vicpc_extra_snap_levels;\n/* 0xa20 */\tu32 mc_stat_emc_filter_set0_adr_limit_upper;\n/* 0xa24 */\tu32 mc_stat_emc_filter_set1_adr_limit_upper;\n/* 0xa28 */\tu32 mc_stat_emc_filter_set0_virtual_adr_limit_upper;\n/* 0xa2c */\tu32 mc_stat_emc_filter_set1_virtual_adr_limit_upper;\n/* 0xa30 */\tu32 rsvd_a30[3];\n/* 0xa3c */\tu32 mc_jpg_extra_snap_levels;\n/* 0xa40 */\tu32 mc_gk2_extra_snap_levels;\n/* 0xa44 */\tu32 mc_sdm_extra_snap_levels;\n/* 0xa48 */\tu32 mc_hdapc_extra_snap_levels;\n/* 0xa4c */\tu32 mc_dfd_extra_snap_levels;\n/* 0xa50 */\tu32 rsvd_a50[14];\n/* 0xa88 */\tu32 mc_smmu_dc1_asid;\n/* 0xa8c */\tu32 rsvd_a8c[2];\n/* 0xa94 */\tu32 mc_smmu_sdmmc1a_asid;\n/* 0xa98 */\tu32 mc_smmu_sdmmc2a_asid;\n/* 0xa9c */\tu32 mc_smmu_sdmmc3a_asid;\n/* 0xaa0 */\tu32 mc_smmu_sdmmc4a_asid;\n/* 0xaa4 */\tu32 mc_smmu_isp2b_asid;\n/* 0xaa8 */\tu32 mc_smmu_gpu_asid;\n/* 0xaac */\tu32 mc_smmu_gpub_asid;\n/* 0xab0 */\tu32 mc_smmu_ppcs2_asid;\n/* 0xab4 */\tu32 mc_smmu_nvdec_asid;\n/* 0xab8 */\tu32 mc_smmu_ape_asid;\n/* 0xabc */\tu32 mc_smmu_se_asid;\n/* 0xac0 */\tu32 mc_smmu_nvjpg_asid;\n/* 0xac4 */\tu32 mc_smmu_hc1_asid;\n/* 0xac8 */\tu32 mc_smmu_se1_asid;\n/* 0xacc */\tu32 mc_smmu_axiap_asid;\n/* 0xad0 */\tu32 mc_smmu_etr_asid;\n/* 0xad4 */\tu32 mc_smmu_tsecb_asid;\n/* 0xad8 */\tu32 mc_smmu_tsec1_asid;\n/* 0xadc */\tu32 mc_smmu_tsecb1_asid;\n/* 0xae0 */\tu32 mc_smmu_nvdec1_asid;\n/* 0xae4 */\tu32 rsvd_ae4[8];\n/* 0xb04 */\tu32 mc_min_length_gpu_0;\n/* 0xb08 */\tu32 rsvd_b08[2];\n/* 0xb10 */\tu32 mc_min_length_sdmmca_0;\n/* 0xb14 */\tu32 mc_min_length_sdmmcaa_0;\n/* 0xb18 */\tu32 mc_min_length_sdmmc_0;\n/* 0xb1c */\tu32 mc_min_length_sdmmcab_0;\n/* 0xb20 */\tu32 mc_min_length_dc_3;\n/* 0xb24 */\tu32 rsvd_b24[3];\n/* 0xb30 */\tu32 mc_min_length_nvdec_0;\n/* 0xb34 */\tu32 mc_min_length_ape_0;\n/* 0xb38 */\tu32 mc_min_length_se_0;\n/* 0xb3c */\tu32 mc_min_length_nvjpg_0;\n/* 0xb40 */\tu32 mc_min_length_gpu2_0;\n/* 0xb44 */\tu32 mc_min_length_etr_0;\n/* 0xb48 */\tu32 mc_min_length_tsecb_0;\n/* 0xb4c */\tu32 rsvd_b4c[13];\n/* 0xb80 */\tu32 mc_emem_arb_niso_throttle_mask_1;\n/* 0xb84 */\tu32 mc_emem_arb_hysteresis_4;\n/* 0xb88 */\tu32 mc_stat_emc_filter_set0_client_4;\n/* 0xb8c */\tu32 mc_stat_emc_filter_set1_client_4;\n/* 0xb90 */\tu32 rsvd_b90;\n/* 0xb94 */\tu32 mc_emem_arb_isochronous_4;\n/* 0xb98 */\tu32 mc_smmu_translation_enable_4;\n/* 0xb9c */\tu32 mc_smmu_client_config4;\n/* 0xba0 */\tu32 rsvd_ba0[4];\n/* 0xbb0 */\tu32 mc_emem_arb_dhysteresis_0;\n/* 0xbb4 */\tu32 mc_emem_arb_dhysteresis_1;\n/* 0xbb8 */\tu32 mc_emem_arb_dhysteresis_2;\n/* 0xbbc */\tu32 mc_emem_arb_dhysteresis_3;\n/* 0xbc0 */\tu32 mc_emem_arb_dhysteresis_4;\n/* 0xbc4 */\tu32 rsvd_bc4[2];\n/* 0xbcc */\tu32 mc_emem_arb_dhyst_ctrl;\n/* 0xbd0 */\tu32 mc_emem_arb_dhyst_timeout_util_0;\n/* 0xbd4 */\tu32 mc_emem_arb_dhyst_timeout_util_1;\n/* 0xbd8 */\tu32 mc_emem_arb_dhyst_timeout_util_2;\n/* 0xbdc */\tu32 mc_emem_arb_dhyst_timeout_util_3;\n/* 0xbe0 */\tu32 mc_emem_arb_dhyst_timeout_util_4;\n/* 0xbe4 */\tu32 mc_emem_arb_dhyst_timeout_util_5;\n/* 0xbe8 */\tu32 mc_emem_arb_dhyst_timeout_util_6;\n/* 0xbec */\tu32 mc_emem_arb_dhyst_timeout_util_7;\n/* 0xbf0 */\tu32 rsvd_bf0[4];\n/* 0xc00 */\tu32 mc_err_generalized_carveout_status;\n/* 0xc04 */\tu32 mc_err_generalized_carveout_adr;\n/* 0xc08 */\tu32 mc_security_carveout1_cfg0;\n/* 0xc0c */\tu32 mc_security_carveout1_bom;\n/* 0xc10 */\tu32 mc_security_carveout1_bom_hi;\n/* 0xc14 */\tu32 mc_security_carveout1_size_128kb;\n/* 0xc18 */\tu32 mc_security_carveout1_client_access0;\n/* 0xc1c */\tu32 mc_security_carveout1_client_access1;\n/* 0xc20 */\tu32 mc_security_carveout1_client_access2;\n/* 0xc24 */\tu32 mc_security_carveout1_client_access3;\n/* 0xc28 */\tu32 mc_security_carveout1_client_access4;\n/* 0xc2c */\tu32 mc_security_carveout1_client_force_internal_access0;\n/* 0xc30 */\tu32 mc_security_carveout1_client_force_internal_access1;\n/* 0xc34 */\tu32 mc_security_carveout1_client_force_internal_access2;\n/* 0xc38 */\tu32 mc_security_carveout1_client_force_internal_access3;\n/* 0xc3c */\tu32 mc_security_carveout1_client_force_internal_access4;\n/* 0xc40 */\tu32 rsvd_c40[6];\n/* 0xc58 */\tu32 mc_security_carveout2_cfg0;\n/* 0xc5c */\tu32 mc_security_carveout2_bom;\n/* 0xc60 */\tu32 mc_security_carveout2_bom_hi;\n/* 0xc64 */\tu32 mc_security_carveout2_size_128kb;\n/* 0xc68 */\tu32 mc_security_carveout2_client_access0;\n/* 0xc6c */\tu32 mc_security_carveout2_client_access1;\n/* 0xc70 */\tu32 mc_security_carveout2_client_access2;\n/* 0xc74 */\tu32 mc_security_carveout2_client_access3;\n/* 0xc78 */\tu32 mc_security_carveout2_client_access4;\n/* 0xc7c */\tu32 mc_security_carveout2_client_force_internal_access0;\n/* 0xc80 */\tu32 mc_security_carveout2_client_force_internal_access1;\n/* 0xc84 */\tu32 mc_security_carveout2_client_force_internal_access2;\n/* 0xc88 */\tu32 mc_security_carveout2_client_force_internal_access3;\n/* 0xc8c */\tu32 mc_security_carveout2_client_force_internal_access4;\n/* 0xc90 */\tu32 rsvd_c90[6];\n/* 0xca8 */\tu32 mc_security_carveout3_cfg0;\n/* 0xcac */\tu32 mc_security_carveout3_bom;\n/* 0xcb0 */\tu32 mc_security_carveout3_bom_hi;\n/* 0xcb4 */\tu32 mc_security_carveout3_size_128kb;\n/* 0xcb8 */\tu32 mc_security_carveout3_client_access0;\n/* 0xcbc */\tu32 mc_security_carveout3_client_access1;\n/* 0xcc0 */\tu32 mc_security_carveout3_client_access2;\n/* 0xcc4 */\tu32 mc_security_carveout3_client_access3;\n/* 0xcc8 */\tu32 mc_security_carveout3_client_access4;\n/* 0xccc */\tu32 mc_security_carveout3_client_force_internal_access0;\n/* 0xcd0 */\tu32 mc_security_carveout3_client_force_internal_access1;\n/* 0xcd4 */\tu32 mc_security_carveout3_client_force_internal_access2;\n/* 0xcd8 */\tu32 mc_security_carveout3_client_force_internal_access3;\n/* 0xcdc */\tu32 mc_security_carveout3_client_force_internal_access4;\n/* 0xce0 */\tu32 rsvd_ce0[6];\n/* 0xcf8 */\tu32 mc_security_carveout4_cfg0;\n/* 0xcfc */\tu32 mc_security_carveout4_bom;\n/* 0xd00 */\tu32 mc_security_carveout4_bom_hi;\n/* 0xd04 */\tu32 mc_security_carveout4_size_128kb;\n/* 0xd08 */\tu32 mc_security_carveout4_client_access0;\n/* 0xd0c */\tu32 mc_security_carveout4_client_access1;\n/* 0xd10 */\tu32 mc_security_carveout4_client_access2;\n/* 0xd14 */\tu32 mc_security_carveout4_client_access3;\n/* 0xd18 */\tu32 mc_security_carveout4_client_access4;\n/* 0xd1c */\tu32 mc_security_carveout4_client_force_internal_access0;\n/* 0xd20 */\tu32 mc_security_carveout4_client_force_internal_access1;\n/* 0xd24 */\tu32 mc_security_carveout4_client_force_internal_access2;\n/* 0xd28 */\tu32 mc_security_carveout4_client_force_internal_access3;\n/* 0xd2c */\tu32 mc_security_carveout4_client_force_internal_access4;\n/* 0xd30 */\tu32 rsvd_d30[6];\n/* 0xd48 */\tu32 mc_security_carveout5_cfg0;\n/* 0xd4c */\tu32 mc_security_carveout5_bom;\n/* 0xd50 */\tu32 mc_security_carveout5_bom_hi;\n/* 0xd54 */\tu32 mc_security_carveout5_size_128kb;\n/* 0xd58 */\tu32 mc_security_carveout5_client_access0;\n/* 0xd5c */\tu32 mc_security_carveout5_client_access1;\n/* 0xd60 */\tu32 mc_security_carveout5_client_access2;\n/* 0xd64 */\tu32 mc_security_carveout5_client_access3;\n/* 0xd68 */\tu32 mc_security_carveout5_client_access4;\n/* 0xd6c */\tu32 mc_security_carveout5_client_force_internal_access0;\n/* 0xd70 */\tu32 mc_security_carveout5_client_force_internal_access1;\n/* 0xd74 */\tu32 mc_security_carveout5_client_force_internal_access2;\n/* 0xd78 */\tu32 mc_security_carveout5_client_force_internal_access3;\n/* 0xd7c */\tu32 mc_security_carveout5_client_force_internal_access4;\n/* 0xd80 */\tu32 rsvd_d80[20];\n/* 0xdd0 */\tu32 mc_pcfifo_client_config0;\n/* 0xdd4 */\tu32 mc_pcfifo_client_config1;\n/* 0xdd8 */\tu32 mc_pcfifo_client_config2;\n/* 0xddc */\tu32 mc_pcfifo_client_config3;\n/* 0xde0 */\tu32 mc_pcfifo_client_config4;\n} mc_regs_t210_t;\n\n#endif\n"
  },
  {
    "path": "bdk/mem/minerva.c",
    "content": "/*\n * Copyright (c) 2019-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n#include <stdlib.h>\n\n#include \"minerva.h\"\n\n#include <ianos/ianos.h>\n#include <mem/emc_t210.h>\n#include <soc/clock.h>\n#include <soc/fuse.h>\n#include <soc/hw_init.h>\n#include <soc/t210.h>\n\n#define FREQ_NO_TABLE_MAX FREQ_408\n\n#define TABLE_FREQ_KHZ_OFFSET        0x40\n#define TABLE_LA_REGS_T210_OFFSET    0x1284\n#define TABLE_LA_REGS_T210B01_OFFSET 0xFA4\n#define LA_SDMMC1_INDEX 6\n\nstatic bool no_table = false;\nstatic mtc_config_t *mtc_cfg = NULL;\nvoid (*mtc_call)(mtc_config_t *mtc_cfg, void *);\n\nint minerva_init(minerva_str_t *mtc_str)\n{\n\tmtc_call = NULL;\n\tmtc_cfg  = (mtc_config_t *)&mtc_str->mtc_cfg;\n\tno_table = hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01;\n\n#ifdef BDK_MINERVA_CFG_FROM_RAM\n\t// Set table to nyx storage.\n\tmtc_cfg->mtc_table = (emc_table_t *)mtc_str->mtc_table;\n\n\t// Check if Minerva is already initialized.\n\tif (mtc_cfg->init_done == MTC_INIT_MAGIC)\n\t{\n\t\t// Load library and do a periodic training if needed.\n\t\tmtc_cfg->train_mode = OP_PERIODIC_TRAIN;\n\t\tmtc_call = (void *)ianos_static_module(\"bootloader/sys/libsys_minerva.bso\", (void *)mtc_cfg);\n\n\t\treturn !mtc_call ? 1 : 0;\n\t}\n\telse\n\t{\n\t\tmtc_config_t mtc_tmp;\n\n\t\t// Initialize table.\n\t\tmtc_tmp.mtc_table  = mtc_cfg->mtc_table;\n\t\tmtc_tmp.sdram_id   = fuse_read_dramid(false);\n\t\tmtc_tmp.init_done  = !no_table ? MTC_NEW_MAGIC : MTC_IRB_MAGIC;\n\n\t\t// Load library and get table.\n\t\tu32 ep_addr = ianos_static_module(\"bootloader/sys/libsys_minerva.bso\", (void *)&mtc_tmp);\n\n\t\t// Ensure that Minerva is initialized.\n\t\tif (mtc_tmp.init_done == MTC_INIT_MAGIC)\n\t\t\tmtc_call = (void *)ep_addr;\n\t\telse\n\t\t\tmtc_cfg->init_done = 0;\n\n\t\t// Copy Minerva context to Nyx storage.\n\t\tif (mtc_call)\n\t\t\tmemcpy(mtc_cfg, (void *)&mtc_tmp, sizeof(mtc_config_t));\n\t}\n#else\n\t// Fully initialize Minerva.\n\tmemset(mtc_cfg, 0, sizeof(mtc_config_t));\n\n\t// Initialize mtc table.\n\tmtc_cfg->mtc_table  = mtc_str->mtc_table;\n\tmtc_cfg->sdram_id   = fuse_read_dramid(false);\n\tmtc_cfg->init_done  = !no_table ? MTC_NEW_MAGIC : MTC_IRB_MAGIC;\n\n\tu32 ep_addr = ianos_static_module(\"bootloader/sys/libsys_minerva.bso\", (void *)mtc_cfg);\n\n\t// Ensure that Minerva is initialized.\n\tif (mtc_cfg->init_done == MTC_INIT_MAGIC)\n\t\tmtc_call = (void *)ep_addr;\n\telse\n\t\tmtc_cfg->init_done = 0;\n#endif\n\n\tif (!mtc_call)\n\t\treturn 1;\n\n\tif (no_table)\n\t{\n\t\tmtc_cfg->train_mode = OP_SWITCH;\n\t\tmtc_cfg->rate_from = FREQ_204;\n\t\tmtc_cfg->rate_to = FREQ_NO_TABLE_MAX;\n\t\tmtc_call(mtc_cfg, NULL);\n\n\t\treturn 0;\n\t}\n\n\t// Train frequencies.\n\tmtc_cfg->train_mode = OP_TRAIN;\n\tmtc_cfg->rate_from = FREQ_204;\n\tmtc_cfg->rate_to = FREQ_204;\n\tmtc_call(mtc_cfg, NULL);\n\tmtc_cfg->rate_to = FREQ_800;\n\tmtc_call(mtc_cfg, NULL);\n\tmtc_cfg->rate_to = FREQ_1600;\n\tmtc_call(mtc_cfg, NULL);\n\n\t// FSP WAR.\n\tmtc_cfg->train_mode = OP_SWITCH;\n\tmtc_cfg->rate_to = FREQ_800;\n\tmtc_call(mtc_cfg, NULL);\n\n\t// Switch to max.\n\tmtc_cfg->rate_to = FREQ_1600;\n\tmtc_call(mtc_cfg, NULL);\n\n\treturn 0;\n}\n\nvoid minerva_change_freq(minerva_freq_t freq)\n{\n\tif (!mtc_call)\n\t\treturn;\n\n\t// Clamp max allowed frequency when no table exists.\n\tif (no_table && freq > FREQ_NO_TABLE_MAX)\n\t\tfreq = FREQ_NO_TABLE_MAX;\n\n\t// Check if requested frequency is different. Do not allow otherwise because it will hang.\n\tif (mtc_cfg->rate_from != freq)\n\t{\n\t\tmtc_cfg->train_mode = OP_SWITCH;\n\t\tmtc_cfg->rate_to = freq;\n\t\tmtc_call(mtc_cfg, NULL);\n\t}\n}\n\nvoid minerva_deinit()\n{\n\tif (!mtc_cfg)\n\t\treturn;\n\n\tminerva_change_freq(FREQ_204);\n\tmtc_cfg->init_done = 0;\n}\n\nvoid minerva_sdmmc_la_program(void *table, bool t210b01)\n{\n\tu32 freq = *(u32 *)(table + TABLE_FREQ_KHZ_OFFSET);\n\tu32 *la_scale_regs = (u32 *)(table + (t210b01 ? TABLE_LA_REGS_T210B01_OFFSET : TABLE_LA_REGS_T210_OFFSET));\n\n\t// Adjust SDMMC1 latency allowance.\n\tswitch (freq)\n\t{\n\tcase 204000:\n\t\tla_scale_regs[LA_SDMMC1_INDEX] = (la_scale_regs[LA_SDMMC1_INDEX] & 0xFF0000) | 50;\n\t\tbreak;\n\tcase 408000:\n\t\tla_scale_regs[LA_SDMMC1_INDEX] = (la_scale_regs[LA_SDMMC1_INDEX] & 0xFF0000) | 25;\n\t\tbreak;\n\tdefault:\n\t\tla_scale_regs[LA_SDMMC1_INDEX] = (la_scale_regs[LA_SDMMC1_INDEX] & 0xFF0000) | 20;\n\t\tbreak;\n\t}\n}\n\nvoid minerva_prep_boot_hos()\n{\n\tif (!mtc_call)\n\t\treturn;\n\n\t// Restore boot frequency for no table mode.\n\tif (no_table)\n\t{\n\t\tminerva_deinit();\n\n\t\treturn;\n\t}\n\n\t// Check if there's RAM OC. If not exit.\n\tif (mtc_cfg->mtc_table[mtc_cfg->table_entries - 1].rate_khz == FREQ_1600)\n\t\treturn;\n\n\t// FSP WAR.\n\tminerva_change_freq(FREQ_204);\n\t// Scale down to 800 MHz boot freq.\n\tminerva_change_freq(FREQ_800);\n}\n\nvoid minerva_prep_boot_l4t(u32 oc_freq, u32 opt_custom, bool prg_sdmmc_la)\n{\n\tif (!mtc_call || no_table)\n\t\treturn;\n\n\t// Program SDMMC LA regs.\n\tif (prg_sdmmc_la)\n\t\tfor (u32 i = 0; i < mtc_cfg->table_entries; i++)\n\t\t\tminerva_sdmmc_la_program(&mtc_cfg->mtc_table[i], false);\n\n\t// Add OC frequency.\n\tif (oc_freq && mtc_cfg->mtc_table[mtc_cfg->table_entries - 1].rate_khz == FREQ_1600)\n\t{\n\t\tmemcpy(&mtc_cfg->mtc_table[mtc_cfg->table_entries],\n\t\t\t   &mtc_cfg->mtc_table[mtc_cfg->table_entries - 1],\n\t\t\t   sizeof(emc_table_t));\n\n\t\tmtc_cfg->mtc_table[mtc_cfg->table_entries].opt_custom = opt_custom;\n\t\tmtc_cfg->mtc_table[mtc_cfg->table_entries].rate_khz   = oc_freq;\n\t\tmtc_cfg->table_entries++;\n\t}\n\n\t// Trim table.\n\tint entries = 0;\n\tfor (u32 i = 0; i < mtc_cfg->table_entries; i++)\n\t{\n\t\t// Copy frequencies from 204/408/800 MHz and 1333+ MHz.\n\t\tint rate = mtc_cfg->mtc_table[i].rate_khz;\n\t\tif (rate == FREQ_204 ||\n\t\t\trate == FREQ_408 ||\n\t\t\trate == FREQ_800 ||\n\t\t\trate >= FREQ_1333)\n\t\t{\n\t\t\tmemcpy(&mtc_cfg->mtc_table[entries], &mtc_cfg->mtc_table[i], sizeof(emc_table_t));\n\t\t\tentries++;\n\t\t}\n\t}\n\tmtc_cfg->table_entries = entries;\n\n\t// Set init frequency.\n\tminerva_change_freq(FREQ_204);\n\n\t// Train the rest of the frequencies.\n\tmtc_cfg->train_mode = OP_TRAIN;\n\tfor (u32 i = 0; i < mtc_cfg->table_entries; i++)\n\t{\n\t\t// Skip already trained frequencies and OC freq (Arachne handles it).\n\t\tif (mtc_cfg->mtc_table[i].trained || mtc_cfg->rate_to == oc_freq)\n\t\t\tcontinue;\n\n\t\t// Train frequency.\n\t\tmtc_cfg->rate_to = mtc_cfg->mtc_table[i].rate_khz;\n\t\tmtc_call(mtc_cfg, NULL);\n\t}\n\n\t// Do FSP WAR and scale to 800 MHz as boot freq.\n\tbool fsp_opwr_disabled = !(EMC(EMC_MRW3) & 0xC0);\n\tif (fsp_opwr_disabled)\n\t\tminerva_change_freq(FREQ_1333);\n\tminerva_change_freq(FREQ_800);\n\n\t// Do not let other mtc ops.\n\tmtc_cfg->init_done = 0;\n}\n\nvoid minerva_periodic_training()\n{\n\tif (!mtc_call)\n\t\treturn;\n\n\tif (mtc_cfg->rate_from >= FREQ_1066)\n\t{\n\t\tmtc_cfg->train_mode = OP_PERIODIC_TRAIN;\n\t\tmtc_call(mtc_cfg, NULL);\n\t}\n}\n\nemc_table_t *minerva_get_mtc_table()\n{\n\tif (!mtc_call || no_table)\n\t\treturn NULL;\n\n\treturn mtc_cfg->mtc_table;\n}\n\nint minerva_get_mtc_table_entries()\n{\n\tif (!mtc_call || no_table)\n\t\treturn 0;\n\n\treturn mtc_cfg->table_entries;\n}\n"
  },
  {
    "path": "bdk/mem/minerva.h",
    "content": "/*\n * Copyright (c) 2019-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _FE_MINERVA_H_\n#define _FE_MINERVA_H_\n\n#include \"mtc_table.h\"\n#include <utils/types.h>\n\n#define MTC_INIT_MAGIC 0x3043544D\n#define MTC_NEW_MAGIC  0x5243544D\n#define MTC_IRB_MAGIC  0x4943544D\n\n#define EMC_PERIODIC_TRAIN_MS 250\n\ntypedef struct\n{\n\tu32 rate_to;\n\tu32 rate_from;\n\temc_table_t *mtc_table;\n\tu32 table_entries;\n\temc_table_t *current_emc_table;\n\tu32 train_mode;\n\tu32 sdram_id;\n\tu32 prev_temp;\n\tbool emc_2X_clk_src_is_pllmb;\n\tbool fsp_for_src_freq;\n\tbool train_ram_patterns;\n\tu32  init_done;\n} mtc_config_t;\n\ntypedef struct\n{\n\tmtc_config_t mtc_cfg;\n\temc_table_t mtc_table[11]; // 10 + 1.\n} minerva_str_t;\n\nenum train_mode_t\n{\n\tOP_SWITCH         = 0,\n\tOP_TRAIN          = 1,\n\tOP_TRAIN_SWITCH   = 2,\n\tOP_PERIODIC_TRAIN = 3,\n\tOP_TEMP_COMP      = 4\n};\n\ntypedef enum\n{\n\tFREQ_204  = 204000,\n\tFREQ_408  = 408000,\n\tFREQ_666  = 665600,\n\tFREQ_800  = 800000,\n\tFREQ_1066 = 1065600,\n\tFREQ_1333 = 1331200,\n\tFREQ_1600 = 1600000,\n\n\tFREQ_MIN  = FREQ_204,\n\tFREQ_MAX  = FREQ_1600\n} minerva_freq_t;\n\nextern void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *);\nint  minerva_init(minerva_str_t *mtc_str);\nvoid minerva_deinit();\nvoid minerva_change_freq(minerva_freq_t freq);\nvoid minerva_sdmmc_la_program(void *table, bool t210b01);\nvoid minerva_prep_boot_hos();\nvoid minerva_prep_boot_l4t(u32 oc_freq, u32 opt_custom, bool prg_sdmmc_la);\nvoid minerva_periodic_training();\nemc_table_t *minerva_get_mtc_table();\nint minerva_get_mtc_table_entries();\n\n#endif\n"
  },
  {
    "path": "bdk/mem/mtc_table.h",
    "content": "/*\n * Minerva Training Cell\n * DRAM Training for Tegra X1 SoC. Supports DDR2/3 and LPDDR3/4.\n *\n * Copyright (c) 2018 CTCaer  <ctcaer@gmail.com>\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _MTC_TABLE_H_\n#define _MTC_TABLE_H_\n\n#include <utils/types.h>\n\ntypedef struct\n{\n\ts32 pll_osc_in;\n\ts32 pll_out;\n\tu32 pll_feedback_div;\n\tu32 pll_input_div;\n\tu32 pll_post_div;\n} pllm_clk_config_t;\n\ntypedef struct\n{\n\tu32 emc_rc_idx;\n\tu32 emc_rfc_idx;\n\tu32 emc_rfcpb_idx;\n\tu32 emc_refctrl2_idx;\n\tu32 emc_rfc_slr_idx;\n\tu32 emc_ras_idx;\n\tu32 emc_rp_idx;\n\tu32 emc_r2w_idx;\n\tu32 emc_w2r_idx;\n\tu32 emc_r2p_idx;\n\tu32 emc_w2p_idx;\n\tu32 emc_r2r_idx;\n\tu32 emc_tppd_idx;\n\tu32 emc_ccdmw_idx;\n\tu32 emc_rd_rcd_idx;\n\tu32 emc_wr_rcd_idx;\n\tu32 emc_rrd_idx;\n\tu32 emc_rext_idx;\n\tu32 emc_wext_idx;\n\tu32 emc_wdv_chk_idx;\n\tu32 emc_wdv_idx;\n\tu32 emc_wsv_idx;\n\tu32 emc_wev_idx;\n\tu32 emc_wdv_mask_idx;\n\tu32 emc_ws_duration_idx;\n\tu32 emc_we_duration_idx;\n\tu32 emc_quse_idx;\n\tu32 emc_quse_width_idx;\n\tu32 emc_ibdly_idx;\n\tu32 emc_obdly_idx;\n\tu32 emc_einput_idx;\n\tu32 emc_mrw6_idx;\n\tu32 emc_einput_duration_idx;\n\tu32 emc_puterm_extra_idx;\n\tu32 emc_puterm_width_idx;\n\tu32 emc_qrst_idx;\n\tu32 emc_qsafe_idx;\n\tu32 emc_rdv_idx;\n\tu32 emc_rdv_mask_idx;\n\tu32 emc_rdv_early_idx;\n\tu32 emc_rdv_early_mask_idx;\n\tu32 emc_refresh_idx;\n\tu32 emc_burst_refresh_num_idx;\n\tu32 emc_pre_refresh_req_cnt_idx;\n\tu32 emc_pdex2wr_idx;\n\tu32 emc_pdex2rd_idx;\n\tu32 emc_pchg2pden_idx;\n\tu32 emc_act2pden_idx;\n\tu32 emc_ar2pden_idx;\n\tu32 emc_rw2pden_idx;\n\tu32 emc_cke2pden_idx;\n\tu32 emc_pdex2cke_idx;\n\tu32 emc_pdex2mrr_idx;\n\tu32 emc_txsr_idx;\n\tu32 emc_txsrdll_idx;\n\tu32 emc_tcke_idx;\n\tu32 emc_tckesr_idx;\n\tu32 emc_tpd_idx;\n\tu32 emc_tfaw_idx;\n\tu32 emc_trpab_idx;\n\tu32 emc_tclkstable_idx;\n\tu32 emc_tclkstop_idx;\n\tu32 emc_mrw7_idx;\n\tu32 emc_trefbw_idx;\n\tu32 emc_odt_write_idx;\n\tu32 emc_fbio_cfg5_idx;\n\tu32 emc_fbio_cfg7_idx;\n\tu32 emc_cfg_dig_dll_idx;\n\tu32 emc_cfg_dig_dll_period_idx;\n\tu32 emc_pmacro_ib_rxrt_idx;\n\tu32 emc_cfg_pipe_1_idx;\n\tu32 emc_cfg_pipe_2_idx;\n\tu32 emc_pmacro_quse_ddll_rank0_4_idx;\n\tu32 emc_pmacro_quse_ddll_rank0_5_idx;\n\tu32 emc_pmacro_quse_ddll_rank1_4_idx;\n\tu32 emc_pmacro_quse_ddll_rank1_5_idx;\n\tu32 emc_mrw8_idx;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_4_idx;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_5_idx;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_0_idx;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_1_idx;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_2_idx;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_3_idx;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_4_idx;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_5_idx;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_0_idx;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_1_idx;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_2_idx;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_3_idx;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_4_idx;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_5_idx;\n\tu32 emc_pmacro_ddll_long_cmd_0_idx;\n\tu32 emc_pmacro_ddll_long_cmd_1_idx;\n\tu32 emc_pmacro_ddll_long_cmd_2_idx;\n\tu32 emc_pmacro_ddll_long_cmd_3_idx;\n\tu32 emc_pmacro_ddll_long_cmd_4_idx;\n\tu32 emc_pmacro_ddll_short_cmd_0_idx;\n\tu32 emc_pmacro_ddll_short_cmd_1_idx;\n\tu32 emc_pmacro_ddll_short_cmd_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_3_idx;\n\tu32 emc_txdsrvttgen_idx;\n\tu32 emc_fdpd_ctrl_dq_idx;\n\tu32 emc_fdpd_ctrl_cmd_idx;\n\tu32 emc_fbio_spare_idx;\n\tu32 emc_zcal_interval_idx;\n\tu32 emc_zcal_wait_cnt_idx;\n\tu32 emc_mrs_wait_cnt_idx;\n\tu32 emc_mrs_wait_cnt2_idx;\n\tu32 emc_auto_cal_channel_idx;\n\tu32 emc_dll_cfg_0_idx;\n\tu32 emc_dll_cfg_1_idx;\n\tu32 emc_pmacro_autocal_cfg_common_idx;\n\tu32 emc_pmacro_zctrl_idx;\n\tu32 emc_cfg_idx;\n\tu32 emc_cfg_pipe_idx;\n\tu32 emc_dyn_self_ref_control_idx;\n\tu32 emc_qpop_idx;\n\tu32 emc_dqs_brlshft_0_idx;\n\tu32 emc_dqs_brlshft_1_idx;\n\tu32 emc_cmd_brlshft_2_idx;\n\tu32 emc_cmd_brlshft_3_idx;\n\tu32 emc_pmacro_pad_cfg_ctrl_idx;\n\tu32 emc_pmacro_data_pad_rx_ctrl_idx;\n\tu32 emc_pmacro_cmd_pad_rx_ctrl_idx;\n\tu32 emc_pmacro_data_rx_term_mode_idx;\n\tu32 emc_pmacro_cmd_rx_term_mode_idx;\n\tu32 emc_pmacro_cmd_pad_tx_ctrl_idx;\n\tu32 emc_pmacro_data_pad_tx_ctrl_idx;\n\tu32 emc_pmacro_common_pad_tx_ctrl_idx;\n\tu32 emc_pmacro_vttgen_ctrl_0_idx;\n\tu32 emc_pmacro_vttgen_ctrl_1_idx;\n\tu32 emc_pmacro_vttgen_ctrl_2_idx;\n\tu32 emc_pmacro_brick_ctrl_rfu1_idx;\n\tu32 emc_pmacro_cmd_brick_ctrl_fdpd_idx;\n\tu32 emc_pmacro_brick_ctrl_rfu2_idx;\n\tu32 emc_pmacro_data_brick_ctrl_fdpd_idx;\n\tu32 emc_pmacro_bg_bias_ctrl_0_idx;\n\tu32 emc_cfg_3_idx;\n\tu32 emc_pmacro_tx_pwrd_0_idx;\n\tu32 emc_pmacro_tx_pwrd_1_idx;\n\tu32 emc_pmacro_tx_pwrd_2_idx;\n\tu32 emc_pmacro_tx_pwrd_3_idx;\n\tu32 emc_pmacro_tx_pwrd_4_idx;\n\tu32 emc_pmacro_tx_pwrd_5_idx;\n\tu32 emc_config_sample_delay_idx;\n\tu32 emc_pmacro_tx_sel_clk_src_0_idx;\n\tu32 emc_pmacro_tx_sel_clk_src_1_idx;\n\tu32 emc_pmacro_tx_sel_clk_src_2_idx;\n\tu32 emc_pmacro_tx_sel_clk_src_3_idx;\n\tu32 emc_pmacro_tx_sel_clk_src_4_idx;\n\tu32 emc_pmacro_tx_sel_clk_src_5_idx;\n\tu32 emc_pmacro_ddll_bypass_idx;\n\tu32 emc_pmacro_ddll_pwrd_0_idx;\n\tu32 emc_pmacro_ddll_pwrd_1_idx;\n\tu32 emc_pmacro_ddll_pwrd_2_idx;\n\tu32 emc_pmacro_cmd_ctrl_0_idx;\n\tu32 emc_pmacro_cmd_ctrl_1_idx;\n\tu32 emc_pmacro_cmd_ctrl_2_idx;\n\tu32 emc_tr_timing_0_idx;\n\tu32 emc_tr_dvfs_idx;\n\tu32 emc_tr_ctrl_1_idx;\n\tu32 emc_tr_rdv_idx;\n\tu32 emc_tr_qpop_idx;\n\tu32 emc_tr_rdv_mask_idx;\n\tu32 emc_mrw14_idx;\n\tu32 emc_tr_qsafe_idx;\n\tu32 emc_tr_qrst_idx;\n\tu32 emc_training_ctrl_idx;\n\tu32 emc_training_settle_idx;\n\tu32 emc_training_vref_settle_idx;\n\tu32 emc_training_ca_fine_ctrl_idx;\n\tu32 emc_training_ca_ctrl_misc_idx;\n\tu32 emc_training_ca_ctrl_misc1_idx;\n\tu32 emc_training_ca_vref_ctrl_idx;\n\tu32 emc_training_quse_cors_ctrl_idx;\n\tu32 emc_training_quse_fine_ctrl_idx;\n\tu32 emc_training_quse_ctrl_misc_idx;\n\tu32 emc_training_quse_vref_ctrl_idx;\n\tu32 emc_training_read_fine_ctrl_idx;\n\tu32 emc_training_read_ctrl_misc_idx;\n\tu32 emc_training_read_vref_ctrl_idx;\n\tu32 emc_training_write_fine_ctrl_idx;\n\tu32 emc_training_write_ctrl_misc_idx;\n\tu32 emc_training_write_vref_ctrl_idx;\n\tu32 emc_training_mpc_idx;\n\tu32 emc_mrw15_idx;\n} burst_regs_t;\n\n\ntypedef struct\n{\n\tu32 burst_regs[221];\n\tu32 burst_reg_per_ch[8];\n\tu32 shadow_regs_ca_train[221];\n\tu32 shadow_regs_quse_train[221];\n\tu32 shadow_regs_rdwr_train[221];\n} burst_regs_table_t;\n\ntypedef struct\n{\n\tu32 ptfv_dqsosc_movavg_c0d0u0_idx;\n\tu32 ptfv_dqsosc_movavg_c0d0u1_idx;\n\tu32 ptfv_dqsosc_movavg_c0d1u0_idx;\n\tu32 ptfv_dqsosc_movavg_c0d1u1_idx;\n\tu32 ptfv_dqsosc_movavg_c1d0u0_idx;\n\tu32 ptfv_dqsosc_movavg_c1d0u1_idx;\n\tu32 ptfv_dqsosc_movavg_c1d1u0_idx;\n\tu32 ptfv_dqsosc_movavg_c1d1u1_idx;\n\tu32 ptfv_write_samples_idx;\n\tu32 ptfv_dvfs_samples_idx;\n\tu32 ptfv_movavg_weight_idx;\n\tu32 ptfv_config_ctrl_idx;\n} ptfv_list_table_t;\n\ntypedef struct\n{\n\tu32 emc0_mrw10_idx;\n\tu32 emc1_mrw10_idx;\n\tu32 emc0_mrw11_idx;\n\tu32 emc1_mrw11_idx;\n\tu32 emc0_mrw12_idx;\n\tu32 emc1_mrw12_idx;\n\tu32 emc0_mrw13_idx;\n\tu32 emc1_mrw13_idx;\n} burst_reg_per_ch_t;\n\ntypedef struct\n{\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_0_idx;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_1_idx;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_2_idx;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_3_idx;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_0_idx;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_1_idx;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_2_idx;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_3_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_0_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_1_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_2_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_0_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_1_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_2_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_0_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_1_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_2_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_0_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_1_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_2_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_0_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_1_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_2_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_0_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_1_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_2_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_0_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_1_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_2_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_0_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_1_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_2_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_0_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_1_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_2_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_0_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_1_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_2_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_0_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_1_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_2_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_0_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_1_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_2_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_0_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_1_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_2_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_0_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_1_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_2_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_0_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_1_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_2_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_0_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_1_idx;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_2_idx;\n\tu32 emc_pmacro_ib_vref_dqs_0_idx;\n\tu32 emc_pmacro_ib_vref_dqs_1_idx;\n\tu32 emc_pmacro_ib_vref_dq_0_idx;\n\tu32 emc_pmacro_ib_vref_dq_1_idx;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_0_idx;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_1_idx;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_2_idx;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_3_idx;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_4_idx;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_5_idx;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_0_idx;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_1_idx;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_2_idx;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_3_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_2_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_0_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_1_idx;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_2_idx;\n\tu32 emc_pmacro_quse_ddll_rank0_0_idx;\n\tu32 emc_pmacro_quse_ddll_rank0_1_idx;\n\tu32 emc_pmacro_quse_ddll_rank0_2_idx;\n\tu32 emc_pmacro_quse_ddll_rank0_3_idx;\n\tu32 emc_pmacro_quse_ddll_rank1_0_idx;\n\tu32 emc_pmacro_quse_ddll_rank1_1_idx;\n\tu32 emc_pmacro_quse_ddll_rank1_2_idx;\n\tu32 emc_pmacro_quse_ddll_rank1_3_idx;\n} trim_regs_t;\n\ntypedef struct\n{\n\tu32 emc_cmd_brlshft_0_idx;\n\tu32 emc_cmd_brlshft_1_idx;\n\tu32 emc0_data_brlshft_0_idx;\n\tu32 emc1_data_brlshft_0_idx;\n\tu32 emc0_data_brlshft_1_idx;\n\tu32 emc1_data_brlshft_1_idx;\n\tu32 emc_quse_brlshft_0_idx;\n\tu32 emc_quse_brlshft_1_idx;\n\tu32 emc_quse_brlshft_2_idx;\n\tu32 emc_quse_brlshft_3_idx;\n} trim_perch_regs_t;\n\ntypedef struct\n{\n\tu32 t_rp;\n\tu32 t_fc_lpddr4;\n\tu32 t_rfc;\n\tu32 t_pdex;\n\tu32 rl;\n} dram_timings_t;\n\ntypedef struct\n{\n\tu32 emc0_training_opt_dqs_ib_vref_rank0_idx;\n\tu32 emc1_training_opt_dqs_ib_vref_rank0_idx;\n\tu32 emc0_training_opt_dqs_ib_vref_rank1_idx;\n\tu32 emc1_training_opt_dqs_ib_vref_rank1_idx;\n} vref_perch_regs_t;\n\ntypedef struct\n{\n\tu32 trim_regs[138];\n\tu32 trim_perch_regs[10];\n\tu32 vref_perch_regs[4];\n} trim_regs_table_t;\n\ntypedef struct\n{\n\tu32 rev;\n\tchar dvfs_ver[60];\n\tu32 rate_khz;\n\tu32 min_volt;\n\tu32 gpu_min_volt;\n\tchar clock_src[28];\n\tu32 opt_custom;\n\tu32 clk_src_emc;\n\tu32 needs_training;\n\tu32 training_pattern;\n\tu32 trained;\n\tu32 periodic_training;\n\tu32 trained_dram_clktree_c0d0u0;\n\tu32 trained_dram_clktree_c0d0u1;\n\tu32 trained_dram_clktree_c0d1u0;\n\tu32 trained_dram_clktree_c0d1u1;\n\tu32 trained_dram_clktree_c1d0u0;\n\tu32 trained_dram_clktree_c1d0u1;\n\tu32 trained_dram_clktree_c1d1u0;\n\tu32 trained_dram_clktree_c1d1u1;\n\tu32 current_dram_clktree_c0d0u0;\n\tu32 current_dram_clktree_c0d0u1;\n\tu32 current_dram_clktree_c0d1u0;\n\tu32 current_dram_clktree_c0d1u1;\n\tu32 current_dram_clktree_c1d0u0;\n\tu32 current_dram_clktree_c1d0u1;\n\tu32 current_dram_clktree_c1d1u0;\n\tu32 current_dram_clktree_c1d1u1;\n\tu32 run_clocks;\n\tu32 tree_margin;\n\tu32 num_burst;\n\tu32 num_burst_per_ch;\n\tu32 num_trim;\n\tu32 num_trim_per_ch;\n\tu32 num_mc_regs;\n\tu32 num_up_down;\n\tu32 vref_num;\n\tu32 training_mod_num;\n\tu32 dram_timing_num;\n\n\tptfv_list_table_t ptfv_list;\n\n\tburst_regs_t burst_regs;\n\tburst_reg_per_ch_t burst_reg_per_ch;\n\tburst_regs_t shadow_regs_ca_train;\n\tburst_regs_t shadow_regs_quse_train;\n\tburst_regs_t shadow_regs_rdwr_train;\n\ttrim_regs_t trim_regs;\n\ttrim_perch_regs_t trim_perch_regs;\n\tvref_perch_regs_t vref_perch_regs;\n\tdram_timings_t dram_timings;\n\n\tu32 training_mod_regs[20];\n\tu32 save_restore_mod_regs[12];\n\tu32 burst_mc_regs[33];\n\tu32 la_scale_regs[24];\n\n\tu32 min_mrs_wait;\n\tu32 emc_mrw;\n\tu32 emc_mrw2;\n\tu32 emc_mrw3;\n\tu32 emc_mrw4;\n\tu32 emc_mrw9;\n\tu32 emc_mrs;\n\tu32 emc_emrs;\n\tu32 emc_emrs2;\n\tu32 emc_auto_cal_config;\n\tu32 emc_auto_cal_config2;\n\tu32 emc_auto_cal_config3;\n\tu32 emc_auto_cal_config4;\n\tu32 emc_auto_cal_config5;\n\tu32 emc_auto_cal_config6;\n\tu32 emc_auto_cal_config7;\n\tu32 emc_auto_cal_config8;\n\tu32 emc_cfg_2;\n\tu32 emc_sel_dpd_ctrl;\n\tu32 emc_fdpd_ctrl_cmd_no_ramp;\n\tu32 dll_clk_src;\n\tu32 clk_out_enb_x_0_clk_enb_emc_dll;\n\tu32 latency;\n} emc_table_t;\n\n#endif"
  },
  {
    "path": "bdk/mem/sdram.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018 balika011\n * Copyright (c) 2019-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <mem/mc.h>\n#include <mem/emc_t210.h>\n#include <mem/sdram.h>\n#include <mem/sdram_param_t210.h>\n#include <mem/sdram_param_t210b01.h>\n#include <memory_map.h>\n#include <power/max77620.h>\n#include <power/max7762x.h>\n#include <soc/clock.h>\n#include <soc/fuse.h>\n#include <soc/hw_init.h>\n#include <soc/i2c.h>\n#include <soc/pmc.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n\n#define DRAM_ID(x) BIT(x)\n#define DRAM_CC(x) BIT(x)\n\ntypedef struct _sdram_vendor_patch_t\n{\n\tu32 val;\n\tu32 dramcf:16;\n\tu32 offset:16;\n} sdram_vendor_patch_t;\n\nstatic const u8 dram_encoding_t210b01[] = {\n/* 00 */\tLPDDR4X_UNUSED,\n/* 01 */\tLPDDR4X_UNUSED,\n/* 02 */\tLPDDR4X_UNUSED,\n/* 03 */\tLPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE,\n/* 04 */\tLPDDR4X_UNUSED,\n/* 05 */\tLPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE,\n/* 06 */\tLPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE,\n/* 07 */\tLPDDR4X_UNUSED,\n/* 08 */\tLPDDR4X_NO_PATCH,\n/* 09 */\tLPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ,\n/* 10 */\tLPDDR4X_NO_PATCH,\n/* 11 */\tLPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE,\n/* 12 */\tLPDDR4X_NO_PATCH,\n/* 13 */\tLPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ,\n/* 14 */\tLPDDR4X_NO_PATCH,\n/* 15 */\tLPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE,\n/* 16 */\tLPDDR4X_UNUSED,\n/* 17 */\tLPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL,\n/* 18 */\tLPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL,\n/* 19 */\tLPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL,\n/* 20 */\tLPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL,\n/* 21 */\tLPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL,\n/* 22 */\tLPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL,\n/* 23 */\tLPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL,\n/* 24 */\tLPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL,\n/* 25 */\tLPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF,\n/* 26 */\tLPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF,\n/* 27 */\tLPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF,\n/* 28 */\tLPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL,\n/* 29 */\tLPDDR4X_4GB_HYNIX_H54G46CYRBX267,\n/* 30 */\tLPDDR4X_4GB_HYNIX_H54G46CYRBX267,\n/* 31 */\tLPDDR4X_4GB_HYNIX_H54G46CYRBX267,\n/* 32 */\tLPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB,\n/* 33 */\tLPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB,\n/* 34 */\tLPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB,\n};\n\n#include \"sdram_config.inl\"\n#include \"sdram_config_t210b01.inl\"\n\nstatic int _sdram_wait_emc_status(u32 reg_offset, u32 bit_mask, bool updated_state, s32 emc_channel)\n{\n\tint err = 1;\n\n\tfor (s32 i = 0; i < EMC_STATUS_UPDATE_TIMEOUT; i++)\n\t{\n\t\tif (emc_channel)\n\t\t{\n\t\t\tif (emc_channel != 1)\n\t\t\t\tgoto done;\n\n\t\t\tif (((EMC_CH1(reg_offset) & bit_mask) != 0) == updated_state)\n\t\t\t{\n\t\t\t\terr = 0;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse if (((EMC(reg_offset) & bit_mask) != 0) == updated_state)\n\t\t{\n\t\t\terr = 0;\n\t\t\tbreak;\n\t\t}\n\t\tusleep(1);\n\t}\n\ndone:\n\treturn err;\n}\n\nstatic void _sdram_req_mrr_data(u32 data, bool dual_channel)\n{\n\tEMC(EMC_MRR) = data;\n\t_sdram_wait_emc_status(EMC_EMC_STATUS, EMC_STATUS_MRR_DIVLD, true, EMC_CHAN0);\n\tif (dual_channel)\n\t\t_sdram_wait_emc_status(EMC_EMC_STATUS, EMC_STATUS_MRR_DIVLD, true, EMC_CHAN1);\n}\n\nemc_mr_data_t sdram_read_mrx(emc_mr_t mrx)\n{\n\temc_mr_data_t data;\n\tu32 mrr;\n\tbool dual_rank    = EMC(EMC_ADR_CFG) & 1;\n\tbool dual_channel = (EMC(EMC_FBIO_CFG7) >> 2) & 1; // Each EMC channel is a RAM chip module.\n\n\t// Clear left overs.\n\tfor (u32 i = 0; i < 16; i++)\n\t{\n\t\t(void)EMC(EMC_MRR);\n\t\tusleep(1);\n\t}\n\n\tmemset(&data, 0xFF, sizeof(emc_mr_data_t));\n\n\t/*\n\t * When a dram chip has only one rank, then the info from the 2 ranks differs.\n\t * Info not matching is only allowed on different channels.\n\t */\n\n\t// Get Device 0 (Rank 0) info from both dram chips (channels).\n\t_sdram_req_mrr_data((2u << 30) | (mrx << 16), dual_channel);\n\n\t// Ram module 0 info.\n\tmrr = EMC_CH0(EMC_MRR);\n\tdata.chip0.rank0_ch0 = mrr & 0xFF;\n\tdata.chip0.rank0_ch1 = (mrr & 0xFF00 >> 8);\n\n\t// Ram module 1 info.\n\tif (dual_channel)\n\t{\n\t\tmrr = EMC_CH1(EMC_MRR);\n\t\tdata.chip1.rank0_ch0 = mrr & 0xFF;\n\t\tdata.chip1.rank0_ch1 = (mrr & 0xFF00 >> 8);\n\t}\n\n\t// If Rank 1 exists, get info.\n\tif (dual_rank)\n\t{\n\t\t// Get Device 1 (Rank 1) info from both dram chips (channels).\n\t\t_sdram_req_mrr_data((1u << 30) | (mrx << 16), dual_channel);\n\n\t\t// Ram module 0 info.\n\t\tmrr = EMC_CH0(EMC_MRR);\n\t\tdata.chip0.rank1_ch0 = mrr & 0xFF;\n\t\tdata.chip0.rank1_ch1 = (mrr & 0xFF00 >> 8);\n\n\t\t// Ram module 1 info.\n\t\tif (dual_channel)\n\t\t{\n\t\t\tmrr = EMC_CH1(EMC_MRR);\n\t\t\tdata.chip1.rank1_ch0 = mrr & 0xFF;\n\t\t\tdata.chip1.rank1_ch1 = (mrr & 0xFF00 >> 8);\n\t\t}\n\t}\n\n\treturn data;\n}\n\nstatic void _sdram_config_t210(const sdram_params_t210_t *params)\n{\n\t// VDDP Select.\n\tPMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel;\n\tusleep(params->pmc_vddp_sel_wait);\n\n\t// Set DDR pad voltage.\n\tPMC(APBDEV_PMC_DDR_PWR) = PMC(APBDEV_PMC_DDR_PWR); // Normally params->pmc_ddr_pwr.\n\n\t// Turn on MEM IO Power.\n\tPMC(APBDEV_PMC_NO_IOPOWER) &= PMC_NO_IOPOWER_SDMMC1; // Only keep SDMMC1 state. (Was params->pmc_no_io_power).\n\tPMC(APBDEV_PMC_REG_SHORT)   = params->pmc_reg_short;\n\n\tPMC(APBDEV_PMC_DDR_CNTRL)   = params->pmc_ddr_ctrl;\n\n\t// Patch 1 using BCT spare variables\n\tif (params->emc_bct_spare0)\n\t\t*(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1;\n\n\t// Program DPD3/DPD4 regs (coldboot path).\n\t// Enable sel_dpd on unused pins.\n\tu32 dpd_req = (params->emc_pmc_scratch1 & 0x3FFFFFFF) | PMC_IO_DPD_REQ_DPD_ON;\n\tPMC(APBDEV_PMC_IO_DPD3_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF;\n\tusleep(params->pmc_io_dpd3_req_wait);\n\n\t// Disable e_dpd_vttgen.\n\tdpd_req = (params->emc_pmc_scratch2 & 0x3FFFFFFF) | PMC_IO_DPD_REQ_DPD_ON;\n\tPMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req & 0xFFFF0000) ^ 0x3FFF0000;\n\tusleep(params->pmc_io_dpd4_req_wait);\n\n\t// Disable e_dpd_bg.\n\tPMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF;\n\tusleep(params->pmc_io_dpd4_req_wait);\n\n\tPMC(APBDEV_PMC_WEAK_BIAS) = 0;\n\tusleep(1);\n\n\t// Start PLLM.\n\tCLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = params->pllm_setup_control;\n\tCLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = 0;\n\n\tu32 pllm_div = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20);\n\tCLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = pllm_div;\n\tCLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = pllm_div | PLL_BASE_ENABLE;\n\n\tu32 wait_end = get_tmr_us() + 300;\n\twhile (!(CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) & BIT(27)))\n\t{\n\t\tif (get_tmr_us() >= wait_end)\n\t\t\tgoto lock_timeout;\n\t}\n\tusleep(10);\n\nlock_timeout:\n\t// Set clock sources.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = ((params->mc_emem_arb_misc0 >> 11) & 0x10000) | (params->emc_clock_source & 0xFFFEFFFF);\n\tif (params->emc_clock_source_dll)\n\t\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll;\n\tif (params->clear_clock2_mc1)\n\t\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = BIT(CLK_W_MC1); // Clear Reset to MC1.\n\n\t// Enable and clear reset for memory clocks.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = BIT(CLK_H_EMC) | BIT(CLK_H_MEM);\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = BIT(CLK_X_EMC_DLL);\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = BIT(CLK_H_EMC) | BIT(CLK_H_MEM);\n\n\t// Set pad vtt levels.\n\tEMC(EMC_PMACRO_VTTGEN_CTRL_0) = params->emc_pmacro_vttgen_ctrl0;\n\tEMC(EMC_PMACRO_VTTGEN_CTRL_1) = params->emc_pmacro_vttgen_ctrl1;\n\tEMC(EMC_PMACRO_VTTGEN_CTRL_2) = params->emc_pmacro_vttgen_ctrl2;\n\n\t// Trigger timing update so above writes take place.\n\tEMC(EMC_TIMING_CONTROL) = 1;\n\tusleep(10); // Ensure the regulators settle.\n\n\t// Select EMC write mux.\n\tEMC(EMC_DBG) = (params->emc_dbg_write_mux << 1) | params->emc_dbg;\n\n\t// Patch 2 using BCT spare variables.\n\tif (params->emc_bct_spare2)\n\t\t*(vu32 *)params->emc_bct_spare2 = params->emc_bct_spare3;\n\n\t// Program CMD mapping. Required before brick mapping, else\n\t// we can't guarantee CK will be differential at all times.\n\tEMC(EMC_FBIO_CFG7)          = params->emc_fbio_cfg7;\n\tEMC(EMC_CMD_MAPPING_CMD0_0) = params->emc_cmd_mapping_cmd0_0;\n\tEMC(EMC_CMD_MAPPING_CMD0_1) = params->emc_cmd_mapping_cmd0_1;\n\tEMC(EMC_CMD_MAPPING_CMD0_2) = params->emc_cmd_mapping_cmd0_2;\n\tEMC(EMC_CMD_MAPPING_CMD1_0) = params->emc_cmd_mapping_cmd1_0;\n\tEMC(EMC_CMD_MAPPING_CMD1_1) = params->emc_cmd_mapping_cmd1_1;\n\tEMC(EMC_CMD_MAPPING_CMD1_2) = params->emc_cmd_mapping_cmd1_2;\n\tEMC(EMC_CMD_MAPPING_CMD2_0) = params->emc_cmd_mapping_cmd2_0;\n\tEMC(EMC_CMD_MAPPING_CMD2_1) = params->emc_cmd_mapping_cmd2_1;\n\tEMC(EMC_CMD_MAPPING_CMD2_2) = params->emc_cmd_mapping_cmd2_2;\n\tEMC(EMC_CMD_MAPPING_CMD3_0) = params->emc_cmd_mapping_cmd3_0;\n\tEMC(EMC_CMD_MAPPING_CMD3_1) = params->emc_cmd_mapping_cmd3_1;\n\tEMC(EMC_CMD_MAPPING_CMD3_2) = params->emc_cmd_mapping_cmd3_2;\n\tEMC(EMC_CMD_MAPPING_BYTE)   = params->emc_cmd_mapping_byte;\n\n\t// Program brick mapping.\n\tEMC(EMC_PMACRO_BRICK_MAPPING_0) = params->emc_pmacro_brick_mapping0;\n\tEMC(EMC_PMACRO_BRICK_MAPPING_1) = params->emc_pmacro_brick_mapping1;\n\tEMC(EMC_PMACRO_BRICK_MAPPING_2) = params->emc_pmacro_brick_mapping2;\n\n\tEMC(EMC_PMACRO_BRICK_CTRL_RFU1) = (params->emc_pmacro_brick_ctrl_rfu1 & 0x1120112) | 0x1EED1EED;\n\n\t// This is required to do any reads from the pad macros.\n\tEMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay;\n\n\t// Set data pipes mode.\n\tEMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8;\n\n\t// Set swizzle for Rank 0.\n\tEMC(EMC_SWIZZLE_RANK0_BYTE0) = params->emc_swizzle_rank0_byte0;\n\tEMC(EMC_SWIZZLE_RANK0_BYTE1) = params->emc_swizzle_rank0_byte1;\n\tEMC(EMC_SWIZZLE_RANK0_BYTE2) = params->emc_swizzle_rank0_byte2;\n\tEMC(EMC_SWIZZLE_RANK0_BYTE3) = params->emc_swizzle_rank0_byte3;\n\t// Set swizzle for Rank 1.\n\tEMC(EMC_SWIZZLE_RANK1_BYTE0) = params->emc_swizzle_rank1_byte0;\n\tEMC(EMC_SWIZZLE_RANK1_BYTE1) = params->emc_swizzle_rank1_byte1;\n\tEMC(EMC_SWIZZLE_RANK1_BYTE2) = params->emc_swizzle_rank1_byte2;\n\tEMC(EMC_SWIZZLE_RANK1_BYTE3) = params->emc_swizzle_rank1_byte3;\n\n\t// Patch 3 using BCT spare variables.\n\tif (params->emc_bct_spare6)\n\t\t*(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7;\n\n\t// Program calibration impedance.\n\tEMC(EMC_XM2COMPPADCTRL)  = params->emc_xm2_comp_pad_ctrl;\n\tEMC(EMC_XM2COMPPADCTRL2) = params->emc_xm2_comp_pad_ctrl2;\n\tEMC(EMC_XM2COMPPADCTRL3) = params->emc_xm2_comp_pad_ctrl3;\n\n\t// Program Autocal controls.\n\tEMC(EMC_AUTO_CAL_CONFIG2) = params->emc_auto_cal_config2;\n\tEMC(EMC_AUTO_CAL_CONFIG3) = params->emc_auto_cal_config3;\n\tEMC(EMC_AUTO_CAL_CONFIG4) = params->emc_auto_cal_config4;\n\tEMC(EMC_AUTO_CAL_CONFIG5) = params->emc_auto_cal_config5;\n\tEMC(EMC_AUTO_CAL_CONFIG6) = params->emc_auto_cal_config6;\n\tEMC(EMC_AUTO_CAL_CONFIG7) = params->emc_auto_cal_config7;\n\tEMC(EMC_AUTO_CAL_CONFIG8) = params->emc_auto_cal_config8;\n\n\t// Program termination and drive strength\n\tEMC(EMC_PMACRO_RX_TERM)            = params->emc_pmacro_rx_term;\n\tEMC(EMC_PMACRO_DQ_TX_DRV)          = params->emc_pmacro_dq_tx_drive;\n\tEMC(EMC_PMACRO_CA_TX_DRV)          = params->emc_pmacro_ca_tx_drive;\n\tEMC(EMC_PMACRO_CMD_TX_DRV)         = params->emc_pmacro_cmd_tx_drive;\n\tEMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = params->emc_pmacro_auto_cal_common;\n\tEMC(EMC_AUTO_CAL_CHANNEL)          = params->emc_auto_cal_channel;\n\tEMC(EMC_PMACRO_ZCTRL)              = params->emc_pmacro_zcrtl;\n\n\t// Program dll config.\n\tEMC(EMC_DLL_CFG_0)     = params->emc_dll_cfg0;\n\tEMC(EMC_DLL_CFG_1)     = params->emc_dll_cfg1;\n\tEMC(EMC_CFG_DIG_DLL_1) = params->emc_cfg_dig_dll_1;\n\n\t// Program barrelshift.\n\tEMC(EMC_DATA_BRLSHFT_0) = params->emc_data_brlshft0;\n\tEMC(EMC_DATA_BRLSHFT_1) = params->emc_data_brlshft1;\n\tEMC(EMC_DQS_BRLSHFT_0)  = params->emc_dqs_brlshft0;\n\tEMC(EMC_DQS_BRLSHFT_1)  = params->emc_dqs_brlshft1;\n\tEMC(EMC_CMD_BRLSHFT_0)  = params->emc_cmd_brlshft0;\n\tEMC(EMC_CMD_BRLSHFT_1)  = params->emc_cmd_brlshft1;\n\tEMC(EMC_CMD_BRLSHFT_2)  = params->emc_cmd_brlshft2;\n\tEMC(EMC_CMD_BRLSHFT_3)  = params->emc_cmd_brlshft3;\n\tEMC(EMC_QUSE_BRLSHFT_0) = params->emc_quse_brlshft0;\n\tEMC(EMC_QUSE_BRLSHFT_1) = params->emc_quse_brlshft1;\n\tEMC(EMC_QUSE_BRLSHFT_2) = params->emc_quse_brlshft2;\n\tEMC(EMC_QUSE_BRLSHFT_3) = params->emc_quse_brlshft3;\n\n\t// Program pad macros controls and termination.\n\tEMC(EMC_PMACRO_BRICK_CTRL_RFU1) = (params->emc_pmacro_brick_ctrl_rfu1 & 0x1BF01BF) | 0x1E401E40;\n\tEMC(EMC_PMACRO_PAD_CFG_CTRL)    = params->emc_pmacro_pad_cfg_ctrl;\n\n\tEMC(EMC_PMACRO_CMD_BRICK_CTRL_FDPD)  = params->emc_pmacro_cmd_brick_ctrl_fdpd;\n\tEMC(EMC_PMACRO_BRICK_CTRL_RFU2)      = params->emc_pmacro_brick_ctrl_rfu2 & 0xFF7FFF7F;\n\tEMC(EMC_PMACRO_DATA_BRICK_CTRL_FDPD) = params->emc_pmacro_data_brick_ctrl_fdpd;\n\tEMC(EMC_PMACRO_BG_BIAS_CTRL_0)       = params->emc_pmacro_bg_bias_ctrl0;\n\tEMC(EMC_PMACRO_DATA_PAD_RX_CTRL)     = params->emc_pmacro_data_pad_rx_ctrl;\n\tEMC(EMC_PMACRO_CMD_PAD_RX_CTRL)      = params->emc_pmacro_cmd_pad_rx_ctrl;\n\tEMC(EMC_PMACRO_DATA_PAD_TX_CTRL)     = params->emc_pmacro_data_pad_tx_ctrl;\n\tEMC(EMC_PMACRO_DATA_RX_TERM_MODE)    = params->emc_pmacro_data_rx_term_mode;\n\tEMC(EMC_PMACRO_CMD_RX_TERM_MODE)     = params->emc_pmacro_cmd_rx_term_mode;\n\tEMC(EMC_PMACRO_CMD_PAD_TX_CTRL)      = params->emc_pmacro_cmd_pad_tx_ctrl;\n\n\t// Program pad macro pins/bytes.\n\tEMC(EMC_CFG_3)                   = params->emc_cfg3;\n\tEMC(EMC_PMACRO_TX_PWRD_0)        = params->emc_pmacro_tx_pwrd0;\n\tEMC(EMC_PMACRO_TX_PWRD_1)        = params->emc_pmacro_tx_pwrd1;\n\tEMC(EMC_PMACRO_TX_PWRD_2)        = params->emc_pmacro_tx_pwrd2;\n\tEMC(EMC_PMACRO_TX_PWRD_3)        = params->emc_pmacro_tx_pwrd3;\n\tEMC(EMC_PMACRO_TX_PWRD_4)        = params->emc_pmacro_tx_pwrd4;\n\tEMC(EMC_PMACRO_TX_PWRD_5)        = params->emc_pmacro_tx_pwrd5;\n\tEMC(EMC_PMACRO_TX_SEL_CLK_SRC_0) = params->emc_pmacro_tx_sel_clk_src0;\n\tEMC(EMC_PMACRO_TX_SEL_CLK_SRC_1) = params->emc_pmacro_tx_sel_clk_src1;\n\tEMC(EMC_PMACRO_TX_SEL_CLK_SRC_2) = params->emc_pmacro_tx_sel_clk_src2;\n\tEMC(EMC_PMACRO_TX_SEL_CLK_SRC_3) = params->emc_pmacro_tx_sel_clk_src3;\n\tEMC(EMC_PMACRO_TX_SEL_CLK_SRC_4) = params->emc_pmacro_tx_sel_clk_src4;\n\tEMC(EMC_PMACRO_TX_SEL_CLK_SRC_5) = params->emc_pmacro_tx_sel_clk_src5;\n\tEMC(EMC_PMACRO_DDLL_BYPASS)      = params->emc_pmacro_ddll_bypass;\n\tEMC(EMC_PMACRO_DDLL_PWRD_0)      = params->emc_pmacro_ddll_pwrd0;\n\tEMC(EMC_PMACRO_DDLL_PWRD_1)      = params->emc_pmacro_ddll_pwrd1;\n\tEMC(EMC_PMACRO_DDLL_PWRD_2)      = params->emc_pmacro_ddll_pwrd2;\n\tEMC(EMC_PMACRO_CMD_CTRL_0)       = params->emc_pmacro_cmd_ctrl0;\n\tEMC(EMC_PMACRO_CMD_CTRL_1)       = params->emc_pmacro_cmd_ctrl1;\n\tEMC(EMC_PMACRO_CMD_CTRL_2)       = params->emc_pmacro_cmd_ctrl2;\n\n\t// Program inbound vref setting.\n\tEMC(EMC_PMACRO_IB_VREF_DQ_0)     = params->emc_pmacro_ib_vref_dq_0;\n\tEMC(EMC_PMACRO_IB_VREF_DQ_1)     = params->emc_pmacro_ib_vref_dq_1;\n\tEMC(EMC_PMACRO_IB_VREF_DQS_0)    = params->emc_pmacro_ib_vref_dqs_0;\n\tEMC(EMC_PMACRO_IB_VREF_DQS_1)    = params->emc_pmacro_ib_vref_dqs_1;\n\tEMC(EMC_PMACRO_IB_RXRT)          = params->emc_pmacro_ib_rxrt;\n\n\t// Program quse trimmers.\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK0_0) = params->emc_pmacro_quse_ddll_rank0_0;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK0_1) = params->emc_pmacro_quse_ddll_rank0_1;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK0_2) = params->emc_pmacro_quse_ddll_rank0_2;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK0_3) = params->emc_pmacro_quse_ddll_rank0_3;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK0_4) = params->emc_pmacro_quse_ddll_rank0_4;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK0_5) = params->emc_pmacro_quse_ddll_rank0_5;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK1_0) = params->emc_pmacro_quse_ddll_rank1_0;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK1_1) = params->emc_pmacro_quse_ddll_rank1_1;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK1_2) = params->emc_pmacro_quse_ddll_rank1_2;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK1_3) = params->emc_pmacro_quse_ddll_rank1_3;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK1_4) = params->emc_pmacro_quse_ddll_rank1_4;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK1_5) = params->emc_pmacro_quse_ddll_rank1_5;\n\tEMC(EMC_PMACRO_BRICK_CTRL_RFU1)   = params->emc_pmacro_brick_ctrl_rfu1;\n\n\t// Program outbound trimmers.\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0) = params->emc_pmacro_ob_ddll_long_dq_rank0_0;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1) = params->emc_pmacro_ob_ddll_long_dq_rank0_1;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) = params->emc_pmacro_ob_ddll_long_dq_rank0_2;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3) = params->emc_pmacro_ob_ddll_long_dq_rank0_3;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4) = params->emc_pmacro_ob_ddll_long_dq_rank0_4;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5) = params->emc_pmacro_ob_ddll_long_dq_rank0_5;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0) = params->emc_pmacro_ob_ddll_long_dq_rank1_0;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1) = params->emc_pmacro_ob_ddll_long_dq_rank1_1;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2) = params->emc_pmacro_ob_ddll_long_dq_rank1_2;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3) = params->emc_pmacro_ob_ddll_long_dq_rank1_3;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4) = params->emc_pmacro_ob_ddll_long_dq_rank1_4;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5) = params->emc_pmacro_ob_ddll_long_dq_rank1_5;\n\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0) = params->emc_pmacro_ob_ddll_long_dqs_rank0_0;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1) = params->emc_pmacro_ob_ddll_long_dqs_rank0_1;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2) = params->emc_pmacro_ob_ddll_long_dqs_rank0_2;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3) = params->emc_pmacro_ob_ddll_long_dqs_rank0_3;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4) = params->emc_pmacro_ob_ddll_long_dqs_rank0_4;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5) = params->emc_pmacro_ob_ddll_long_dqs_rank0_5;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0) = params->emc_pmacro_ob_ddll_long_dqs_rank1_0;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1) = params->emc_pmacro_ob_ddll_long_dqs_rank1_1;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2) = params->emc_pmacro_ob_ddll_long_dqs_rank1_2;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3) = params->emc_pmacro_ob_ddll_long_dqs_rank1_3;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4) = params->emc_pmacro_ob_ddll_long_dqs_rank1_4;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5) = params->emc_pmacro_ob_ddll_long_dqs_rank1_5;\n\tEMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0) = params->emc_pmacro_ib_ddll_long_dqs_rank0_0;\n\tEMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1) = params->emc_pmacro_ib_ddll_long_dqs_rank0_1;\n\tEMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2) = params->emc_pmacro_ib_ddll_long_dqs_rank0_2;\n\tEMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3) = params->emc_pmacro_ib_ddll_long_dqs_rank0_3;\n\tEMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0) = params->emc_pmacro_ib_ddll_long_dqs_rank1_0;\n\tEMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1) = params->emc_pmacro_ib_ddll_long_dqs_rank1_1;\n\tEMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2) = params->emc_pmacro_ib_ddll_long_dqs_rank1_2;\n\tEMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3) = params->emc_pmacro_ib_ddll_long_dqs_rank1_3;\n\n\t// Program clock trimmers.\n\tEMC(EMC_PMACRO_DDLL_LONG_CMD_0)  = params->emc_pmacro_ddll_long_cmd_0;\n\tEMC(EMC_PMACRO_DDLL_LONG_CMD_1)  = params->emc_pmacro_ddll_long_cmd_1;\n\tEMC(EMC_PMACRO_DDLL_LONG_CMD_2)  = params->emc_pmacro_ddll_long_cmd_2;\n\tEMC(EMC_PMACRO_DDLL_LONG_CMD_3)  = params->emc_pmacro_ddll_long_cmd_3;\n\tEMC(EMC_PMACRO_DDLL_LONG_CMD_4)  = params->emc_pmacro_ddll_long_cmd_4;\n\tEMC(EMC_PMACRO_DDLL_SHORT_CMD_0) = params->emc_pmacro_ddll_short_cmd_0;\n\tEMC(EMC_PMACRO_DDLL_SHORT_CMD_1) = params->emc_pmacro_ddll_short_cmd_1;\n\tEMC(EMC_PMACRO_DDLL_SHORT_CMD_2) = params->emc_pmacro_ddll_short_cmd_2;\n\n\t// Common pad macro (cpm).\n\tEMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = (params->emc_pmacro_common_pad_tx_ctrl & 1) | 0xE;\n\n\t// Patch 4 using BCT spare variables.\n\tif (params->emc_bct_spare4)\n\t\t*(vu32 *)params->emc_bct_spare4 = params->emc_bct_spare5;\n\n\t// Trigger timing update so above writes take place.\n\tEMC(EMC_TIMING_CONTROL) = 1;\n\n\t// Initialize MC VPR settings.\n\tMC(MC_VIDEO_PROTECT_BOM)            = params->mc_video_protect_bom;\n\tMC(MC_VIDEO_PROTECT_BOM_ADR_HI)     = params->mc_video_protect_bom_adr_hi;\n\tMC(MC_VIDEO_PROTECT_SIZE_MB)        = params->mc_video_protect_size_mb;\n\tMC(MC_VIDEO_PROTECT_VPR_OVERRIDE)   = params->mc_video_protect_vpr_override;\n\tMC(MC_VIDEO_PROTECT_VPR_OVERRIDE1)  = params->mc_video_protect_vpr_override1;\n\tMC(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) = params->mc_video_protect_gpu_override0;\n\tMC(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) = params->mc_video_protect_gpu_override1;\n\n\t// Program SDRAM geometry parameters.\n\tMC(MC_EMEM_ADR_CFG)              = params->mc_emem_adr_cfg;\n\tMC(MC_EMEM_ADR_CFG_DEV0)         = params->mc_emem_adr_cfg_dev0;\n\tMC(MC_EMEM_ADR_CFG_DEV1)         = params->mc_emem_adr_cfg_dev1;\n\tMC(MC_EMEM_ADR_CFG_CHANNEL_MASK) = params->mc_emem_adr_cfg_channel_mask;\n\n\t// Program bank swizzling.\n\tMC(MC_EMEM_ADR_CFG_BANK_MASK_0) = params->mc_emem_adr_cfg_bank_mask0;\n\tMC(MC_EMEM_ADR_CFG_BANK_MASK_1) = params->mc_emem_adr_cfg_bank_mask1;\n\tMC(MC_EMEM_ADR_CFG_BANK_MASK_2) = params->mc_emem_adr_cfg_bank_mask2;\n\n\t// Program external memory aperture (base and size).\n\tMC(MC_EMEM_CFG) = params->mc_emem_cfg;\n\n\t// Program SEC carveout (base and size).\n\tMC(MC_SEC_CARVEOUT_BOM)     = params->mc_sec_carveout_bom;\n\tMC(MC_SEC_CARVEOUT_ADR_HI)  = params->mc_sec_carveout_adr_hi;\n\tMC(MC_SEC_CARVEOUT_SIZE_MB) = params->mc_sec_carveout_size_mb;\n\n\t// Program MTS carveout (base and size).\n\tMC(MC_MTS_CARVEOUT_BOM)     = params->mc_mts_carveout_bom;\n\tMC(MC_MTS_CARVEOUT_ADR_HI)  = params->mc_mts_carveout_adr_hi;\n\tMC(MC_MTS_CARVEOUT_SIZE_MB) = params->mc_mts_carveout_size_mb;\n\n\t// Program the memory arbiter.\n\tMC(MC_EMEM_ARB_CFG)             = params->mc_emem_arb_cfg;\n\tMC(MC_EMEM_ARB_OUTSTANDING_REQ) = params->mc_emem_arb_outstanding_req;\n\tMC(MC_EMEM_ARB_REFPB_HP_CTRL)   = params->emc_emem_arb_refpb_hp_ctrl;\n\tMC(MC_EMEM_ARB_REFPB_BANK_CTRL) = params->emc_emem_arb_refpb_bank_ctrl;\n\tMC(MC_EMEM_ARB_TIMING_RCD)      = params->mc_emem_arb_timing_rcd;\n\tMC(MC_EMEM_ARB_TIMING_RP)       = params->mc_emem_arb_timing_rp;\n\tMC(MC_EMEM_ARB_TIMING_RC)       = params->mc_emem_arb_timing_rc;\n\tMC(MC_EMEM_ARB_TIMING_RAS)      = params->mc_emem_arb_timing_ras;\n\tMC(MC_EMEM_ARB_TIMING_FAW)      = params->mc_emem_arb_timing_faw;\n\tMC(MC_EMEM_ARB_TIMING_RRD)      = params->mc_emem_arb_timing_rrd;\n\tMC(MC_EMEM_ARB_TIMING_RAP2PRE)  = params->mc_emem_arb_timing_rap2pre;\n\tMC(MC_EMEM_ARB_TIMING_WAP2PRE)  = params->mc_emem_arb_timing_wap2pre;\n\tMC(MC_EMEM_ARB_TIMING_R2R)      = params->mc_emem_arb_timing_r2r;\n\tMC(MC_EMEM_ARB_TIMING_W2W)      = params->mc_emem_arb_timing_w2w;\n\tMC(MC_EMEM_ARB_TIMING_CCDMW)    = params->mc_emem_arb_timing_ccdmw;\n\tMC(MC_EMEM_ARB_TIMING_R2W)      = params->mc_emem_arb_timing_r2w;\n\tMC(MC_EMEM_ARB_TIMING_W2R)      = params->mc_emem_arb_timing_w2r;\n\tMC(MC_EMEM_ARB_TIMING_RFCPB)    = params->mc_emem_arb_timing_rfcpb;\n\tMC(MC_EMEM_ARB_DA_TURNS)        = params->mc_emem_arb_da_turns;\n\tMC(MC_EMEM_ARB_DA_COVERS)       = params->mc_emem_arb_da_covers;\n\tMC(MC_EMEM_ARB_MISC0)           = params->mc_emem_arb_misc0;\n\tMC(MC_EMEM_ARB_MISC1)           = params->mc_emem_arb_misc1;\n\tMC(MC_EMEM_ARB_MISC2)           = params->mc_emem_arb_misc2;\n\tMC(MC_EMEM_ARB_RING1_THROTTLE)  = params->mc_emem_arb_ring1_throttle;\n\tMC(MC_EMEM_ARB_OVERRIDE)        = params->mc_emem_arb_override;\n\tMC(MC_EMEM_ARB_OVERRIDE_1)      = params->mc_emem_arb_override1;\n\tMC(MC_EMEM_ARB_RSV)             = params->mc_emem_arb_rsv;\n\tMC(MC_DA_CONFIG0)               = params->mc_da_cfg0;\n\n\t// Trigger MC timing update.\n\tMC(MC_TIMING_CONTROL) = 1;\n\n\t// Program second-level clock enable overrides.\n\tMC(MC_CLKEN_OVERRIDE) = params->mc_clken_override;\n\n\t// Program statistics gathering.\n\tMC(MC_STAT_CONTROL) = params->mc_stat_control;\n\n\t// Program SDRAM geometry parameters.\n\tEMC(EMC_ADR_CFG) = params->emc_adr_cfg;\n\n\t// Program second-level clock enable overrides.\n\tEMC(EMC_CLKEN_OVERRIDE) = params->emc_clken_override;\n\n\t// Program EMC pad auto calibration.\n\tEMC(EMC_PMACRO_AUTOCAL_CFG_0) = params->emc_pmacro_auto_cal_cfg0;\n\tEMC(EMC_PMACRO_AUTOCAL_CFG_1) = params->emc_pmacro_auto_cal_cfg1;\n\tEMC(EMC_PMACRO_AUTOCAL_CFG_2) = params->emc_pmacro_auto_cal_cfg2;\n\n\tEMC(EMC_AUTO_CAL_VREF_SEL_0) = params->emc_auto_cal_vref_sel0;\n\tEMC(EMC_AUTO_CAL_VREF_SEL_1) = params->emc_auto_cal_vref_sel1;\n\n\t// Program/Start auto calibration.\n\tEMC(EMC_AUTO_CAL_INTERVAL) = params->emc_auto_cal_interval;\n\tEMC(EMC_AUTO_CAL_CONFIG)   = params->emc_auto_cal_config;\n\tusleep(params->emc_auto_cal_wait);\n\n\t// Patch 5 using BCT spare variables.\n\tif (params->emc_bct_spare8)\n\t\t*(vu32 *)params->emc_bct_spare8 = params->emc_bct_spare9;\n\n\t// Program EMC timing configuration.\n\tEMC(EMC_CFG_2)           = params->emc_cfg2;\n\tEMC(EMC_CFG_PIPE)        = params->emc_cfg_pipe;\n\tEMC(EMC_CFG_PIPE_1)      = params->emc_cfg_pipe1;\n\tEMC(EMC_CFG_PIPE_2)      = params->emc_cfg_pipe2;\n\tEMC(EMC_CMDQ)            = params->emc_cmd_q;\n\tEMC(EMC_MC2EMCQ)         = params->emc_mc2emc_q;\n\tEMC(EMC_MRS_WAIT_CNT)    = params->emc_mrs_wait_cnt;\n\tEMC(EMC_MRS_WAIT_CNT2)   = params->emc_mrs_wait_cnt2;\n\tEMC(EMC_FBIO_CFG5)       = params->emc_fbio_cfg5;\n\tEMC(EMC_RC)              = params->emc_rc;\n\tEMC(EMC_RFC)             = params->emc_rfc;\n\tEMC(EMC_RFCPB)           = params->emc_rfc_pb;\n\tEMC(EMC_REFCTRL2)        = params->emc_ref_ctrl2;\n\tEMC(EMC_RFC_SLR)         = params->emc_rfc_slr;\n\tEMC(EMC_RAS)             = params->emc_ras;\n\tEMC(EMC_RP)              = params->emc_rp;\n\tEMC(EMC_TPPD)            = params->emc_tppd;\n\tEMC(EMC_R2R)             = params->emc_r2r;\n\tEMC(EMC_W2W)             = params->emc_w2w;\n\tEMC(EMC_R2W)             = params->emc_r2w;\n\tEMC(EMC_W2R)             = params->emc_w2r;\n\tEMC(EMC_R2P)             = params->emc_r2p;\n\tEMC(EMC_W2P)             = params->emc_w2p;\n\tEMC(EMC_CCDMW)           = params->emc_ccdmw;\n\tEMC(EMC_RD_RCD)          = params->emc_rd_rcd;\n\tEMC(EMC_WR_RCD)          = params->emc_wr_rcd;\n\tEMC(EMC_RRD)             = params->emc_rrd;\n\tEMC(EMC_REXT)            = params->emc_rext;\n\tEMC(EMC_WEXT)            = params->emc_wext;\n\tEMC(EMC_WDV)             = params->emc_wdv;\n\tEMC(EMC_WDV_CHK)         = params->emc_wdv_chk;\n\tEMC(EMC_WSV)             = params->emc_wsv;\n\tEMC(EMC_WEV)             = params->emc_wev;\n\tEMC(EMC_WDV_MASK)        = params->emc_wdv_mask;\n\tEMC(EMC_WS_DURATION)     = params->emc_ws_duration;\n\tEMC(EMC_WE_DURATION)     = params->emc_we_duration;\n\tEMC(EMC_QUSE)            = params->emc_quse;\n\tEMC(EMC_QUSE_WIDTH)      = params->emc_quse_width;\n\tEMC(EMC_IBDLY)           = params->emc_ibdly;\n\tEMC(EMC_OBDLY)           = params->emc_obdly;\n\tEMC(EMC_EINPUT)          = params->emc_einput;\n\tEMC(EMC_EINPUT_DURATION) = params->emc_einput_duration;\n\tEMC(EMC_PUTERM_EXTRA)    = params->emc_puterm_extra;\n\tEMC(EMC_PUTERM_WIDTH)    = params->emc_puterm_width;\n\n\tEMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = params->emc_pmacro_common_pad_tx_ctrl;\n\tEMC(EMC_DBG)                 = params->emc_dbg;\n\n\t// Clear read fifo.\n\tEMC(EMC_QRST)                = params->emc_qrst;\n\tEMC(EMC_ISSUE_QRST)          = 1;\n\tEMC(EMC_ISSUE_QRST)          = 0;\n\n\t// Program the rest of EMC timing configuration.\n\tEMC(EMC_QSAFE)               = params->emc_qsafe;\n\tEMC(EMC_RDV)                 = params->emc_rdv;\n\tEMC(EMC_RDV_MASK)            = params->emc_rdv_mask;\n\tEMC(EMC_RDV_EARLY)           = params->emc_rdv_early;\n\tEMC(EMC_RDV_EARLY_MASK)      = params->emc_rdv_early_mask;\n\tEMC(EMC_QPOP)                = params->emc_qpop;\n\tEMC(EMC_REFRESH)             = params->emc_refresh;\n\tEMC(EMC_BURST_REFRESH_NUM)   = params->emc_burst_refresh_num;\n\tEMC(EMC_PRE_REFRESH_REQ_CNT) = params->emc_prerefresh_req_cnt;\n\tEMC(EMC_PDEX2WR)             = params->emc_pdex2wr;\n\tEMC(EMC_PDEX2RD)             = params->emc_pdex2rd;\n\tEMC(EMC_PCHG2PDEN)           = params->emc_pchg2pden;\n\tEMC(EMC_ACT2PDEN)            = params->emc_act2pden;\n\tEMC(EMC_AR2PDEN)             = params->emc_ar2pden;\n\tEMC(EMC_RW2PDEN)             = params->emc_rw2pden;\n\tEMC(EMC_CKE2PDEN)            = params->emc_cke2pden;\n\tEMC(EMC_PDEX2CKE)            = params->emc_pdex2che;\n\tEMC(EMC_PDEX2MRR)            = params->emc_pdex2mrr;\n\tEMC(EMC_TXSR)                = params->emc_txsr;\n\tEMC(EMC_TXSRDLL)             = params->emc_txsr_dll;\n\tEMC(EMC_TCKE)                = params->emc_tcke;\n\tEMC(EMC_TCKESR)              = params->emc_tckesr;\n\tEMC(EMC_TPD)                 = params->emc_tpd;\n\tEMC(EMC_TFAW)                = params->emc_tfaw;\n\tEMC(EMC_TRPAB)               = params->emc_trpab;\n\tEMC(EMC_TCLKSTABLE)          = params->emc_tclkstable;\n\tEMC(EMC_TCLKSTOP)            = params->emc_tclkstop;\n\tEMC(EMC_TREFBW)              = params->emc_trefbw;\n\tEMC(EMC_ODT_WRITE)           = params->emc_odt_write;\n\tEMC(EMC_CFG_DIG_DLL)         = params->emc_cfg_dig_dll;\n\tEMC(EMC_CFG_DIG_DLL_PERIOD)  = params->emc_cfg_dig_dll_period;\n\n\t// Don't write CFG_ADR_EN (bit 1) here - lock bit written later.\n\tEMC(EMC_FBIO_SPARE)   = params->emc_fbio_spare & 0xFFFFFFFD;\n\tEMC(EMC_CFG_RSV)      = params->emc_cfg_rsv;\n\tEMC(EMC_PMC_SCRATCH1) = params->emc_pmc_scratch1;\n\tEMC(EMC_PMC_SCRATCH2) = params->emc_pmc_scratch2;\n\tEMC(EMC_PMC_SCRATCH3) = params->emc_pmc_scratch3;\n\tEMC(EMC_ACPD_CONTROL) = params->emc_acpd_control;\n\tEMC(EMC_TXDSRVTTGEN)  = params->emc_txdsrvttgen;\n\n\t// Set pipe bypass enable bits before sending any DRAM commands.\n\tEMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000;\n\n\t// Patch BootROM.\n\tif (params->boot_rom_patch_control & BIT(31))\n\t{\n\t\t*(vu32 *)(APB_MISC_BASE + params->boot_rom_patch_control * 4) = params->boot_rom_patch_data;\n\n\t\t// Trigger MC timing update.\n\t\tMC(MC_TIMING_CONTROL) = 1;\n\t}\n\n\t// Release SEL_DPD_CMD.\n\tPMC(APBDEV_PMC_IO_DPD3_REQ) = (params->emc_pmc_scratch1 & 0xFFF0000) | PMC_IO_DPD_REQ_DPD_OFF;\n\tusleep(params->pmc_io_dpd3_req_wait);\n\n\t// Stall auto call measurements if periodic calibration is disabled.\n\tif (!params->emc_auto_cal_interval)\n\t\tEMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config | 0x200;\n\n\tEMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2;\n\n\t// ZQ CAL setup (not actually issuing ZQ CAL now).\n\tif (params->emc_zcal_warm_cold_boot_enables & 1)\n\t{\n\t\tEMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt;\n\t\tEMC(EMC_ZCAL_MRW_CMD)  = params->emc_zcal_mrw_cmd;\n\t}\n\n\t// Trigger timing update so above writes take place.\n\tEMC(EMC_TIMING_CONTROL) = 1;\n\tusleep(params->emc_timing_control_wait);\n\n\t// Deassert HOLD_CKE_LOW.\n\tPMC(APBDEV_PMC_DDR_CNTRL) &= 0xFFF8007F;\n\tusleep(params->pmc_ddr_ctrl_wait);\n\n\t// Set clock enable signal.\n\tu32 pin_gpio_cfg = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12);\n\tEMC(EMC_PIN) = pin_gpio_cfg;\n\t(void)EMC(EMC_PIN);\n\tusleep(params->emc_pin_extra_wait + 200);\n\tEMC(EMC_PIN) = pin_gpio_cfg | 0x100;\n\t(void)EMC(EMC_PIN);\n\n\tusleep(params->emc_pin_extra_wait + 2000);\n\n\t// Enable clock enable signal.\n\tEMC(EMC_PIN) = pin_gpio_cfg | 0x101;\n\t(void)EMC(EMC_PIN);\n\tusleep(params->emc_pin_program_wait);\n\n\t// Init zq calibration,\n\t// Patch 6 using BCT spare variables.\n\tif (params->emc_bct_spare10)\n\t\t*(vu32 *)params->emc_bct_spare10 = params->emc_bct_spare11;\n\n\t// Write mode registers.\n\tEMC(EMC_MRW2)  = params->emc_mrw2;\n\tEMC(EMC_MRW)   = params->emc_mrw1;\n\tEMC(EMC_MRW3)  = params->emc_mrw3;\n\tEMC(EMC_MRW4)  = params->emc_mrw4;\n\tEMC(EMC_MRW6)  = params->emc_mrw6;\n\tEMC(EMC_MRW14) = params->emc_mrw14;\n\n\tEMC(EMC_MRW8)  = params->emc_mrw8;\n\tEMC(EMC_MRW12) = params->emc_mrw12;\n\tEMC(EMC_MRW9)  = params->emc_mrw9;\n\tEMC(EMC_MRW13) = params->emc_mrw13;\n\n\tif (params->emc_zcal_warm_cold_boot_enables & 1)\n\t{\n\t\t// Issue ZQCAL start, device 0.\n\t\tEMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0;\n\t\tusleep(params->emc_zcal_init_wait);\n\n\t\t// Issue ZQCAL latch.\n\t\tEMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0 ^ 3;\n\t\t// Same for device 1.\n\t\tif (!(params->emc_dev_select & 2))\n\t\t{\n\t\t\tEMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1;\n\t\t\tusleep(params->emc_zcal_init_wait);\n\t\t\tEMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1 ^ 3;\n\t\t}\n\t}\n\n\t// Set package and DPD pad control.\n\tPMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg;\n\n\t// Start periodic ZQ calibration (LPDDRx only).\n\tEMC(EMC_ZCAL_INTERVAL) = params->emc_zcal_interval;\n\tEMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt;\n\tEMC(EMC_ZCAL_MRW_CMD)  = params->emc_zcal_mrw_cmd;\n\n\t// Patch 7 using BCT spare variables.\n\tif (params->emc_bct_spare12)\n\t\t*(vu32 *)params->emc_bct_spare12 = params->emc_bct_spare13;\n\n\t// Trigger timing update so above writes take place.\n\tEMC(EMC_TIMING_CONTROL) = 1;\n\n\tif (params->emc_extra_refresh_num)\n\t\tEMC(EMC_REF) = (((1 << params->emc_extra_refresh_num) - 1) << 8) | (params->emc_dev_select << 30) | 3;\n\n\t// Enable refresh.\n\tEMC(EMC_REFCTRL) = params->emc_dev_select | BIT(31);\n\n\tEMC(EMC_DYN_SELF_REF_CONTROL) = params->emc_dyn_self_ref_control;\n\tEMC(EMC_CFG_UPDATE)    = params->emc_cfg_update;\n\tEMC(EMC_CFG)           = params->emc_cfg;\n\tEMC(EMC_FDPD_CTRL_DQ)  = params->emc_fdpd_ctrl_dq;\n\tEMC(EMC_FDPD_CTRL_CMD) = params->emc_fdpd_ctrl_cmd;\n\tEMC(EMC_SEL_DPD_CTRL)  = params->emc_sel_dpd_ctrl;\n\n\t// Write addr swizzle lock bit.\n\tEMC(EMC_FBIO_SPARE) = params->emc_fbio_spare | BIT(1);\n\n\t// Re-trigger timing to latch power saving functions.\n\tEMC(EMC_TIMING_CONTROL) = 1;\n\n\t// Enable EMC pipe clock gating.\n\tEMC(EMC_CFG_PIPE_CLK) = params->emc_cfg_pipe_clk;\n\n\t// Depending on freqency, enable CMD/CLK fdpd.\n\tEMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = params->emc_fdpd_ctrl_cmd_no_ramp;\n\n\t// Enable arbiter.\n\tSYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | (params->ahb_arbitration_xbar_ctrl_meminit_done << 16);\n\n\t// Lock carveouts per BCT cfg.\n\tMC(MC_VIDEO_PROTECT_REG_CTRL) = params->mc_video_protect_write_access;\n\tMC(MC_SEC_CARVEOUT_REG_CTRL)  = params->mc_sec_carveout_protect_write_access;\n\tMC(MC_MTS_CARVEOUT_REG_CTRL)  = params->mc_mts_carveout_reg_ctrl;\n\n\t// Disable write access to a bunch of EMC registers.\n\tMC(MC_EMEM_CFG_ACCESS_CTRL) = 1;\n}\n\nstatic void _sdram_config_t210b01(const sdram_params_t210b01_t *params)\n{\n\t// VDDP Select.\n\tPMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel;\n\tusleep(params->pmc_vddp_sel_wait);\n\n\t// Turn on MEM IO Power.\n\tPMC(APBDEV_PMC_NO_IOPOWER) &= PMC_NO_IOPOWER_SDMMC1; // Only keep SDMMC1 state. (Was params->pmc_no_io_power).\n\tPMC(APBDEV_PMC_REG_SHORT)   = params->pmc_reg_short;\n\n\tPMC(APBDEV_PMC_DDR_CNTRL)   = params->pmc_ddr_ctrl;\n\n\t// Patch 1 using BCT spare variables\n\tif (params->emc_bct_spare0)\n\t\t*(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1;\n\n\t// Override HW FSM if needed.\n\tif (params->clk_rst_pllm_misc20_override_enable)\n\t\tCLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = params->clk_rst_pllm_misc20_override;\n\n\t// Program DPD3/DPD4 regs (coldboot path).\n\t// Enable sel_dpd on unused pins.\n\tu32 pmc_scratch1 = ~params->emc_pmc_scratch1;\n\tPMC(APBDEV_PMC_WEAK_BIAS)   = (pmc_scratch1 & 0x1000) << 19 | (pmc_scratch1 & 0xFFF) << 18 | (pmc_scratch1 & 0x8000) << 15;\n\tPMC(APBDEV_PMC_IO_DPD3_REQ) = (pmc_scratch1 & 0x9FFF) | PMC_IO_DPD_REQ_DPD_ON;\n\tusleep(params->pmc_io_dpd3_req_wait);\n\n\t// Disable e_dpd_vttgen.\n\tu32 pmc_scratch2 = ~params->emc_pmc_scratch2;\n\tPMC(APBDEV_PMC_IO_DPD4_REQ) = (pmc_scratch2 & 0x3FFF0000) | PMC_IO_DPD_REQ_DPD_ON;\n\tusleep(params->pmc_io_dpd4_req_wait);\n\n\t// Disable e_dpd_bg.\n\tPMC(APBDEV_PMC_IO_DPD4_REQ) = (pmc_scratch2 & 0x1FFF) | PMC_IO_DPD_REQ_DPD_ON;\n\tusleep(1);\n\n\t// Program CMD mapping. Required before brick mapping, else\n\t// we can't guarantee CK will be differential at all times.\n\tEMC(EMC_FBIO_CFG7)          = params->emc_fbio_cfg7;\n\tEMC(EMC_CMD_MAPPING_CMD0_0) = params->emc_cmd_mapping_cmd0_0;\n\tEMC(EMC_CMD_MAPPING_CMD0_1) = params->emc_cmd_mapping_cmd0_1;\n\tEMC(EMC_CMD_MAPPING_CMD0_2) = params->emc_cmd_mapping_cmd0_2;\n\tEMC(EMC_CMD_MAPPING_CMD1_0) = params->emc_cmd_mapping_cmd1_0;\n\tEMC(EMC_CMD_MAPPING_CMD1_1) = params->emc_cmd_mapping_cmd1_1;\n\tEMC(EMC_CMD_MAPPING_CMD1_2) = params->emc_cmd_mapping_cmd1_2;\n\tEMC(EMC_CMD_MAPPING_CMD2_0) = params->emc_cmd_mapping_cmd2_0;\n\tEMC(EMC_CMD_MAPPING_CMD2_1) = params->emc_cmd_mapping_cmd2_1;\n\tEMC(EMC_CMD_MAPPING_CMD2_2) = params->emc_cmd_mapping_cmd2_2;\n\tEMC(EMC_CMD_MAPPING_CMD3_0) = params->emc_cmd_mapping_cmd3_0;\n\tEMC(EMC_CMD_MAPPING_CMD3_1) = params->emc_cmd_mapping_cmd3_1;\n\tEMC(EMC_CMD_MAPPING_CMD3_2) = params->emc_cmd_mapping_cmd3_2;\n\tEMC(EMC_CMD_MAPPING_BYTE)   = params->emc_cmd_mapping_byte;\n\n\t// Program brick mapping.\n\tEMC(EMC_PMACRO_BRICK_MAPPING_0) = params->emc_pmacro_brick_mapping0;\n\tEMC(EMC_PMACRO_BRICK_MAPPING_1) = params->emc_pmacro_brick_mapping1;\n\tEMC(EMC_PMACRO_BRICK_MAPPING_2) = params->emc_pmacro_brick_mapping2;\n\n\t// Set pad macros.\n\tEMC(EMC_PMACRO_VTTGEN_CTRL_0) = params->emc_pmacro_vttgen_ctrl0;\n\tEMC(EMC_PMACRO_VTTGEN_CTRL_1) = params->emc_pmacro_vttgen_ctrl1;\n\tEMC(EMC_PMACRO_VTTGEN_CTRL_2) = params->emc_pmacro_vttgen_ctrl2;\n\n\t// Set pad macros bias.\n\tEMC(EMC_PMACRO_BG_BIAS_CTRL_0) = params->emc_pmacro_bg_bias_ctrl0;\n\n\t// Patch 1 to 3 using BCT spare secure variables.\n\tif (params->emc_bct_spare_secure0)\n\t\t*(vu32 *)params->emc_bct_spare_secure0 = params->emc_bct_spare_secure1;\n\tif (params->emc_bct_spare_secure2)\n\t\t*(vu32 *)params->emc_bct_spare_secure2 = params->emc_bct_spare_secure3;\n\tif (params->emc_bct_spare_secure4)\n\t\t*(vu32 *)params->emc_bct_spare_secure4 = params->emc_bct_spare_secure5;\n\n\t// Trigger timing update so above writes take place.\n\tEMC(EMC_TIMING_CONTROL) = 1;\n\tusleep(params->pmc_vddp_sel_wait + 2); // Ensure the regulators settle.\n\n\t// Set clock sources.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC)     = params->emc_clock_source;\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll;\n\n\t// Select EMC write mux.\n\tEMC(EMC_DBG) = (params->emc_dbg_write_mux << 1) | params->emc_dbg;\n\n\t// Patch 2 using BCT spare variables.\n\tif (params->emc_bct_spare2)\n\t\t*(vu32 *)params->emc_bct_spare2 = params->emc_bct_spare3;\n\n\t// This is required to do any reads from the pad macros.\n\tEMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay;\n\n\t// Set data pipes mode.\n\tEMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8;\n\n\t// Set swizzle for Rank 0.\n\tEMC(EMC_SWIZZLE_RANK0_BYTE0) = params->emc_swizzle_rank0_byte0;\n\tEMC(EMC_SWIZZLE_RANK0_BYTE1) = params->emc_swizzle_rank0_byte1;\n\tEMC(EMC_SWIZZLE_RANK0_BYTE2) = params->emc_swizzle_rank0_byte2;\n\tEMC(EMC_SWIZZLE_RANK0_BYTE3) = params->emc_swizzle_rank0_byte3;\n\t// Set swizzle for Rank 1.\n\tEMC(EMC_SWIZZLE_RANK1_BYTE0) = params->emc_swizzle_rank1_byte0;\n\tEMC(EMC_SWIZZLE_RANK1_BYTE1) = params->emc_swizzle_rank1_byte1;\n\tEMC(EMC_SWIZZLE_RANK1_BYTE2) = params->emc_swizzle_rank1_byte2;\n\tEMC(EMC_SWIZZLE_RANK1_BYTE3) = params->emc_swizzle_rank1_byte3;\n\n\t// Patch 3 using BCT spare variables.\n\tif (params->emc_bct_spare6)\n\t\t*(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7;\n\n\t// Program calibration impedance.\n\tEMC(EMC_XM2COMPPADCTRL)  = params->emc_xm2_comp_pad_ctrl;\n\tEMC(EMC_XM2COMPPADCTRL2) = params->emc_xm2_comp_pad_ctrl2;\n\tEMC(EMC_XM2COMPPADCTRL3) = params->emc_xm2_comp_pad_ctrl3;\n\n\t// Program Autocal controls.\n\tEMC(EMC_AUTO_CAL_CONFIG2) = params->emc_auto_cal_config2;\n\tEMC(EMC_AUTO_CAL_CONFIG3) = params->emc_auto_cal_config3;\n\tEMC(EMC_AUTO_CAL_CONFIG4) = params->emc_auto_cal_config4;\n\tEMC(EMC_AUTO_CAL_CONFIG5) = params->emc_auto_cal_config5;\n\tEMC(EMC_AUTO_CAL_CONFIG6) = params->emc_auto_cal_config6;\n\tEMC(EMC_AUTO_CAL_CONFIG7) = params->emc_auto_cal_config7;\n\tEMC(EMC_AUTO_CAL_CONFIG8) = params->emc_auto_cal_config8;\n\n\t// Program termination and drive strength\n\tEMC(EMC_PMACRO_RX_TERM)            = params->emc_pmacro_rx_term;\n\tEMC(EMC_PMACRO_DQ_TX_DRV)          = params->emc_pmacro_dq_tx_drive;\n\tEMC(EMC_PMACRO_CA_TX_DRV)          = params->emc_pmacro_ca_tx_drive;\n\tEMC(EMC_PMACRO_CMD_TX_DRV)         = params->emc_pmacro_cmd_tx_drive;\n\tEMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = params->emc_pmacro_auto_cal_common;\n\tEMC(EMC_AUTO_CAL_CHANNEL)          = params->emc_auto_cal_channel;\n\tEMC(EMC_PMACRO_ZCTRL)              = params->emc_pmacro_zcrtl;\n\n\t// Program dll config.\n\tEMC(EMC_DLL_CFG_0)     = params->emc_dll_cfg0;\n\tEMC(EMC_DLL_CFG_1)     = params->emc_dll_cfg1;\n\tEMC(EMC_CFG_DIG_DLL_1) = params->emc_cfg_dig_dll_1;\n\n\t// Program barrelshift.\n\tEMC(EMC_DATA_BRLSHFT_0) = params->emc_data_brlshft0;\n\tEMC(EMC_DATA_BRLSHFT_1) = params->emc_data_brlshft1;\n\tEMC(EMC_DQS_BRLSHFT_0)  = params->emc_dqs_brlshft0;\n\tEMC(EMC_DQS_BRLSHFT_1)  = params->emc_dqs_brlshft1;\n\tEMC(EMC_CMD_BRLSHFT_0)  = params->emc_cmd_brlshft0;\n\tEMC(EMC_CMD_BRLSHFT_1)  = params->emc_cmd_brlshft1;\n\tEMC(EMC_CMD_BRLSHFT_2)  = params->emc_cmd_brlshft2;\n\tEMC(EMC_CMD_BRLSHFT_3)  = params->emc_cmd_brlshft3;\n\tEMC(EMC_QUSE_BRLSHFT_0) = params->emc_quse_brlshft0;\n\tEMC(EMC_QUSE_BRLSHFT_1) = params->emc_quse_brlshft1;\n\tEMC(EMC_QUSE_BRLSHFT_2) = params->emc_quse_brlshft2;\n\tEMC(EMC_QUSE_BRLSHFT_3) = params->emc_quse_brlshft3;\n\n\t// Program pad macros controls and termination.\n\tEMC(EMC_PMACRO_BRICK_CTRL_RFU1) = params->emc_pmacro_brick_ctrl_rfu1;\n\tEMC(EMC_PMACRO_PAD_CFG_CTRL)    = params->emc_pmacro_pad_cfg_ctrl;\n\n\tEMC(EMC_PMACRO_CMD_BRICK_CTRL_FDPD)  = params->emc_pmacro_cmd_brick_ctrl_fdpd;\n\tEMC(EMC_PMACRO_BRICK_CTRL_RFU2)      = params->emc_pmacro_brick_ctrl_rfu2;\n\tEMC(EMC_PMACRO_DATA_BRICK_CTRL_FDPD) = params->emc_pmacro_data_brick_ctrl_fdpd;\n\tEMC(EMC_PMACRO_DATA_PAD_RX_CTRL)     = params->emc_pmacro_data_pad_rx_ctrl;\n\tEMC(EMC_PMACRO_CMD_PAD_RX_CTRL)      = params->emc_pmacro_cmd_pad_rx_ctrl;\n\tEMC(EMC_PMACRO_DATA_PAD_TX_CTRL)     = params->emc_pmacro_data_pad_tx_ctrl;\n\tEMC(EMC_PMACRO_DATA_RX_TERM_MODE)    = params->emc_pmacro_data_rx_term_mode;\n\tEMC(EMC_PMACRO_CMD_RX_TERM_MODE)     = params->emc_pmacro_cmd_rx_term_mode;\n\tEMC(EMC_PMACRO_CMD_PAD_TX_CTRL)      = params->emc_pmacro_cmd_pad_tx_ctrl & 0xEFFFFFFF;\n\n\t// Program pad macro pins/bytes.\n\tEMC(EMC_CFG_3)                   = params->emc_cfg3;\n\tEMC(EMC_PMACRO_TX_PWRD_0)        = params->emc_pmacro_tx_pwrd0;\n\tEMC(EMC_PMACRO_TX_PWRD_1)        = params->emc_pmacro_tx_pwrd1;\n\tEMC(EMC_PMACRO_TX_PWRD_2)        = params->emc_pmacro_tx_pwrd2;\n\tEMC(EMC_PMACRO_TX_PWRD_3)        = params->emc_pmacro_tx_pwrd3;\n\tEMC(EMC_PMACRO_TX_PWRD_4)        = params->emc_pmacro_tx_pwrd4;\n\tEMC(EMC_PMACRO_TX_PWRD_5)        = params->emc_pmacro_tx_pwrd5;\n\tEMC(EMC_PMACRO_TX_SEL_CLK_SRC_0) = params->emc_pmacro_tx_sel_clk_src0;\n\tEMC(EMC_PMACRO_TX_SEL_CLK_SRC_1) = params->emc_pmacro_tx_sel_clk_src1;\n\tEMC(EMC_PMACRO_TX_SEL_CLK_SRC_2) = params->emc_pmacro_tx_sel_clk_src2;\n\tEMC(EMC_PMACRO_TX_SEL_CLK_SRC_3) = params->emc_pmacro_tx_sel_clk_src3;\n\tEMC(EMC_PMACRO_TX_SEL_CLK_SRC_4) = params->emc_pmacro_tx_sel_clk_src4;\n\tEMC(EMC_PMACRO_TX_SEL_CLK_SRC_5) = params->emc_pmacro_tx_sel_clk_src5;\n\n\t// Program per bit pad macros.\n\tEMC(EMC_PMACRO_PERBIT_FGCG_CTRL_0_B01) = params->emc_pmacro_perbit_fgcg_ctrl0;\n\tEMC(EMC_PMACRO_PERBIT_FGCG_CTRL_1_B01) = params->emc_pmacro_perbit_fgcg_ctrl1;\n\tEMC(EMC_PMACRO_PERBIT_FGCG_CTRL_2_B01) = params->emc_pmacro_perbit_fgcg_ctrl2;\n\tEMC(EMC_PMACRO_PERBIT_FGCG_CTRL_3_B01) = params->emc_pmacro_perbit_fgcg_ctrl3;\n\tEMC(EMC_PMACRO_PERBIT_FGCG_CTRL_4_B01) = params->emc_pmacro_perbit_fgcg_ctrl4;\n\tEMC(EMC_PMACRO_PERBIT_FGCG_CTRL_5_B01) = params->emc_pmacro_perbit_fgcg_ctrl5;\n\tEMC(EMC_PMACRO_PERBIT_RFU_CTRL_0_B01)  = params->emc_pmacro_perbit_rfu_ctrl0;\n\tEMC(EMC_PMACRO_PERBIT_RFU_CTRL_1_B01)  = params->emc_pmacro_perbit_rfu_ctrl1;\n\tEMC(EMC_PMACRO_PERBIT_RFU_CTRL_2_B01)  = params->emc_pmacro_perbit_rfu_ctrl2;\n\tEMC(EMC_PMACRO_PERBIT_RFU_CTRL_3_B01)  = params->emc_pmacro_perbit_rfu_ctrl3;\n\tEMC(EMC_PMACRO_PERBIT_RFU_CTRL_4_B01)  = params->emc_pmacro_perbit_rfu_ctrl4;\n\tEMC(EMC_PMACRO_PERBIT_RFU_CTRL_5_B01)  = params->emc_pmacro_perbit_rfu_ctrl5;\n\tEMC(EMC_PMACRO_PERBIT_RFU1_CTRL_0_B01) = params->emc_pmacro_perbit_rfu1_ctrl0;\n\tEMC(EMC_PMACRO_PERBIT_RFU1_CTRL_1_B01) = params->emc_pmacro_perbit_rfu1_ctrl1;\n\tEMC(EMC_PMACRO_PERBIT_RFU1_CTRL_2_B01) = params->emc_pmacro_perbit_rfu1_ctrl2;\n\tEMC(EMC_PMACRO_PERBIT_RFU1_CTRL_3_B01) = params->emc_pmacro_perbit_rfu1_ctrl3;\n\tEMC(EMC_PMACRO_PERBIT_RFU1_CTRL_4_B01) = params->emc_pmacro_perbit_rfu1_ctrl4;\n\tEMC(EMC_PMACRO_PERBIT_RFU1_CTRL_5_B01) = params->emc_pmacro_perbit_rfu1_ctrl5;\n\tEMC(EMC_PMACRO_DATA_PI_CTRL_B01)       = params->emc_pmacro_data_pi_ctrl;\n\tEMC(EMC_PMACRO_CMD_PI_CTRL_B01)        = params->emc_pmacro_cmd_pi_ctrl;\n\n\tEMC(EMC_PMACRO_DDLL_BYPASS)   = params->emc_pmacro_ddll_bypass;\n\tEMC(EMC_PMACRO_DDLL_PWRD_0)   = params->emc_pmacro_ddll_pwrd0;\n\tEMC(EMC_PMACRO_DDLL_PWRD_1)   = params->emc_pmacro_ddll_pwrd1;\n\tEMC(EMC_PMACRO_DDLL_PWRD_2)   = params->emc_pmacro_ddll_pwrd2;\n\tEMC(EMC_PMACRO_CMD_CTRL_0)    = params->emc_pmacro_cmd_ctrl0;\n\tEMC(EMC_PMACRO_CMD_CTRL_1)    = params->emc_pmacro_cmd_ctrl1;\n\tEMC(EMC_PMACRO_CMD_CTRL_2)    = params->emc_pmacro_cmd_ctrl2;\n\n\t// Program inbound vref setting.\n\tEMC(EMC_PMACRO_IB_VREF_DQ_0)  = params->emc_pmacro_ib_vref_dq_0;\n\tEMC(EMC_PMACRO_IB_VREF_DQ_1)  = params->emc_pmacro_ib_vref_dq_1;\n\tEMC(EMC_PMACRO_IB_VREF_DQS_0) = params->emc_pmacro_ib_vref_dqs_0;\n\tEMC(EMC_PMACRO_IB_VREF_DQS_1) = params->emc_pmacro_ib_vref_dqs_1;\n\tEMC(EMC_PMACRO_IB_RXRT)       = params->emc_pmacro_ib_rxrt;\n\n\t// Program quse trimmers.\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK0_0) = params->emc_pmacro_quse_ddll_rank0_0;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK0_1) = params->emc_pmacro_quse_ddll_rank0_1;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK0_2) = params->emc_pmacro_quse_ddll_rank0_2;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK0_3) = params->emc_pmacro_quse_ddll_rank0_3;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK0_4) = params->emc_pmacro_quse_ddll_rank0_4;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK0_5) = params->emc_pmacro_quse_ddll_rank0_5;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK1_0) = params->emc_pmacro_quse_ddll_rank1_0;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK1_1) = params->emc_pmacro_quse_ddll_rank1_1;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK1_2) = params->emc_pmacro_quse_ddll_rank1_2;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK1_3) = params->emc_pmacro_quse_ddll_rank1_3;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK1_4) = params->emc_pmacro_quse_ddll_rank1_4;\n\tEMC(EMC_PMACRO_QUSE_DDLL_RANK1_5) = params->emc_pmacro_quse_ddll_rank1_5;\n\n\t// Program outbound trimmers.\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0) = params->emc_pmacro_ob_ddll_long_dq_rank0_0;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1) = params->emc_pmacro_ob_ddll_long_dq_rank0_1;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) = params->emc_pmacro_ob_ddll_long_dq_rank0_2;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3) = params->emc_pmacro_ob_ddll_long_dq_rank0_3;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4) = params->emc_pmacro_ob_ddll_long_dq_rank0_4;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5) = params->emc_pmacro_ob_ddll_long_dq_rank0_5;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0) = params->emc_pmacro_ob_ddll_long_dq_rank1_0;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1) = params->emc_pmacro_ob_ddll_long_dq_rank1_1;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2) = params->emc_pmacro_ob_ddll_long_dq_rank1_2;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3) = params->emc_pmacro_ob_ddll_long_dq_rank1_3;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4) = params->emc_pmacro_ob_ddll_long_dq_rank1_4;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5) = params->emc_pmacro_ob_ddll_long_dq_rank1_5;\n\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0) = params->emc_pmacro_ob_ddll_long_dqs_rank0_0;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1) = params->emc_pmacro_ob_ddll_long_dqs_rank0_1;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2) = params->emc_pmacro_ob_ddll_long_dqs_rank0_2;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3) = params->emc_pmacro_ob_ddll_long_dqs_rank0_3;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4) = params->emc_pmacro_ob_ddll_long_dqs_rank0_4;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5) = params->emc_pmacro_ob_ddll_long_dqs_rank0_5;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0) = params->emc_pmacro_ob_ddll_long_dqs_rank1_0;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1) = params->emc_pmacro_ob_ddll_long_dqs_rank1_1;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2) = params->emc_pmacro_ob_ddll_long_dqs_rank1_2;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3) = params->emc_pmacro_ob_ddll_long_dqs_rank1_3;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4) = params->emc_pmacro_ob_ddll_long_dqs_rank1_4;\n\tEMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5) = params->emc_pmacro_ob_ddll_long_dqs_rank1_5;\n\tEMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0) = params->emc_pmacro_ib_ddll_long_dqs_rank0_0;\n\tEMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1) = params->emc_pmacro_ib_ddll_long_dqs_rank0_1;\n\tEMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2) = params->emc_pmacro_ib_ddll_long_dqs_rank0_2;\n\tEMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3) = params->emc_pmacro_ib_ddll_long_dqs_rank0_3;\n\tEMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0) = params->emc_pmacro_ib_ddll_long_dqs_rank1_0;\n\tEMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1) = params->emc_pmacro_ib_ddll_long_dqs_rank1_1;\n\tEMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2) = params->emc_pmacro_ib_ddll_long_dqs_rank1_2;\n\tEMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3) = params->emc_pmacro_ib_ddll_long_dqs_rank1_3;\n\n\t// Program clock trimmers.\n\tEMC(EMC_PMACRO_DDLL_LONG_CMD_0)  = params->emc_pmacro_ddll_long_cmd_0;\n\tEMC(EMC_PMACRO_DDLL_LONG_CMD_1)  = params->emc_pmacro_ddll_long_cmd_1;\n\tEMC(EMC_PMACRO_DDLL_LONG_CMD_2)  = params->emc_pmacro_ddll_long_cmd_2;\n\tEMC(EMC_PMACRO_DDLL_LONG_CMD_3)  = params->emc_pmacro_ddll_long_cmd_3;\n\tEMC(EMC_PMACRO_DDLL_LONG_CMD_4)  = params->emc_pmacro_ddll_long_cmd_4;\n\tEMC(EMC_PMACRO_DDLL_SHORT_CMD_0) = params->emc_pmacro_ddll_short_cmd_0;\n\tEMC(EMC_PMACRO_DDLL_SHORT_CMD_1) = params->emc_pmacro_ddll_short_cmd_1;\n\tEMC(EMC_PMACRO_DDLL_SHORT_CMD_2) = params->emc_pmacro_ddll_short_cmd_2;\n\n\t// Set DLL periodic offset.\n\tEMC(EMC_PMACRO_DDLL_PERIODIC_OFFSET) = params->emc_pmacro_ddll_periodic_offset;\n\n\t// Patch 4 using BCT spare variables.\n\tif (params->emc_bct_spare4)\n\t\t*(vu32 *)params->emc_bct_spare4 = params->emc_bct_spare5;\n\n\t// Patch 4 to 6 using BCT spare secure variables.\n\tif (params->emc_bct_spare_secure6)\n\t\t*(vu32 *)params->emc_bct_spare_secure6  = params->emc_bct_spare_secure7;\n\tif (params->emc_bct_spare_secure8)\n\t\t*(vu32 *)params->emc_bct_spare_secure8  = params->emc_bct_spare_secure9;\n\tif (params->emc_bct_spare_secure10)\n\t\t*(vu32 *)params->emc_bct_spare_secure10 = params->emc_bct_spare_secure11;\n\n\t// Trigger timing update so above writes take place.\n\tEMC(EMC_TIMING_CONTROL) = 1;\n\n\t// Initialize MC VPR settings.\n\tMC(MC_VIDEO_PROTECT_BOM)            = params->mc_video_protect_bom;\n\tMC(MC_VIDEO_PROTECT_BOM_ADR_HI)     = params->mc_video_protect_bom_adr_hi;\n\tMC(MC_VIDEO_PROTECT_SIZE_MB)        = params->mc_video_protect_size_mb;\n\tMC(MC_VIDEO_PROTECT_VPR_OVERRIDE)   = params->mc_video_protect_vpr_override;\n\tMC(MC_VIDEO_PROTECT_VPR_OVERRIDE1)  = params->mc_video_protect_vpr_override1;\n\tMC(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) = params->mc_video_protect_gpu_override0;\n\tMC(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) = params->mc_video_protect_gpu_override1;\n\n\t// Program SDRAM geometry parameters.\n\tMC(MC_EMEM_ADR_CFG)              = params->mc_emem_adr_cfg;\n\tMC(MC_EMEM_ADR_CFG_DEV0)         = params->mc_emem_adr_cfg_dev0;\n\tMC(MC_EMEM_ADR_CFG_DEV1)         = params->mc_emem_adr_cfg_dev1;\n\tMC(MC_EMEM_ADR_CFG_CHANNEL_MASK) = params->mc_emem_adr_cfg_channel_mask;\n\n\t// Program bank swizzling.\n\tMC(MC_EMEM_ADR_CFG_BANK_MASK_0) = params->mc_emem_adr_cfg_bank_mask0;\n\tMC(MC_EMEM_ADR_CFG_BANK_MASK_1) = params->mc_emem_adr_cfg_bank_mask1;\n\tMC(MC_EMEM_ADR_CFG_BANK_MASK_2) = params->mc_emem_adr_cfg_bank_mask2;\n\n\t// Program external memory aperture (base and size).\n\tMC(MC_EMEM_CFG) = params->mc_emem_cfg;\n\n\t// Program SEC carveout (base and size).\n\tMC(MC_SEC_CARVEOUT_BOM)     = params->mc_sec_carveout_bom;\n\tMC(MC_SEC_CARVEOUT_ADR_HI)  = params->mc_sec_carveout_adr_hi;\n\tMC(MC_SEC_CARVEOUT_SIZE_MB) = params->mc_sec_carveout_size_mb;\n\n\t// Program MTS carveout (base and size).\n\tMC(MC_MTS_CARVEOUT_BOM)     = params->mc_mts_carveout_bom;\n\tMC(MC_MTS_CARVEOUT_ADR_HI)  = params->mc_mts_carveout_adr_hi;\n\tMC(MC_MTS_CARVEOUT_SIZE_MB) = params->mc_mts_carveout_size_mb;\n\n\t// Program the memory arbiter.\n\tMC(MC_EMEM_ARB_CFG)             = params->mc_emem_arb_cfg;\n\tMC(MC_EMEM_ARB_OUTSTANDING_REQ) = params->mc_emem_arb_outstanding_req;\n\tMC(MC_EMEM_ARB_REFPB_HP_CTRL)   = params->emc_emem_arb_refpb_hp_ctrl;\n\tMC(MC_EMEM_ARB_REFPB_BANK_CTRL) = params->emc_emem_arb_refpb_bank_ctrl;\n\tMC(MC_EMEM_ARB_TIMING_RCD)      = params->mc_emem_arb_timing_rcd;\n\tMC(MC_EMEM_ARB_TIMING_RP)       = params->mc_emem_arb_timing_rp;\n\tMC(MC_EMEM_ARB_TIMING_RC)       = params->mc_emem_arb_timing_rc;\n\tMC(MC_EMEM_ARB_TIMING_RAS)      = params->mc_emem_arb_timing_ras;\n\tMC(MC_EMEM_ARB_TIMING_FAW)      = params->mc_emem_arb_timing_faw;\n\tMC(MC_EMEM_ARB_TIMING_RRD)      = params->mc_emem_arb_timing_rrd;\n\tMC(MC_EMEM_ARB_TIMING_RAP2PRE)  = params->mc_emem_arb_timing_rap2pre;\n\tMC(MC_EMEM_ARB_TIMING_WAP2PRE)  = params->mc_emem_arb_timing_wap2pre;\n\tMC(MC_EMEM_ARB_TIMING_R2R)      = params->mc_emem_arb_timing_r2r;\n\tMC(MC_EMEM_ARB_TIMING_W2W)      = params->mc_emem_arb_timing_w2w;\n\tMC(MC_EMEM_ARB_TIMING_CCDMW)    = params->mc_emem_arb_timing_ccdmw;\n\tMC(MC_EMEM_ARB_TIMING_R2W)      = params->mc_emem_arb_timing_r2w;\n\tMC(MC_EMEM_ARB_TIMING_W2R)      = params->mc_emem_arb_timing_w2r;\n\tMC(MC_EMEM_ARB_TIMING_RFCPB)    = params->mc_emem_arb_timing_rfcpb;\n\tMC(MC_EMEM_ARB_DA_TURNS)        = params->mc_emem_arb_da_turns;\n\tMC(MC_EMEM_ARB_DA_COVERS)       = params->mc_emem_arb_da_covers;\n\tMC(MC_EMEM_ARB_MISC0)           = params->mc_emem_arb_misc0;\n\tMC(MC_EMEM_ARB_MISC1)           = params->mc_emem_arb_misc1;\n\tMC(MC_EMEM_ARB_MISC2)           = params->mc_emem_arb_misc2;\n\tMC(MC_EMEM_ARB_RING1_THROTTLE)  = params->mc_emem_arb_ring1_throttle;\n\tMC(MC_EMEM_ARB_OVERRIDE)        = params->mc_emem_arb_override;\n\tMC(MC_EMEM_ARB_OVERRIDE_1)      = params->mc_emem_arb_override1;\n\tMC(MC_EMEM_ARB_RSV)             = params->mc_emem_arb_rsv;\n\tMC(MC_DA_CONFIG0)               = params->mc_da_cfg0;\n\n\t// Trigger MC timing update.\n\tMC(MC_TIMING_CONTROL) = 1;\n\n\t// Program second-level clock enable overrides.\n\tMC(MC_CLKEN_OVERRIDE) = params->mc_clken_override;\n\n\t// Program statistics gathering.\n\tMC(MC_STAT_CONTROL) = params->mc_stat_control;\n\n\t// Program SDRAM geometry parameters.\n\tEMC(EMC_ADR_CFG) = params->emc_adr_cfg;\n\n\t// Program second-level clock enable overrides.\n\tEMC(EMC_CLKEN_OVERRIDE) = params->emc_clken_override;\n\n\t// Program EMC pad auto calibration.\n\tEMC(EMC_PMACRO_AUTOCAL_CFG_0) = params->emc_pmacro_auto_cal_cfg0;\n\tEMC(EMC_PMACRO_AUTOCAL_CFG_1) = params->emc_pmacro_auto_cal_cfg1;\n\tEMC(EMC_PMACRO_AUTOCAL_CFG_2) = params->emc_pmacro_auto_cal_cfg2;\n\n\tEMC(EMC_AUTO_CAL_VREF_SEL_0) = params->emc_auto_cal_vref_sel0;\n\tEMC(EMC_AUTO_CAL_VREF_SEL_1) = params->emc_auto_cal_vref_sel1;\n\n\t// Program/Start auto calibration.\n\tEMC(EMC_AUTO_CAL_INTERVAL) = params->emc_auto_cal_interval;\n\tEMC(EMC_AUTO_CAL_CONFIG)   = params->emc_auto_cal_config;\n\tusleep(params->emc_auto_cal_wait);\n\n\t// Patch 5 using BCT spare variables.\n\tif (params->emc_bct_spare8)\n\t\t*(vu32 *)params->emc_bct_spare8 = params->emc_bct_spare9;\n\n\tEMC(EMC_AUTO_CAL_CONFIG9_B01) = params->emc_auto_cal_config9;\n\n\t// Program EMC timing configuration.\n\tEMC(EMC_CFG_2)           = params->emc_cfg2;\n\tEMC(EMC_CFG_PIPE)        = params->emc_cfg_pipe;\n\tEMC(EMC_CFG_PIPE_1)      = params->emc_cfg_pipe1;\n\tEMC(EMC_CFG_PIPE_2)      = params->emc_cfg_pipe2;\n\tEMC(EMC_CMDQ)            = params->emc_cmd_q;\n\tEMC(EMC_MC2EMCQ)         = params->emc_mc2emc_q;\n\tEMC(EMC_MRS_WAIT_CNT)    = params->emc_mrs_wait_cnt;\n\tEMC(EMC_MRS_WAIT_CNT2)   = params->emc_mrs_wait_cnt2;\n\tEMC(EMC_FBIO_CFG5)       = params->emc_fbio_cfg5;\n\tEMC(EMC_RC)              = params->emc_rc;\n\tEMC(EMC_RFC)             = params->emc_rfc;\n\tEMC(EMC_RFCPB)           = params->emc_rfc_pb;\n\tEMC(EMC_REFCTRL2)        = params->emc_ref_ctrl2;\n\tEMC(EMC_RFC_SLR)         = params->emc_rfc_slr;\n\tEMC(EMC_RAS)             = params->emc_ras;\n\tEMC(EMC_RP)              = params->emc_rp;\n\tEMC(EMC_TPPD)            = params->emc_tppd;\n\tEMC(EMC_TRTM_B01)        = params->emc_trtm;\n\tEMC(EMC_TWTM_B01)        = params->emc_twtm;\n\tEMC(EMC_TRATM_B01)       = params->emc_tratm;\n\tEMC(EMC_TWATM_B01)       = params->emc_twatm;\n\tEMC(EMC_TR2REF_B01)      = params->emc_tr2ref;\n\tEMC(EMC_R2R)             = params->emc_r2r;\n\tEMC(EMC_W2W)             = params->emc_w2w;\n\tEMC(EMC_R2W)             = params->emc_r2w;\n\tEMC(EMC_W2R)             = params->emc_w2r;\n\tEMC(EMC_R2P)             = params->emc_r2p;\n\tEMC(EMC_W2P)             = params->emc_w2p;\n\tEMC(EMC_CCDMW)           = params->emc_ccdmw;\n\tEMC(EMC_RD_RCD)          = params->emc_rd_rcd;\n\tEMC(EMC_WR_RCD)          = params->emc_wr_rcd;\n\tEMC(EMC_RRD)             = params->emc_rrd;\n\tEMC(EMC_REXT)            = params->emc_rext;\n\tEMC(EMC_WEXT)            = params->emc_wext;\n\tEMC(EMC_WDV)             = params->emc_wdv;\n\tEMC(EMC_WDV_CHK)         = params->emc_wdv_chk;\n\tEMC(EMC_WSV)             = params->emc_wsv;\n\tEMC(EMC_WEV)             = params->emc_wev;\n\tEMC(EMC_WDV_MASK)        = params->emc_wdv_mask;\n\tEMC(EMC_WS_DURATION)     = params->emc_ws_duration;\n\tEMC(EMC_WE_DURATION)     = params->emc_we_duration;\n\tEMC(EMC_QUSE)            = params->emc_quse;\n\tEMC(EMC_QUSE_WIDTH)      = params->emc_quse_width;\n\tEMC(EMC_IBDLY)           = params->emc_ibdly;\n\tEMC(EMC_OBDLY)           = params->emc_obdly;\n\tEMC(EMC_EINPUT)          = params->emc_einput;\n\tEMC(EMC_EINPUT_DURATION) = params->emc_einput_duration;\n\tEMC(EMC_PUTERM_EXTRA)    = params->emc_puterm_extra;\n\tEMC(EMC_PUTERM_WIDTH)    = params->emc_puterm_width;\n\n\tEMC(EMC_DBG)                 = params->emc_dbg;\n\n\t// Clear read fifo.\n\tEMC(EMC_QRST)                = params->emc_qrst;\n\tEMC(EMC_ISSUE_QRST)          = 1;\n\tEMC(EMC_ISSUE_QRST)          = 0;\n\n\t// Program the rest of EMC timing configuration.\n\tEMC(EMC_QSAFE)               = params->emc_qsafe;\n\tEMC(EMC_RDV)                 = params->emc_rdv;\n\tEMC(EMC_RDV_MASK)            = params->emc_rdv_mask;\n\tEMC(EMC_RDV_EARLY)           = params->emc_rdv_early;\n\tEMC(EMC_RDV_EARLY_MASK)      = params->emc_rdv_early_mask;\n\tEMC(EMC_QPOP)                = params->emc_qpop;\n\tEMC(EMC_REFRESH)             = params->emc_refresh;\n\tEMC(EMC_BURST_REFRESH_NUM)   = params->emc_burst_refresh_num;\n\tEMC(EMC_PRE_REFRESH_REQ_CNT) = params->emc_prerefresh_req_cnt;\n\tEMC(EMC_PDEX2WR)             = params->emc_pdex2wr;\n\tEMC(EMC_PDEX2RD)             = params->emc_pdex2rd;\n\tEMC(EMC_PCHG2PDEN)           = params->emc_pchg2pden;\n\tEMC(EMC_ACT2PDEN)            = params->emc_act2pden;\n\tEMC(EMC_AR2PDEN)             = params->emc_ar2pden;\n\tEMC(EMC_RW2PDEN)             = params->emc_rw2pden;\n\tEMC(EMC_CKE2PDEN)            = params->emc_cke2pden;\n\tEMC(EMC_PDEX2CKE)            = params->emc_pdex2che;\n\tEMC(EMC_PDEX2MRR)            = params->emc_pdex2mrr;\n\tEMC(EMC_TXSR)                = params->emc_txsr;\n\tEMC(EMC_TXSRDLL)             = params->emc_txsr_dll;\n\tEMC(EMC_TCKE)                = params->emc_tcke;\n\tEMC(EMC_TCKESR)              = params->emc_tckesr;\n\tEMC(EMC_TPD)                 = params->emc_tpd;\n\tEMC(EMC_TFAW)                = params->emc_tfaw;\n\tEMC(EMC_TRPAB)               = params->emc_trpab;\n\tEMC(EMC_TCLKSTABLE)          = params->emc_tclkstable;\n\tEMC(EMC_TCLKSTOP)            = params->emc_tclkstop;\n\tEMC(EMC_TREFBW)              = params->emc_trefbw;\n\tEMC(EMC_ODT_WRITE)           = params->emc_odt_write;\n\tEMC(EMC_CFG_DIG_DLL)         = params->emc_cfg_dig_dll;\n\tEMC(EMC_CFG_DIG_DLL_PERIOD)  = params->emc_cfg_dig_dll_period;\n\n\t// Don't write CFG_ADR_EN (bit 1) here - lock bit written later.\n\tEMC(EMC_FBIO_SPARE)   = params->emc_fbio_spare & 0xFFFFFFFD;\n\tEMC(EMC_CFG_RSV)      = params->emc_cfg_rsv;\n\tEMC(EMC_PMC_SCRATCH1) = params->emc_pmc_scratch1;\n\tEMC(EMC_PMC_SCRATCH2) = params->emc_pmc_scratch2;\n\tEMC(EMC_PMC_SCRATCH3) = params->emc_pmc_scratch3;\n\tEMC(EMC_ACPD_CONTROL) = params->emc_acpd_control;\n\tEMC(EMC_TXDSRVTTGEN)  = params->emc_txdsrvttgen;\n\tEMC(EMC_PMACRO_DSR_VTTGEN_CTRL_0_B01) = params->emc_pmacro_dsr_vttgen_ctrl0;\n\n\t// Set pipe bypass enable bits before sending any DRAM commands.\n\tEMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000;\n\n\t// BootROM patching is used as a generic patch here.\n\tif (params->boot_rom_patch_control)\n\t{\n\t\t*(vu32 *)params->boot_rom_patch_control = params->boot_rom_patch_data;\n\n\t\t// Trigger MC timing update.\n\t\tMC(MC_TIMING_CONTROL) = 1;\n\t}\n\n\t// Patch 7 to 9 using BCT spare secure variables.\n\tif (params->emc_bct_spare_secure12)\n\t\t*(vu32 *)params->emc_bct_spare_secure12 = params->emc_bct_spare_secure13;\n\tif (params->emc_bct_spare_secure14)\n\t\t*(vu32 *)params->emc_bct_spare_secure14 = params->emc_bct_spare_secure15;\n\tif (params->emc_bct_spare_secure16)\n\t\t*(vu32 *)params->emc_bct_spare_secure16 = params->emc_bct_spare_secure17;\n\n\t// Release SEL_DPD_CMD.\n\tPMC(APBDEV_PMC_IO_DPD3_REQ) = (params->emc_pmc_scratch1 & 0xFFF0000) | PMC_IO_DPD_REQ_DPD_OFF;\n\tusleep(params->pmc_io_dpd3_req_wait);\n\n\t// Set transmission pad control parameters.\n\tEMC(EMC_PMACRO_CMD_PAD_TX_CTRL) = params->emc_pmacro_cmd_pad_tx_ctrl;\n\n\t// ZQ CAL setup (not actually issuing ZQ CAL now).\n\tif (params->emc_zcal_warm_cold_boot_enables & 1)\n\t{\n\t\tEMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt;\n\t\tEMC(EMC_ZCAL_MRW_CMD)  = params->emc_zcal_mrw_cmd;\n\t}\n\n\t// Trigger timing update so above writes take place.\n\tEMC(EMC_TIMING_CONTROL) = 1;\n\tusleep(params->emc_timing_control_wait);\n\n\t// Deassert HOLD_CKE_LOW.\n\tPMC(APBDEV_PMC_DDR_CNTRL) &= 0xFF78007F;\n\tusleep(params->pmc_ddr_ctrl_wait);\n\n\t// Set clock enable signal.\n\tu32 pin_gpio_cfg = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12);\n\tEMC(EMC_PIN) = pin_gpio_cfg;\n\t(void)EMC(EMC_PIN);\n\tusleep(params->emc_pin_extra_wait + 200);\n\tEMC(EMC_PIN) = pin_gpio_cfg | 0x100;\n\t(void)EMC(EMC_PIN);\n\n\tusleep(params->emc_pin_extra_wait + 2000);\n\n\t// Enable clock enable signal.\n\tEMC(EMC_PIN) = pin_gpio_cfg | 0x101;\n\t(void)EMC(EMC_PIN);\n\tusleep(params->emc_pin_program_wait);\n\n\t// Init zq calibration,\n\t// Patch 6 using BCT spare variables.\n\tif (params->emc_bct_spare10)\n\t\t*(vu32 *)params->emc_bct_spare10 = params->emc_bct_spare11;\n\n\t// Write mode registers.\n\tEMC(EMC_MRW2)  = params->emc_mrw2;\n\tEMC(EMC_MRW)   = params->emc_mrw1;\n\tEMC(EMC_MRW3)  = params->emc_mrw3;\n\tEMC(EMC_MRW4)  = params->emc_mrw4;\n\tEMC(EMC_MRW6)  = params->emc_mrw6;\n\tEMC(EMC_MRW14) = params->emc_mrw14;\n\n\tEMC(EMC_MRW8)  = params->emc_mrw8;\n\tEMC(EMC_MRW12) = params->emc_mrw12;\n\tEMC(EMC_MRW9)  = params->emc_mrw9;\n\tEMC(EMC_MRW13) = params->emc_mrw13;\n\n\tif (params->emc_zcal_warm_cold_boot_enables & 1)\n\t{\n\t\t// Issue ZQCAL start, device 0.\n\t\tEMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0;\n\t\tusleep(params->emc_zcal_init_wait);\n\n\t\t// Issue ZQCAL latch.\n\t\tEMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0 ^ 3;\n\t\t// Same for device 1.\n\t\tif (!(params->emc_dev_select & 2))\n\t\t{\n\t\t\tEMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1;\n\t\t\tusleep(params->emc_zcal_init_wait);\n\t\t\tEMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1 ^ 3;\n\t\t}\n\t}\n\n\t// Patch 10 to 12 using BCT spare secure variables.\n\tif (params->emc_bct_spare_secure18)\n\t\t*(vu32 *)params->emc_bct_spare_secure18 = params->emc_bct_spare_secure19;\n\tif (params->emc_bct_spare_secure20)\n\t\t*(vu32 *)params->emc_bct_spare_secure20 = params->emc_bct_spare_secure21;\n\tif (params->emc_bct_spare_secure22)\n\t\t*(vu32 *)params->emc_bct_spare_secure22 = params->emc_bct_spare_secure23;\n\n\t// Set package and DPD pad control.\n\tPMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg;\n\n\t// Start periodic ZQ calibration (LPDDRx only).\n\tEMC(EMC_ZCAL_INTERVAL) = params->emc_zcal_interval;\n\tEMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt;\n\tEMC(EMC_ZCAL_MRW_CMD)  = params->emc_zcal_mrw_cmd;\n\n\t// Patch 7 using BCT spare variables.\n\tif (params->emc_bct_spare12)\n\t\t*(vu32 *)params->emc_bct_spare12 = params->emc_bct_spare13;\n\n\t// Trigger timing update so above writes take place.\n\tEMC(EMC_TIMING_CONTROL) = 1;\n\n\tif (params->emc_extra_refresh_num)\n\t\tEMC(EMC_REF) = ((1 << params->emc_extra_refresh_num << 8) - 253) | (params->emc_dev_select << 30);\n\n\t// Enable refresh.\n\tEMC(EMC_REFCTRL) = params->emc_dev_select | BIT(31);\n\n\tEMC(EMC_DYN_SELF_REF_CONTROL) = params->emc_dyn_self_ref_control;\n\tEMC(EMC_CFG)           = params->emc_cfg;\n\tEMC(EMC_FDPD_CTRL_DQ)  = params->emc_fdpd_ctrl_dq;\n\tEMC(EMC_FDPD_CTRL_CMD) = params->emc_fdpd_ctrl_cmd;\n\tEMC(EMC_SEL_DPD_CTRL)  = params->emc_sel_dpd_ctrl;\n\n\t// Write addr swizzle lock bit.\n\tEMC(EMC_FBIO_SPARE) = params->emc_fbio_spare | BIT(1);\n\n\t// Re-trigger timing to latch power saving functions.\n\tEMC(EMC_TIMING_CONTROL) = 1;\n\n\tEMC(EMC_CFG_UPDATE) = params->emc_cfg_update;\n\n\t// Enable EMC pipe clock gating.\n\tEMC(EMC_CFG_PIPE_CLK) = params->emc_cfg_pipe_clk;\n\n\t// Depending on freqency, enable CMD/CLK fdpd.\n\tEMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = params->emc_fdpd_ctrl_cmd_no_ramp;\n\n\t// Set untranslated region requirements.\n\tMC(MC_UNTRANSLATED_REGION_CHECK_B01) = params->mc_untranslated_region_check;\n\n\t// Lock carveouts per BCT cfg.\n\tMC(MC_VIDEO_PROTECT_REG_CTRL) = params->mc_video_protect_write_access;\n\tMC(MC_SEC_CARVEOUT_REG_CTRL)  = params->mc_sec_carveout_protect_write_access;\n\tMC(MC_MTS_CARVEOUT_REG_CTRL)  = params->mc_mts_carveout_reg_ctrl;\n\n\t// Disable write access to a bunch of EMC registers.\n\tMC(MC_EMEM_CFG_ACCESS_CTRL) = 1;\n\n\t// Enable arbiter.\n\tSYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | (params->ahb_arbitration_xbar_ctrl_meminit_done << 16);\n}\n\nstatic void *_sdram_get_params_t210()\n{\n\t// Check if id is proper.\n\tu32 dramid = fuse_read_dramid(false);\n\n\t// Copy base parameters.\n\tu32 *params = (u32 *)SDRAM_PARAMS_ADDR;\n\tmemcpy(params, &_dram_cfg_0_samsung_4gb, sizeof(sdram_params_t210_t));\n\n\t// Patch parameters if needed.\n\tfor (u32 i = 0; i < ARRAY_SIZE(sdram_cfg_vendor_patches_t210); i++)\n\t\tif (sdram_cfg_vendor_patches_t210[i].dramcf & DRAM_ID(dramid))\n\t\t\tparams[sdram_cfg_vendor_patches_t210[i].offset] = sdram_cfg_vendor_patches_t210[i].val;\n\n\treturn (void *)params;\n}\n\nvoid *sdram_get_params_t210b01()\n{\n\t// Check if id is proper.\n\tu32 dramid = fuse_read_dramid(false);\n\n\t// Copy base parameters.\n\tu32 *params = (u32 *)SDRAM_PARAMS_ADDR;\n\tmemcpy(params, &_dram_cfg_08_10_12_14_samsung_hynix_4gb, sizeof(sdram_params_t210b01_t));\n\n\t// Patch parameters if needed.\n\tu8 dram_code = dram_encoding_t210b01[dramid];\n\tif (!dram_code)\n\t\treturn (void *)params;\n\n\tfor (u32 i = 0; i < ARRAY_SIZE(sdram_cfg_vendor_patches_t210b01); i++)\n\t\tif (sdram_cfg_vendor_patches_t210b01[i].dramcf & DRAM_CC(dram_code))\n\t\t\tparams[sdram_cfg_vendor_patches_t210b01[i].offset] = sdram_cfg_vendor_patches_t210b01[i].val;\n\n\treturn (void *)params;\n}\n\n/*\n * Function: sdram_get_params_patched\n *\n * This code implements a warmboot exploit. Warmboot, that is actually so hot, it burns Nvidia once again.\n * If the boot_rom_patch_control's MSB is set, it uses it as an index to\n * APB_MISC_BASE (u32 array) and sets it to the value of boot_rom_patch_data.\n * (The MSB falls out when it gets multiplied by sizeof(u32)).\n * Because the bootrom does not do any boundary checks, it lets us write anywhere and anything.\n * Ipatch hardware let us apply 12 changes to the bootrom and can be changed any time.\n * The first patch is not needed any more when the exploit is triggered, so we overwrite that.\n * 0x10459E is the address where it returns an error when the signature is not valid.\n * We change that to MOV R0, #0, so we pass the check.\n *\n * Note: The modulus in the header must match and validated.\n */\n\nvoid *sdram_get_params_patched()\n{\n\t#define IPATCH_CONFIG(addr, data) ((((addr) - 0x100000) / 2) << 16 | ((data) & 0xffff))\n\tsdram_params_t210_t *sdram_params = _sdram_get_params_t210();\n\n\t// Disable Warmboot signature check.\n\tsdram_params->boot_rom_patch_control = BIT(31) | (((IPATCH_BASE + 4) - APB_MISC_BASE) / 4);\n\tsdram_params->boot_rom_patch_data = IPATCH_CONFIG(0x10459E, 0x2000);\n/*\n\t// Disable SBK lock.\n\tsdram_params->emc_bct_spare8 = (IPATCH_BASE + 7 * 4);\n\tsdram_params->emc_bct_spare9 = IPATCH_CONFIG(0x10210E, 0x2000);\n\n\t// Disable bootrom read lock.\n\tsdram_params->emc_bct_spare10 = (IPATCH_BASE + 10 * 4);\n\tsdram_params->emc_bct_spare11 = IPATCH_CONFIG(0x100FDC, 0xF000);\n\tsdram_params->emc_bct_spare12 = (IPATCH_BASE + 11 * 4);\n\tsdram_params->emc_bct_spare13 = IPATCH_CONFIG(0x100FDE, 0xE320);\n*/\n\treturn (void *)sdram_params;\n}\n\nvoid sdram_init()\n{\n\t// Disable remote sense for SD1.\n\ti2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, MAX77620_SD_CNF2_ROVS_EN_SD0 | MAX77620_SD_CNF2_RSVD);\n\n\tif (hw_get_chip_id() == GP_HIDREV_MAJOR_T210)\n\t{\n\t\tconst sdram_params_t210_t *params = (const sdram_params_t210_t *)_sdram_get_params_t210();\n\t\tif (params->memory_type != MEMORY_TYPE_LPDDR4)\n\t\t\treturn;\n\n\t\t// Set DRAM voltage.\n\t\tmax7762x_regulator_set_voltage(REGULATOR_SD1, 1125000); // HOS: 1.125V. Bootloader: 1.1V.\n\n\t\t_sdram_config_t210(params);\n\t}\n\telse\n\t{\n\t\tconst sdram_params_t210b01_t *params = (const sdram_params_t210b01_t *)sdram_get_params_t210b01();\n\t\tif (params->memory_type != MEMORY_TYPE_LPDDR4)\n\t\t\treturn;\n\n\t\t_sdram_config_t210b01(params);\n\t}\n}\n"
  },
  {
    "path": "bdk/mem/sdram.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2020-2024 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _SDRAM_H_\n#define _SDRAM_H_\n\n#include <mem/emc_t210.h>\n\n/*\n * Tegra X1/X1+ EMC/DRAM Bandwidth Chart:\n *\n * Note: Max BWbits = Hz x ddr x bus width x channels = Hz x 2 x 32 x 2.\n *       Max BWbits = Hz x ddr x bus width x channels = Hz x 2 x 64 x 1.\n *       Configurations supported: 1x32, 2x32, 1x64.\n *       x64 ram modules can be used by combining the 2 32-bit channels into one.\n *\n *  204.0 MHz:  3.04 <-- Tegra X1/X1+ Init/SC7 Frequency\n *  408.0 MHz:  6.08\n *  665.6 MHz:  9.92\n *  800.0 MHz: 11.92 <-- Tegra X1/X1+ Nvidia OS Boot Frequency\n * 1065.6 MHz: 15.89\n * 1331.2 MHz: 19.84\n * 1600.0 MHz: 23.84\n * 1862.4 MHz: 27.75 <-- Tegra X1  Official Max Frequency\n * 2131.2 MHz: 31.76 <-- Tegra X1+ Official Max Frequency. Not all regs have support for > 2046 MHz.\n */\n\nenum sdram_ids_erista\n{\n\t// LPDDR4 3200Mbps.\n\tLPDDR4_ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH        = 0, // Die-B. (2y-01).\n\tLPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE       = 1, // Die-M. (2y-01).\n\tLPDDR4_ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WTC = 2, // Die-C. (2y-01).\n\n\tLPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH        = 4, // Die-C. (2y-01).\n\n\t/*\n\t * Custom hekate/L4T supported 8GB. 7 dram id can be easily applied in fuses.\n\t *\n\t * 4GB modules:\n\t * Samsung K4FBE3D4HM-MGCH/CJ/CL. MG/TF/GF/TH/GH: Package + Temperature.\n\t * Hynix   H9HCNNNCPUMLXR-NME/NEE/NEI. E/I: Temperature.\n\t * Hynix   H54G56BYYVX046/QX046/PX046. V/Q/P: Package + Temperature.\n\t */\n\tLPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX        = 7, // XX: CH/CJ/CL.\n};\n\nenum sdram_ids_mariko\n{\n\t/*\n\t * Nintendo Switch LPDRR4X generations:\n\t * - 1x   nm are 1st-gen\n\t * - 1y   nm are 2nd-gen\n\t * - 1z/a nm are 3rd-gen\n\t */\n\n\t// LPDDR4X 4266Mbps.\n\tLPDDR4X_HOAG_4GB_HYNIX_H9HCNNNBKMMLXR_NEE       = 3, // Die-M. (1y-01).\n\tLPDDR4X_AULA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE       = 5, // Die-M. (1y-01).\n\tLPDDR4X_IOWA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE       = 6, // Die-M. (1y-01).\n\n\t// LPDDR4X 3733Mbps.\n\tLPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AM_MGCJ        = 8,  // Die-M. (1x-03).\n\tLPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AM_MGCJ        = 9,  // Die-M. (1x-03).\n\tLPDDR4X_IOWA_4GB_HYNIX_H9HCNNNBKMMLHR_NME       = 10, // Die-M. (1x-03).\n\tLPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTE = 11, // Die-E. (1x-03). D9WGB. 4266Mbps.\n\n\tLPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AM_MGCJ        = 12, // Die-M. (1x-03).\n\tLPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AM_MGCJ        = 13, // Die-M. (1x-03).\n\tLPDDR4X_HOAG_4GB_HYNIX_H9HCNNNBKMMLHR_NME       = 14, // Die-M. (1x-03).\n\tLPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTE = 15, // Die-E. (1x-03). D9WGB. 4266Mbps.\n\n\t// LPDDR4X 4266Mbps.\n\tLPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AA_MGCL        = 17, // Die-A. (1y-X03).\n\tLPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AA_MGCL        = 18, // Die-A. (1y-X03).\n\tLPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AA_MGCL        = 19, // Die-A. (1y-X03).\n\n\tLPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AB_MGCL        = 20, // Die-B. (1z-01). 40% lp.\n\tLPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AB_MGCL        = 21, // Die-B. (1z-01). 40% lp.\n\tLPDDR4X_AULA_4GB_SAMSUNG_K4U6E3S4AB_MGCL        = 22, // Die-B. (1z-01). 40% lp.\n\n\tLPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AA_MGCL        = 23, // Die-A. (1y-X03).\n\tLPDDR4X_AULA_4GB_SAMSUNG_K4U6E3S4AA_MGCL        = 24, // Die-A. (1y-X03).\n\n\tLPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTF = 25, // Die-F. (1y-01). D9XRR.\n\tLPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTF = 26, // Die-F. (1y-01). D9XRR.\n\tLPDDR4X_AULA_4GB_MICRON_MT53E512M32D2NP_046_WTF = 27, // Die-F. (1y-01). D9XRR.\n\n\tLPDDR4X_AULA_8GB_SAMSUNG_K4UBE3D4AA_MGCL        = 28, // Die-A. (1y-X03). 2nd gen.\n\n\t// Old naming scheme: H9HCNNNBKMCLXR-NEE\n\tLPDDR4X_IOWA_4GB_HYNIX_H54G46CYRBX267           = 29, // Die-C. (1a-01). 61% lp.\n\tLPDDR4X_HOAG_4GB_HYNIX_H54G46CYRBX267           = 30, // Die-C. (1a-01). 61% lp.\n\tLPDDR4X_AULA_4GB_HYNIX_H54G46CYRBX267           = 31, // Die-C. (1a-01). 61% lp.\n\n\tLPDDR4X_IOWA_4GB_MICRON_MT53E512M32D1NP_046_WTB = 32, // Die-B. (1a-01). D8BQM. 61% lp.\n\tLPDDR4X_HOAG_4GB_MICRON_MT53E512M32D1NP_046_WTB = 33, // Die-B. (1a-01). D8BQM. 61% lp.\n\tLPDDR4X_AULA_4GB_MICRON_MT53E512M32D1NP_046_WTB = 34, // Die-B. (1a-01). D8BQM. 61% lp.\n};\n\nenum sdram_codes_mariko\n{\n\tLPDDR4X_NO_PATCH                           = 0,\n\tLPDDR4X_UNUSED                             = 0,\n\n\t// LPDDR4X_4GB_SAMSUNG_K4U6E3S4AM_MGCJ          DRAM IDs: 08, 12.\n\t// LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLHR_NME         DRAM IDs: 10, 14.\n\n\tLPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ        = 1, // DRAM IDs: 09, 13.\n\tLPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE = 2, // DRAM IDs: 11, 15.\n\tLPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL        = 3, // DRAM IDs: 17, 19, 24.\n\tLPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL        = 4, // DRAM IDs: 18, 23, 28.\n\tLPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL        = 5, // DRAM IDs: 20, 21, 22.\n\tLPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF = 6, // DRAM IDs: 25, 26, 27.\n\tLPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE       = 7, // DRAM IDs: 03, 05, 06.\n\tLPDDR4X_4GB_HYNIX_H54G46CYRBX267           = 8, // DRAM IDs: 29, 30, 31.\n\tLPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB = 9, // DRAM IDs: 32, 33, 34.\n};\n\nvoid sdram_init();\nvoid *sdram_get_params_patched();\nvoid *sdram_get_params_t210b01();\nvoid sdram_lp0_save_params(const void *params);\nemc_mr_data_t sdram_read_mrx(emc_mr_t mrx);\n\n#endif\n"
  },
  {
    "path": "bdk/mem/sdram_config.inl",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2020-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#define DRAM_CFG_T210_SIZE 1896\n\nstatic const sdram_params_t210_t _dram_cfg_0_samsung_4gb = {\n\t/* Specifies the type of memory device */\n\t.memory_type                                     = MEMORY_TYPE_LPDDR4,\n\n\t/* MC/EMC clock source configuration */\n\t.pllm_input_divider                              = 0x00000001, // M div.\n\t.pllm_feedback_divider                           = 0x00000022, // N div.\n\t.pllm_stable_time                                = 0x0000012C,\n\t.pllm_setup_control                              = 0x00000000,\n\t.pllm_post_divider                               = 0x00000000, // P div.\n\t.pllm_kcp                                        = 0x00000000,\n\t.pllm_kvco                                       = 0x00000000,\n\n\t/* Spare BCT params */\n\t.emc_bct_spare0                                  = 0x00000000,\n\t.emc_bct_spare1                                  = 0x00000000,\n\t.emc_bct_spare2                                  = 0x00000000,\n\t.emc_bct_spare3                                  = 0x00000000,\n\t.emc_bct_spare4                                  = 0x7001BC68, // EMC_PMACRO_COMMON_PAD_TX_CTRL.\n\t.emc_bct_spare5                                  = 0x0000000A,\n\t.emc_bct_spare6                                  = 0x7001B404, // EMC_SWIZZLE_RANK0_BYTE0.\n\t.emc_bct_spare7                                  = 0x76543201,\n\t.emc_bct_spare8                                  = 0x7000E6C8, // APBDEV_PMC_WEAK_BIAS.\n\t.emc_bct_spare9                                  = 0x00000000,\n\t.emc_bct_spare10                                 = 0x00000000,\n\t.emc_bct_spare11                                 = 0x00000000,\n\t.emc_bct_spare12                                 = 0x00000000, // Used to hold EMC_PMACRO_BG_BIAS_CTRL.\n\t.emc_bct_spare13                                 = 0x00000034,\n\n\t/* EMC clock configuration */\n\t.emc_clock_source                                = 0x40188002,\n\t.emc_clock_source_dll                            = 0x40000000,\n\n\t.clk_rst_pllm_misc20_override                    = 0x00000000,\n\t.clk_rst_pllm_misc20_override_enable             = 0x00000000,\n\n\t.clear_clock2_mc1                                = 0x00000000,\n\n\t/* Auto-calibration of EMC pads */\n\t.emc_auto_cal_interval                           = 0x001FFFFF,\n\n\t.emc_auto_cal_config                             = 0xA01A51D8,\n\t.emc_auto_cal_config2                            = 0x05500000,\n\t.emc_auto_cal_config3                            = 0x00770000,\n\n\t.emc_auto_cal_config4                            = 0x00770000,\n\t.emc_auto_cal_config5                            = 0x00770000,\n\t.emc_auto_cal_config6                            = 0x00770000,\n\t.emc_auto_cal_config7                            = 0x00770000,\n\t.emc_auto_cal_config8                            = 0x00770000,\n\n\t.emc_auto_cal_vref_sel0                          = 0xB3AFA6A6,\n\t.emc_auto_cal_vref_sel1                          = 0x00009E3C,\n\n\t.emc_auto_cal_channel                            = 0xC1E00303,\n\n\t.emc_pmacro_auto_cal_cfg0                        = 0x04040404,\n\t.emc_pmacro_auto_cal_cfg1                        = 0x04040404,\n\t.emc_pmacro_auto_cal_cfg2                        = 0x00000000,\n\n\t.emc_pmacro_rx_term                              = 0x1F1F1F1F,\n\t.emc_pmacro_dq_tx_drive                          = 0x1F1F1F1F,\n\t.emc_pmacro_ca_tx_drive                          = 0x1F1F1F1F,\n\t.emc_pmacro_cmd_tx_drive                         = 0x00001F1F,\n\t.emc_pmacro_auto_cal_common                      = 0x00000804,\n\t.emc_pmacro_zcrtl                                = 0x00000550,\n\n\t/* Specifies the time for the calibration to stabilize (in microseconds) */\n\t.emc_auto_cal_wait                               = 0x000001A1,\n\n\t.emc_xm2_comp_pad_ctrl                           = 0x00000032,\n\t.emc_xm2_comp_pad_ctrl2                          = 0x00000000,\n\t.emc_xm2_comp_pad_ctrl3                          = 0x00000000,\n\n\t/*\n\t * DRAM size information\n\t * Specifies the value for EMC_ADR_CFG\n\t */\n\t.emc_adr_cfg                                     = 0x00000001, // 2 Ranks.\n\n\t/*\n\t * Specifies the time to wait after asserting pin\n\t * CKE (in microseconds)\n\t */\n\t.emc_pin_program_wait                            = 0x00000002,\n\t/* Specifies the extra delay before/after pin RESET/CKE command */\n\t.emc_pin_extra_wait                              = 0x00000000,\n\n\t.emc_pin_gpio_enable                             = 0x00000003,\n\t.emc_pin_gpio                                    = 0x00000003,\n\n\t/* Specifies the extra delay after the first writing of EMC_TIMING_CONTROL */\n\t.emc_timing_control_wait                         = 0x0000001E,\n\n\t/* Timing parameters required for the SDRAM */\n\t.emc_rc                                          = 0x0000000D,\n\t.emc_rfc                                         = 0x00000025,\n\t.emc_rfc_pb                                      = 0x00000013,\n\t.emc_ref_ctrl2                                   = 0x00000000,\n\t.emc_rfc_slr                                     = 0x00000000,\n\t.emc_ras                                         = 0x00000009,\n\t.emc_rp                                          = 0x00000004,\n\t.emc_r2r                                         = 0x00000000,\n\t.emc_w2w                                         = 0x00000000,\n\t.emc_r2w                                         = 0x0000000B,\n\t.emc_w2r                                         = 0x0000000D,\n\t.emc_r2p                                         = 0x00000008,\n\t.emc_w2p                                         = 0x0000000B,\n\t.emc_tppd                                        = 0x00000004,\n\t.emc_ccdmw                                       = 0x00000020,\n\t.emc_rd_rcd                                      = 0x00000006,\n\t.emc_wr_rcd                                      = 0x00000006,\n\t.emc_rrd                                         = 0x00000006,\n\t.emc_rext                                        = 0x00000003,\n\t.emc_wext                                        = 0x00000000,\n\t.emc_wdv                                         = 0x00000004,\n\t.emc_wdv_chk                                     = 0x00000006,\n\t.emc_wsv                                         = 0x00000002,\n\t.emc_wev                                         = 0x00000000,\n\t.emc_wdv_mask                                    = 0x00000004,\n\t.emc_ws_duration                                 = 0x00000008,\n\t.emc_we_duration                                 = 0x0000000D,\n\t.emc_quse                                        = 0x00000005,\n\t.emc_quse_width                                  = 0x00000006,\n\t.emc_ibdly                                       = 0x00000000,\n\t.emc_obdly                                       = 0x00000000,\n\t.emc_einput                                      = 0x00000002,\n\t.emc_einput_duration                             = 0x0000000D,\n\t.emc_puterm_extra                                = 0x00000000,\n\t.emc_puterm_width                                = 0x0000000B,\n\t.emc_qrst                                        = 0x00010000,\n\t.emc_qsafe                                       = 0x00000012,\n\t.emc_rdv                                         = 0x00000014,\n\t.emc_rdv_mask                                    = 0x00000016,\n\t.emc_rdv_early                                   = 0x00000012,\n\t.emc_rdv_early_mask                              = 0x00000014,\n\t.emc_qpop                                        = 0x0000000A,\n\t.emc_refresh                                     = 0x00000304,\n\t.emc_burst_refresh_num                           = 0x00000000,\n\t.emc_prerefresh_req_cnt                          = 0x000000C1,\n\t.emc_pdex2wr                                     = 0x00000008,\n\t.emc_pdex2rd                                     = 0x00000008,\n\t.emc_pchg2pden                                   = 0x00000003,\n\t.emc_act2pden                                    = 0x00000003,\n\t.emc_ar2pden                                     = 0x00000003,\n\t.emc_rw2pden                                     = 0x00000014,\n\t.emc_cke2pden                                    = 0x00000005,\n\t.emc_pdex2che                                    = 0x00000002,\n\t.emc_pdex2mrr                                    = 0x0000000D,\n\t.emc_txsr                                        = 0x00000027,\n\t.emc_txsr_dll                                    = 0x00000027,\n\t.emc_tcke                                        = 0x00000005,\n\t.emc_tckesr                                      = 0x00000005,\n\t.emc_tpd                                         = 0x00000004,\n\t.emc_tfaw                                        = 0x00000009,\n\t.emc_trpab                                       = 0x00000005,\n\t.emc_tclkstable                                  = 0x00000004,\n\t.emc_tclkstop                                    = 0x00000009,\n\t.emc_trefbw                                      = 0x0000031C,\n\n\t/* FBIO configuration values */\n\t.emc_fbio_cfg5                                   = 0x9160A00D,\n\t.emc_fbio_cfg7                                   = 0x00003BBF,\n\t.emc_fbio_cfg8                                   = 0x0CF30000,\n\n\t/* Command mapping for CMD brick 0 */\n\t.emc_cmd_mapping_cmd0_0                          = 0x061B0504,\n\t.emc_cmd_mapping_cmd0_1                          = 0x1C070302,\n\t.emc_cmd_mapping_cmd0_2                          = 0x05252523,\n\t.emc_cmd_mapping_cmd1_0                          = 0x0A091D08,\n\t.emc_cmd_mapping_cmd1_1                          = 0x0D1E0B24,\n\t.emc_cmd_mapping_cmd1_2                          = 0x0326260C,\n\t.emc_cmd_mapping_cmd2_0                          = 0x231C1B02,\n\t.emc_cmd_mapping_cmd2_1                          = 0x05070403,\n\t.emc_cmd_mapping_cmd2_2                          = 0x02252506,\n\t.emc_cmd_mapping_cmd3_0                          = 0x0D1D0B0A,\n\t.emc_cmd_mapping_cmd3_1                          = 0x1E090C08,\n\t.emc_cmd_mapping_cmd3_2                          = 0x08262624,\n\t.emc_cmd_mapping_byte                            = 0x9A070624,\n\n\t.emc_fbio_spare                                  = 0x00000012,\n\t.emc_cfg_rsv                                     = 0xFF00FF00,\n\n\t/* MRS command values */\n\t.emc_mrs                                         = 0x00000000,\n\t.emc_emrs                                        = 0x00000000,\n\t.emc_emrs2                                       = 0x00000000,\n\t.emc_emrs3                                       = 0x00000000,\n\t.emc_mrw1                                        = 0x08010004,\n\t.emc_mrw2                                        = 0x08020000,\n\t.emc_mrw3                                        = 0x080D0000,\n\t.emc_mrw4                                        = 0xC0000000,\n\t.emc_mrw6                                        = 0x08037171,\n\t.emc_mrw8                                        = 0x080B0000,\n\t.emc_mrw9                                        = 0x0C0E7272,\n\t.emc_mrw10                                       = 0x00000000,\n\t.emc_mrw12                                       = 0x0C0D0808,\n\t.emc_mrw13                                       = 0x0C0D0000,\n\t.emc_mrw14                                       = 0x08161414,\n\t.emc_mrw_extra                                   = 0x08010004,\n\t.emc_warm_boot_mrw_extra                         = 0x08110000,\n\t.emc_warm_boot_extramode_reg_write_enable        = 0x00000001,\n\t.emc_extramode_reg_write_enable                  = 0x00000000,\n\t.emc_mrw_reset_command                           = 0x00000000,\n\t.emc_mrw_reset_ninit_wait                        = 0x00000000,\n\t.emc_mrs_wait_cnt                                = 0x00CC0015,\n\t.emc_mrs_wait_cnt2                               = 0x0033000A,\n\n\t/* EMC miscellaneous configurations */\n\t.emc_cfg                                         = 0xF3200000,\n\t.emc_cfg2                                        = 0x00110805,\n\t.emc_cfg_pipe                                    = 0x0FFF0FFF,\n\t.emc_cfg_pipe_clk                                = 0x00000000,\n\t.emc_fdpd_ctrl_cmd_no_ramp                       = 0x00000001,\n\t.emc_cfg_update                                  = 0x70000301,\n\t.emc_dbg                                         = 0x01000C00,\n\t.emc_dbg_write_mux                               = 0x00000001,\n\t.emc_cmd_q                                       = 0x10004408,\n\t.emc_mc2emc_q                                    = 0x06000404,\n\t.emc_dyn_self_ref_control                        = 0x80000713,\n\t.ahb_arbitration_xbar_ctrl_meminit_done          = 0x00000001,\n\t.emc_cfg_dig_dll                                 = 0x002C00A0,\n\t.emc_cfg_dig_dll_1                               = 0x00003701,\n\t.emc_cfg_dig_dll_period                          = 0x00008000,\n\t.emc_dev_select                                  = 0x00000000, // Both Ranks.\n\t.emc_sel_dpd_ctrl                                = 0x00040008,\n\n\t/* Pads trimmer delays */\n\t.emc_fdpd_ctrl_dq                                = 0x8020221F,\n\t.emc_fdpd_ctrl_cmd                               = 0x0220F40F,\n\t.emc_pmacro_ib_vref_dq_0                         = 0x28282828,\n\t.emc_pmacro_ib_vref_dq_1                         = 0x28282828,\n\t.emc_pmacro_ib_vref_dqs_0                        = 0x11111111,\n\t.emc_pmacro_ib_vref_dqs_1                        = 0x11111111,\n\t.emc_pmacro_ib_rxrt                              = 0x000000BE,\n\t.emc_cfg_pipe1                                   = 0x0FFF0FFF,\n\t.emc_cfg_pipe2                                   = 0x0FFF0FFF,\n\n\t.emc_pmacro_quse_ddll_rank0_0                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank0_1                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank0_2                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank0_3                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank0_4                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank0_5                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank1_0                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank1_1                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank1_2                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank1_3                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank1_4                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank1_5                    = 0x00000000,\n\n\t.emc_pmacro_ob_ddll_long_dq_rank0_0              = 0x00000000,\n\t.emc_pmacro_ob_ddll_long_dq_rank0_1              = 0x00000000,\n\t.emc_pmacro_ob_ddll_long_dq_rank0_2              = 0x00000000,\n\t.emc_pmacro_ob_ddll_long_dq_rank0_3              = 0x00000000,\n\t.emc_pmacro_ob_ddll_long_dq_rank0_4              = 0x00120014,\n\t.emc_pmacro_ob_ddll_long_dq_rank0_5              = 0x00140010,\n\t.emc_pmacro_ob_ddll_long_dq_rank1_0              = 0x00000000,\n\t.emc_pmacro_ob_ddll_long_dq_rank1_1              = 0x00000000,\n\t.emc_pmacro_ob_ddll_long_dq_rank1_2              = 0x00000000,\n\t.emc_pmacro_ob_ddll_long_dq_rank1_3              = 0x00000000,\n\t.emc_pmacro_ob_ddll_long_dq_rank1_4              = 0x00120014,\n\t.emc_pmacro_ob_ddll_long_dq_rank1_5              = 0x00140010,\n\n\t.emc_pmacro_ob_ddll_long_dqs_rank0_0             = 0x002E0030,\n\t.emc_pmacro_ob_ddll_long_dqs_rank0_1             = 0x00300033,\n\t.emc_pmacro_ob_ddll_long_dqs_rank0_2             = 0x00350033,\n\t.emc_pmacro_ob_ddll_long_dqs_rank0_3             = 0x00320030,\n\t.emc_pmacro_ob_ddll_long_dqs_rank0_4             = 0x00000005,\n\t.emc_pmacro_ob_ddll_long_dqs_rank0_5             = 0x00000000,\n\t.emc_pmacro_ob_ddll_long_dqs_rank1_0             = 0x002E0030,\n\t.emc_pmacro_ob_ddll_long_dqs_rank1_1             = 0x00300033,\n\t.emc_pmacro_ob_ddll_long_dqs_rank1_2             = 0x00350033,\n\t.emc_pmacro_ob_ddll_long_dqs_rank1_3             = 0x00320030,\n\t.emc_pmacro_ob_ddll_long_dqs_rank1_4             = 0x00000005,\n\t.emc_pmacro_ob_ddll_long_dqs_rank1_5             = 0x00000000,\n\n\t.emc_pmacro_ib_ddll_long_dqs_rank0_0             = 0x00280028,\n\t.emc_pmacro_ib_ddll_long_dqs_rank0_1             = 0x00280028,\n\t.emc_pmacro_ib_ddll_long_dqs_rank0_2             = 0x00280028,\n\t.emc_pmacro_ib_ddll_long_dqs_rank0_3             = 0x00280028,\n\t.emc_pmacro_ib_ddll_long_dqs_rank1_0             = 0x00280028,\n\t.emc_pmacro_ib_ddll_long_dqs_rank1_1             = 0x00280028,\n\t.emc_pmacro_ib_ddll_long_dqs_rank1_2             = 0x00280028,\n\t.emc_pmacro_ib_ddll_long_dqs_rank1_3             = 0x00280028,\n\n\t.emc_pmacro_ddll_long_cmd_0                      = 0x00140014,\n\t.emc_pmacro_ddll_long_cmd_1                      = 0x00120012,\n\t.emc_pmacro_ddll_long_cmd_2                      = 0x00100010,\n\t.emc_pmacro_ddll_long_cmd_3                      = 0x00140014,\n\t.emc_pmacro_ddll_long_cmd_4                      = 0x00000014,\n\t.emc_pmacro_ddll_short_cmd_0                     = 0x00000000,\n\t.emc_pmacro_ddll_short_cmd_1                     = 0x00000000,\n\t.emc_pmacro_ddll_short_cmd_2                     = 0x00000000,\n\n\t/*\n\t * Specifies the delay after asserting CKE pin during a WarmBoot0\n\t * sequence (in microseconds)\n\t */\n\t.warm_boot_wait                                  = 0x00000001,\n\n\t.emc_odt_write                                   = 0x00000000,\n\n\t/* Periodic ZQ calibration */\n\n\t/*\n\t * Specifies the value for EMC_ZCAL_INTERVAL\n\t * Value 0 disables ZQ calibration\n\t */\n\t.emc_zcal_interval                               = 0x00064000,\n\t.emc_zcal_wait_cnt                               = 0x000900CC,\n\t.emc_zcal_mrw_cmd                                = 0x0051004F,\n\n\t/* DRAM initialization sequence flow control */\n\t.emc_mrs_reset_dll                               = 0x00000000,\n\t.emc_zcal_init_dev0                              = 0x80000001,\n\t.emc_zcal_init_dev1                              = 0x40000001,\n\t/*\n\t * Specifies the wait time after programming a ZQ initialization\n\t * command (in microseconds)\n\t */\n\t.emc_zcal_init_wait                              = 0x00000001,\n\t/*\n\t * Specifies the enable for ZQ calibration at cold boot [bit 0]\n\t * and warm boot [bit 1]\n\t */\n\t.emc_zcal_warm_cold_boot_enables                 = 0x00000003,\n\n\t/*\n\t * Specifies the MRW command to LPDDR2 for ZQ calibration\n\t * on warmboot\n\t */\n\t/* Is issued to both devices separately */\n\t.emc_mrw_lpddr2zcal_warm_boot                    = 0x040A00AB,\n\t/*\n\t * Specifies the ZQ command to DDR3 for ZQ calibration on warmboot\n\t * Is issued to both devices separately\n\t */\n\t.emc_zqcal_ddr3_warm_boot                        = 0x00000011,\n\t.emc_zqcal_lpddr4_warm_boot                      = 0x00000001,\n\n\t/*\n\t * Specifies the wait time for ZQ calibration on warmboot\n\t * (in microseconds)\n\t */\n\t.emc_zcal_warm_boot_wait                         = 0x00000001,\n\t/*\n\t * Specifies the enable for DRAM Mode Register programming\n\t * at warm boot\n\t */\n\t.emc_mrs_warm_boot_enable                        = 0x00000001,\n\t.emc_mrs_reset_dll_wait                          = 0x00000000,\n\t.emc_mrs_extra                                   = 0x00000000,\n\t.emc_warm_boot_mrs_extra                         = 0x00000000,\n\t.emc_emrs_ddr2_dll_enable                        = 0x00000000,\n\t.emc_mrs_ddr2_dll_reset                          = 0x00000000,\n\t.emc_emrs_ddr2_ocd_calib                         = 0x00000000,\n\t/*\n\t * Specifies the wait between initializing DDR and setting OCD\n\t * calibration (in microseconds)\n\t */\n\t.emc_ddr2_wait                                   = 0x00000000,\n\t.emc_clken_override                              = 0x00000000,\n\t/*\n\t * Specifies LOG2 of the extra refresh numbers after booting\n\t * Program 0 to disable\n\t */\n\t.emc_extra_refresh_num                           = 0x00000002,\n\t.emc_clken_override_allwarm_boot                 = 0x00000000,\n\t.mc_clken_override_allwarm_boot                  = 0x00000000,\n\t/* Specifies digital dll period, choosing between 4 to 64 ms */\n\t.emc_cfg_dig_dll_period_warm_boot                = 0x00000003,\n\n\t/* Pad controls */\n\t.pmc_vddp_sel                                    = 0x00000001,\n\t.pmc_vddp_sel_wait                               = 0x00000002,\n\t.pmc_ddr_pwr                                     = 0x0000000F,\n\t.pmc_ddr_cfg                                     = 0x04220100,\n\t.pmc_io_dpd3_req                                 = 0x4FAFFFFF,\n\t.pmc_io_dpd3_req_wait                            = 0x00000001,\n\t.pmc_io_dpd4_req_wait                            = 0x00000002,\n\t.pmc_reg_short                                   = 0x00000000,\n\t.pmc_no_io_power                                 = 0x00000000,\n\t.pmc_ddr_ctrl_wait                               = 0x00000000,\n\t.pmc_ddr_ctrl                                    = 0x0007FF8B,\n\t.emc_acpd_control                                = 0x00000000,\n\n\t.emc_swizzle_rank0_byte0                         = 0x76543201, // Overridden to 0x76543201 by spare6/7.\n\t.emc_swizzle_rank0_byte1                         = 0x65324710,\n\t.emc_swizzle_rank0_byte2                         = 0x25763410,\n\t.emc_swizzle_rank0_byte3                         = 0x25673401,\n\t.emc_swizzle_rank1_byte0                         = 0x32647501,\n\t.emc_swizzle_rank1_byte1                         = 0x34567201,\n\t.emc_swizzle_rank1_byte2                         = 0x56742310,\n\t.emc_swizzle_rank1_byte3                         = 0x67324501,\n\n\t.emc_txdsrvttgen                                 = 0x00000000,\n\n\t.emc_data_brlshft0                               = 0x00249249,\n\t.emc_data_brlshft1                               = 0x00249249,\n\n\t.emc_dqs_brlshft0                                = 0x00000000,\n\t.emc_dqs_brlshft1                                = 0x00000000,\n\n\t.emc_cmd_brlshft0                                = 0x00000000,\n\t.emc_cmd_brlshft1                                = 0x00000000,\n\t.emc_cmd_brlshft2                                = 0x0000001B,\n\t.emc_cmd_brlshft3                                = 0x0000001B,\n\n\t.emc_quse_brlshft0                               = 0x00000000,\n\t.emc_quse_brlshft1                               = 0x00000000,\n\t.emc_quse_brlshft2                               = 0x00000000,\n\t.emc_quse_brlshft3                               = 0x00000000,\n\n\t.emc_dll_cfg0                                    = 0x1F13412F,\n\t.emc_dll_cfg1                                    = 0x00010014,\n\n\t.emc_pmc_scratch1                                = 0x4FAFFFFF, // APBDEV_PMC_IO_DPD3_REQ.\n\t.emc_pmc_scratch2                                = 0x7FFFFFFF,\n\t.emc_pmc_scratch3                                = 0x4006D70B, // APBDEV_PMC_DDR_CNTRL.\n\n\t.emc_pmacro_pad_cfg_ctrl                         = 0x00020000,\n\t.emc_pmacro_vttgen_ctrl0                         = 0x00030808,\n\t.emc_pmacro_vttgen_ctrl1                         = 0x00015C00,\n\t.emc_pmacro_vttgen_ctrl2                         = 0x00101010,\n\t.emc_pmacro_brick_ctrl_rfu1                      = 0x00001600,\n\t.emc_pmacro_cmd_brick_ctrl_fdpd                  = 0x00000000,\n\t.emc_pmacro_brick_ctrl_rfu2                      = 0x00000000,\n\t.emc_pmacro_data_brick_ctrl_fdpd                 = 0x00000000,\n\t.emc_pmacro_bg_bias_ctrl0                        = 0x00000034,\n\t.emc_pmacro_data_pad_rx_ctrl                     = 0x00050037,\n\t.emc_pmacro_cmd_pad_rx_ctrl                      = 0x00000000,\n\t.emc_pmacro_data_rx_term_mode                    = 0x00000010,\n\t.emc_pmacro_cmd_rx_term_mode                     = 0x00003000,\n\t.emc_pmacro_data_pad_tx_ctrl                     = 0x02000111,\n\t.emc_pmacro_common_pad_tx_ctrl                   = 0x00000008, // Overridden to 0x0000000A by spare4/5.\n\t.emc_pmacro_cmd_pad_tx_ctrl                      = 0x0A000000,\n\n\t.emc_cfg3                                        = 0x00000040,\n\n\t.emc_pmacro_tx_pwrd0                             = 0x10000000,\n\t.emc_pmacro_tx_pwrd1                             = 0x08000000,\n\t.emc_pmacro_tx_pwrd2                             = 0x08000000,\n\t.emc_pmacro_tx_pwrd3                             = 0x00000000,\n\t.emc_pmacro_tx_pwrd4                             = 0x00000000,\n\t.emc_pmacro_tx_pwrd5                             = 0x00001000,\n\n\t.emc_config_sample_delay                         = 0x00000020,\n\n\t.emc_pmacro_brick_mapping0                       = 0x28091081,\n\t.emc_pmacro_brick_mapping1                       = 0x44A53293,\n\t.emc_pmacro_brick_mapping2                       = 0x76678A5B,\n\n\t.emc_pmacro_tx_sel_clk_src0                      = 0x00000000,\n\t.emc_pmacro_tx_sel_clk_src1                      = 0x00000000,\n\t.emc_pmacro_tx_sel_clk_src2                      = 0x00000000,\n\t.emc_pmacro_tx_sel_clk_src3                      = 0x00000000,\n\t.emc_pmacro_tx_sel_clk_src4                      = 0x00000000,\n\t.emc_pmacro_tx_sel_clk_src5                      = 0x00000000,\n\n\t.emc_pmacro_ddll_bypass                          = 0xEFFFEFFF,\n\n\t.emc_pmacro_ddll_pwrd0                           = 0xC0C0C0C0,\n\t.emc_pmacro_ddll_pwrd1                           = 0xC0C0C0C0,\n\t.emc_pmacro_ddll_pwrd2                           = 0xDCDCDCDC,\n\n\t.emc_pmacro_cmd_ctrl0                            = 0x0A0A0A0A,\n\t.emc_pmacro_cmd_ctrl1                            = 0x0A0A0A0A,\n\t.emc_pmacro_cmd_ctrl2                            = 0x0A0A0A0A,\n\n\t/* DRAM size information */\n\t.mc_emem_adr_cfg                                 = 0x00000001, // 2 Ranks.\n\t.mc_emem_adr_cfg_dev0                            = 0x00070302, // Chip 0 Density 512MB.\n\t.mc_emem_adr_cfg_dev1                            = 0x00070302, // Chip 1 Density 512MB.\n\t.mc_emem_adr_cfg_channel_mask                    = 0xFFFF2400,\n\t.mc_emem_adr_cfg_bank_mask0                      = 0x6E574400,\n\t.mc_emem_adr_cfg_bank_mask1                      = 0x39722800,\n\t.mc_emem_adr_cfg_bank_mask2                      = 0x4B9C1000,\n\t/*\n\t * Specifies the value for MC_EMEM_CFG which holds the external memory\n\t * size (in MBytes)\n\t */\n\t.mc_emem_cfg                                     = 0x00001000, // 4GB total density. Max 8GB.\n\n\t/* MC arbitration configuration */\n\t.mc_emem_arb_cfg                                 = 0x08000001,\n\t.mc_emem_arb_outstanding_req                     = 0x8000004C,\n\t.emc_emem_arb_refpb_hp_ctrl                      = 0x000A1020,\n\t.emc_emem_arb_refpb_bank_ctrl                    = 0x80001028,\n\n\t.mc_emem_arb_timing_rcd                          = 0x00000001,\n\t.mc_emem_arb_timing_rp                           = 0x00000000,\n\t.mc_emem_arb_timing_rc                           = 0x00000003,\n\t.mc_emem_arb_timing_ras                          = 0x00000001,\n\t.mc_emem_arb_timing_faw                          = 0x00000002,\n\t.mc_emem_arb_timing_rrd                          = 0x00000001,\n\t.mc_emem_arb_timing_rap2pre                      = 0x00000002,\n\t.mc_emem_arb_timing_wap2pre                      = 0x00000005,\n\t.mc_emem_arb_timing_r2r                          = 0x00000002,\n\t.mc_emem_arb_timing_w2w                          = 0x00000001,\n\t.mc_emem_arb_timing_r2w                          = 0x00000004,\n\t.mc_emem_arb_timing_w2r                          = 0x00000005,\n\t.mc_emem_arb_timing_rfcpb                        = 0x00000004,\n\n\t.mc_emem_arb_da_turns                            = 0x02020001,\n\t.mc_emem_arb_da_covers                           = 0x00030201,\n\t.mc_emem_arb_misc0                               = 0x71C30504,\n\t.mc_emem_arb_misc1                               = 0x70000F0F,\n\t.mc_emem_arb_misc2                               = 0x00000000,\n\n\t.mc_emem_arb_ring1_throttle                      = 0x001F0000,\n\t.mc_emem_arb_override                            = 0x10000000,\n\t.mc_emem_arb_override1                           = 0x00000000,\n\t.mc_emem_arb_rsv                                 = 0xFF00FF00,\n\n\t.mc_da_cfg0                                      = 0x00000001,\n\t.mc_emem_arb_timing_ccdmw                        = 0x00000008,\n\n\t.mc_clken_override                               = 0x00008000,\n\n\t.mc_stat_control                                 = 0x00000000,\n\n\t/* VPR carveout configuration */\n\t.mc_video_protect_bom                            = 0xFFF00000,\n\t.mc_video_protect_bom_adr_hi                     = 0x00000000,\n\t.mc_video_protect_size_mb                        = 0x00000000,\n\n\t// Disable access:\n\t//  AFI (PCIE), BPMP, HC (HOST1x), ISP2, CCPLEX, PPCS (AHB), SATA, VI, XUSB_HOST, XUSB_DEV, ADSP, PPCS1 (AHB), DC1 (WinT), SDMMC1/2/3. Plus TSEC, NVENC.\n\t// Enable access:\n\t//  DC, DCB, HDA, VIC.\n\t.mc_video_protect_vpr_override                   = 0xE4FACB43, // Stock/Reset: 0xE4BAC343. HOS new: 0xE4FACB43. + TSEC, NVENC.\n\t// Disable access:\n\t//  SDMMC4, ISP2B, PPCS2 (AHB), APE, SE, HC1, SE1, AXIAP, ETR. Plus TSECB, TSEC1, TSECB1.\n\t// Enable access:\n\t//  GPU, GPUB, NVDEC, NVJPG, NVDEC1.\n\t.mc_video_protect_vpr_override1                  = 0x0000FED3, // Stock/Reset: 0x00001ED3. HOS new: 0x0000FED3. + TSECB, TSEC1, TSECB1.\n\n\t// VPR CYA. L4T override (set PD, SCC, SKED, L1 as UNTRUSTED).\n\t.mc_video_protect_gpu_override0                  = VPR_OVR0_CYA_TRUST_GCC(VPR_TRUST_GRAPHICS)    |\n\t\t\t\t\t\t\t\t\t\t\t\t\t   VPR_OVR0_CYA_TRUST_RASTER(VPR_TRUST_GRAPHICS) |\n\t\t\t\t\t\t\t\t\t\t\t\t\t   VPR_OVR0_CYA_TRUST_PE(VPR_TRUST_GRAPHICS)     |\n\t\t\t\t\t\t\t\t\t\t\t\t\t   VPR_OVR0_CYA_TRUST_TEX(VPR_TRUST_GRAPHICS)    |\n\t\t\t\t\t\t\t\t\t\t\t\t\t   VPR_OVR0_CYA_TRUST_OVERRIDE,                 // Stock: 0. HOS: VPR_OVR0_CYA_TRUST_DEFAULT.\n\t.mc_video_protect_gpu_override1                  = VPR_OVR1_CYA_TRUST_PROP(VPR_TRUST_GRAPHICS), // Stock: 0. HOS: 0.\n\n\t/* TZDRAM carveout configuration */\n\t.mc_sec_carveout_bom                             = 0xFFF00000,\n\t.mc_sec_carveout_adr_hi                          = 0x00000000,\n\t.mc_sec_carveout_size_mb                         = 0x00000000,\n\n\t.mc_video_protect_write_access                   = 0x00000000,\n\t.mc_sec_carveout_protect_write_access            = 0x00000000,\n\n\t.mc_generalized_carveout1_bom                    = 0x00000000,\n\t.mc_generalized_carveout1_bom_hi                 = 0x00000000,\n\t.mc_generalized_carveout1_size_128kb             = 0x00000008,\n\t.mc_generalized_carveout1_access0                = 0x00000000,\n\t.mc_generalized_carveout1_access1                = 0x00000000,\n\t.mc_generalized_carveout1_access2                = 0x00300000,\n\t.mc_generalized_carveout1_access3                = 0x03000000,\n\t.mc_generalized_carveout1_access4                = 0x00000000,\n\t.mc_generalized_carveout1_force_internal_access0 = 0x00000000,\n\t.mc_generalized_carveout1_force_internal_access1 = 0x00000000,\n\t.mc_generalized_carveout1_force_internal_access2 = 0x00000000,\n\t.mc_generalized_carveout1_force_internal_access3 = 0x00000000,\n\t.mc_generalized_carveout1_force_internal_access4 = 0x00000000,\n\t.mc_generalized_carveout1_cfg0                   = 0x04000C76,\n\n\t.mc_generalized_carveout2_bom                    = 0x00000000,\n\t.mc_generalized_carveout2_bom_hi                 = 0x00000000,\n\t.mc_generalized_carveout2_size_128kb             = 0x00000002,\n\t.mc_generalized_carveout2_access0                = 0x00000000,\n\t.mc_generalized_carveout2_access1                = 0x00000000,\n\t.mc_generalized_carveout2_access2                = 0x03000000,\n\t.mc_generalized_carveout2_access3                = 0x00000000,\n\t.mc_generalized_carveout2_access4                = 0x00000300,\n\t.mc_generalized_carveout2_force_internal_access0 = 0x00000000,\n\t.mc_generalized_carveout2_force_internal_access1 = 0x00000000,\n\t.mc_generalized_carveout2_force_internal_access2 = 0x00000000,\n\t.mc_generalized_carveout2_force_internal_access3 = 0x00000000,\n\t.mc_generalized_carveout2_force_internal_access4 = 0x00000000,\n\t.mc_generalized_carveout2_cfg0                   = 0x0440167E,\n\n\t.mc_generalized_carveout3_bom                    = 0x00000000,\n\t.mc_generalized_carveout3_bom_hi                 = 0x00000000,\n\t.mc_generalized_carveout3_size_128kb             = 0x00000000,\n\t.mc_generalized_carveout3_access0                = 0x00000000,\n\t.mc_generalized_carveout3_access1                = 0x00000000,\n\t.mc_generalized_carveout3_access2                = 0x03000000,\n\t.mc_generalized_carveout3_access3                = 0x00000000,\n\t.mc_generalized_carveout3_access4                = 0x00000300,\n\t.mc_generalized_carveout3_force_internal_access0 = 0x00000000,\n\t.mc_generalized_carveout3_force_internal_access1 = 0x00000000,\n\t.mc_generalized_carveout3_force_internal_access2 = 0x00000000,\n\t.mc_generalized_carveout3_force_internal_access3 = 0x00000000,\n\t.mc_generalized_carveout3_force_internal_access4 = 0x00000000,\n\t.mc_generalized_carveout3_cfg0                   = 0x04401E7E,\n\n\t.mc_generalized_carveout4_bom                    = 0x00000000,\n\t.mc_generalized_carveout4_bom_hi                 = 0x00000000,\n\t.mc_generalized_carveout4_size_128kb             = 0x00000008,\n\t.mc_generalized_carveout4_access0                = 0x00000000,\n\t.mc_generalized_carveout4_access1                = 0x00000000,\n\t.mc_generalized_carveout4_access2                = 0x00300000,\n\t.mc_generalized_carveout4_access3                = 0x00000000,\n\t.mc_generalized_carveout4_access4                = 0x000000C0,\n\t.mc_generalized_carveout4_force_internal_access0 = 0x00000000,\n\t.mc_generalized_carveout4_force_internal_access1 = 0x00000000,\n\t.mc_generalized_carveout4_force_internal_access2 = 0x00000000,\n\t.mc_generalized_carveout4_force_internal_access3 = 0x00000000,\n\t.mc_generalized_carveout4_force_internal_access4 = 0x00000000,\n\t.mc_generalized_carveout4_cfg0                   = 0x04002446,\n\n\t.mc_generalized_carveout5_bom                    = 0x00000000,\n\t.mc_generalized_carveout5_bom_hi                 = 0x00000000,\n\t.mc_generalized_carveout5_size_128kb             = 0x00000008,\n\t.mc_generalized_carveout5_access0                = 0x00000000,\n\t.mc_generalized_carveout5_access1                = 0x00000000,\n\t.mc_generalized_carveout5_access2                = 0x00300000,\n\t.mc_generalized_carveout5_access3                = 0x00000000,\n\t.mc_generalized_carveout5_access4                = 0x00000000,\n\t.mc_generalized_carveout5_force_internal_access0 = 0x00000000,\n\t.mc_generalized_carveout5_force_internal_access1 = 0x00000000,\n\t.mc_generalized_carveout5_force_internal_access2 = 0x00000000,\n\t.mc_generalized_carveout5_force_internal_access3 = 0x00000000,\n\t.mc_generalized_carveout5_force_internal_access4 = 0x00000000,\n\t.mc_generalized_carveout5_cfg0                   = 0x04002C46,\n\n\t/* Specifies enable for CA training */\n\t.emc_ca_training_enable                          = 0x00000000,\n\t/* Set if bit 6 select is greater than bit 7 select; uses aremc.spec packet SWIZZLE_BIT6_GT_BIT7 */\n\t.swizzle_rank_byte_encode                        = 0x000000EC,\n\n\t/* Specifies enable and offset for patched boot rom write */\n\t.boot_rom_patch_control                          = 0x00000000,\n\t/* Specifies data for patched boot rom write */\n\t.boot_rom_patch_data                             = 0x00000000,\n\n\t/* CPU FW carveout configuration */\n\t.mc_mts_carveout_bom                             = 0xFFF00000,\n\t.mc_mts_carveout_adr_hi                          = 0x00000000,\n\t.mc_mts_carveout_size_mb                         = 0x00000000,\n\t.mc_mts_carveout_reg_ctrl                        = 0x00000000\n};\n\n#define DCFG_OFFSET_OF(m) (OFFSET_OF(sdram_params_t210_t, m) / 4)\nstatic const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210[] = {\n\t// Hynix timing config.\n\t{ 0x0000000D, DRAM_ID(LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE), DCFG_OFFSET_OF(emc_r2w)                      },\n\t{ 0x00000001, DRAM_ID(LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE), DCFG_OFFSET_OF(emc_puterm_extra)             },\n\t{ 0x80000000, DRAM_ID(LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE), DCFG_OFFSET_OF(emc_puterm_width)             },\n\t{ 0x00000210, DRAM_ID(LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE), DCFG_OFFSET_OF(emc_pmacro_data_rx_term_mode) },\n\t{ 0x00000005, DRAM_ID(LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE), DCFG_OFFSET_OF(mc_emem_arb_timing_r2w)       },\n\n\t// Samsung 6GB density config.\n\t{ 0x000C0302, DRAM_ID(LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH),  DCFG_OFFSET_OF(mc_emem_adr_cfg_dev0)         }, // 768MB Chip 0 density.\n\t{ 0x000C0302, DRAM_ID(LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH),  DCFG_OFFSET_OF(mc_emem_adr_cfg_dev1)         }, // 768MB Chip 1 density.\n\t{ 0x00001800, DRAM_ID(LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH),  DCFG_OFFSET_OF(mc_emem_cfg)                  }, // 6GB total density. Max 8GB.\n\n\t// Samsung 8GB density config.\n\t{ 0x0000003A, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX),  DCFG_OFFSET_OF(emc_rfc)                      },\n\t{ 0x0000001D, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX),  DCFG_OFFSET_OF(emc_rfc_pb)                   },\n\t{ 0x0000003B, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX),  DCFG_OFFSET_OF(emc_txsr)                     },\n\t{ 0x0000003B, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX),  DCFG_OFFSET_OF(emc_txsr_dll)                 },\n\t{ 0x00080302, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX),  DCFG_OFFSET_OF(mc_emem_adr_cfg_dev0)         }, // 1024MB Chip 0 density.\n\t{ 0x00080302, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX),  DCFG_OFFSET_OF(mc_emem_adr_cfg_dev1)         }, // 1024MB Chip 1 density.\n\t{ 0x00002000, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX),  DCFG_OFFSET_OF(mc_emem_cfg)                  }, // 8GB total density. Max 8GB.\n\t{ 0x00000007, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX),  DCFG_OFFSET_OF(mc_emem_arb_timing_rfcpb)     },\n\t{ 0x72A30504, DRAM_ID(LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX),  DCFG_OFFSET_OF(mc_emem_arb_misc0)            },\n};\n#undef DCFG_OFFSET_OF\n"
  },
  {
    "path": "bdk/mem/sdram_config_t210b01.inl",
    "content": "/*\n * Copyright (c) 2020-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#define DRAM_CFG_T210B01_SIZE 2104\n\nstatic const sdram_params_t210b01_t _dram_cfg_08_10_12_14_samsung_hynix_4gb = {\n\t/* Specifies the type of memory device */\n\t.memory_type                                     = MEMORY_TYPE_LPDDR4,\n\n\t/* MC/EMC clock source configuration */\n\t.pllm_input_divider                              = 0x00000001, // M div.\n\t.pllm_feedback_divider                           = 0x00000022, // N div.\n\t.pllm_stable_time                                = 0x0000012C,\n\t.pllm_setup_control                              = 0x00000000,\n\t.pllm_post_divider                               = 0x00000000, // P div.\n\t.pllm_kcp                                        = 0x00000000,\n\t.pllm_kvco                                       = 0x00000000,\n\n\t/* Spare BCT params */\n\t.emc_bct_spare0                                  = 0x00000000,\n\t.emc_bct_spare1                                  = 0x00000000,\n\t.emc_bct_spare2                                  = 0x00000000,\n\t.emc_bct_spare3                                  = 0x00000000,\n\t.emc_bct_spare4                                  = 0x00000000,\n\t.emc_bct_spare5                                  = 0x00000000,\n\t.emc_bct_spare6                                  = 0x00000000,\n\t.emc_bct_spare7                                  = 0x00000000,\n\t.emc_bct_spare8                                  = 0x00000000,\n\t.emc_bct_spare9                                  = 0x00000000,\n\t.emc_bct_spare10                                 = 0x00000000,\n\t.emc_bct_spare11                                 = 0x00000000,\n\t.emc_bct_spare12                                 = 0x00000000,\n\t.emc_bct_spare13                                 = 0x00000000,\n\n\t.emc_bct_spare_secure0                           = 0x00000000,\n\t.emc_bct_spare_secure1                           = 0x00000000,\n\t.emc_bct_spare_secure2                           = 0x00000000,\n\t.emc_bct_spare_secure3                           = 0x00000000,\n\t.emc_bct_spare_secure4                           = 0x00000000,\n\t.emc_bct_spare_secure5                           = 0x00000000,\n\t.emc_bct_spare_secure6                           = 0x00000000,\n\t.emc_bct_spare_secure7                           = 0x00000000,\n\t.emc_bct_spare_secure8                           = 0x00000000,\n\t.emc_bct_spare_secure9                           = 0x00000000,\n\t.emc_bct_spare_secure10                          = 0x00000000,\n\t.emc_bct_spare_secure11                          = 0x00000000,\n\t.emc_bct_spare_secure12                          = 0x00000000,\n\t.emc_bct_spare_secure13                          = 0x00000000,\n\t.emc_bct_spare_secure14                          = 0x00000000,\n\t.emc_bct_spare_secure15                          = 0x00000000,\n\t.emc_bct_spare_secure16                          = 0x00000000,\n\t.emc_bct_spare_secure17                          = 0x00000000,\n\t.emc_bct_spare_secure18                          = 0x00000000,\n\t.emc_bct_spare_secure19                          = 0x00000000,\n\t.emc_bct_spare_secure20                          = 0x00000000,\n\t.emc_bct_spare_secure21                          = 0x00000000,\n\t.emc_bct_spare_secure22                          = 0x00000000,\n\t.emc_bct_spare_secure23                          = 0x00000000,\n\n\t/* EMC clock configuration */\n\t.emc_clock_source                                = 0x40188002,\n\t.emc_clock_source_dll                            = 0x40000000,\n\n\t.clk_rst_pllm_misc20_override                    = 0x00000000,\n\t.clk_rst_pllm_misc20_override_enable             = 0x00000000,\n\n\t.clear_clock2_mc1                                = 0x00000000,\n\n\t/* Auto-calibration of EMC pads */\n\t.emc_auto_cal_interval                           = 0x001FFFFF,\n\n\t.emc_auto_cal_config                             = 0xA01A51D8,\n\t.emc_auto_cal_config2                            = 0x00000000,\n\t.emc_auto_cal_config3                            = 0x00880000,\n\n\t.emc_auto_cal_config4                            = 0x00880000,\n\t.emc_auto_cal_config5                            = 0x00001220,\n\t.emc_auto_cal_config6                            = 0x00880000,\n\t.emc_auto_cal_config7                            = 0x00880000,\n\t.emc_auto_cal_config8                            = 0x00880000,\n\t.emc_auto_cal_config9                            = 0x00000000,\n\n\t.emc_auto_cal_vref_sel0                          = 0xB3C5BCBC,\n\t.emc_auto_cal_vref_sel1                          = 0x00009E3C,\n\n\t.emc_auto_cal_channel                            = 0xC1E00302,\n\n\t.emc_pmacro_auto_cal_cfg0                        = 0x04040404,\n\t.emc_pmacro_auto_cal_cfg1                        = 0x04040404,\n\t.emc_pmacro_auto_cal_cfg2                        = 0x04040404,\n\n\t.emc_pmacro_rx_term                              = 0x3F3F3F3F,\n\t.emc_pmacro_dq_tx_drive                          = 0x3F3F3F3F,\n\t.emc_pmacro_ca_tx_drive                          = 0x3F3F3F3F,\n\t.emc_pmacro_cmd_tx_drive                         = 0x00001220,\n\t.emc_pmacro_auto_cal_common                      = 0x00000804,\n\t.emc_pmacro_zcrtl                                = 0x00505050,\n\n\t/* Specifies the time for the calibration to stabilize (in microseconds) */\n\t.emc_auto_cal_wait                               = 0x000001A1,\n\n\t.emc_xm2_comp_pad_ctrl                           = 0x00000030,\n\t.emc_xm2_comp_pad_ctrl2                          = 0x16001000,\n\t.emc_xm2_comp_pad_ctrl3                          = 0x00901000,\n\n\t/*\n\t * DRAM size information\n\t * Specifies the value for EMC_ADR_CFG\n\t */\n\t.emc_adr_cfg                                     = 0x00000000, // 1 Rank.\n\n\t/*\n\t * Specifies the time to wait after asserting pin\n\t * CKE (in microseconds)\n\t */\n\t.emc_pin_program_wait                            = 0x00000002,\n\t/* Specifies the extra delay before/after pin RESET/CKE command */\n\t.emc_pin_extra_wait                              = 0x00000000,\n\n\t.emc_pin_gpio_enable                             = 0x00000003,\n\t.emc_pin_gpio                                    = 0x00000003,\n\n\t/* Specifies the extra delay after the first writing of EMC_TIMING_CONTROL */\n\t.emc_timing_control_wait                         = 0x0000001E,\n\n\t/* Timing parameters required for the SDRAM */\n\t.emc_rc                                          = 0x0000000D,\n\t.emc_rfc                                         = 0x0000003A,\n\t.emc_rfc_pb                                      = 0x0000001D,\n\t.emc_ref_ctrl2                                   = 0x00000000,\n\t.emc_rfc_slr                                     = 0x00000000,\n\t.emc_ras                                         = 0x00000009,\n\t.emc_rp                                          = 0x00000004,\n\t.emc_r2r                                         = 0x00000000,\n\t.emc_w2w                                         = 0x00000000,\n\t.emc_r2w                                         = 0x0000000B,\n\t.emc_w2r                                         = 0x0000000D,\n\t.emc_r2p                                         = 0x00000008,\n\t.emc_w2p                                         = 0x0000000B,\n\t.emc_tppd                                        = 0x00000004,\n\t.emc_trtm                                        = 0x00000017,\n\t.emc_twtm                                        = 0x00000015,\n\t.emc_tratm                                       = 0x00000017,\n\t.emc_twatm                                       = 0x0000001B,\n\t.emc_tr2ref                                      = 0x00000000,\n\t.emc_ccdmw                                       = 0x00000020,\n\t.emc_rd_rcd                                      = 0x00000006,\n\t.emc_wr_rcd                                      = 0x00000006,\n\t.emc_rrd                                         = 0x00000006,\n\t.emc_rext                                        = 0x00000003,\n\t.emc_wext                                        = 0x00000000,\n\t.emc_wdv                                         = 0x00000004,\n\t.emc_wdv_chk                                     = 0x00000006,\n\t.emc_wsv                                         = 0x00000002,\n\t.emc_wev                                         = 0x00000000,\n\t.emc_wdv_mask                                    = 0x00000004,\n\t.emc_ws_duration                                 = 0x00000008,\n\t.emc_we_duration                                 = 0x0000000E,\n\t.emc_quse                                        = 0x00000005,\n\t.emc_quse_width                                  = 0x00000006,\n\t.emc_ibdly                                       = 0x00000000,\n\t.emc_obdly                                       = 0x00000000,\n\t.emc_einput                                      = 0x00000002,\n\t.emc_einput_duration                             = 0x0000000D,\n\t.emc_puterm_extra                                = 0x00000001,\n\t.emc_puterm_width                                = 0x80000000,\n\t.emc_qrst                                        = 0x00010000,\n\t.emc_qsafe                                       = 0x00000012,\n\t.emc_rdv                                         = 0x00000018,\n\t.emc_rdv_mask                                    = 0x0000001A,\n\t.emc_rdv_early                                   = 0x00000016,\n\t.emc_rdv_early_mask                              = 0x00000018,\n\t.emc_qpop                                        = 0x0000000A,\n\t.emc_refresh                                     = 0x00000304,\n\t.emc_burst_refresh_num                           = 0x00000000,\n\t.emc_prerefresh_req_cnt                          = 0x000000C1,\n\t.emc_pdex2wr                                     = 0x00000008,\n\t.emc_pdex2rd                                     = 0x00000008,\n\t.emc_pchg2pden                                   = 0x00000003,\n\t.emc_act2pden                                    = 0x0000000A,\n\t.emc_ar2pden                                     = 0x00000003,\n\t.emc_rw2pden                                     = 0x00000014,\n\t.emc_cke2pden                                    = 0x00000005,\n\t.emc_pdex2che                                    = 0x00000002,\n\t.emc_pdex2mrr                                    = 0x0000000D,\n\t.emc_txsr                                        = 0x0000003B,\n\t.emc_txsr_dll                                    = 0x0000003B,\n\t.emc_tcke                                        = 0x00000005,\n\t.emc_tckesr                                      = 0x00000005,\n\t.emc_tpd                                         = 0x00000004,\n\t.emc_tfaw                                        = 0x00000009,\n\t.emc_trpab                                       = 0x00000005,\n\t.emc_tclkstable                                  = 0x00000004,\n\t.emc_tclkstop                                    = 0x00000009,\n\t.emc_trefbw                                      = 0x0000031C,\n\n\t/* FBIO configuration values */\n\t.emc_fbio_cfg5                                   = 0x9160A00D,\n\t.emc_fbio_cfg7                                   = 0x00003A3F,\n\t.emc_fbio_cfg8                                   = 0x0CF30000,\n\n\t/* Command mapping for CMD brick 0 */\n\t.emc_cmd_mapping_cmd0_0                          = 0x061B0504,\n\t.emc_cmd_mapping_cmd0_1                          = 0x1C070302,\n\t.emc_cmd_mapping_cmd0_2                          = 0x05252523,\n\t.emc_cmd_mapping_cmd1_0                          = 0x0A091D08,\n\t.emc_cmd_mapping_cmd1_1                          = 0x0D1E0B24,\n\t.emc_cmd_mapping_cmd1_2                          = 0x0326260C,\n\t.emc_cmd_mapping_cmd2_0                          = 0x231C1B02,\n\t.emc_cmd_mapping_cmd2_1                          = 0x05070403,\n\t.emc_cmd_mapping_cmd2_2                          = 0x02252506,\n\t.emc_cmd_mapping_cmd3_0                          = 0x0D1D0B0A,\n\t.emc_cmd_mapping_cmd3_1                          = 0x1E090C08,\n\t.emc_cmd_mapping_cmd3_2                          = 0x08262624,\n\t.emc_cmd_mapping_byte                            = 0x9A070624,\n\n\t.emc_fbio_spare                                  = 0x00000012,\n\t.emc_cfg_rsv                                     = 0xFF00FF00,\n\n\t/* MRS command values */\n\t.emc_mrs                                         = 0x00000000,\n\t.emc_emrs                                        = 0x00000000,\n\t.emc_emrs2                                       = 0x00000000,\n\t.emc_emrs3                                       = 0x00000000,\n\t.emc_mrw1                                        = 0x88010004,\n\t.emc_mrw2                                        = 0x88020000,\n\t.emc_mrw3                                        = 0x880D0000,\n\t.emc_mrw4                                        = 0xC0000000,\n\t.emc_mrw6                                        = 0x88033131,\n\t.emc_mrw8                                        = 0x880B0000,\n\t.emc_mrw9                                        = 0x8C0E5D5D,\n\t.emc_mrw10                                       = 0x880C5D5D,\n\t.emc_mrw12                                       = 0x8C0D0808,\n\t.emc_mrw13                                       = 0x8C0D0000,\n\t.emc_mrw14                                       = 0x88161616,\n\t.emc_mrw_extra                                   = 0x88010004,\n\t.emc_warm_boot_mrw_extra                         = 0x08110000,\n\t.emc_warm_boot_extramode_reg_write_enable        = 0x00000001,\n\t.emc_extramode_reg_write_enable                  = 0x00000000,\n\t.emc_mrw_reset_command                           = 0x00000000,\n\t.emc_mrw_reset_ninit_wait                        = 0x00000000,\n\t.emc_mrs_wait_cnt                                = 0x00CC0010,\n\t.emc_mrs_wait_cnt2                               = 0x0033000A,\n\n\t/* EMC miscellaneous configurations */\n\t.emc_cfg                                         = 0xF3200000,\n\t.emc_cfg2                                        = 0x00110825,\n\t.emc_cfg_pipe                                    = 0x0FFF0000,\n\t.emc_cfg_pipe_clk                                = 0x00000000,\n\t.emc_fdpd_ctrl_cmd_no_ramp                       = 0x00000001,\n\t.emc_cfg_update                                  = 0x70000301,\n\t.emc_dbg                                         = 0x01000C00,\n\t.emc_dbg_write_mux                               = 0x00000001,\n\t.emc_cmd_q                                       = 0x10004408,\n\t.emc_mc2emc_q                                    = 0x06000404,\n\t.emc_dyn_self_ref_control                        = 0x00000713,\n\t.ahb_arbitration_xbar_ctrl_meminit_done          = 0x00000001,\n\t.emc_cfg_dig_dll                                 = 0x002C00A0,\n\t.emc_cfg_dig_dll_1                               = 0x000F3701,\n\t.emc_cfg_dig_dll_period                          = 0x00008000,\n\t.emc_dev_select                                  = 0x00000002, // Rank 0 only.\n\t.emc_sel_dpd_ctrl                                = 0x0004000C,\n\n\t/* Pads trimmer delays */\n\t.emc_fdpd_ctrl_dq                                = 0x8020221F,\n\t.emc_fdpd_ctrl_cmd                               = 0x0220F40F,\n\t.emc_pmacro_ib_vref_dq_0                         = 0x29292929,\n\t.emc_pmacro_ib_vref_dq_1                         = 0x29292929,\n\t.emc_pmacro_ib_vref_dqs_0                        = 0x29292929,\n\t.emc_pmacro_ib_vref_dqs_1                        = 0x29292929,\n\t.emc_pmacro_ib_rxrt                              = 0x00000078,\n\t.emc_cfg_pipe1                                   = 0x0FFF0000,\n\t.emc_cfg_pipe2                                   = 0x00000000,\n\n\t.emc_pmacro_quse_ddll_rank0_0                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank0_1                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank0_2                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank0_3                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank0_4                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank0_5                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank1_0                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank1_1                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank1_2                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank1_3                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank1_4                    = 0x00000000,\n\t.emc_pmacro_quse_ddll_rank1_5                    = 0x00000000,\n\n\t.emc_pmacro_ob_ddll_long_dq_rank0_0              = 0x00000000,\n\t.emc_pmacro_ob_ddll_long_dq_rank0_1              = 0x00000000,\n\t.emc_pmacro_ob_ddll_long_dq_rank0_2              = 0x00000000,\n\t.emc_pmacro_ob_ddll_long_dq_rank0_3              = 0x00000000,\n\t.emc_pmacro_ob_ddll_long_dq_rank0_4              = 0x000D0016,\n\t.emc_pmacro_ob_ddll_long_dq_rank0_5              = 0x0017000B,\n\t.emc_pmacro_ob_ddll_long_dq_rank1_0              = 0x00000000,\n\t.emc_pmacro_ob_ddll_long_dq_rank1_1              = 0x00000000,\n\t.emc_pmacro_ob_ddll_long_dq_rank1_2              = 0x00000000,\n\t.emc_pmacro_ob_ddll_long_dq_rank1_3              = 0x00000000,\n\t.emc_pmacro_ob_ddll_long_dq_rank1_4              = 0x000D0016,\n\t.emc_pmacro_ob_ddll_long_dq_rank1_5              = 0x0017000B,\n\n\t.emc_pmacro_ob_ddll_long_dqs_rank0_0             = 0x00450043,\n\t.emc_pmacro_ob_ddll_long_dqs_rank0_1             = 0x00430045,\n\t.emc_pmacro_ob_ddll_long_dqs_rank0_2             = 0x00470046,\n\t.emc_pmacro_ob_ddll_long_dqs_rank0_3             = 0x00460041,\n\t.emc_pmacro_ob_ddll_long_dqs_rank0_4             = 0x0003000C,\n\t.emc_pmacro_ob_ddll_long_dqs_rank0_5             = 0x000D0000,\n\t.emc_pmacro_ob_ddll_long_dqs_rank1_0             = 0x00450043,\n\t.emc_pmacro_ob_ddll_long_dqs_rank1_1             = 0x00430045,\n\t.emc_pmacro_ob_ddll_long_dqs_rank1_2             = 0x00470046,\n\t.emc_pmacro_ob_ddll_long_dqs_rank1_3             = 0x00460041,\n\t.emc_pmacro_ob_ddll_long_dqs_rank1_4             = 0x0003000C,\n\t.emc_pmacro_ob_ddll_long_dqs_rank1_5             = 0x000D0000,\n\n\t.emc_pmacro_ib_ddll_long_dqs_rank0_0             = 0x00280028,\n\t.emc_pmacro_ib_ddll_long_dqs_rank0_1             = 0x00280028,\n\t.emc_pmacro_ib_ddll_long_dqs_rank0_2             = 0x00280028,\n\t.emc_pmacro_ib_ddll_long_dqs_rank0_3             = 0x00280028,\n\t.emc_pmacro_ib_ddll_long_dqs_rank1_0             = 0x00280028,\n\t.emc_pmacro_ib_ddll_long_dqs_rank1_1             = 0x00280028,\n\t.emc_pmacro_ib_ddll_long_dqs_rank1_2             = 0x00280028,\n\t.emc_pmacro_ib_ddll_long_dqs_rank1_3             = 0x00280028,\n\n\t.emc_pmacro_ddll_long_cmd_0                      = 0x00160016,\n\t.emc_pmacro_ddll_long_cmd_1                      = 0x000D000D,\n\t.emc_pmacro_ddll_long_cmd_2                      = 0x000B000B,\n\t.emc_pmacro_ddll_long_cmd_3                      = 0x00170017,\n\t.emc_pmacro_ddll_long_cmd_4                      = 0x00000016,\n\t.emc_pmacro_ddll_short_cmd_0                     = 0x00000000,\n\t.emc_pmacro_ddll_short_cmd_1                     = 0x00000000,\n\t.emc_pmacro_ddll_short_cmd_2                     = 0x00000000,\n\n\t.emc_pmacro_ddll_periodic_offset                 = 0x00000000,\n\n\t/*\n\t * Specifies the delay after asserting CKE pin during a WarmBoot0\n\t * sequence (in microseconds)\n\t */\n\t.warm_boot_wait                                  = 0x00000001,\n\n\t.emc_odt_write                                   = 0x00000000,\n\n\t/* Periodic ZQ calibration */\n\n\t/*\n\t * Specifies the value for EMC_ZCAL_INTERVAL\n\t * Value 0 disables ZQ calibration\n\t */\n\t.emc_zcal_interval                               = 0x00064000,\n\t.emc_zcal_wait_cnt                               = 0x000900CC,\n\t.emc_zcal_mrw_cmd                                = 0x8051004F,\n\n\t/* DRAM initialization sequence flow control */\n\t.emc_mrs_reset_dll                               = 0x00000000,\n\t.emc_zcal_init_dev0                              = 0x80000001,\n\t.emc_zcal_init_dev1                              = 0x00000000,\n\t/*\n\t * Specifies the wait time after programming a ZQ initialization\n\t * command (in microseconds)\n\t */\n\t.emc_zcal_init_wait                              = 0x00000001,\n\t/*\n\t * Specifies the enable for ZQ calibration at cold boot [bit 0]\n\t * and warm boot [bit 1]\n\t */\n\t.emc_zcal_warm_cold_boot_enables                 = 0x00000003,\n\n\t/*\n\t * Specifies the MRW command to LPDDR2 for ZQ calibration\n\t * on warmboot\n\t */\n\t/* Is issued to both devices separately */\n\t.emc_mrw_lpddr2zcal_warm_boot                    = 0x040A00AB,\n\t/*\n\t * Specifies the ZQ command to DDR3 for ZQ calibration on warmboot\n\t * Is issued to both devices separately\n\t */\n\t.emc_zqcal_ddr3_warm_boot                        = 0x00000011,\n\t.emc_zqcal_lpddr4_warm_boot                      = 0x00000001,\n\n\t/*\n\t * Specifies the wait time for ZQ calibration on warmboot\n\t * (in microseconds)\n\t */\n\t.emc_zcal_warm_boot_wait                         = 0x00000001,\n\t/*\n\t * Specifies the enable for DRAM Mode Register programming\n\t * at warm boot\n\t */\n\t.emc_mrs_warm_boot_enable                        = 0x00000001,\n\t.emc_mrs_reset_dll_wait                          = 0x00000000,\n\t.emc_mrs_extra                                   = 0x00000000,\n\t.emc_warm_boot_mrs_extra                         = 0x00000000,\n\t.emc_emrs_ddr2_dll_enable                        = 0x00000000,\n\t.emc_mrs_ddr2_dll_reset                          = 0x00000000,\n\t.emc_emrs_ddr2_ocd_calib                         = 0x00000000,\n\t/*\n\t * Specifies the wait between initializing DDR and setting OCD\n\t * calibration (in microseconds)\n\t */\n\t.emc_ddr2_wait                                   = 0x00000000,\n\t.emc_clken_override                              = 0x00000000,\n\t/*\n\t * Specifies LOG2 of the extra refresh numbers after booting\n\t * Program 0 to disable\n\t */\n\t.emc_extra_refresh_num                           = 0x00000002,\n\t.emc_clken_override_allwarm_boot                 = 0x00000000,\n\t.mc_clken_override_allwarm_boot                  = 0x00000000,\n\t/* Specifies digital dll period, choosing between 4 to 64 ms */\n\t.emc_cfg_dig_dll_period_warm_boot                = 0x00000003,\n\n\t/* Pad controls */\n\t.pmc_vddp_sel                                    = 0x00000001,\n\t.pmc_vddp_sel_wait                               = 0x00000002,\n\t.pmc_ddr_cfg                                     = 0x04220100,\n\t.pmc_io_dpd3_req                                 = 0x4FAF9FFF,\n\t.pmc_io_dpd3_req_wait                            = 0x00000001,\n\t.pmc_io_dpd4_req_wait                            = 0x00000002,\n\t.pmc_reg_short                                   = 0x00000000,\n\t.pmc_no_io_power                                 = 0x00000000,\n\t.pmc_ddr_ctrl_wait                               = 0x00000000,\n\t.pmc_ddr_ctrl                                    = 0x0037FF9F,\n\t.emc_acpd_control                                = 0x00000000,\n\n\t.emc_swizzle_rank0_byte0                         = 0x76543201,\n\t.emc_swizzle_rank0_byte1                         = 0x65324710,\n\t.emc_swizzle_rank0_byte2                         = 0x25763410,\n\t.emc_swizzle_rank0_byte3                         = 0x25673401,\n\t.emc_swizzle_rank1_byte0                         = 0x32647501,\n\t.emc_swizzle_rank1_byte1                         = 0x34567201,\n\t.emc_swizzle_rank1_byte2                         = 0x56742310,\n\t.emc_swizzle_rank1_byte3                         = 0x67324501,\n\n\t.emc_txdsrvttgen                                 = 0x00000000,\n\n\t.emc_data_brlshft0                               = 0x00249249,\n\t.emc_data_brlshft1                               = 0x00249249,\n\n\t.emc_dqs_brlshft0                                = 0x00000000,\n\t.emc_dqs_brlshft1                                = 0x00000000,\n\n\t.emc_cmd_brlshft0                                = 0x00000000,\n\t.emc_cmd_brlshft1                                = 0x00000000,\n\t.emc_cmd_brlshft2                                = 0x00000012,\n\t.emc_cmd_brlshft3                                = 0x00000012,\n\n\t.emc_quse_brlshft0                               = 0x00000000,\n\t.emc_quse_brlshft1                               = 0x00000000,\n\t.emc_quse_brlshft2                               = 0x00000000,\n\t.emc_quse_brlshft3                               = 0x00000000,\n\n\t.emc_dll_cfg0                                    = 0x1F134120,\n\t.emc_dll_cfg1                                    = 0x00010014,\n\n\t.emc_pmc_scratch1                                = 0x4FAF9FFF,\n\t.emc_pmc_scratch2                                = 0x7FFFFFFF,\n\t.emc_pmc_scratch3                                = 0x4036D71F,\n\n\t.emc_pmacro_pad_cfg_ctrl                         = 0x00000000,\n\t.emc_pmacro_vttgen_ctrl0                         = 0x00090000,\n\t.emc_pmacro_vttgen_ctrl1                         = 0x00103400,\n\t.emc_pmacro_vttgen_ctrl2                         = 0x00000000,\n\t.emc_pmacro_dsr_vttgen_ctrl0                     = 0x00000009,\n\t.emc_pmacro_brick_ctrl_rfu1                      = 0x00000000,\n\t.emc_pmacro_cmd_brick_ctrl_fdpd                  = 0x00000000,\n\t.emc_pmacro_brick_ctrl_rfu2                      = 0x00000000,\n\t.emc_pmacro_data_brick_ctrl_fdpd                 = 0x00000000,\n\t.emc_pmacro_bg_bias_ctrl0                        = 0x00000000,\n\t.emc_pmacro_data_pad_rx_ctrl                     = 0x05050003,\n\t.emc_pmacro_cmd_pad_rx_ctrl                      = 0x05000000,\n\t.emc_pmacro_data_rx_term_mode                    = 0x00000210,\n\t.emc_pmacro_cmd_rx_term_mode                     = 0x00002000,\n\t.emc_pmacro_data_pad_tx_ctrl                     = 0x00000421,\n\t.emc_pmacro_cmd_pad_tx_ctrl                      = 0x00000000,\n\n\t.emc_cfg3                                        = 0x00000040,\n\n\t.emc_pmacro_tx_pwrd0                             = 0x10000000,\n\t.emc_pmacro_tx_pwrd1                             = 0x00000000,\n\t.emc_pmacro_tx_pwrd2                             = 0x00000000,\n\t.emc_pmacro_tx_pwrd3                             = 0x00000000,\n\t.emc_pmacro_tx_pwrd4                             = 0x00400080,\n\t.emc_pmacro_tx_pwrd5                             = 0x00801004,\n\n\t.emc_config_sample_delay                         = 0x00000020,\n\n\t.emc_pmacro_brick_mapping0                       = 0x28091081,\n\t.emc_pmacro_brick_mapping1                       = 0x44A53293,\n\t.emc_pmacro_brick_mapping2                       = 0x76678A5B,\n\n\t.emc_pmacro_tx_sel_clk_src0                      = 0x00000000,\n\t.emc_pmacro_tx_sel_clk_src1                      = 0x00000000,\n\t.emc_pmacro_tx_sel_clk_src2                      = 0x00000000,\n\t.emc_pmacro_tx_sel_clk_src3                      = 0x00000000,\n\t.emc_pmacro_tx_sel_clk_src4                      = 0x00000000,\n\t.emc_pmacro_tx_sel_clk_src5                      = 0x00000000,\n\n\t.emc_pmacro_perbit_fgcg_ctrl0                    = 0x00000000,\n\t.emc_pmacro_perbit_fgcg_ctrl1                    = 0x00000000,\n\t.emc_pmacro_perbit_fgcg_ctrl2                    = 0x00000000,\n\t.emc_pmacro_perbit_fgcg_ctrl3                    = 0x00000000,\n\t.emc_pmacro_perbit_fgcg_ctrl4                    = 0x00000000,\n\t.emc_pmacro_perbit_fgcg_ctrl5                    = 0x00000000,\n\t.emc_pmacro_perbit_rfu_ctrl0                     = 0x00000000,\n\t.emc_pmacro_perbit_rfu_ctrl1                     = 0x00000000,\n\t.emc_pmacro_perbit_rfu_ctrl2                     = 0x00000000,\n\t.emc_pmacro_perbit_rfu_ctrl3                     = 0x00000000,\n\t.emc_pmacro_perbit_rfu_ctrl4                     = 0x00000000,\n\t.emc_pmacro_perbit_rfu_ctrl5                     = 0x00000000,\n\t.emc_pmacro_perbit_rfu1_ctrl0                    = 0x00000000,\n\t.emc_pmacro_perbit_rfu1_ctrl1                    = 0x00000000,\n\t.emc_pmacro_perbit_rfu1_ctrl2                    = 0x00000000,\n\t.emc_pmacro_perbit_rfu1_ctrl3                    = 0x00000000,\n\t.emc_pmacro_perbit_rfu1_ctrl4                    = 0x00000000,\n\t.emc_pmacro_perbit_rfu1_ctrl5                    = 0x00000000,\n\n\t.emc_pmacro_data_pi_ctrl                         = 0x00001010,\n\t.emc_pmacro_cmd_pi_ctrl                          = 0x00001010,\n\n\t.emc_pmacro_ddll_bypass                          = 0xEF00EF00,\n\n\t.emc_pmacro_ddll_pwrd0                           = 0x00000000,\n\t.emc_pmacro_ddll_pwrd1                           = 0x00000000,\n\t.emc_pmacro_ddll_pwrd2                           = 0x1C1C1C1C,\n\n\t.emc_pmacro_cmd_ctrl0                            = 0x00000000,\n\t.emc_pmacro_cmd_ctrl1                            = 0x00000000,\n\t.emc_pmacro_cmd_ctrl2                            = 0x00000000,\n\n\t/* DRAM size information */\n\t.mc_emem_adr_cfg                                 = 0x00000000, // 1 Rank.\n\t.mc_emem_adr_cfg_dev0                            = 0x00080302, // Chip 0 Density 1024MB.\n\t.mc_emem_adr_cfg_dev1                            = 0x00080302, // Chip 1 Density 1024MB.\n\t.mc_emem_adr_cfg_channel_mask                    = 0xFFFF2400,\n\t.mc_emem_adr_cfg_bank_mask0                      = 0x6E574400,\n\t.mc_emem_adr_cfg_bank_mask1                      = 0x39722800,\n\t.mc_emem_adr_cfg_bank_mask2                      = 0x4B9C1000,\n\t/*\n\t * Specifies the value for MC_EMEM_CFG which holds the external memory\n\t * size (in MBytes)\n\t */\n\t.mc_emem_cfg                                     = 0x00001000, // 4GB total density. Max 8GB.\n\n\t/* MC arbitration configuration */\n\t.mc_emem_arb_cfg                                 = 0x08000001,\n\t.mc_emem_arb_outstanding_req                     = 0x8000004C,\n\t.emc_emem_arb_refpb_hp_ctrl                      = 0x000A1020,\n\t.emc_emem_arb_refpb_bank_ctrl                    = 0x80001028,\n\n\t.mc_emem_arb_timing_rcd                          = 0x00000001,\n\t.mc_emem_arb_timing_rp                           = 0x00000000,\n\t.mc_emem_arb_timing_rc                           = 0x00000003,\n\t.mc_emem_arb_timing_ras                          = 0x00000001,\n\t.mc_emem_arb_timing_faw                          = 0x00000002,\n\t.mc_emem_arb_timing_rrd                          = 0x00000001,\n\t.mc_emem_arb_timing_rap2pre                      = 0x00000002,\n\t.mc_emem_arb_timing_wap2pre                      = 0x00000005,\n\t.mc_emem_arb_timing_r2r                          = 0x00000001,\n\t.mc_emem_arb_timing_w2w                          = 0x00000001,\n\t.mc_emem_arb_timing_r2w                          = 0x00000004,\n\t.mc_emem_arb_timing_w2r                          = 0x00000005,\n\t.mc_emem_arb_timing_rfcpb                        = 0x00000007,\n\n\t.mc_emem_arb_da_turns                            = 0x02020000,\n\t.mc_emem_arb_da_covers                           = 0x00030201,\n\t.mc_emem_arb_misc0                               = 0x72A30504,\n\t.mc_emem_arb_misc1                               = 0x70000F0F,\n\t.mc_emem_arb_misc2                               = 0x00000000,\n\n\t.mc_emem_arb_ring1_throttle                      = 0x001F0000,\n\t.mc_emem_arb_override                            = 0x10000000,\n\t.mc_emem_arb_override1                           = 0x00000000,\n\t.mc_emem_arb_rsv                                 = 0xFF00FF00,\n\n\t.mc_da_cfg0                                      = 0x00000001,\n\t.mc_emem_arb_timing_ccdmw                        = 0x00000008,\n\n\t.mc_clken_override                               = 0x00008000,\n\n\t.mc_stat_control                                 = 0x00000000,\n\t.mc_video_protect_bom                            = 0xFFF00000,\n\t.mc_video_protect_bom_adr_hi                     = 0x00000000,\n\t.mc_video_protect_size_mb                        = 0x00000000,\n\n\t// Disable access:\n\t//  AFI (PCIE), BPMP, HC (HOST1x), ISP2, CCPLEX, PPCS (AHB), SATA, VI, XUSB_HOST, XUSB_DEV, ADSP, PPCS1 (AHB), DC1 (WinT), SDMMC1/2/3. Plus TSEC, NVENC.\n\t// Enable access:\n\t//  DC, DCB, HDA, VIC.\n\t.mc_video_protect_vpr_override                   = 0xE4FACB43, // Stock/Reset: 0xE4BAC343. HOS new: 0xE4FACB43. + TSEC, NVENC.\n\t// Disable access:\n\t//  SDMMC4, ISP2B, PPCS2 (AHB), APE, SE, HC1, SE1, AXIAP, ETR, SE2, SE2B. Plus TSECB, TSEC1, TSECB1.\n\t// Enable access:\n\t//  GPU, GPUB, NVDEC, NVJPG, NVDEC1.\n\t.mc_video_protect_vpr_override1                  = 0x0600FED3, // Reset: 0x06001ED3. HOS new: 0x0600FED3. + TSECB, TSEC1, TSECB1.\n\n\t// VPR CYA. L4T override (set PD, SCC, SKED, L1 as UNTRUSTED).\n\t.mc_video_protect_gpu_override0                  = VPR_OVR0_CYA_TRUST_GCC(VPR_TRUST_GRAPHICS)    |\n\t\t\t\t\t\t\t\t\t\t\t\t\t   VPR_OVR0_CYA_TRUST_RASTER(VPR_TRUST_GRAPHICS) |\n\t\t\t\t\t\t\t\t\t\t\t\t\t   VPR_OVR0_CYA_TRUST_PE(VPR_TRUST_GRAPHICS)     |\n\t\t\t\t\t\t\t\t\t\t\t\t\t   VPR_OVR0_CYA_TRUST_TEX(VPR_TRUST_GRAPHICS)    |\n\t\t\t\t\t\t\t\t\t\t\t\t\t   VPR_OVR0_CYA_TRUST_OVERRIDE,                 // Stock: 0. HOS: VPR_OVR0_CYA_TRUST_DEFAULT.\n\t.mc_video_protect_gpu_override1                  = VPR_OVR1_CYA_TRUST_PROP(VPR_TRUST_GRAPHICS), // Stock: 0. HOS: 0.\n\n\t/* TZDRAM carveout configuration */\n\t.mc_sec_carveout_bom                             = 0xFFF00000,\n\t.mc_sec_carveout_adr_hi                          = 0x00000000,\n\t.mc_sec_carveout_size_mb                         = 0x00000000,\n\n\t.mc_video_protect_write_access                   = 0x00000000,\n\t.mc_sec_carveout_protect_write_access            = 0x00000000,\n\n\t.mc_generalized_carveout1_bom                    = 0x00000000,\n\t.mc_generalized_carveout1_bom_hi                 = 0x00000000,\n\t.mc_generalized_carveout1_size_128kb             = 0x00000008,\n\t.mc_generalized_carveout1_access0                = 0x00000000,\n\t.mc_generalized_carveout1_access1                = 0x00000000,\n\t.mc_generalized_carveout1_access2                = 0x00300000,\n\t.mc_generalized_carveout1_access3                = 0x03000000,\n\t.mc_generalized_carveout1_access4                = 0x00000000,\n\t.mc_generalized_carveout1_force_internal_access0 = 0x00000000,\n\t.mc_generalized_carveout1_force_internal_access1 = 0x00000000,\n\t.mc_generalized_carveout1_force_internal_access2 = 0x00000000,\n\t.mc_generalized_carveout1_force_internal_access3 = 0x00000000,\n\t.mc_generalized_carveout1_force_internal_access4 = 0x00000000,\n\t.mc_generalized_carveout1_cfg0                   = 0x04000C76,\n\n\t.mc_generalized_carveout2_bom                    = 0x00000000,\n\t.mc_generalized_carveout2_bom_hi                 = 0x00000000,\n\t.mc_generalized_carveout2_size_128kb             = 0x00000002,\n\t.mc_generalized_carveout2_access0                = 0x00000000,\n\t.mc_generalized_carveout2_access1                = 0x00000000,\n\t.mc_generalized_carveout2_access2                = 0x03000000,\n\t.mc_generalized_carveout2_access3                = 0x00000000,\n\t.mc_generalized_carveout2_access4                = 0x00000300,\n\t.mc_generalized_carveout2_force_internal_access0 = 0x00000000,\n\t.mc_generalized_carveout2_force_internal_access1 = 0x00000000,\n\t.mc_generalized_carveout2_force_internal_access2 = 0x00000000,\n\t.mc_generalized_carveout2_force_internal_access3 = 0x00000000,\n\t.mc_generalized_carveout2_force_internal_access4 = 0x00000000,\n\t.mc_generalized_carveout2_cfg0                   = 0x0440167E,\n\n\t.mc_generalized_carveout3_bom                    = 0x00000000,\n\t.mc_generalized_carveout3_bom_hi                 = 0x00000000,\n\t.mc_generalized_carveout3_size_128kb             = 0x00000000,\n\t.mc_generalized_carveout3_access0                = 0x00000000,\n\t.mc_generalized_carveout3_access1                = 0x00000000,\n\t.mc_generalized_carveout3_access2                = 0x03000000,\n\t.mc_generalized_carveout3_access3                = 0x00000000,\n\t.mc_generalized_carveout3_access4                = 0x00000300,\n\t.mc_generalized_carveout3_force_internal_access0 = 0x00000000,\n\t.mc_generalized_carveout3_force_internal_access1 = 0x00000000,\n\t.mc_generalized_carveout3_force_internal_access2 = 0x00000000,\n\t.mc_generalized_carveout3_force_internal_access3 = 0x00000000,\n\t.mc_generalized_carveout3_force_internal_access4 = 0x00000000,\n\t.mc_generalized_carveout3_cfg0                   = 0x04401E7E,\n\n\t.mc_generalized_carveout4_bom                    = 0x00000000,\n\t.mc_generalized_carveout4_bom_hi                 = 0x00000000,\n\t.mc_generalized_carveout4_size_128kb             = 0x00000008,\n\t.mc_generalized_carveout4_access0                = 0x00000000,\n\t.mc_generalized_carveout4_access1                = 0x00000000,\n\t.mc_generalized_carveout4_access2                = 0x00300000,\n\t.mc_generalized_carveout4_access3                = 0x00000000,\n\t.mc_generalized_carveout4_access4                = 0x000000C0,\n\t.mc_generalized_carveout4_force_internal_access0 = 0x00000000,\n\t.mc_generalized_carveout4_force_internal_access1 = 0x00000000,\n\t.mc_generalized_carveout4_force_internal_access2 = 0x00000000,\n\t.mc_generalized_carveout4_force_internal_access3 = 0x00000000,\n\t.mc_generalized_carveout4_force_internal_access4 = 0x00000000,\n\t.mc_generalized_carveout4_cfg0                   = 0x04002446,\n\n\t.mc_generalized_carveout5_bom                    = 0x00000000,\n\t.mc_generalized_carveout5_bom_hi                 = 0x00000000,\n\t.mc_generalized_carveout5_size_128kb             = 0x00000008,\n\t.mc_generalized_carveout5_access0                = 0x00000000,\n\t.mc_generalized_carveout5_access1                = 0x00000000,\n\t.mc_generalized_carveout5_access2                = 0x00300000,\n\t.mc_generalized_carveout5_access3                = 0x00000000,\n\t.mc_generalized_carveout5_access4                = 0x00000000,\n\t.mc_generalized_carveout5_force_internal_access0 = 0x00000000,\n\t.mc_generalized_carveout5_force_internal_access1 = 0x00000000,\n\t.mc_generalized_carveout5_force_internal_access2 = 0x00000000,\n\t.mc_generalized_carveout5_force_internal_access3 = 0x00000000,\n\t.mc_generalized_carveout5_force_internal_access4 = 0x00000000,\n\t.mc_generalized_carveout5_cfg0                   = 0x04002C46,\n\n\t/* Specifies enable for CA training */\n\t.emc_ca_training_enable                          = 0x00000000,\n\t/* Set if bit 6 select is greater than bit 7 select; uses aremc.spec packet SWIZZLE_BIT6_GT_BIT7 */\n\t.swizzle_rank_byte_encode                        = 0x000000EC,\n\n\t/* Specifies enable and offset for patched boot rom write */\n\t.boot_rom_patch_control                          = 0x00000000,\n\t/* Specifies data for patched boot rom write */\n\t.boot_rom_patch_data                             = 0x00000000,\n\n\t.mc_mts_carveout_bom                             = 0xFFF00000,\n\t.mc_mts_carveout_adr_hi                          = 0x00000000,\n\t.mc_mts_carveout_size_mb                         = 0x00000000,\n\t.mc_mts_carveout_reg_ctrl                        = 0x00000000,\n\n\t/* Specifies the untranslated memory access control */\n\t.mc_untranslated_region_check                    = 0x00000000,\n\n\t/* Just a place holder for special usage when there is no BCT for certain registers */\n\t.bct_na                                          = 0x00000000,\n};\n\n#define DRAM_CC_LPDDR4X_PMACRO_IB      (DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ))\n\n#define DRAM_CC_LPDDR4X_PUPD_VPR       (DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ)        | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE) | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL)        | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL)        | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF) | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE)       | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_HYNIX_H54G46CYRBX267)           | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB) | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL))\n\n#define DRAM_CC_LPDDR4X_DSR            (DRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTE) | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL)        | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF) | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE)       | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_HYNIX_H54G46CYRBX267)           | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB) | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL))\n\n#define DRAM_CC_LPDDR4X_QUSE           (DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ)        | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AA_MGCL)        | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL)        | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF) | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE)       | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_HYNIX_H54G46CYRBX267)           | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB) | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL))\n\n#define DRAM_CC_LPDDR4X_FAW            (DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL)        | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D2NP_046_WTF) | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE)       | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB))\n\n#define DRAM_CC_LPDDR4X_VPR            (DRAM_CC(LPDDR4X_4GB_HYNIX_H9HCNNNBKMMLXR_NEE)       | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_HYNIX_H54G46CYRBX267)           | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_MICRON_MT53E512M32D1NP_046_WTB) | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_4GB_SAMSUNG_K4U6E3S4AB_MGCL))\n\n#define DRAM_CC_LPDDR4X_8GB            (DRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AM_MGCJ)        | \\\n\t\t\t\t\t\t\t\t\t\tDRAM_CC(LPDDR4X_8GB_SAMSUNG_K4UBE3D4AA_MGCL))\n\n#define DCFG_OFFSET_OF(m) (OFFSET_OF(sdram_params_t210b01_t, m) / 4)\nstatic const sdram_vendor_patch_t sdram_cfg_vendor_patches_t210b01[] = {\n\n\t// Samsung LPDDR4X 8GB K4UBE3D4AM-MGCJ Die-M for SDEV Iowa and Hoag.\n\t{ 0x35353535, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_vref_dq_0)             },\n\t{ 0x35353535, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_vref_dq_1)             },\n\t{ 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank0_0) },\n\t{ 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank0_1) },\n\t{ 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank0_2) },\n\t{ 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank0_3) },\n\t{ 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank1_0) },\n\t{ 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank1_1) },\n\t{ 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank1_2) },\n\t{ 0x00100010, DRAM_CC_LPDDR4X_PMACRO_IB, DCFG_OFFSET_OF(emc_pmacro_ib_ddll_long_dqs_rank1_3) },\n\n\t/*! Shared patched between DRAM Codes. */\n\t{ 0x05500000, DRAM_CC_LPDDR4X_PUPD_VPR,  DCFG_OFFSET_OF(emc_auto_cal_config2)                },\n\t{ 0xC9AFBCBC, DRAM_CC_LPDDR4X_PUPD_VPR,  DCFG_OFFSET_OF(emc_auto_cal_vref_sel0)              },\n\n\t// Moved to default config.\n\t// { 0x2A800000, DRAM_CC_LPDDR4X_PUPD_VPR,  DCFG_OFFSET_OF(mc_video_protect_gpu_override0)      },\n\t// { 0x00000002, DRAM_CC_LPDDR4X_PUPD_VPR,  DCFG_OFFSET_OF(mc_video_protect_gpu_override1)      },\n\n\t{ 0x88161414, DRAM_CC_LPDDR4X_DSR,       DCFG_OFFSET_OF(emc_mrw14)                           },\n\t{ 0x80000713, DRAM_CC_LPDDR4X_DSR,       DCFG_OFFSET_OF(emc_dyn_self_ref_control)            },\n\n\t{ 0x00000006, DRAM_CC_LPDDR4X_QUSE,      DCFG_OFFSET_OF(emc_quse)                            },\n\t{ 0x00000005, DRAM_CC_LPDDR4X_QUSE,      DCFG_OFFSET_OF(emc_quse_width)                      },\n\t{ 0x00000003, DRAM_CC_LPDDR4X_QUSE,      DCFG_OFFSET_OF(emc_einput)                          },\n\t{ 0x0000000C, DRAM_CC_LPDDR4X_QUSE,      DCFG_OFFSET_OF(emc_einput_duration)                 },\n\n\t{ 0x00000008, DRAM_CC_LPDDR4X_FAW,       DCFG_OFFSET_OF(emc_tfaw)                            },\n\t{ 0x00000001, DRAM_CC_LPDDR4X_FAW,       DCFG_OFFSET_OF(mc_emem_arb_timing_faw)              },\n\n\t// Moved to default config.\n\t// { 0xE4FACB43, DRAM_CC_LPDDR4X_VPR,       DCFG_OFFSET_OF(mc_video_protect_vpr_override)       }, // + TSEC,  NVENC.\n\t// { 0x0600FED3, DRAM_CC_LPDDR4X_VPR,       DCFG_OFFSET_OF(mc_video_protect_vpr_override1)      }, // + TSECB, TSEC1, TSECB1.\n\n\t{ 0x00000001, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(emc_adr_cfg)                         }, // 2 Ranks.\n\t{ 0x08010004, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(emc_mrw1)                            },\n\t{ 0x08020000, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(emc_mrw2)                            },\n\t{ 0x080D0000, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(emc_mrw3)                            },\n\t{ 0x08033131, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(emc_mrw6)                            },\n\t{ 0x080B0000, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(emc_mrw8)                            },\n\t{ 0x0C0E5D5D, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(emc_mrw9)                            },\n\t{ 0x080C5D5D, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(emc_mrw10)                           },\n\t{ 0x0C0D0808, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(emc_mrw12)                           },\n\t{ 0x0C0D0000, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(emc_mrw13)                           },\n\t{ 0x08161414, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(emc_mrw14)                           },\n\t{ 0x08010004, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(emc_mrw_extra)                       },\n\t{ 0x00000000, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(emc_dev_select)                      }, // Both devices.\n\t{ 0x0051004F, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(emc_zcal_mrw_cmd)                    },\n\t{ 0x40000001, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(emc_zcal_init_dev1)                  },\n\t{ 0x00000000, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(emc_pmacro_tx_pwrd4)                 },\n\t{ 0x00001000, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(emc_pmacro_tx_pwrd5)                 },\n\t{ 0x00000001, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(mc_emem_adr_cfg)                     }, // 2 Ranks.\n\t{ 0x00002000, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(mc_emem_cfg)                         }, // 8GB total density. Max 8GB.\n\t{ 0x00000002, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(mc_emem_arb_timing_r2r)              },\n\t{ 0x02020001, DRAM_CC_LPDDR4X_8GB,       DCFG_OFFSET_OF(mc_emem_arb_da_turns)                },\n};\n#undef DCFG_OFFSET_OF\n"
  },
  {
    "path": "bdk/mem/sdram_param_t210.h",
    "content": "/*\n * Copyright (c) 2015, NVIDIA CORPORATION.  All rights reserved.\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n *\n * See file CREDITS for list of people who contributed to this\n * project.\n */\n\n/**\n * Defines the SDRAM parameter structure.\n *\n * Note that PLLM is used by EMC.\n */\n\n#ifndef _SDRAM_PARAM_T210_H_\n#define _SDRAM_PARAM_T210_H_\n\n#define MEMORY_TYPE_NONE   0\n#define MEMORY_TYPE_DDR    0\n#define MEMORY_TYPE_LPDDR  0\n#define MEMORY_TYPE_DDR2   0\n#define MEMORY_TYPE_LPDDR2 1\n#define MEMORY_TYPE_DDR3L  2\n#define MEMORY_TYPE_LPDDR4 3\n\n/**\n * Defines the SDRAM parameter structure\n */\ntypedef struct _sdram_params_t210_t\n{\n\t/* Specifies the type of memory device */\n\tu32 memory_type;\n\n\t/* MC/EMC clock source configuration */\n\n\t/* Specifies the M value for PllM */\n\tu32 pllm_input_divider;\n\t/* Specifies the N value for PllM */\n\tu32 pllm_feedback_divider;\n\t/* Specifies the time to wait for PLLM to lock (in microseconds) */\n\tu32 pllm_stable_time;\n\t/* Specifies misc. control bits */\n\tu32 pllm_setup_control;\n\t/* Specifies the P value for PLLM */\n\tu32 pllm_post_divider;\n\t/* Specifies value for Charge Pump Gain Control */\n\tu32 pllm_kcp;\n\t/* Specifies VCO gain */\n\tu32 pllm_kvco;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare0;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare1;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare2;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare3;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare4;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare5;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare6;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare7;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare8;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare9;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare10;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare11;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare12;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare13;\n\n\t/* Defines EMC_2X_CLK_SRC, EMC_2X_CLK_DIVISOR, EMC_INVERT_DCD */\n\tu32 emc_clock_source;\n\tu32 emc_clock_source_dll;\n\n\t/* Defines possible override for PLLLM_MISC2 */\n\tu32 clk_rst_pllm_misc20_override;\n\t/* enables override for PLLLM_MISC2 */\n\tu32 clk_rst_pllm_misc20_override_enable;\n\t/* defines CLK_ENB_MC1 in register clk_rst_controller_clk_enb_w_clr */\n\tu32 clear_clock2_mc1;\n\n\t/* Auto-calibration of EMC pads */\n\n\t/* Specifies the value for EMC_AUTO_CAL_INTERVAL */\n\tu32 emc_auto_cal_interval;\n\t/*\n\t * Specifies the value for EMC_AUTO_CAL_CONFIG\n\t * Note: Trigger bits are set by the SDRAM code.\n\t */\n\tu32 emc_auto_cal_config;\n\n\t/* Specifies the value for EMC_AUTO_CAL_CONFIG2 */\n\tu32 emc_auto_cal_config2;\n\n\t/* Specifies the value for EMC_AUTO_CAL_CONFIG3 */\n\tu32 emc_auto_cal_config3;\n\tu32 emc_auto_cal_config4;\n\tu32 emc_auto_cal_config5;\n\tu32 emc_auto_cal_config6;\n\tu32 emc_auto_cal_config7;\n\tu32 emc_auto_cal_config8;\n\t/* Specifies the value for EMC_AUTO_CAL_VREF_SEL_0 */\n\tu32 emc_auto_cal_vref_sel0;\n\tu32 emc_auto_cal_vref_sel1;\n\n\t/* Specifies the value for EMC_AUTO_CAL_CHANNEL */\n\tu32 emc_auto_cal_channel;\n\n\t/* Specifies the value for EMC_PMACRO_AUTOCAL_CFG_0 */\n\tu32 emc_pmacro_auto_cal_cfg0;\n\tu32 emc_pmacro_auto_cal_cfg1;\n\tu32 emc_pmacro_auto_cal_cfg2;\n\n\tu32 emc_pmacro_rx_term;\n\tu32 emc_pmacro_dq_tx_drive;\n\tu32 emc_pmacro_ca_tx_drive;\n\tu32 emc_pmacro_cmd_tx_drive;\n\tu32 emc_pmacro_auto_cal_common;\n\tu32 emc_pmacro_zcrtl;\n\n\t/*\n\t * Specifies the time for the calibration\n\t * to stabilize (in microseconds)\n\t */\n\tu32 emc_auto_cal_wait;\n\n\tu32 emc_xm2_comp_pad_ctrl;\n\tu32 emc_xm2_comp_pad_ctrl2;\n\tu32 emc_xm2_comp_pad_ctrl3;\n\n\t/*\n\t * DRAM size information\n\t * Specifies the value for EMC_ADR_CFG\n\t */\n\tu32 emc_adr_cfg;\n\n\t/*\n\t * Specifies the time to wait after asserting pin\n\t * CKE (in microseconds)\n\t */\n\tu32 emc_pin_program_wait;\n\t/* Specifies the extra delay before/after pin RESET/CKE command */\n\tu32 emc_pin_extra_wait;\n\n\tu32 emc_pin_gpio_enable;\n\tu32 emc_pin_gpio;\n\n\t/*\n\t * Specifies the extra delay after the first writing\n\t * of EMC_TIMING_CONTROL\n\t */\n\tu32 emc_timing_control_wait;\n\n\t/* Timing parameters required for the SDRAM */\n\n\t/* Specifies the value for EMC_RC */\n\tu32 emc_rc;\n\t/* Specifies the value for EMC_RFC */\n\tu32 emc_rfc;\n\n\tu32 emc_rfc_pb;\n\tu32 emc_ref_ctrl2;\n\n\t/* Specifies the value for EMC_RFC_SLR */\n\tu32 emc_rfc_slr;\n\t/* Specifies the value for EMC_RAS */\n\tu32 emc_ras;\n\t/* Specifies the value for EMC_RP */\n\tu32 emc_rp;\n\t/* Specifies the value for EMC_R2R */\n\tu32 emc_r2r;\n\t/* Specifies the value for EMC_W2W */\n\tu32 emc_w2w;\n\t/* Specifies the value for EMC_R2W */\n\tu32 emc_r2w;\n\t/* Specifies the value for EMC_W2R */\n\tu32 emc_w2r;\n\t/* Specifies the value for EMC_R2P */\n\tu32 emc_r2p;\n\t/* Specifies the value for EMC_W2P */\n\tu32 emc_w2p;\n\t/* Specifies the value for EMC_RD_RCD */\n\n\tu32 emc_tppd;\n\tu32 emc_ccdmw;\n\n\tu32 emc_rd_rcd;\n\t/* Specifies the value for EMC_WR_RCD */\n\tu32 emc_wr_rcd;\n\t/* Specifies the value for EMC_RRD */\n\tu32 emc_rrd;\n\t/* Specifies the value for EMC_REXT */\n\tu32 emc_rext;\n\t/* Specifies the value for EMC_WEXT */\n\tu32 emc_wext;\n\t/* Specifies the value for EMC_WDV */\n\tu32 emc_wdv;\n\n\tu32 emc_wdv_chk;\n\tu32 emc_wsv;\n\tu32 emc_wev;\n\n\t/* Specifies the value for EMC_WDV_MASK */\n\tu32 emc_wdv_mask;\n\n\tu32 emc_ws_duration;\n\tu32 emc_we_duration;\n\n\t/* Specifies the value for EMC_QUSE */\n\tu32 emc_quse;\n\t/* Specifies the value for EMC_QUSE_WIDTH */\n\tu32 emc_quse_width;\n\t/* Specifies the value for EMC_IBDLY */\n\tu32 emc_ibdly;\n\n\tu32 emc_obdly;\n\n\t/* Specifies the value for EMC_EINPUT */\n\tu32 emc_einput;\n\t/* Specifies the value for EMC_EINPUT_DURATION */\n\tu32 emc_einput_duration;\n\t/* Specifies the value for EMC_PUTERM_EXTRA */\n\tu32 emc_puterm_extra;\n\t/* Specifies the value for EMC_PUTERM_WIDTH */\n\tu32 emc_puterm_width;\n\n\tu32 emc_qrst;\n\tu32 emc_qsafe;\n\tu32 emc_rdv;\n\tu32 emc_rdv_mask;\n\n\tu32 emc_rdv_early;\n\tu32 emc_rdv_early_mask;\n\n\t/* Specifies the value for EMC_QPOP */\n\tu32 emc_qpop;\n\n\t/* Specifies the value for EMC_REFRESH */\n\tu32 emc_refresh;\n\t/* Specifies the value for EMC_BURST_REFRESH_NUM */\n\tu32 emc_burst_refresh_num;\n\t/* Specifies the value for EMC_PRE_REFRESH_REQ_CNT */\n\tu32 emc_prerefresh_req_cnt;\n\t/* Specifies the value for EMC_PDEX2WR */\n\tu32 emc_pdex2wr;\n\t/* Specifies the value for EMC_PDEX2RD */\n\tu32 emc_pdex2rd;\n\t/* Specifies the value for EMC_PCHG2PDEN */\n\tu32 emc_pchg2pden;\n\t/* Specifies the value for EMC_ACT2PDEN */\n\tu32 emc_act2pden;\n\t/* Specifies the value for EMC_AR2PDEN */\n\tu32 emc_ar2pden;\n\t/* Specifies the value for EMC_RW2PDEN */\n\tu32 emc_rw2pden;\n\n\tu32 emc_cke2pden;\n\tu32 emc_pdex2che;\n\tu32 emc_pdex2mrr;\n\n\t/* Specifies the value for EMC_TXSR */\n\tu32 emc_txsr;\n\t/* Specifies the value for EMC_TXSRDLL */\n\tu32 emc_txsr_dll;\n\t/* Specifies the value for EMC_TCKE */\n\tu32 emc_tcke;\n\t/* Specifies the value for EMC_TCKESR */\n\tu32 emc_tckesr;\n\t/* Specifies the value for EMC_TPD */\n\tu32 emc_tpd;\n\t/* Specifies the value for EMC_TFAW */\n\tu32 emc_tfaw;\n\t/* Specifies the value for EMC_TRPAB */\n\tu32 emc_trpab;\n\t/* Specifies the value for EMC_TCLKSTABLE */\n\tu32 emc_tclkstable;\n\t/* Specifies the value for EMC_TCLKSTOP */\n\tu32 emc_tclkstop;\n\t/* Specifies the value for EMC_TREFBW */\n\tu32 emc_trefbw;\n\n\t/* FBIO configuration values */\n\n\t/* Specifies the value for EMC_FBIO_CFG5 */\n\tu32 emc_fbio_cfg5;\n\t/* Specifies the value for EMC_FBIO_CFG7 */\n\tu32 emc_fbio_cfg7;\n\tu32 emc_fbio_cfg8;\n\n\t/* Command mapping for CMD brick 0 */\n\tu32 emc_cmd_mapping_cmd0_0;\n\tu32 emc_cmd_mapping_cmd0_1;\n\tu32 emc_cmd_mapping_cmd0_2;\n\tu32 emc_cmd_mapping_cmd1_0;\n\tu32 emc_cmd_mapping_cmd1_1;\n\tu32 emc_cmd_mapping_cmd1_2;\n\tu32 emc_cmd_mapping_cmd2_0;\n\tu32 emc_cmd_mapping_cmd2_1;\n\tu32 emc_cmd_mapping_cmd2_2;\n\tu32 emc_cmd_mapping_cmd3_0;\n\tu32 emc_cmd_mapping_cmd3_1;\n\tu32 emc_cmd_mapping_cmd3_2;\n\tu32 emc_cmd_mapping_byte;\n\n\t/* Specifies the value for EMC_FBIO_SPARE */\n\tu32 emc_fbio_spare;\n\n\t/* Specifies the value for EMC_CFG_RSV */\n\tu32 emc_cfg_rsv;\n\n\t/* MRS command values */\n\n\t/* Specifies the value for EMC_MRS */\n\tu32 emc_mrs;\n\t/* Specifies the MP0 command to initialize mode registers */\n\tu32 emc_emrs;\n\t/* Specifies the MP2 command to initialize mode registers */\n\tu32 emc_emrs2;\n\t/* Specifies the MP3 command to initialize mode registers */\n\tu32 emc_emrs3;\n\t/* Specifies the programming to LPDDR2 Mode Register 1 at cold boot */\n\tu32 emc_mrw1;\n\t/* Specifies the programming to LPDDR2 Mode Register 2 at cold boot */\n\tu32 emc_mrw2;\n\t/* Specifies the programming to LPDDR2 Mode Register 3 at cold boot */\n\tu32 emc_mrw3;\n\t/* Specifies the programming to LPDDR2 Mode Register 11 at cold boot */\n\tu32 emc_mrw4;\n\n\t/* Specifies the programming to LPDDR4 Mode Register 3 at cold boot */\n\tu32 emc_mrw6;\n\t/* Specifies the programming to LPDDR4 Mode Register 11 at cold boot */\n\tu32 emc_mrw8;\n\t/* Specifies the programming to LPDDR4 Mode Register 11 at cold boot */\n\tu32 emc_mrw9;\n\t/* Specifies the programming to LPDDR4 Mode Register 12 at cold boot */\n\tu32 emc_mrw10;\n\t/* Specifies the programming to LPDDR4 Mode Register 14 at cold boot */\n\tu32 emc_mrw12;\n\t/* Specifies the programming to LPDDR4 Mode Register 14 at cold boot */\n\tu32 emc_mrw13;\n\t/* Specifies the programming to LPDDR4 Mode Register 22 at cold boot */\n\tu32 emc_mrw14;\n\n\t/*\n\t * Specifies the programming to extra LPDDR2 Mode Register\n\t * at cold boot\n\t */\n\tu32 emc_mrw_extra;\n\t/*\n\t * Specifies the programming to extra LPDDR2 Mode Register\n\t * at warm boot\n\t */\n\tu32 emc_warm_boot_mrw_extra;\n\t/*\n\t * Specify the enable of extra Mode Register programming at\n\t * warm boot\n\t */\n\tu32 emc_warm_boot_extramode_reg_write_enable;\n\t/*\n\t * Specify the enable of extra Mode Register programming at\n\t * cold boot\n\t */\n\tu32 emc_extramode_reg_write_enable;\n\n\t/* Specifies the EMC_MRW reset command value */\n\tu32 emc_mrw_reset_command;\n\t/* Specifies the EMC Reset wait time (in microseconds) */\n\tu32 emc_mrw_reset_ninit_wait;\n\t/* Specifies the value for EMC_MRS_WAIT_CNT */\n\tu32 emc_mrs_wait_cnt;\n\t/* Specifies the value for EMC_MRS_WAIT_CNT2 */\n\tu32 emc_mrs_wait_cnt2;\n\n\t/* EMC miscellaneous configurations */\n\n\t/* Specifies the value for EMC_CFG */\n\tu32 emc_cfg;\n\t/* Specifies the value for EMC_CFG_2 */\n\tu32 emc_cfg2;\n\t/* Specifies the pipe bypass controls */\n\tu32 emc_cfg_pipe;\n\n\tu32 emc_cfg_pipe_clk;\n\tu32 emc_fdpd_ctrl_cmd_no_ramp;\n\tu32 emc_cfg_update;\n\n\t/* Specifies the value for EMC_DBG */\n\tu32 emc_dbg;\n\n\tu32 emc_dbg_write_mux;\n\n\t/* Specifies the value for EMC_CMDQ */\n\tu32 emc_cmd_q;\n\t/* Specifies the value for EMC_MC2EMCQ */\n\tu32 emc_mc2emc_q;\n\t/* Specifies the value for EMC_DYN_SELF_REF_CONTROL */\n\tu32 emc_dyn_self_ref_control;\n\n\t/* Specifies the value for MEM_INIT_DONE */\n\tu32 ahb_arbitration_xbar_ctrl_meminit_done;\n\n\t/* Specifies the value for EMC_CFG_DIG_DLL */\n\tu32 emc_cfg_dig_dll;\n\tu32 emc_cfg_dig_dll_1;\n\n\t/* Specifies the value for EMC_CFG_DIG_DLL_PERIOD */\n\tu32 emc_cfg_dig_dll_period;\n\t/* Specifies the value of *DEV_SELECTN of various EMC registers */\n\tu32 emc_dev_select;\n\n\t/* Specifies the value for EMC_SEL_DPD_CTRL */\n\tu32 emc_sel_dpd_ctrl;\n\n\t/* Pads trimmer delays */\n\tu32 emc_fdpd_ctrl_dq;\n\tu32 emc_fdpd_ctrl_cmd;\n\tu32 emc_pmacro_ib_vref_dq_0;\n\tu32 emc_pmacro_ib_vref_dq_1;\n\tu32 emc_pmacro_ib_vref_dqs_0;\n\tu32 emc_pmacro_ib_vref_dqs_1;\n\tu32 emc_pmacro_ib_rxrt;\n\tu32 emc_cfg_pipe1;\n\tu32 emc_cfg_pipe2;\n\n\t/* Specifies the value for EMC_PMACRO_QUSE_DDLL_RANK0_0 */\n\tu32 emc_pmacro_quse_ddll_rank0_0;\n\tu32 emc_pmacro_quse_ddll_rank0_1;\n\tu32 emc_pmacro_quse_ddll_rank0_2;\n\tu32 emc_pmacro_quse_ddll_rank0_3;\n\tu32 emc_pmacro_quse_ddll_rank0_4;\n\tu32 emc_pmacro_quse_ddll_rank0_5;\n\tu32 emc_pmacro_quse_ddll_rank1_0;\n\tu32 emc_pmacro_quse_ddll_rank1_1;\n\tu32 emc_pmacro_quse_ddll_rank1_2;\n\tu32 emc_pmacro_quse_ddll_rank1_3;\n\tu32 emc_pmacro_quse_ddll_rank1_4;\n\tu32 emc_pmacro_quse_ddll_rank1_5;\n\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_0;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_1;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_2;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_3;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_4;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_5;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_0;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_1;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_2;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_3;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_4;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_5;\n\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_0;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_1;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_2;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_3;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_4;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_5;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_0;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_1;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_2;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_3;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_4;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_5;\n\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_0;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_1;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_2;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_3;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_0;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_1;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_2;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_3;\n\n\tu32 emc_pmacro_ddll_long_cmd_0;\n\tu32 emc_pmacro_ddll_long_cmd_1;\n\tu32 emc_pmacro_ddll_long_cmd_2;\n\tu32 emc_pmacro_ddll_long_cmd_3;\n\tu32 emc_pmacro_ddll_long_cmd_4;\n\tu32 emc_pmacro_ddll_short_cmd_0;\n\tu32 emc_pmacro_ddll_short_cmd_1;\n\tu32 emc_pmacro_ddll_short_cmd_2;\n\n\t/*\n\t * Specifies the delay after asserting CKE pin during a WarmBoot0\n\t * sequence (in microseconds)\n\t */\n\tu32 warm_boot_wait;\n\n\t/* Specifies the value for EMC_ODT_WRITE */\n\tu32 emc_odt_write;\n\n\t/* Periodic ZQ calibration */\n\n\t/*\n\t * Specifies the value for EMC_ZCAL_INTERVAL\n\t * Value 0 disables ZQ calibration\n\t */\n\tu32 emc_zcal_interval;\n\t/* Specifies the value for EMC_ZCAL_WAIT_CNT */\n\tu32 emc_zcal_wait_cnt;\n\t/* Specifies the value for EMC_ZCAL_MRW_CMD */\n\tu32 emc_zcal_mrw_cmd;\n\n\t/* DRAM initialization sequence flow control */\n\n\t/* Specifies the MRS command value for resetting DLL */\n\tu32 emc_mrs_reset_dll;\n\t/* Specifies the command for ZQ initialization of device 0 */\n\tu32 emc_zcal_init_dev0;\n\t/* Specifies the command for ZQ initialization of device 1 */\n\tu32 emc_zcal_init_dev1;\n\t/*\n\t * Specifies the wait time after programming a ZQ initialization\n\t * command (in microseconds)\n\t */\n\tu32 emc_zcal_init_wait;\n\t/*\n\t * Specifies the enable for ZQ calibration at cold boot [bit 0]\n\t * and warm boot [bit 1]\n\t */\n\tu32 emc_zcal_warm_cold_boot_enables;\n\n\t/*\n\t * Specifies the MRW command to LPDDR2 for ZQ calibration\n\t * on warmboot\n\t */\n\t/* Is issued to both devices separately */\n\tu32 emc_mrw_lpddr2zcal_warm_boot;\n\t/*\n\t * Specifies the ZQ command to DDR3 for ZQ calibration on warmboot\n\t * Is issued to both devices separately\n\t */\n\tu32 emc_zqcal_ddr3_warm_boot;\n\n\tu32 emc_zqcal_lpddr4_warm_boot;\n\n\t/*\n\t * Specifies the wait time for ZQ calibration on warmboot\n\t * (in microseconds)\n\t */\n\tu32 emc_zcal_warm_boot_wait;\n\t/*\n\t * Specifies the enable for DRAM Mode Register programming\n\t * at warm boot\n\t */\n\tu32 emc_mrs_warm_boot_enable;\n\t/*\n\t * Specifies the wait time after sending an MRS DLL reset command\n\t * in microseconds)\n\t */\n\tu32 emc_mrs_reset_dll_wait;\n\t/* Specifies the extra MRS command to initialize mode registers */\n\tu32 emc_mrs_extra;\n\t/* Specifies the extra MRS command at warm boot */\n\tu32 emc_warm_boot_mrs_extra;\n\t/* Specifies the EMRS command to enable the DDR2 DLL */\n\tu32 emc_emrs_ddr2_dll_enable;\n\t/* Specifies the MRS command to reset the DDR2 DLL */\n\tu32 emc_mrs_ddr2_dll_reset;\n\t/* Specifies the EMRS command to set OCD calibration */\n\tu32 emc_emrs_ddr2_ocd_calib;\n\t/*\n\t * Specifies the wait between initializing DDR and setting OCD\n\t * calibration (in microseconds)\n\t */\n\tu32 emc_ddr2_wait;\n\t/* Specifies the value for EMC_CLKEN_OVERRIDE */\n\tu32 emc_clken_override;\n\t/*\n\t * Specifies LOG2 of the extra refresh numbers after booting\n\t * Program 0 to disable\n\t */\n\tu32 emc_extra_refresh_num;\n\t/* Specifies the master override for all EMC clocks */\n\tu32 emc_clken_override_allwarm_boot;\n\t/* Specifies the master override for all MC clocks */\n\tu32 mc_clken_override_allwarm_boot;\n\t/* Specifies digital dll period, choosing between 4 to 64 ms */\n\tu32 emc_cfg_dig_dll_period_warm_boot;\n\n\t/* Pad controls */\n\n\t/* Specifies the value for PMC_VDDP_SEL */\n\tu32 pmc_vddp_sel;\n\t/* Specifies the wait time after programming PMC_VDDP_SEL */\n\tu32 pmc_vddp_sel_wait;\n\t/* Specifies the value for PMC_DDR_PWR */\n\tu32 pmc_ddr_pwr;\n\t/* Specifies the value for PMC_DDR_CFG */\n\tu32 pmc_ddr_cfg;\n\t/* Specifies the value for PMC_IO_DPD3_REQ */\n\tu32 pmc_io_dpd3_req;\n\t/* Specifies the wait time after programming PMC_IO_DPD3_REQ */\n\tu32 pmc_io_dpd3_req_wait;\n\n\tu32 pmc_io_dpd4_req_wait;\n\n\t/* Specifies the value for PMC_REG_SHORT */\n\tu32 pmc_reg_short;\n\t/* Specifies the value for PMC_NO_IOPOWER */\n\tu32 pmc_no_io_power;\n\n\tu32 pmc_ddr_ctrl_wait;\n\tu32 pmc_ddr_ctrl;\n\n\t/* Specifies the value for EMC_ACPD_CONTROL */\n\tu32 emc_acpd_control;\n\n\t/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE0 */\n\tu32 emc_swizzle_rank0_byte0;\n\t/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE1 */\n\tu32 emc_swizzle_rank0_byte1;\n\t/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE2 */\n\tu32 emc_swizzle_rank0_byte2;\n\t/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE3 */\n\tu32 emc_swizzle_rank0_byte3;\n\t/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE0 */\n\tu32 emc_swizzle_rank1_byte0;\n\t/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE1 */\n\tu32 emc_swizzle_rank1_byte1;\n\t/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE2 */\n\tu32 emc_swizzle_rank1_byte2;\n\t/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE3 */\n\tu32 emc_swizzle_rank1_byte3;\n\n\t/* Specifies the value for EMC_TXDSRVTTGEN */\n\tu32 emc_txdsrvttgen;\n\n\t/* Specifies the value for EMC_DATA_BRLSHFT_0 */\n\tu32 emc_data_brlshft0;\n\tu32 emc_data_brlshft1;\n\n\tu32 emc_dqs_brlshft0;\n\tu32 emc_dqs_brlshft1;\n\n\tu32 emc_cmd_brlshft0;\n\tu32 emc_cmd_brlshft1;\n\tu32 emc_cmd_brlshft2;\n\tu32 emc_cmd_brlshft3;\n\n\tu32 emc_quse_brlshft0;\n\tu32 emc_quse_brlshft1;\n\tu32 emc_quse_brlshft2;\n\tu32 emc_quse_brlshft3;\n\n\tu32 emc_dll_cfg0;\n\tu32 emc_dll_cfg1;\n\n\tu32 emc_pmc_scratch1;\n\tu32 emc_pmc_scratch2;\n\tu32 emc_pmc_scratch3;\n\n\tu32 emc_pmacro_pad_cfg_ctrl;\n\n\tu32 emc_pmacro_vttgen_ctrl0;\n\tu32 emc_pmacro_vttgen_ctrl1;\n\tu32 emc_pmacro_vttgen_ctrl2;\n\n\tu32 emc_pmacro_brick_ctrl_rfu1;\n\tu32 emc_pmacro_cmd_brick_ctrl_fdpd;\n\tu32 emc_pmacro_brick_ctrl_rfu2;\n\tu32 emc_pmacro_data_brick_ctrl_fdpd;\n\tu32 emc_pmacro_bg_bias_ctrl0;\n\tu32 emc_pmacro_data_pad_rx_ctrl;\n\tu32 emc_pmacro_cmd_pad_rx_ctrl;\n\tu32 emc_pmacro_data_rx_term_mode;\n\tu32 emc_pmacro_cmd_rx_term_mode;\n\tu32 emc_pmacro_data_pad_tx_ctrl;\n\tu32 emc_pmacro_common_pad_tx_ctrl;\n\tu32 emc_pmacro_cmd_pad_tx_ctrl;\n\tu32 emc_cfg3;\n\n\tu32 emc_pmacro_tx_pwrd0;\n\tu32 emc_pmacro_tx_pwrd1;\n\tu32 emc_pmacro_tx_pwrd2;\n\tu32 emc_pmacro_tx_pwrd3;\n\tu32 emc_pmacro_tx_pwrd4;\n\tu32 emc_pmacro_tx_pwrd5;\n\n\tu32 emc_config_sample_delay;\n\n\tu32 emc_pmacro_brick_mapping0;\n\tu32 emc_pmacro_brick_mapping1;\n\tu32 emc_pmacro_brick_mapping2;\n\n\tu32 emc_pmacro_tx_sel_clk_src0;\n\tu32 emc_pmacro_tx_sel_clk_src1;\n\tu32 emc_pmacro_tx_sel_clk_src2;\n\tu32 emc_pmacro_tx_sel_clk_src3;\n\tu32 emc_pmacro_tx_sel_clk_src4;\n\tu32 emc_pmacro_tx_sel_clk_src5;\n\n\tu32 emc_pmacro_ddll_bypass;\n\n\tu32 emc_pmacro_ddll_pwrd0;\n\tu32 emc_pmacro_ddll_pwrd1;\n\tu32 emc_pmacro_ddll_pwrd2;\n\n\tu32 emc_pmacro_cmd_ctrl0;\n\tu32 emc_pmacro_cmd_ctrl1;\n\tu32 emc_pmacro_cmd_ctrl2;\n\n\t/* DRAM size information */\n\n\t/* Specifies the value for MC_EMEM_ADR_CFG */\n\tu32 mc_emem_adr_cfg;\n\t/* Specifies the value for MC_EMEM_ADR_CFG_DEV0 */\n\tu32 mc_emem_adr_cfg_dev0;\n\t/* Specifies the value for MC_EMEM_ADR_CFG_DEV1 */\n\tu32 mc_emem_adr_cfg_dev1;\n\n\tu32 mc_emem_adr_cfg_channel_mask;\n\n\t/* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG0 */\n\tu32 mc_emem_adr_cfg_bank_mask0;\n\t/* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG1 */\n\tu32 mc_emem_adr_cfg_bank_mask1;\n\t/* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG2 */\n\tu32 mc_emem_adr_cfg_bank_mask2;\n\n\t/*\n\t * Specifies the value for MC_EMEM_CFG which holds the external memory\n\t * size (in KBytes)\n\t */\n\tu32 mc_emem_cfg;\n\n\t/* MC arbitration configuration */\n\n\t/* Specifies the value for MC_EMEM_ARB_CFG */\n\tu32 mc_emem_arb_cfg;\n\t/* Specifies the value for MC_EMEM_ARB_OUTSTANDING_REQ */\n\tu32 mc_emem_arb_outstanding_req;\n\n\tu32 emc_emem_arb_refpb_hp_ctrl;\n\tu32 emc_emem_arb_refpb_bank_ctrl;\n\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RCD */\n\tu32 mc_emem_arb_timing_rcd;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RP */\n\tu32 mc_emem_arb_timing_rp;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RC */\n\tu32 mc_emem_arb_timing_rc;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RAS */\n\tu32 mc_emem_arb_timing_ras;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_FAW */\n\tu32 mc_emem_arb_timing_faw;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RRD */\n\tu32 mc_emem_arb_timing_rrd;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RAP2PRE */\n\tu32 mc_emem_arb_timing_rap2pre;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_WAP2PRE */\n\tu32 mc_emem_arb_timing_wap2pre;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_R2R */\n\tu32 mc_emem_arb_timing_r2r;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_W2W */\n\tu32 mc_emem_arb_timing_w2w;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_R2W */\n\tu32 mc_emem_arb_timing_r2w;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_W2R */\n\tu32 mc_emem_arb_timing_w2r;\n\n\tu32 mc_emem_arb_timing_rfcpb;\n\n\t/* Specifies the value for MC_EMEM_ARB_DA_TURNS */\n\tu32 mc_emem_arb_da_turns;\n\t/* Specifies the value for MC_EMEM_ARB_DA_COVERS */\n\tu32 mc_emem_arb_da_covers;\n\t/* Specifies the value for MC_EMEM_ARB_MISC0 */\n\tu32 mc_emem_arb_misc0;\n\t/* Specifies the value for MC_EMEM_ARB_MISC1 */\n\tu32 mc_emem_arb_misc1;\n\tu32 mc_emem_arb_misc2;\n\n\t/* Specifies the value for MC_EMEM_ARB_RING1_THROTTLE */\n\tu32 mc_emem_arb_ring1_throttle;\n\t/* Specifies the value for MC_EMEM_ARB_OVERRIDE */\n\tu32 mc_emem_arb_override;\n\t/* Specifies the value for MC_EMEM_ARB_OVERRIDE_1 */\n\tu32 mc_emem_arb_override1;\n\t/* Specifies the value for MC_EMEM_ARB_RSV */\n\tu32 mc_emem_arb_rsv;\n\n\tu32 mc_da_cfg0;\n\tu32 mc_emem_arb_timing_ccdmw;\n\n\t/* Specifies the value for MC_CLKEN_OVERRIDE */\n\tu32 mc_clken_override;\n\n\t/* Specifies the value for MC_STAT_CONTROL */\n\tu32 mc_stat_control;\n\t/* Specifies the value for MC_VIDEO_PROTECT_BOM */\n\tu32 mc_video_protect_bom;\n\t/* Specifies the value for MC_VIDEO_PROTECT_BOM_ADR_HI */\n\tu32 mc_video_protect_bom_adr_hi;\n\t/* Specifies the value for MC_VIDEO_PROTECT_SIZE_MB */\n\tu32 mc_video_protect_size_mb;\n\t/* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE */\n\tu32 mc_video_protect_vpr_override;\n\t/* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE1 */\n\tu32 mc_video_protect_vpr_override1;\n\t/* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_0 */\n\tu32 mc_video_protect_gpu_override0;\n\t/* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_1 */\n\tu32 mc_video_protect_gpu_override1;\n\t/* Specifies the value for MC_SEC_CARVEOUT_BOM */\n\tu32 mc_sec_carveout_bom;\n\t/* Specifies the value for MC_SEC_CARVEOUT_ADR_HI */\n\tu32 mc_sec_carveout_adr_hi;\n\t/* Specifies the value for MC_SEC_CARVEOUT_SIZE_MB */\n\tu32 mc_sec_carveout_size_mb;\n\t/* Specifies the value for MC_VIDEO_PROTECT_REG_CTRL.VIDEO_PROTECT_WRITE_ACCESS */\n\tu32 mc_video_protect_write_access;\n\t/* Specifies the value for MC_SEC_CARVEOUT_REG_CTRL.SEC_CARVEOUT_WRITE_ACCESS */\n\tu32 mc_sec_carveout_protect_write_access;\n\n\tu32 mc_generalized_carveout1_bom;\n\tu32 mc_generalized_carveout1_bom_hi;\n\tu32 mc_generalized_carveout1_size_128kb;\n\tu32 mc_generalized_carveout1_access0;\n\tu32 mc_generalized_carveout1_access1;\n\tu32 mc_generalized_carveout1_access2;\n\tu32 mc_generalized_carveout1_access3;\n\tu32 mc_generalized_carveout1_access4;\n\tu32 mc_generalized_carveout1_force_internal_access0;\n\tu32 mc_generalized_carveout1_force_internal_access1;\n\tu32 mc_generalized_carveout1_force_internal_access2;\n\tu32 mc_generalized_carveout1_force_internal_access3;\n\tu32 mc_generalized_carveout1_force_internal_access4;\n\tu32 mc_generalized_carveout1_cfg0;\n\n\tu32 mc_generalized_carveout2_bom;\n\tu32 mc_generalized_carveout2_bom_hi;\n\tu32 mc_generalized_carveout2_size_128kb;\n\tu32 mc_generalized_carveout2_access0;\n\tu32 mc_generalized_carveout2_access1;\n\tu32 mc_generalized_carveout2_access2;\n\tu32 mc_generalized_carveout2_access3;\n\tu32 mc_generalized_carveout2_access4;\n\tu32 mc_generalized_carveout2_force_internal_access0;\n\tu32 mc_generalized_carveout2_force_internal_access1;\n\tu32 mc_generalized_carveout2_force_internal_access2;\n\tu32 mc_generalized_carveout2_force_internal_access3;\n\tu32 mc_generalized_carveout2_force_internal_access4;\n\tu32 mc_generalized_carveout2_cfg0;\n\n\tu32 mc_generalized_carveout3_bom;\n\tu32 mc_generalized_carveout3_bom_hi;\n\tu32 mc_generalized_carveout3_size_128kb;\n\tu32 mc_generalized_carveout3_access0;\n\tu32 mc_generalized_carveout3_access1;\n\tu32 mc_generalized_carveout3_access2;\n\tu32 mc_generalized_carveout3_access3;\n\tu32 mc_generalized_carveout3_access4;\n\tu32 mc_generalized_carveout3_force_internal_access0;\n\tu32 mc_generalized_carveout3_force_internal_access1;\n\tu32 mc_generalized_carveout3_force_internal_access2;\n\tu32 mc_generalized_carveout3_force_internal_access3;\n\tu32 mc_generalized_carveout3_force_internal_access4;\n\tu32 mc_generalized_carveout3_cfg0;\n\n\tu32 mc_generalized_carveout4_bom;\n\tu32 mc_generalized_carveout4_bom_hi;\n\tu32 mc_generalized_carveout4_size_128kb;\n\tu32 mc_generalized_carveout4_access0;\n\tu32 mc_generalized_carveout4_access1;\n\tu32 mc_generalized_carveout4_access2;\n\tu32 mc_generalized_carveout4_access3;\n\tu32 mc_generalized_carveout4_access4;\n\tu32 mc_generalized_carveout4_force_internal_access0;\n\tu32 mc_generalized_carveout4_force_internal_access1;\n\tu32 mc_generalized_carveout4_force_internal_access2;\n\tu32 mc_generalized_carveout4_force_internal_access3;\n\tu32 mc_generalized_carveout4_force_internal_access4;\n\tu32 mc_generalized_carveout4_cfg0;\n\n\tu32 mc_generalized_carveout5_bom;\n\tu32 mc_generalized_carveout5_bom_hi;\n\tu32 mc_generalized_carveout5_size_128kb;\n\tu32 mc_generalized_carveout5_access0;\n\tu32 mc_generalized_carveout5_access1;\n\tu32 mc_generalized_carveout5_access2;\n\tu32 mc_generalized_carveout5_access3;\n\tu32 mc_generalized_carveout5_access4;\n\tu32 mc_generalized_carveout5_force_internal_access0;\n\tu32 mc_generalized_carveout5_force_internal_access1;\n\tu32 mc_generalized_carveout5_force_internal_access2;\n\tu32 mc_generalized_carveout5_force_internal_access3;\n\tu32 mc_generalized_carveout5_force_internal_access4;\n\tu32 mc_generalized_carveout5_cfg0;\n\n\t/* Specifies enable for CA training */\n\tu32 emc_ca_training_enable;\n\t/* Set if bit 6 select is greater than bit 7 select; uses aremc.spec packet SWIZZLE_BIT6_GT_BIT7 */\n\tu32 swizzle_rank_byte_encode;\n\t/* Specifies enable and offset for patched boot rom write */\n\tu32 boot_rom_patch_control;\n\t/* Specifies data for patched boot rom write */\n\tu32 boot_rom_patch_data;\n\n\t/* Specifies the value for MC_MTS_CARVEOUT_BOM */\n\tu32 mc_mts_carveout_bom;\n\t/* Specifies the value for MC_MTS_CARVEOUT_ADR_HI */\n\tu32 mc_mts_carveout_adr_hi;\n\t/* Specifies the value for MC_MTS_CARVEOUT_SIZE_MB */\n\tu32 mc_mts_carveout_size_mb;\n\t/* Specifies the value for MC_MTS_CARVEOUT_REG_CTRL */\n\tu32 mc_mts_carveout_reg_ctrl;\n} sdram_params_t210_t;\n\n#endif\n"
  },
  {
    "path": "bdk/mem/sdram_param_t210b01.h",
    "content": "/*\n * Copyright (c) 2020 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n */\n\n#ifndef _SDRAM_PARAM_T210B01_H_\n#define _SDRAM_PARAM_T210B01_H_\n\ntypedef struct _sdram_params_t210b01_t\n{\n\t/* Specifies the type of memory device */\n\tu32 memory_type;\n\n\t/* MC/EMC clock source configuration */\n\n\t/* Specifies the M value for PllM */\n\tu32 pllm_input_divider;\n\t/* Specifies the N value for PllM */\n\tu32 pllm_feedback_divider;\n\t/* Specifies the time to wait for PLLM to lock (in microseconds) */\n\tu32 pllm_stable_time;\n\t/* Specifies misc. control bits */\n\tu32 pllm_setup_control;\n\t/* Specifies the P value for PLLM */\n\tu32 pllm_post_divider;\n\t/* Specifies value for Charge Pump Gain Control */\n\tu32 pllm_kcp;\n\t/* Specifies VCO gain */\n\tu32 pllm_kvco;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare0;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare1;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare2;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare3;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare4;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare5;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare6;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare7;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare8;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare9;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare10;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare11;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare12;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare13;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure0;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure1;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure2;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure3;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure4;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure5;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure6;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure7;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure8;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure9;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure10;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure11;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure12;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure13;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure14;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure15;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure16;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure17;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure18;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure19;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure20;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure21;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure22;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure23;\n\n\t/* Defines EMC_2X_CLK_SRC, EMC_2X_CLK_DIVISOR, EMC_INVERT_DCD */\n\tu32 emc_clock_source;\n\tu32 emc_clock_source_dll;\n\n\t/* Defines possible override for PLLLM_MISC2 */\n\tu32 clk_rst_pllm_misc20_override;\n\t/* enables override for PLLLM_MISC2 */\n\tu32 clk_rst_pllm_misc20_override_enable;\n\t/* defines CLK_ENB_MC1 in register clk_rst_controller_clk_enb_w_clr */\n\tu32 clear_clock2_mc1;\n\n\t/* Auto-calibration of EMC pads */\n\n\t/* Specifies the value for EMC_AUTO_CAL_INTERVAL */\n\tu32 emc_auto_cal_interval;\n\t/*\n\t * Specifies the value for EMC_AUTO_CAL_CONFIG\n\t * Note: Trigger bits are set by the SDRAM code.\n\t */\n\tu32 emc_auto_cal_config;\n\n\t/* Specifies the value for EMC_AUTO_CAL_CONFIG2 */\n\tu32 emc_auto_cal_config2;\n\n\t/* Specifies the value for EMC_AUTO_CAL_CONFIG3 */\n\tu32 emc_auto_cal_config3;\n\tu32 emc_auto_cal_config4;\n\tu32 emc_auto_cal_config5;\n\tu32 emc_auto_cal_config6;\n\tu32 emc_auto_cal_config7;\n\tu32 emc_auto_cal_config8;\n\tu32 emc_auto_cal_config9;\n\n\t/* Specifies the value for EMC_AUTO_CAL_VREF_SEL_0 */\n\tu32 emc_auto_cal_vref_sel0;\n\tu32 emc_auto_cal_vref_sel1;\n\n\t/* Specifies the value for EMC_AUTO_CAL_CHANNEL */\n\tu32 emc_auto_cal_channel;\n\n\t/* Specifies the value for EMC_PMACRO_AUTOCAL_CFG_0 */\n\tu32 emc_pmacro_auto_cal_cfg0;\n\tu32 emc_pmacro_auto_cal_cfg1;\n\tu32 emc_pmacro_auto_cal_cfg2;\n\n\tu32 emc_pmacro_rx_term;\n\tu32 emc_pmacro_dq_tx_drive;\n\tu32 emc_pmacro_ca_tx_drive;\n\tu32 emc_pmacro_cmd_tx_drive;\n\tu32 emc_pmacro_auto_cal_common;\n\tu32 emc_pmacro_zcrtl;\n\n\t/*\n\t * Specifies the time for the calibration\n\t * to stabilize (in microseconds)\n\t */\n\tu32 emc_auto_cal_wait;\n\n\tu32 emc_xm2_comp_pad_ctrl;\n\tu32 emc_xm2_comp_pad_ctrl2;\n\tu32 emc_xm2_comp_pad_ctrl3;\n\n\t/*\n\t * DRAM size information\n\t * Specifies the value for EMC_ADR_CFG\n\t */\n\tu32 emc_adr_cfg;\n\n\t/*\n\t * Specifies the time to wait after asserting pin\n\t * CKE (in microseconds)\n\t */\n\tu32 emc_pin_program_wait;\n\t/* Specifies the extra delay before/after pin RESET/CKE command */\n\tu32 emc_pin_extra_wait;\n\n\tu32 emc_pin_gpio_enable;\n\tu32 emc_pin_gpio;\n\n\t/*\n\t * Specifies the extra delay after the first writing\n\t * of EMC_TIMING_CONTROL\n\t */\n\tu32 emc_timing_control_wait;\n\n\t/* Timing parameters required for the SDRAM */\n\n\t/* Specifies the value for EMC_RC */\n\tu32 emc_rc;\n\t/* Specifies the value for EMC_RFC */\n\tu32 emc_rfc;\n\n\tu32 emc_rfc_pb;\n\tu32 emc_ref_ctrl2;\n\n\t/* Specifies the value for EMC_RFC_SLR */\n\tu32 emc_rfc_slr;\n\t/* Specifies the value for EMC_RAS */\n\tu32 emc_ras;\n\t/* Specifies the value for EMC_RP */\n\tu32 emc_rp;\n\t/* Specifies the value for EMC_R2R */\n\tu32 emc_r2r;\n\t/* Specifies the value for EMC_W2W */\n\tu32 emc_w2w;\n\t/* Specifies the value for EMC_R2W */\n\tu32 emc_r2w;\n\t/* Specifies the value for EMC_W2R */\n\tu32 emc_w2r;\n\t/* Specifies the value for EMC_R2P */\n\tu32 emc_r2p;\n\t/* Specifies the value for EMC_W2P */\n\tu32 emc_w2p;\n\n\tu32 emc_tppd;\n\tu32 emc_trtm;\n\tu32 emc_twtm;\n\tu32 emc_tratm;\n\tu32 emc_twatm;\n\tu32 emc_tr2ref;\n\tu32 emc_ccdmw;\n\n\t/* Specifies the value for EMC_RD_RCD */\n\tu32 emc_rd_rcd;\n\t/* Specifies the value for EMC_WR_RCD */\n\tu32 emc_wr_rcd;\n\t/* Specifies the value for EMC_RRD */\n\tu32 emc_rrd;\n\t/* Specifies the value for EMC_REXT */\n\tu32 emc_rext;\n\t/* Specifies the value for EMC_WEXT */\n\tu32 emc_wext;\n\t/* Specifies the value for EMC_WDV */\n\tu32 emc_wdv;\n\n\tu32 emc_wdv_chk;\n\tu32 emc_wsv;\n\tu32 emc_wev;\n\n\t/* Specifies the value for EMC_WDV_MASK */\n\tu32 emc_wdv_mask;\n\n\tu32 emc_ws_duration;\n\tu32 emc_we_duration;\n\n\t/* Specifies the value for EMC_QUSE */\n\tu32 emc_quse;\n\t/* Specifies the value for EMC_QUSE_WIDTH */\n\tu32 emc_quse_width;\n\t/* Specifies the value for EMC_IBDLY */\n\tu32 emc_ibdly;\n\n\tu32 emc_obdly;\n\n\t/* Specifies the value for EMC_EINPUT */\n\tu32 emc_einput;\n\t/* Specifies the value for EMC_EINPUT_DURATION */\n\tu32 emc_einput_duration;\n\t/* Specifies the value for EMC_PUTERM_EXTRA */\n\tu32 emc_puterm_extra;\n\t/* Specifies the value for EMC_PUTERM_WIDTH */\n\tu32 emc_puterm_width;\n\n\tu32 emc_qrst;\n\tu32 emc_qsafe;\n\tu32 emc_rdv;\n\tu32 emc_rdv_mask;\n\n\tu32 emc_rdv_early;\n\tu32 emc_rdv_early_mask;\n\n\t/* Specifies the value for EMC_QPOP */\n\tu32 emc_qpop;\n\n\t/* Specifies the value for EMC_REFRESH */\n\tu32 emc_refresh;\n\t/* Specifies the value for EMC_BURST_REFRESH_NUM */\n\tu32 emc_burst_refresh_num;\n\t/* Specifies the value for EMC_PRE_REFRESH_REQ_CNT */\n\tu32 emc_prerefresh_req_cnt;\n\t/* Specifies the value for EMC_PDEX2WR */\n\tu32 emc_pdex2wr;\n\t/* Specifies the value for EMC_PDEX2RD */\n\tu32 emc_pdex2rd;\n\t/* Specifies the value for EMC_PCHG2PDEN */\n\tu32 emc_pchg2pden;\n\t/* Specifies the value for EMC_ACT2PDEN */\n\tu32 emc_act2pden;\n\t/* Specifies the value for EMC_AR2PDEN */\n\tu32 emc_ar2pden;\n\t/* Specifies the value for EMC_RW2PDEN */\n\tu32 emc_rw2pden;\n\n\tu32 emc_cke2pden;\n\tu32 emc_pdex2che;\n\tu32 emc_pdex2mrr;\n\n\t/* Specifies the value for EMC_TXSR */\n\tu32 emc_txsr;\n\t/* Specifies the value for EMC_TXSRDLL */\n\tu32 emc_txsr_dll;\n\t/* Specifies the value for EMC_TCKE */\n\tu32 emc_tcke;\n\t/* Specifies the value for EMC_TCKESR */\n\tu32 emc_tckesr;\n\t/* Specifies the value for EMC_TPD */\n\tu32 emc_tpd;\n\t/* Specifies the value for EMC_TFAW */\n\tu32 emc_tfaw;\n\t/* Specifies the value for EMC_TRPAB */\n\tu32 emc_trpab;\n\t/* Specifies the value for EMC_TCLKSTABLE */\n\tu32 emc_tclkstable;\n\t/* Specifies the value for EMC_TCLKSTOP */\n\tu32 emc_tclkstop;\n\t/* Specifies the value for EMC_TREFBW */\n\tu32 emc_trefbw;\n\n\t/* FBIO configuration values */\n\n\t/* Specifies the value for EMC_FBIO_CFG5 */\n\tu32 emc_fbio_cfg5;\n\t/* Specifies the value for EMC_FBIO_CFG7 */\n\tu32 emc_fbio_cfg7;\n\tu32 emc_fbio_cfg8;\n\n\t/* Command mapping for CMD brick 0 */\n\tu32 emc_cmd_mapping_cmd0_0;\n\tu32 emc_cmd_mapping_cmd0_1;\n\tu32 emc_cmd_mapping_cmd0_2;\n\tu32 emc_cmd_mapping_cmd1_0;\n\tu32 emc_cmd_mapping_cmd1_1;\n\tu32 emc_cmd_mapping_cmd1_2;\n\tu32 emc_cmd_mapping_cmd2_0;\n\tu32 emc_cmd_mapping_cmd2_1;\n\tu32 emc_cmd_mapping_cmd2_2;\n\tu32 emc_cmd_mapping_cmd3_0;\n\tu32 emc_cmd_mapping_cmd3_1;\n\tu32 emc_cmd_mapping_cmd3_2;\n\tu32 emc_cmd_mapping_byte;\n\n\t/* Specifies the value for EMC_FBIO_SPARE */\n\tu32 emc_fbio_spare;\n\n\t/* Specifies the value for EMC_CFG_RSV */\n\tu32 emc_cfg_rsv;\n\n\t/* MRS command values */\n\n\t/* Specifies the value for EMC_MRS */\n\tu32 emc_mrs;\n\t/* Specifies the MP0 command to initialize mode registers */\n\tu32 emc_emrs;\n\t/* Specifies the MP2 command to initialize mode registers */\n\tu32 emc_emrs2;\n\t/* Specifies the MP3 command to initialize mode registers */\n\tu32 emc_emrs3;\n\t/* Specifies the programming to LPDDR2 Mode Register 1 at cold boot */\n\tu32 emc_mrw1;\n\t/* Specifies the programming to LPDDR2 Mode Register 2 at cold boot */\n\tu32 emc_mrw2;\n\t/* Specifies the programming to LPDDR2 Mode Register 3 at cold boot */\n\tu32 emc_mrw3;\n\t/* Specifies the programming to LPDDR2 Mode Register 11 at cold boot */\n\tu32 emc_mrw4;\n\n\t/* Specifies the programming to LPDDR4 Mode Register 3 at cold boot */\n\tu32 emc_mrw6;\n\t/* Specifies the programming to LPDDR4 Mode Register 11 at cold boot */\n\tu32 emc_mrw8;\n\t/* Specifies the programming to LPDDR4 Mode Register 11 at cold boot */\n\tu32 emc_mrw9;\n\t/* Specifies the programming to LPDDR4 Mode Register 12 at cold boot */\n\tu32 emc_mrw10;\n\t/* Specifies the programming to LPDDR4 Mode Register 14 at cold boot */\n\tu32 emc_mrw12;\n\t/* Specifies the programming to LPDDR4 Mode Register 14 at cold boot */\n\tu32 emc_mrw13;\n\t/* Specifies the programming to LPDDR4 Mode Register 22 at cold boot */\n\tu32 emc_mrw14;\n\n\t/*\n\t * Specifies the programming to extra LPDDR2 Mode Register\n\t * at cold boot\n\t */\n\tu32 emc_mrw_extra;\n\t/*\n\t * Specifies the programming to extra LPDDR2 Mode Register\n\t * at warm boot\n\t */\n\tu32 emc_warm_boot_mrw_extra;\n\t/*\n\t * Specify the enable of extra Mode Register programming at\n\t * warm boot\n\t */\n\tu32 emc_warm_boot_extramode_reg_write_enable;\n\t/*\n\t * Specify the enable of extra Mode Register programming at\n\t * cold boot\n\t */\n\tu32 emc_extramode_reg_write_enable;\n\n\t/* Specifies the EMC_MRW reset command value */\n\tu32 emc_mrw_reset_command;\n\t/* Specifies the EMC Reset wait time (in microseconds) */\n\tu32 emc_mrw_reset_ninit_wait;\n\t/* Specifies the value for EMC_MRS_WAIT_CNT */\n\tu32 emc_mrs_wait_cnt;\n\t/* Specifies the value for EMC_MRS_WAIT_CNT2 */\n\tu32 emc_mrs_wait_cnt2;\n\n\t/* EMC miscellaneous configurations */\n\n\t/* Specifies the value for EMC_CFG */\n\tu32 emc_cfg;\n\t/* Specifies the value for EMC_CFG_2 */\n\tu32 emc_cfg2;\n\t/* Specifies the pipe bypass controls */\n\tu32 emc_cfg_pipe;\n\n\tu32 emc_cfg_pipe_clk;\n\tu32 emc_fdpd_ctrl_cmd_no_ramp;\n\tu32 emc_cfg_update;\n\n\t/* Specifies the value for EMC_DBG */\n\tu32 emc_dbg;\n\n\tu32 emc_dbg_write_mux;\n\n\t/* Specifies the value for EMC_CMDQ */\n\tu32 emc_cmd_q;\n\t/* Specifies the value for EMC_MC2EMCQ */\n\tu32 emc_mc2emc_q;\n\t/* Specifies the value for EMC_DYN_SELF_REF_CONTROL */\n\tu32 emc_dyn_self_ref_control;\n\n\t/* Specifies the value for MEM_INIT_DONE */\n\tu32 ahb_arbitration_xbar_ctrl_meminit_done;\n\n\t/* Specifies the value for EMC_CFG_DIG_DLL */\n\tu32 emc_cfg_dig_dll;\n\tu32 emc_cfg_dig_dll_1;\n\n\t/* Specifies the value for EMC_CFG_DIG_DLL_PERIOD */\n\tu32 emc_cfg_dig_dll_period;\n\t/* Specifies the value of *DEV_SELECTN of various EMC registers */\n\tu32 emc_dev_select;\n\n\t/* Specifies the value for EMC_SEL_DPD_CTRL */\n\tu32 emc_sel_dpd_ctrl;\n\n\t/* Pads trimmer delays */\n\tu32 emc_fdpd_ctrl_dq;\n\tu32 emc_fdpd_ctrl_cmd;\n\tu32 emc_pmacro_ib_vref_dq_0;\n\tu32 emc_pmacro_ib_vref_dq_1;\n\tu32 emc_pmacro_ib_vref_dqs_0;\n\tu32 emc_pmacro_ib_vref_dqs_1;\n\tu32 emc_pmacro_ib_rxrt;\n\tu32 emc_cfg_pipe1;\n\tu32 emc_cfg_pipe2;\n\n\t/* Specifies the value for EMC_PMACRO_QUSE_DDLL_RANK0_0 */\n\tu32 emc_pmacro_quse_ddll_rank0_0;\n\tu32 emc_pmacro_quse_ddll_rank0_1;\n\tu32 emc_pmacro_quse_ddll_rank0_2;\n\tu32 emc_pmacro_quse_ddll_rank0_3;\n\tu32 emc_pmacro_quse_ddll_rank0_4;\n\tu32 emc_pmacro_quse_ddll_rank0_5;\n\tu32 emc_pmacro_quse_ddll_rank1_0;\n\tu32 emc_pmacro_quse_ddll_rank1_1;\n\tu32 emc_pmacro_quse_ddll_rank1_2;\n\tu32 emc_pmacro_quse_ddll_rank1_3;\n\tu32 emc_pmacro_quse_ddll_rank1_4;\n\tu32 emc_pmacro_quse_ddll_rank1_5;\n\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_0;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_1;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_2;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_3;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_4;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_5;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_0;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_1;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_2;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_3;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_4;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_5;\n\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_0;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_1;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_2;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_3;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_4;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_5;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_0;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_1;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_2;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_3;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_4;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_5;\n\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_0;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_1;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_2;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_3;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_0;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_1;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_2;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_3;\n\n\tu32 emc_pmacro_ddll_long_cmd_0;\n\tu32 emc_pmacro_ddll_long_cmd_1;\n\tu32 emc_pmacro_ddll_long_cmd_2;\n\tu32 emc_pmacro_ddll_long_cmd_3;\n\tu32 emc_pmacro_ddll_long_cmd_4;\n\tu32 emc_pmacro_ddll_short_cmd_0;\n\tu32 emc_pmacro_ddll_short_cmd_1;\n\tu32 emc_pmacro_ddll_short_cmd_2;\n\n\tu32 emc_pmacro_ddll_periodic_offset;\n\n\t/*\n\t * Specifies the delay after asserting CKE pin during a WarmBoot0\n\t * sequence (in microseconds)\n\t */\n\tu32 warm_boot_wait;\n\n\t/* Specifies the value for EMC_ODT_WRITE */\n\tu32 emc_odt_write;\n\n\t/* Periodic ZQ calibration */\n\n\t/*\n\t * Specifies the value for EMC_ZCAL_INTERVAL\n\t * Value 0 disables ZQ calibration\n\t */\n\tu32 emc_zcal_interval;\n\t/* Specifies the value for EMC_ZCAL_WAIT_CNT */\n\tu32 emc_zcal_wait_cnt;\n\t/* Specifies the value for EMC_ZCAL_MRW_CMD */\n\tu32 emc_zcal_mrw_cmd;\n\n\t/* DRAM initialization sequence flow control */\n\n\t/* Specifies the MRS command value for resetting DLL */\n\tu32 emc_mrs_reset_dll;\n\t/* Specifies the command for ZQ initialization of device 0 */\n\tu32 emc_zcal_init_dev0;\n\t/* Specifies the command for ZQ initialization of device 1 */\n\tu32 emc_zcal_init_dev1;\n\t/*\n\t * Specifies the wait time after programming a ZQ initialization\n\t * command (in microseconds)\n\t */\n\tu32 emc_zcal_init_wait;\n\t/*\n\t * Specifies the enable for ZQ calibration at cold boot [bit 0]\n\t * and warm boot [bit 1]\n\t */\n\tu32 emc_zcal_warm_cold_boot_enables;\n\n\t/*\n\t * Specifies the MRW command to LPDDR2 for ZQ calibration\n\t * on warmboot\n\t */\n\t/* Is issued to both devices separately */\n\tu32 emc_mrw_lpddr2zcal_warm_boot;\n\t/*\n\t * Specifies the ZQ command to DDR3 for ZQ calibration on warmboot\n\t * Is issued to both devices separately\n\t */\n\tu32 emc_zqcal_ddr3_warm_boot;\n\n\tu32 emc_zqcal_lpddr4_warm_boot;\n\n\t/*\n\t * Specifies the wait time for ZQ calibration on warmboot\n\t * (in microseconds)\n\t */\n\tu32 emc_zcal_warm_boot_wait;\n\t/*\n\t * Specifies the enable for DRAM Mode Register programming\n\t * at warm boot\n\t */\n\tu32 emc_mrs_warm_boot_enable;\n\t/*\n\t * Specifies the wait time after sending an MRS DLL reset command\n\t * in microseconds)\n\t */\n\tu32 emc_mrs_reset_dll_wait;\n\t/* Specifies the extra MRS command to initialize mode registers */\n\tu32 emc_mrs_extra;\n\t/* Specifies the extra MRS command at warm boot */\n\tu32 emc_warm_boot_mrs_extra;\n\t/* Specifies the EMRS command to enable the DDR2 DLL */\n\tu32 emc_emrs_ddr2_dll_enable;\n\t/* Specifies the MRS command to reset the DDR2 DLL */\n\tu32 emc_mrs_ddr2_dll_reset;\n\t/* Specifies the EMRS command to set OCD calibration */\n\tu32 emc_emrs_ddr2_ocd_calib;\n\t/*\n\t * Specifies the wait between initializing DDR and setting OCD\n\t * calibration (in microseconds)\n\t */\n\tu32 emc_ddr2_wait;\n\t/* Specifies the value for EMC_CLKEN_OVERRIDE */\n\tu32 emc_clken_override;\n\t/*\n\t * Specifies LOG2 of the extra refresh numbers after booting\n\t * Program 0 to disable\n\t */\n\tu32 emc_extra_refresh_num;\n\t/* Specifies the master override for all EMC clocks */\n\tu32 emc_clken_override_allwarm_boot;\n\t/* Specifies the master override for all MC clocks */\n\tu32 mc_clken_override_allwarm_boot;\n\t/* Specifies digital dll period, choosing between 4 to 64 ms */\n\tu32 emc_cfg_dig_dll_period_warm_boot;\n\n\t/* Pad controls */\n\n\t/* Specifies the value for PMC_VDDP_SEL */\n\tu32 pmc_vddp_sel;\n\t/* Specifies the wait time after programming PMC_VDDP_SEL */\n\tu32 pmc_vddp_sel_wait;\n\t/* Specifies the value for PMC_DDR_CFG */\n\tu32 pmc_ddr_cfg;\n\t/* Specifies the value for PMC_IO_DPD3_REQ */\n\tu32 pmc_io_dpd3_req;\n\t/* Specifies the wait time after programming PMC_IO_DPD3_REQ */\n\tu32 pmc_io_dpd3_req_wait;\n\n\tu32 pmc_io_dpd4_req_wait;\n\n\t/* Specifies the value for PMC_REG_SHORT */\n\tu32 pmc_reg_short;\n\t/* Specifies the value for PMC_NO_IOPOWER */\n\tu32 pmc_no_io_power;\n\n\tu32 pmc_ddr_ctrl_wait;\n\tu32 pmc_ddr_ctrl;\n\n\t/* Specifies the value for EMC_ACPD_CONTROL */\n\tu32 emc_acpd_control;\n\n\t/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE0 */\n\tu32 emc_swizzle_rank0_byte0;\n\t/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE1 */\n\tu32 emc_swizzle_rank0_byte1;\n\t/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE2 */\n\tu32 emc_swizzle_rank0_byte2;\n\t/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE3 */\n\tu32 emc_swizzle_rank0_byte3;\n\t/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE0 */\n\tu32 emc_swizzle_rank1_byte0;\n\t/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE1 */\n\tu32 emc_swizzle_rank1_byte1;\n\t/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE2 */\n\tu32 emc_swizzle_rank1_byte2;\n\t/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE3 */\n\tu32 emc_swizzle_rank1_byte3;\n\n\t/* Specifies the value for EMC_TXDSRVTTGEN */\n\tu32 emc_txdsrvttgen;\n\n\t/* Specifies the value for EMC_DATA_BRLSHFT_0 */\n\tu32 emc_data_brlshft0;\n\tu32 emc_data_brlshft1;\n\n\tu32 emc_dqs_brlshft0;\n\tu32 emc_dqs_brlshft1;\n\n\tu32 emc_cmd_brlshft0;\n\tu32 emc_cmd_brlshft1;\n\tu32 emc_cmd_brlshft2;\n\tu32 emc_cmd_brlshft3;\n\n\tu32 emc_quse_brlshft0;\n\tu32 emc_quse_brlshft1;\n\tu32 emc_quse_brlshft2;\n\tu32 emc_quse_brlshft3;\n\n\tu32 emc_dll_cfg0;\n\tu32 emc_dll_cfg1;\n\n\tu32 emc_pmc_scratch1;\n\tu32 emc_pmc_scratch2;\n\tu32 emc_pmc_scratch3;\n\n\tu32 emc_pmacro_pad_cfg_ctrl;\n\n\tu32 emc_pmacro_vttgen_ctrl0;\n\tu32 emc_pmacro_vttgen_ctrl1;\n\tu32 emc_pmacro_vttgen_ctrl2;\n\tu32 emc_pmacro_dsr_vttgen_ctrl0;\n\tu32 emc_pmacro_brick_ctrl_rfu1;\n\tu32 emc_pmacro_cmd_brick_ctrl_fdpd;\n\tu32 emc_pmacro_brick_ctrl_rfu2;\n\tu32 emc_pmacro_data_brick_ctrl_fdpd;\n\tu32 emc_pmacro_bg_bias_ctrl0;\n\tu32 emc_pmacro_data_pad_rx_ctrl;\n\tu32 emc_pmacro_cmd_pad_rx_ctrl;\n\tu32 emc_pmacro_data_rx_term_mode;\n\tu32 emc_pmacro_cmd_rx_term_mode;\n\tu32 emc_pmacro_data_pad_tx_ctrl;\n\tu32 emc_pmacro_cmd_pad_tx_ctrl;\n\tu32 emc_cfg3;\n\n\tu32 emc_pmacro_tx_pwrd0;\n\tu32 emc_pmacro_tx_pwrd1;\n\tu32 emc_pmacro_tx_pwrd2;\n\tu32 emc_pmacro_tx_pwrd3;\n\tu32 emc_pmacro_tx_pwrd4;\n\tu32 emc_pmacro_tx_pwrd5;\n\n\tu32 emc_config_sample_delay;\n\n\tu32 emc_pmacro_brick_mapping0;\n\tu32 emc_pmacro_brick_mapping1;\n\tu32 emc_pmacro_brick_mapping2;\n\n\tu32 emc_pmacro_tx_sel_clk_src0;\n\tu32 emc_pmacro_tx_sel_clk_src1;\n\tu32 emc_pmacro_tx_sel_clk_src2;\n\tu32 emc_pmacro_tx_sel_clk_src3;\n\tu32 emc_pmacro_tx_sel_clk_src4;\n\tu32 emc_pmacro_tx_sel_clk_src5;\n\n\tu32 emc_pmacro_perbit_fgcg_ctrl0;\n\tu32 emc_pmacro_perbit_fgcg_ctrl1;\n\tu32 emc_pmacro_perbit_fgcg_ctrl2;\n\tu32 emc_pmacro_perbit_fgcg_ctrl3;\n\tu32 emc_pmacro_perbit_fgcg_ctrl4;\n\tu32 emc_pmacro_perbit_fgcg_ctrl5;\n\tu32 emc_pmacro_perbit_rfu_ctrl0;\n\tu32 emc_pmacro_perbit_rfu_ctrl1;\n\tu32 emc_pmacro_perbit_rfu_ctrl2;\n\tu32 emc_pmacro_perbit_rfu_ctrl3;\n\tu32 emc_pmacro_perbit_rfu_ctrl4;\n\tu32 emc_pmacro_perbit_rfu_ctrl5;\n\tu32 emc_pmacro_perbit_rfu1_ctrl0;\n\tu32 emc_pmacro_perbit_rfu1_ctrl1;\n\tu32 emc_pmacro_perbit_rfu1_ctrl2;\n\tu32 emc_pmacro_perbit_rfu1_ctrl3;\n\tu32 emc_pmacro_perbit_rfu1_ctrl4;\n\tu32 emc_pmacro_perbit_rfu1_ctrl5;\n\n\tu32 emc_pmacro_data_pi_ctrl;\n\tu32 emc_pmacro_cmd_pi_ctrl;\n\n\tu32 emc_pmacro_ddll_bypass;\n\n\tu32 emc_pmacro_ddll_pwrd0;\n\tu32 emc_pmacro_ddll_pwrd1;\n\tu32 emc_pmacro_ddll_pwrd2;\n\n\tu32 emc_pmacro_cmd_ctrl0;\n\tu32 emc_pmacro_cmd_ctrl1;\n\tu32 emc_pmacro_cmd_ctrl2;\n\n\t/* DRAM size information */\n\n\t/* Specifies the value for MC_EMEM_ADR_CFG */\n\tu32 mc_emem_adr_cfg;\n\t/* Specifies the value for MC_EMEM_ADR_CFG_DEV0 */\n\tu32 mc_emem_adr_cfg_dev0;\n\t/* Specifies the value for MC_EMEM_ADR_CFG_DEV1 */\n\tu32 mc_emem_adr_cfg_dev1;\n\n\tu32 mc_emem_adr_cfg_channel_mask;\n\n\t/* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG0 */\n\tu32 mc_emem_adr_cfg_bank_mask0;\n\t/* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG1 */\n\tu32 mc_emem_adr_cfg_bank_mask1;\n\t/* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG2 */\n\tu32 mc_emem_adr_cfg_bank_mask2;\n\n\t/*\n\t * Specifies the value for MC_EMEM_CFG which holds the external memory\n\t * size (in KBytes)\n\t */\n\tu32 mc_emem_cfg;\n\n\t/* MC arbitration configuration */\n\n\t/* Specifies the value for MC_EMEM_ARB_CFG */\n\tu32 mc_emem_arb_cfg;\n\t/* Specifies the value for MC_EMEM_ARB_OUTSTANDING_REQ */\n\tu32 mc_emem_arb_outstanding_req;\n\n\tu32 emc_emem_arb_refpb_hp_ctrl;\n\tu32 emc_emem_arb_refpb_bank_ctrl;\n\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RCD */\n\tu32 mc_emem_arb_timing_rcd;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RP */\n\tu32 mc_emem_arb_timing_rp;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RC */\n\tu32 mc_emem_arb_timing_rc;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RAS */\n\tu32 mc_emem_arb_timing_ras;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_FAW */\n\tu32 mc_emem_arb_timing_faw;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RRD */\n\tu32 mc_emem_arb_timing_rrd;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RAP2PRE */\n\tu32 mc_emem_arb_timing_rap2pre;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_WAP2PRE */\n\tu32 mc_emem_arb_timing_wap2pre;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_R2R */\n\tu32 mc_emem_arb_timing_r2r;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_W2W */\n\tu32 mc_emem_arb_timing_w2w;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_R2W */\n\tu32 mc_emem_arb_timing_r2w;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_W2R */\n\tu32 mc_emem_arb_timing_w2r;\n\n\tu32 mc_emem_arb_timing_rfcpb;\n\n\t/* Specifies the value for MC_EMEM_ARB_DA_TURNS */\n\tu32 mc_emem_arb_da_turns;\n\t/* Specifies the value for MC_EMEM_ARB_DA_COVERS */\n\tu32 mc_emem_arb_da_covers;\n\t/* Specifies the value for MC_EMEM_ARB_MISC0 */\n\tu32 mc_emem_arb_misc0;\n\t/* Specifies the value for MC_EMEM_ARB_MISC1 */\n\tu32 mc_emem_arb_misc1;\n\tu32 mc_emem_arb_misc2;\n\n\t/* Specifies the value for MC_EMEM_ARB_RING1_THROTTLE */\n\tu32 mc_emem_arb_ring1_throttle;\n\t/* Specifies the value for MC_EMEM_ARB_OVERRIDE */\n\tu32 mc_emem_arb_override;\n\t/* Specifies the value for MC_EMEM_ARB_OVERRIDE_1 */\n\tu32 mc_emem_arb_override1;\n\t/* Specifies the value for MC_EMEM_ARB_RSV */\n\tu32 mc_emem_arb_rsv;\n\n\tu32 mc_da_cfg0;\n\tu32 mc_emem_arb_timing_ccdmw;\n\n\t/* Specifies the value for MC_CLKEN_OVERRIDE */\n\tu32 mc_clken_override;\n\n\t/* Specifies the value for MC_STAT_CONTROL */\n\tu32 mc_stat_control;\n\t/* Specifies the value for MC_VIDEO_PROTECT_BOM */\n\tu32 mc_video_protect_bom;\n\t/* Specifies the value for MC_VIDEO_PROTECT_BOM_ADR_HI */\n\tu32 mc_video_protect_bom_adr_hi;\n\t/* Specifies the value for MC_VIDEO_PROTECT_SIZE_MB */\n\tu32 mc_video_protect_size_mb;\n\t/* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE */\n\tu32 mc_video_protect_vpr_override;\n\t/* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE1 */\n\tu32 mc_video_protect_vpr_override1;\n\t/* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_0 */\n\tu32 mc_video_protect_gpu_override0;\n\t/* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_1 */\n\tu32 mc_video_protect_gpu_override1;\n\t/* Specifies the value for MC_SEC_CARVEOUT_BOM */\n\tu32 mc_sec_carveout_bom;\n\t/* Specifies the value for MC_SEC_CARVEOUT_ADR_HI */\n\tu32 mc_sec_carveout_adr_hi;\n\t/* Specifies the value for MC_SEC_CARVEOUT_SIZE_MB */\n\tu32 mc_sec_carveout_size_mb;\n\t/* Specifies the value for MC_VIDEO_PROTECT_REG_CTRL.VIDEO_PROTECT_WRITE_ACCESS */\n\tu32 mc_video_protect_write_access;\n\t/* Specifies the value for MC_SEC_CARVEOUT_REG_CTRL.SEC_CARVEOUT_WRITE_ACCESS */\n\tu32 mc_sec_carveout_protect_write_access;\n\n\tu32 mc_generalized_carveout1_bom;\n\tu32 mc_generalized_carveout1_bom_hi;\n\tu32 mc_generalized_carveout1_size_128kb;\n\tu32 mc_generalized_carveout1_access0;\n\tu32 mc_generalized_carveout1_access1;\n\tu32 mc_generalized_carveout1_access2;\n\tu32 mc_generalized_carveout1_access3;\n\tu32 mc_generalized_carveout1_access4;\n\tu32 mc_generalized_carveout1_force_internal_access0;\n\tu32 mc_generalized_carveout1_force_internal_access1;\n\tu32 mc_generalized_carveout1_force_internal_access2;\n\tu32 mc_generalized_carveout1_force_internal_access3;\n\tu32 mc_generalized_carveout1_force_internal_access4;\n\tu32 mc_generalized_carveout1_cfg0;\n\n\tu32 mc_generalized_carveout2_bom;\n\tu32 mc_generalized_carveout2_bom_hi;\n\tu32 mc_generalized_carveout2_size_128kb;\n\tu32 mc_generalized_carveout2_access0;\n\tu32 mc_generalized_carveout2_access1;\n\tu32 mc_generalized_carveout2_access2;\n\tu32 mc_generalized_carveout2_access3;\n\tu32 mc_generalized_carveout2_access4;\n\tu32 mc_generalized_carveout2_force_internal_access0;\n\tu32 mc_generalized_carveout2_force_internal_access1;\n\tu32 mc_generalized_carveout2_force_internal_access2;\n\tu32 mc_generalized_carveout2_force_internal_access3;\n\tu32 mc_generalized_carveout2_force_internal_access4;\n\tu32 mc_generalized_carveout2_cfg0;\n\n\tu32 mc_generalized_carveout3_bom;\n\tu32 mc_generalized_carveout3_bom_hi;\n\tu32 mc_generalized_carveout3_size_128kb;\n\tu32 mc_generalized_carveout3_access0;\n\tu32 mc_generalized_carveout3_access1;\n\tu32 mc_generalized_carveout3_access2;\n\tu32 mc_generalized_carveout3_access3;\n\tu32 mc_generalized_carveout3_access4;\n\tu32 mc_generalized_carveout3_force_internal_access0;\n\tu32 mc_generalized_carveout3_force_internal_access1;\n\tu32 mc_generalized_carveout3_force_internal_access2;\n\tu32 mc_generalized_carveout3_force_internal_access3;\n\tu32 mc_generalized_carveout3_force_internal_access4;\n\tu32 mc_generalized_carveout3_cfg0;\n\n\tu32 mc_generalized_carveout4_bom;\n\tu32 mc_generalized_carveout4_bom_hi;\n\tu32 mc_generalized_carveout4_size_128kb;\n\tu32 mc_generalized_carveout4_access0;\n\tu32 mc_generalized_carveout4_access1;\n\tu32 mc_generalized_carveout4_access2;\n\tu32 mc_generalized_carveout4_access3;\n\tu32 mc_generalized_carveout4_access4;\n\tu32 mc_generalized_carveout4_force_internal_access0;\n\tu32 mc_generalized_carveout4_force_internal_access1;\n\tu32 mc_generalized_carveout4_force_internal_access2;\n\tu32 mc_generalized_carveout4_force_internal_access3;\n\tu32 mc_generalized_carveout4_force_internal_access4;\n\tu32 mc_generalized_carveout4_cfg0;\n\n\tu32 mc_generalized_carveout5_bom;\n\tu32 mc_generalized_carveout5_bom_hi;\n\tu32 mc_generalized_carveout5_size_128kb;\n\tu32 mc_generalized_carveout5_access0;\n\tu32 mc_generalized_carveout5_access1;\n\tu32 mc_generalized_carveout5_access2;\n\tu32 mc_generalized_carveout5_access3;\n\tu32 mc_generalized_carveout5_access4;\n\tu32 mc_generalized_carveout5_force_internal_access0;\n\tu32 mc_generalized_carveout5_force_internal_access1;\n\tu32 mc_generalized_carveout5_force_internal_access2;\n\tu32 mc_generalized_carveout5_force_internal_access3;\n\tu32 mc_generalized_carveout5_force_internal_access4;\n\tu32 mc_generalized_carveout5_cfg0;\n\n\t/* Specifies enable for CA training */\n\tu32 emc_ca_training_enable;\n\t/* Set if bit 6 select is greater than bit 7 select; uses aremc.spec packet SWIZZLE_BIT6_GT_BIT7 */\n\tu32 swizzle_rank_byte_encode;\n\t/* Specifies enable and offset for patched boot rom write */\n\tu32 boot_rom_patch_control;\n\t/* Specifies data for patched boot rom write */\n\tu32 boot_rom_patch_data;\n\n\t/* Specifies the value for MC_MTS_CARVEOUT_BOM */\n\tu32 mc_mts_carveout_bom;\n\t/* Specifies the value for MC_MTS_CARVEOUT_ADR_HI */\n\tu32 mc_mts_carveout_adr_hi;\n\t/* Specifies the value for MC_MTS_CARVEOUT_SIZE_MB */\n\tu32 mc_mts_carveout_size_mb;\n\t/* Specifies the value for MC_MTS_CARVEOUT_REG_CTRL */\n\tu32 mc_mts_carveout_reg_ctrl;\n\n\t/* Specifies the clients that are allowed to access untranslated memory */\n\tu32 mc_untranslated_region_check;\n\n\t/* Just a place holder for special usage when there is no BCT for certain registers */\n\tu32 bct_na;\n} sdram_params_t210b01_t;\n\n#endif\n"
  },
  {
    "path": "bdk/mem/smmu.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018 balika011\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <soc/bpmp.h>\n#include <soc/ccplex.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n#include <mem/mc_t210.h>\n#include <mem/smmu.h>\n#include <memory_map.h>\n\n/*! SMMU register defines */\n#define SMMU_ASID(asid)          (((asid) << 24u) | ((asid) << 16u) | ((asid) << 8u) | (asid))\n#define SMMU_ENABLE              BIT(31)\n#define SMMU_TLB_ACTIVE_LINES(l) ((l) << 0u)\n#define SMMU_TLB_RR_ARBITRATION  BIT(28)\n#define SMMU_TLB_HIT_UNDER_MISS  BIT(29)\n#define SMMU_TLB_STATS_ENABLE    BIT(31)\n#define SMUU_PTC_INDEX_MAP(m)    ((m) << 0u)\n#define SMUU_PTC_LINE_MASK(m)    ((m) << 8u)\n#define SMUU_PTC_REQ_LIMIT(l)    ((l) << 24u)\n#define SMUU_PTC_CACHE_ENABLE    BIT(29)\n#define SMUU_PTC_STATS_ENABLE    BIT(31)\n\n/*! Page table defines */\n#define SMMU_4MB_REGION 0\n#define SMMU_PAGE_TABLE 1\n#define SMMU_PDIR_COUNT 1024\n#define SMMU_PTBL_COUNT 1024\n#define SMMU_PAGE_SHIFT 12u\n#define SMMU_PTN_SHIFT  SMMU_PAGE_SHIFT\n#define SMMU_PDN_SHIFT  22u\n#define SMMU_ADDR_TO_PFN(addr) ((addr) >> SMMU_PAGE_SHIFT)\n#define SMMU_ADDR_TO_PTN(addr) ((addr) >> SMMU_PTN_SHIFT)\n#define SMMU_ADDR_TO_PDN(addr) ((addr) >> SMMU_PDN_SHIFT)\n#define SMMU_PTN_TO_ADDR(ptn)  ((ptn)  << SMMU_PTN_SHIFT)\n#define SMMU_PDN_TO_ADDR(pdn)  ((pdn)  << SMMU_PDN_SHIFT)\n#define SMMU_PTB(page, attr) (((attr) << 29u) | ((page) >> SMMU_PAGE_SHIFT))\n\n#define SMMU_PAYLOAD_EN_SHIFT 4\n#define SMMU_PAYLOAD_EN_SET   0x20\n#define SMMU_PAYLOAD_EN_UNSET 0x00\n\n// Enabling SMMU requires a TZ (EL3) secure write. MC(MC_SMMU_CONFIG) = 1;\nstatic u8 smmu_enable_payload[] = {\n\t0xC1, 0x00, 0x00, 0x18, // 0x00: LDR  W1, =0x70019010\n\t0x20, 0x00, 0x80, 0xD2, // 0x04: MOV  X0, #0x1\n\t0x20, 0x00, 0x00, 0xB9, // 0x08: STR  W0, [X1]\n\t0x1F, 0x71, 0x08, 0xD5, // 0x0C: IC   IALLUIS\n\t0x9F, 0x3B, 0x03, 0xD5, // 0x10: DSB  ISH\n\t0xFE, 0xFF, 0xFF, 0x17, // 0x14: B    loop\n\t0x10, 0x90, 0x01, 0x70, // 0x18: MC_SMMU_CONFIG\n};\n\nstatic void *smmu_heap    = (void *)SMMU_HEAP_ADDR;\nstatic bool  smmu_enabled = false;\n\nvoid *smmu_page_zalloc(u32 num)\n{\n\tvoid *page = smmu_heap;\n\tmemset(page, 0, SZ_PAGE * num);\n\n\tsmmu_heap += SZ_PAGE * num;\n\n\treturn page;\n}\n\nstatic pde_t *_smmu_pdir_alloc()\n{\n\tpde_t *pdir = (pde_t *)smmu_page_zalloc(1);\n\n\t// Initialize pdes with no permissions.\n\tfor (u32 pdn = 0; pdn < SMMU_PDIR_COUNT; pdn++)\n\t\tpdir[pdn].huge.page = pdn;\n\n\treturn pdir;\n}\n\nstatic void _smmu_flush_regs()\n{\n\t(void)MC(MC_SMMU_PTB_DATA);\n}\n\nvoid smmu_flush_all()\n{\n\t// Flush the entire page table cache.\n\tMC(MC_SMMU_PTC_FLUSH) = 0;\n\t_smmu_flush_regs();\n\n\t// Flush the entire table.\n\tMC(MC_SMMU_TLB_FLUSH) = 0;\n\t_smmu_flush_regs();\n}\n\nvoid smmu_init()\n{\n\tMC(MC_SMMU_PTB_ASID)   = 0;\n\tMC(MC_SMMU_PTB_DATA)   = 0;\n\tMC(MC_SMMU_TLB_CONFIG) = SMMU_TLB_HIT_UNDER_MISS | SMMU_TLB_RR_ARBITRATION | SMMU_TLB_ACTIVE_LINES(48);\n\tMC(MC_SMMU_PTC_CONFIG) = SMUU_PTC_CACHE_ENABLE | SMUU_PTC_REQ_LIMIT(8) | SMUU_PTC_LINE_MASK(0xF) | SMUU_PTC_INDEX_MAP(0x3F);\n\tMC(MC_SMMU_PTC_FLUSH)  = 0;\n\tMC(MC_SMMU_TLB_FLUSH)  = 0;\n}\n\nvoid smmu_enable()\n{\n\tif (smmu_enabled)\n\t\treturn;\n\n\t// Launch payload on CCPLEX in order to set SMMU enable bit.\n\tccplex_boot_cpu0((u32)smmu_enable_payload, false);\n\tmsleep(100);\n\tccplex_powergate_cpu0();\n\n\tsmmu_flush_all();\n\n\tsmmu_enabled = true;\n}\n\nvoid smmu_disable()\n{\n\tif (!smmu_enabled)\n\t\treturn;\n\n\t// Set payload to disable SMMU.\n\tsmmu_enable_payload[SMMU_PAYLOAD_EN_SHIFT] = SMMU_PAYLOAD_EN_UNSET;\n\n\tsmmu_flush_all();\n\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);\n\n\t// Launch payload on CCPLEX in order to set SMMU enable bit.\n\tccplex_boot_cpu0((u32)smmu_enable_payload, false);\n\tmsleep(100);\n\tccplex_powergate_cpu0();\n\n\tsmmu_flush_all();\n\n\t// Restore payload to SMMU enable.\n\tsmmu_enable_payload[SMMU_PAYLOAD_EN_SHIFT] = SMMU_PAYLOAD_EN_SET;\n\n\tsmmu_enabled = false;\n\tsmmu_heap    = (void *)SMMU_HEAP_ADDR;\n}\n\nvoid smmu_reset_heap()\n{\n\tsmmu_heap = (void *)SMMU_HEAP_ADDR;\n}\n\nvoid *smmu_domain_init(u32 dev_base, u32 asid)\n{\n\tvoid *ptb = _smmu_pdir_alloc();\n\n\tMC(MC_SMMU_PTB_ASID) = asid;\n\tMC(MC_SMMU_PTB_DATA) = SMMU_PTB((u32)ptb, SMMU_ATTR_ALL);\n\t_smmu_flush_regs();\n\n\t// Use the same macro for both quad and single domains. Reserved bits are not set anyway.\n\tMC(dev_base) = SMMU_ENABLE | SMMU_ASID(asid);\n\t_smmu_flush_regs();\n\n\treturn ptb;\n}\n\nvoid smmu_domain_deinit(u32 dev_base, u32 asid)\n{\n\tMC(MC_SMMU_PTB_ASID) = asid;\n\tMC(MC_SMMU_PTB_DATA) = 0;\n\tMC(dev_base)         = 0;\n\t_smmu_flush_regs();\n}\n\nvoid smmu_domain_bypass(u32 dev_base, bool bypass)\n{\n\tif (bypass)\n\t{\n\t\tsmmu_flush_all();\n\t\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);\n\t\tMC(dev_base) &= ~SMMU_ENABLE;\n\t}\n\telse\n\t{\n\t\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);\n\t\tMC(dev_base) |=  SMMU_ENABLE;\n\t\tsmmu_flush_all();\n\t}\n\t_smmu_flush_regs();\n}\n\nstatic pte_t *_smmu_get_pte(pde_t *pdir, u32 iova)\n{\n\tu32 pdn = SMMU_ADDR_TO_PDN(iova);\n\tpte_t *ptbl;\n\n\t// Get 4MB page table or initialize one.\n\tif (pdir[pdn].tbl.attr)\n\t\tptbl = (pte_t *)(SMMU_PTN_TO_ADDR(pdir[pdn].tbl.table));\n\telse\n\t{\n\t\t// Allocate page table.\n\t\tptbl = (pte_t *)smmu_page_zalloc(1);\n\n\t\t// Get address.\n\t\tu32 addr = SMMU_PDN_TO_ADDR(pdn);\n\n\t\t// Initialize page table with no permissions.\n\t\tfor (u32 pn = 0; pn < SMMU_PTBL_COUNT; pn++, addr += SZ_PAGE)\n\t\t\tptbl[pn].page = SMMU_ADDR_TO_PFN(addr);\n\n\t\t// Set page table to the page directory.\n\t\tpdir[pdn].tbl.table = SMMU_ADDR_TO_PTN((u32)ptbl);\n\t\tpdir[pdn].tbl.next  = SMMU_PAGE_TABLE;\n\t\tpdir[pdn].tbl.attr  = SMMU_ATTR_ALL;\n\n\t\tsmmu_flush_all();\n\t}\n\n\treturn &ptbl[SMMU_ADDR_TO_PTN(iova) % SMMU_PTBL_COUNT];\n}\n\nvoid smmu_map(void *ptb, u32 iova, u64 iopa, u32 pages, u32 attr)\n{\n\t// Map pages to page table entries. VA/PA should be aligned to 4KB.\n\tfor (u32 i = 0; i < pages; i++)\n\t{\n\t\tpte_t *pte = _smmu_get_pte((pde_t *)ptb, iova);\n\n\t\tpte->page = SMMU_ADDR_TO_PFN(iopa);\n\t\tpte->attr = attr;\n\n\t\tiova += SZ_PAGE;\n\t\tiopa += SZ_PAGE;\n\t}\n\n\tsmmu_flush_all();\n}\n\nvoid smmu_map_huge(void *ptb, u32 iova, u64 iopa, u32 regions, u32 attr)\n{\n\tpde_t *pdir = (pde_t *)ptb;\n\n\t// Map 4MB regions to page directory entries. VA/PA should be aligned to 4MB.\n\tfor (u32 i = 0; i < regions; i++)\n\t{\n\t\tu32 pdn = SMMU_ADDR_TO_PDN(iova);\n\t\tpdir[pdn].huge.page = SMMU_ADDR_TO_PDN(iopa);\n\t\tpdir[pdn].huge.next = SMMU_4MB_REGION;\n\t\tpdir[pdn].huge.attr = attr;\n\n\t\tiova += SZ_4M;\n\t\tiopa += SZ_4M;\n\t}\n\n\tsmmu_flush_all();\n}\n"
  },
  {
    "path": "bdk/mem/smmu.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2024 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _SMMU_H_\n#define _SMMU_H_\n\n#include <utils/types.h>\n#include <assert.h>\n\n#define MC_SMMU_AVPC_ASID            0x23C\n#define MC_SMMU_TSEC_ASID            0x294\n\n#define SMMU_NS    BIT(0)\n#define SMMU_WRITE BIT(1)\n#define SMMU_READ  BIT(2)\n#define SMMU_ATTR_ALL (SMMU_READ | SMMU_WRITE | SMMU_NS)\n\ntypedef struct _pde_t {\n\tunion {\n\t\tunion {\n\t\t\tstruct {\n\t\t\t\tu32 table:22;\n\t\t\t\tu32 rsvd:6;\n\t\t\t\tu32 next:1;\n\t\t\t\tu32 attr:3;\n\t\t\t} tbl;\n\n\t\t\tstruct {\n\t\t\t\tu32 rsvd_:10;\n\t\t\t\tu32 page:12;\n\t\t\t\tu32 rsvd:6;\n\t\t\t\tu32 next:1;\n\t\t\t\tu32 attr:3;\n\t\t\t} huge;\n\t\t};\n\n\t\tu32 pde;\n\t};\n} pde_t;\n\ntypedef struct _pte_t {\n\tu32 page:22;\n\tu32 rsvd:7;\n\tu32 attr:3;\n} pte_t;\n\nstatic_assert(sizeof(pde_t) == sizeof(u32), \"pde_t size is wrong!\");\nstatic_assert(sizeof(pte_t) == sizeof(u32), \"pte_t size is wrong!\");\n\nvoid *smmu_page_zalloc(u32 num);\nvoid  smmu_flush_all();\nvoid  smmu_init();\nvoid  smmu_enable();\nvoid  smmu_disable();\nvoid  smmu_reset_heap();\nvoid *smmu_domain_init(u32 dev_base, u32 asid);\nvoid  smmu_domain_deinit(u32 dev_base, u32 asid);\nvoid  smmu_domain_bypass(u32 dev_base, bool bypass);\nvoid  smmu_map(void *ptb, u32 iova, u64 iopa, u32 pages, u32 attr);\nvoid  smmu_map_huge(void *ptb, u32 iova, u64 iopa, u32 regions, u32 attr);\n\n#endif\n"
  },
  {
    "path": "bdk/memory_map.h",
    "content": "/*\n * Copyright (c) 2019-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _MEMORY_MAP_H_\n#define _MEMORY_MAP_H_\n\n/* --- BIT/BCT: 0x40000000 - 0x40003000 --- */\n/* ---     IPL: 0x40008000 - 0x40028000 --- */\n#define LDR_LOAD_ADDR     0x40007000\n\n#define IPL_LOAD_ADDR     0x40008000\n#define  IPL_SZ_MAX          SZ_128K\n\n#define XUSB_RING_ADDR    0x40020000 // XUSB EP context and TRB ring buffers.\n\n#define SECMON_MIN_START  0x4002B000 // Minimum reserved address for secmon.\n\n#define SDRAM_PARAMS_ADDR 0x40030000 // SDRAM extraction buffer during sdram init.\n#define  SDRAM_PARAMS_SZ       0x838\n\n/* start.S / exception_handlers.S */\n#define SYS_STACK_TOP_INIT 0x4003FF00\n#define FIQ_STACK_TOP      0x40040000\n#define IRQ_STACK_TOP      0x40040000\n#define IPL_RELOC_ADDR     0x4003FF00\n#define  IPL_RELOC_SZ            0x10\n#define EXCP_STORAGE_ADDR  0x4003FF10\n#define  EXCP_STORAGE_SZ         0x10\n\n/* --- DRAM START --- */\n#define DRAM_START     0x80000000\n#define  HOS_RSVD          SZ_16M // Do not write anything in this area.\n\n#define NYX_LOAD_ADDR  0x81000000\n#define  NYX_SZ_MAX        SZ_16M\n/* --- Gap: 0x82000000 - 0x82FFFFFF --- */\n\n// Heap buffer.\n#define IPL_HEAP_START 0x82000000\n#define  IPL_HEAP_SZ     (SZ_256M)\n\n#define SMMU_HEAP_ADDR 0x92000000\n/* --- Gap: 1280MB 0x96000000 - 0xE4FFFFFF --- */\n\n// Virtual disk / Chainloader buffers.\n#define RAM_DISK_ADDR 0x95000000\n#define  RAM_DISK_SZ  0x50000000 // 1280MB.\n\n// L4T Kernel Panic Storage (PSTORE).\n#define PSTORE_ADDR   0xB0000000\n#define  PSTORE_SZ         SZ_2M\n\n// NX BIS driver sector cache.\n#define NX_BIS_CACHE_ADDR  0xC7000000\n#define  NX_BIS_CACHE_SZ   0x10020000 // 256MB.\n#define NX_BIS_LOOKUP_ADDR 0xD8000000\n#define  NX_BIS_LOOKUP_SZ   0x8000000 // 128MB. 512GB eMMC partition max.\n\n//#define DRAM_LIB_ADDR    0xE0000000\n/* --- Chnldr: 252MB 0xC03C0000 - 0xCFFFFFFF --- */ //! Only used when chainloading.\n\n// SDMMC DMA buffer. Used for unaligned DMA buffer address.\n#define SDMMC_ALT_DMA_BUFFER 0xE5000000\n#define  SDMMC_ALT_DMA_BUF_SZ   SZ_128M\n\n// Nyx buffers. !Do not change!\n#define NYX_STORAGE_ADDR 0xED000000\n#define  NYX_STR_SZ          SZ_16M\n#define NYX_RES_ADDR     0xEE000000\n#define  NYX_RES_SZ          SZ_16M\n\n// SDMMC Application DMA aligned buffers.\n#define SDXC_BUF_ALIGNED   0xEF000000 // Also used by UMS.\n#define EMMC_BUF_ALIGNED   0xF0000000\n#define MIXD_BUF_ALIGNED   EMMC_BUF_ALIGNED\n#define  SDMMC_DMA_BUF_SZ      SZ_16M // 4MB currently used.\n\n// Nyx LvGL buffers.\n#define NYX_LV_VDB_ADR   0xF1000000\n#define  NYX_FB_SZ         0x384000 // 1280 x 720 x 4.\n#define NYX_LV_MEM_ADR   0xF1400000\n#define  NYX_LV_MEM_SZ    0x6600000 // 70MB.\n\n// Framebuffer addresses. !Do not change!\n#define IPL_FB_ADDRESS   0xF5A00000\n#define  IPL_FB_SZ         0x384000 // 720 x 1280 x 4.\n#define LOG_FB_ADDRESS   0xF5E00000\n#define  LOG_FB_SZ         0x334000 // 1280 x 656 x 4.\n#define NYX_FB_ADDRESS   0xF6200000\n#define NYX_FB2_ADDRESS  0xF6600000\n#define  NYX_FB_SZ         0x384000 // 1280 x 720 x 4.\n\n// USB buffers.\n#define USBD_ADDR                 0xFEF00000\n#define USB_DESCRIPTOR_ADDR       0xFEF40000\n#define USB_EP_CONTROL_BUF_ADDR   0xFEF80000\n#define USB_EP_BULK_IN_BUF_ADDR   0xFF000000\n#define USB_EP_BULK_OUT_BUF_ADDR  0xFF800000\n#define  USB_EP_BULK_OUT_MAX_XFER      SZ_8M\n\n// #define EXT_PAYLOAD_ADDR    0xC0000000\n// #define RCM_PAYLOAD_ADDR    (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))\n\n#endif\n"
  },
  {
    "path": "bdk/module.h",
    "content": "/*\n * Common Module Header\n * Copyright (c) 2018 M4xw\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n#ifndef _MODULE_H_\n#define _MODULE_H_\n\n#include <stddef.h>\n#include <mem/heap.h>\n\n#define IANOS_EXT1 0x314E4149\n\n// Module Callback\ntypedef void (*cbMainModule_t)(const char *s);\ntypedef void (*memcpy_t)(void *, void *, size_t);\ntypedef void (*memset_t)(void *, int, size_t);\ntypedef int  (*reg_voltage_set_t)(u32, u32);\n\ntypedef struct _bdkParams_t\n{\n\tvoid *gfx_con;\n\tvoid *gfx_ctx;\n\theap_t *heap;\n\tmemcpy_t memcpy;\n\tmemset_t memset;\n\tu32 extension_magic;\n} bdk_params_t;\n\n// Module Caller.\ntypedef void (*moduleEntrypoint)(void *, bdk_params_t *);\n\n#endif\n"
  },
  {
    "path": "bdk/power/bm92t36.c",
    "content": "/*\n * USB-PD driver for Nintendo Switch's TI BM92T36\n *\n * Copyright (c) 2020-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include \"bm92t36.h\"\n#include <soc/i2c.h>\n#include <utils/util.h>\n\n#define ALERT_STATUS_REG    0x2\n#define STATUS1_REG         0x3\n#define STATUS2_REG         0x4\n#define COMMAND_REG         0x5\n#define CONFIG1_REG         0x6\n#define DEV_CAPS_REG        0x7\n#define READ_PDOS_SRC_REG   0x8\n#define CONFIG2_REG         0x17\n#define DP_STATUS_REG       0x18\n#define DP_ALERT_EN_REG     0x19\n#define VENDOR_CONFIG_REG   0x1A\n#define AUTO_NGT_FIXED_REG  0x20\n#define AUTO_NGT_BATT_REG   0x23\n#define SYS_CONFIG1_REG     0x26\n#define SYS_CONFIG2_REG     0x27\n#define CURRENT_PDO_REG     0x28\n#define CURRENT_RDO_REG     0x2B\n#define ALERT_ENABLE_REG    0x2E\n#define SYS_CONFIG3_REG     0x2F\n#define SET_RDO_REG         0x30\n#define PDOS_SNK_REG        0x33\n#define PDOS_SRC_PROV_REG   0x3C\n#define FW_TYPE_REG         0x4B\n#define FW_REVISION_REG     0x4C\n#define MAN_ID_REG          0x4D\n#define DEV_ID_REG          0x4E\n#define REV_ID_REG          0x4F\n#define INCOMING_VDM_REG    0x50\n#define OUTGOING_VDM_REG    0x60\n\n#define STATUS1_INSERT      BIT(7)  // Cable inserted.\n\n#define VER_36     0x36\n#define MAN_ROHM  0x4B5\n#define DEV_BM92T 0x3B0\n\n#define PDO_TYPE_FIXED  0\n#define PDO_TYPE_BATT   1\n#define PDO_TYPE_VAR    2\n#define PDO_TYPE_APDO   3\n\ntypedef struct _pd_object_t {\n\tunsigned int amp:10;\n\tunsigned int volt:10;\n\tunsigned int info:10;\n\tunsigned int type:2;\n} __attribute__((packed)) pd_object_t;\n\nstatic int _bm92t36_read_reg(u8 *buf, u32 size, u32 reg)\n{\n\tmemset(buf, 0, size);\n\treturn i2c_recv_buf_big(buf, size, I2C_1, BM92T36_I2C_ADDR, reg);\n}\n\nint bm92t36_get_version(u32 *value)\n{\n\tu8 buf[2];\n\tu16 version, man, dev;\n\t_bm92t36_read_reg(buf, 2, FW_TYPE_REG);\n\tversion = (buf[0] << 4) | buf[1];\n\t_bm92t36_read_reg(buf, 2, MAN_ID_REG);\n\tman = (buf[1] << 8) | buf[0];\n\t_bm92t36_read_reg(buf, 2, DEV_ID_REG);\n\tdev = (buf[1] << 8) | buf[0];\n\tif (value)\n\t\t*value = (dev << 16) | version;\n\n\tif (version == VER_36 && man == MAN_ROHM && dev == DEV_BM92T)\n\t \treturn 0;\n\telse\n\t\treturn 1;\n}\n\nvoid bm92t36_get_source_info(bool *inserted, usb_pd_objects_t *usb_pd)\n{\n\tu8 buf[32];\n\tpd_object_t pdos[7];\n\n\tif (inserted)\n\t{\n\t\t_bm92t36_read_reg(buf, 2, STATUS1_REG);\n\t\t*inserted = (buf[0] & STATUS1_INSERT) ? true : false;\n\t}\n\n\tif (usb_pd)\n\t{\n\t\t_bm92t36_read_reg(buf, 29, READ_PDOS_SRC_REG);\n\t\tmemcpy(pdos, &buf[1], 28);\n\n\t\tmemset(usb_pd, 0, sizeof(usb_pd_objects_t));\n\t\tusb_pd->pdo_no = buf[0] / sizeof(pd_object_t);\n\n\t\tif (usb_pd->pdo_no > 7)\n\t\t\tusb_pd->pdo_no = 7;\n\n\t\tu32 idx = 0;\n\t\tfor (u32 i = 0; i < usb_pd->pdo_no; i++)\n\t\t{\n\t\t\t// Parse fixed type pdos only.\n\t\t\tif (pdos[i].type != PDO_TYPE_FIXED)\n\t\t\t\tcontinue;\n\n\t\t\tusb_pd->pdos[idx].amperage =  pdos[i].amp  * 10;\n\t\t\tusb_pd->pdos[idx].voltage  = (pdos[i].volt * 50) / 1000;\n\t\t\tidx++;\n\t\t}\n\t\tusb_pd->pdo_no = idx;\n\n\t\t_bm92t36_read_reg(buf, 5, CURRENT_PDO_REG);\n\t\tmemcpy(pdos, &buf[1], 4);\n\t\tusb_pd->selected_pdo.amperage =  pdos[0].amp  * 10;\n\t\tusb_pd->selected_pdo.voltage  = (pdos[0].volt * 50) / 1000;\n\t}\n}\n"
  },
  {
    "path": "bdk/power/bm92t36.h",
    "content": "/*\n * USB-PD driver for Nintendo Switch's TI BM92T36\n *\n * Copyright (c) 2020 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef __BM92T36_H_\n#define __BM92T36_H_\n\n#include <utils/types.h>\n\n#define BM92T36_I2C_ADDR 0x18\n\ntypedef struct _usb_pd_object_t\n{\n\tu32 amperage;\n\tu32 voltage;\n} usb_pd_object_t;\n\ntypedef struct _usb_pd_objects_t\n{\n\tu32 pdo_no;\n\tusb_pd_object_t pdos[7];\n\tusb_pd_object_t selected_pdo;\n} usb_pd_objects_t;\n\nint  bm92t36_get_version(u32 *value);\nvoid bm92t36_get_source_info(bool *inserted, usb_pd_objects_t *usb_pd);\n\n#endif\n"
  },
  {
    "path": "bdk/power/bq24193.c",
    "content": "/*\n * Battery charger driver for Nintendo Switch's TI BQ24193\n *\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include \"bq24193.h\"\n#include <soc/i2c.h>\n#include <utils/util.h>\n\nstatic u8 bq24193_get_reg(u8 reg)\n{\n\treturn i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, reg);\n}\n\nint bq24193_get_version(u32 *value)\n{\n\tu16 data = bq24193_get_reg(BQ24193_VendorPart);\n\tif (value)\n\t\t*value = data;\n\n\tif (data == 0x2F)\n\t\treturn 0;\n\telse\n\t\treturn 1;\n}\n\nint bq24193_get_property(enum BQ24193_reg_prop prop, int *value)\n{\n\tu8 data;\n\n\tswitch (prop)\n\t{\n\tcase BQ24193_InputVoltageLimit: // Input voltage limit (mV).\n\t\tdata = bq24193_get_reg(BQ24193_InputSource);\n\t\tdata = (data & BQ24193_INCONFIG_VINDPM_MASK) >> 3;\n\t\t*value = 0;\n\t\t*value += ((data >> 0) & 1) ? 80 : 0;\n\t\t*value += ((data >> 1) & 1) ? 160 : 0;\n\t\t*value += ((data >> 2) & 1) ? 320 : 0;\n\t\t*value += ((data >> 3) & 1) ? 640 : 0;\n\t\t*value += 3880;\n\t\tbreak;\n\tcase BQ24193_InputCurrentLimit: // Input current limit (mA).\n\t\tdata = bq24193_get_reg(BQ24193_InputSource);\n\t\tdata &= BQ24193_INCONFIG_INLIMIT_MASK;\n\t\tswitch (data)\n\t\t{\n\t\tcase 0:\n\t\t\t*value = 100;\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\t*value = 150;\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\t*value = 500;\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\t*value = 900;\n\t\t\tbreak;\n\t\tcase 4:\n\t\t\t*value = 1200;\n\t\t\tbreak;\n\t\tcase 5:\n\t\t\t*value = 1500;\n\t\t\tbreak;\n\t\tcase 6:\n\t\t\t*value = 2000;\n\t\t\tbreak;\n\t\tcase 7:\n\t\t\t*value = 3000;\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase BQ24193_SystemMinimumVoltage: // Minimum system voltage limit (mV).\n\t\tdata = bq24193_get_reg(BQ24193_PORConfig);\n\t\t*value = (data & BQ24193_PORCONFIG_SYSMIN_MASK) >> 1;\n\t\t*value *= 100;\n\t\t*value += 3000;\n\t\tbreak;\n\tcase BQ24193_FastChargeCurrentLimit: // Fast charge current limit (mA).\n\t\tdata = bq24193_get_reg(BQ24193_ChrgCurr);\n\t\tdata = (data & BQ24193_CHRGCURR_ICHG_MASK) >> 2;\n\t\t*value = 0;\n\t\t*value += ((data >> 0) & 1) ? 64 : 0;\n\t\t*value += ((data >> 1) & 1) ? 128 : 0;\n\t\t*value += ((data >> 2) & 1) ? 256 : 0;\n\t\t*value += ((data >> 3) & 1) ? 512 : 0;\n\t\t*value += ((data >> 4) & 1) ? 1024 : 0;\n\t\t*value += ((data >> 5) & 1) ? 2048 : 0;\n\t\t*value += 512;\n\t\tdata = bq24193_get_reg(BQ24193_ChrgCurr);\n\t\tdata &= BQ24193_CHRGCURR_20PCT_MASK;\n\t\tif (data)\n\t\t\t*value = *value * 20 / 100; // Fast charge current limit is 20%.\n\t\tbreak;\n\tcase BQ24193_ChargeVoltageLimit: // Charge voltage limit (mV).\n\t\tdata = bq24193_get_reg(BQ24193_ChrgVolt);\n\t\tdata = (data & BQ24193_CHRGVOLT_VREG) >> 2;\n\t\t*value = 0;\n\t\t*value += ((data >> 0) & 1) ? 16 : 0;\n\t\t*value += ((data >> 1) & 1) ? 32 : 0;\n\t\t*value += ((data >> 2) & 1) ? 64 : 0;\n\t\t*value += ((data >> 3) & 1) ? 128 : 0;\n\t\t*value += ((data >> 4) & 1) ? 256 : 0;\n\t\t*value += ((data >> 5) & 1) ? 512 : 0;\n\t\t*value += 3504;\n\t\tbreak;\n\tcase BQ24193_RechargeThreshold: // Recharge voltage threshold less than voltage limit (mV).\n\t\tdata = bq24193_get_reg(BQ24193_ChrgVolt);\n\t\tdata &= BQ24193_IRTHERMAL_THERM_MASK;\n\t\tif (data)\n\t\t\t*value = 300;\n\t\telse\n\t\t\t*value = 100;\n\t\tbreak;\n\tcase BQ24193_ThermalRegulation: // Thermal regulation threshold (oC).\n\t\tdata = bq24193_get_reg(BQ24193_IRCompThermal);\n\t\tdata &= BQ24193_IRTHERMAL_THERM_MASK;\n\t\tswitch (data)\n\t\t{\n\t\tcase 0:\n\t\t\t*value = 60;\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\t*value = 80;\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\t*value = 100;\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\t*value = 120;\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase BQ24193_ChargeStatus: // 0: Not charging, 1: Pre-charge, 2: Fast charging, 3: Charge termination done\n\t\tdata = bq24193_get_reg(BQ24193_Status);\n\t\t*value = (data & BQ24193_STATUS_CHRG_MASK) >> 4;\n\t\tbreak;\n\tcase BQ24193_TempStatus: // 0: Normal, 2: Warm, 3: Cool, 5: Cold, 6: Hot.\n\t\tdata = bq24193_get_reg(BQ24193_FaultReg);\n\t\t*value = data & BQ24193_FAULT_THERM_MASK;\n\t\tbreak;\n\tcase BQ24193_DevID: // Dev ID.\n\t\tdata = bq24193_get_reg(BQ24193_VendorPart);\n\t\t*value = data & BQ24193_VENDORPART_DEV_MASK;\n\t\tbreak;\n\tcase BQ24193_ProductNumber: // Product number.\n\t\tdata = bq24193_get_reg(BQ24193_VendorPart);\n\t\t*value = (data & BQ24193_VENDORPART_PN_MASK) >> 3;\n\t\tbreak;\n\tdefault:\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\nvoid bq24193_enable_charger()\n{\n\tu8 reg = bq24193_get_reg(BQ24193_PORConfig);\n\n\treg &= ~BQ24193_PORCONFIG_CHGCONFIG_MASK;\n\treg |= BQ24193_PORCONFIG_CHGCONFIG_CHARGER_EN;\n\n\ti2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_PORConfig, reg);\n}\n\nvoid bq24193_fake_battery_removal()\n{\n\t// Disable watchdog to keep BATFET disabled.\n\tu8 value = bq24193_get_reg(BQ24193_ChrgTermTimer);\n\tvalue &= ~BQ24193_CHRGTERM_WATCHDOG_MASK;\n\ti2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgTermTimer, value);\n\n\t// Force BATFET to disabled state. This disconnects the battery from the system.\n\tvalue = bq24193_get_reg(BQ24193_Misc);\n\tvalue |= BQ24193_MISC_BATFET_DI_MASK;\n\ti2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Misc, value);\n}\n"
  },
  {
    "path": "bdk/power/bq24193.h",
    "content": "/*\n * Battery charger driver for Nintendo Switch's TI BQ24193\n *\n * Copyright (c) 2018 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef __BQ24193_H_\n#define __BQ24193_H_\n\n#include <utils/types.h>\n\n#define BQ24193_I2C_ADDR 0x6B\n\n// REG 0 masks.\n#define BQ24193_INCONFIG_INLIMIT_MASK (7<<0)\n#define BQ24193_INCONFIG_VINDPM_MASK   0x78\n#define BQ24193_INCONFIG_HIZ_EN_MASK  (1<<7)\n\n// REG 1 masks.\n#define BQ24193_PORCONFIG_BOOST_MASK       (1<<0)\n#define BQ24193_PORCONFIG_SYSMIN_MASK      (7<<1) // 3000uV HOS default.\n#define BQ24193_PORCONFIG_CHGCONFIG_MASK   (3<<4)\n#define BQ24193_PORCONFIG_CHGCONFIG_CHARGER_EN (1<<4)\n#define BQ24193_PORCONFIG_I2CWATCHDOG_MASK (1<<6)\n#define BQ24193_PORCONFIG_RESET_MASK       (1<<7)\n\n// REG 2 masks.\n#define BQ24193_CHRGCURR_20PCT_MASK (1<<0)\n#define BQ24193_CHRGCURR_ICHG_MASK   0xFC\n\n// REG 3 masks.\n#define BQ24193_PRECHRG_ITERM   0x0F\n#define BQ24193_PRECHRG_IPRECHG 0xF0\n\n// REG 4 masks.\n#define BQ24193_CHRGVOLT_VTHRES  (1<<0)\n#define BQ24193_CHRGVOLT_BATTLOW (1<<1)\n#define BQ24193_CHRGVOLT_VREG     0xFC\n\n// REG 5 masks.\n#define BQ24193_CHRGTERM_ISET_MASK     (1<<0)\n#define BQ24193_CHRGTERM_CHGTIMER_MASK (3<<1)\n#define BQ24193_CHRGTERM_ENTIMER_MASK  (1<<3)\n#define BQ24193_CHRGTERM_WATCHDOG_MASK (3<<4)\n#define BQ24193_CHRGTERM_TERM_ST_MASK  (1<<6)\n#define BQ24193_CHRGTERM_TERM_EN_MASK  (1<<7)\n\n// REG 6 masks.\n#define BQ24193_IRTHERMAL_THERM_MASK    (3<<0)\n#define BQ24193_IRTHERMAL_VCLAMP_MASK   (7<<2)\n#define BQ24193_IRTHERMAL_BATTCOMP_MASK (7<<5)\n\n// REG 7 masks.\n#define BQ24193_MISC_INT_MASK       (3<<0)\n#define BQ24193_MISC_VSET_MASK      (1<<4)\n#define BQ24193_MISC_BATFET_DI_MASK (1<<5)\n#define BQ24193_MISC_TMR2X_EN_MASK  (1<<6)\n#define BQ24193_MISC_DPDM_EN_MASK   (1<<7)\n\n// REG 8 masks.\n#define BQ24193_STATUS_VSYS_MASK  (1<<0)\n#define BQ24193_STATUS_THERM_MASK (1<<1)\n#define BQ24193_STATUS_PG_MASK    (1<<2)\n#define BQ24193_STATUS_DPM_MASK   (1<<3)\n#define BQ24193_STATUS_CHRG_MASK  (3<<4)\n#define BQ24193_STATUS_VBUS_MASK  (3<<6)\n\n// REG 9 masks.\n#define BQ24193_FAULT_THERM_MASK    (7<<0)\n#define BQ24193_FAULT_BATT_OVP_MASK (1<<3)\n#define BQ24193_FAULT_CHARGE_MASK   (3<<4)\n#define BQ24193_FAULT_BOOST_MASK    (1<<6)\n#define BQ24193_FAULT_WATCHDOG_MASK (1<<7)\n\n// REG A masks.\n#define BQ24193_VENDORPART_DEV_MASK (3<<0)\n#define BQ24193_VENDORPART_PN_MASK  (7<<3)\n\nenum BQ24193_reg {\n\tBQ24193_InputSource     = 0x00,\n\tBQ24193_PORConfig       = 0x01,\n\tBQ24193_ChrgCurr        = 0x02,\n\tBQ24193_PreChrgTerm     = 0x03,\n\tBQ24193_ChrgVolt        = 0x04,\n\tBQ24193_ChrgTermTimer   = 0x05,\n\tBQ24193_IRCompThermal   = 0x06,\n\tBQ24193_Misc            = 0x07,\n\tBQ24193_Status          = 0x08,\n\tBQ24193_FaultReg        = 0x09,\n\tBQ24193_VendorPart      = 0x0A,\n};\n\nenum BQ24193_reg_prop {\n\tBQ24193_InputVoltageLimit,      // REG 0.\n\tBQ24193_InputCurrentLimit,      // REG 0.\n\tBQ24193_SystemMinimumVoltage,   // REG 1.\n\tBQ24193_FastChargeCurrentLimit, // REG 2.\n\tBQ24193_ChargeVoltageLimit,     // REG 4.\n\tBQ24193_RechargeThreshold,      // REG 4.\n\tBQ24193_ThermalRegulation,      // REG 6.\n\tBQ24193_ChargeStatus,           // REG 8.\n\tBQ24193_TempStatus,             // REG 9.\n\tBQ24193_DevID,                  // REG A.\n\tBQ24193_ProductNumber,          // REG A.\n};\n\nint  bq24193_get_version(u32 *value);\nint  bq24193_get_property(enum BQ24193_reg_prop prop, int *value);\nvoid bq24193_enable_charger();\nvoid bq24193_fake_battery_removal();\n\n#endif /* __BQ24193_H_ */\n"
  },
  {
    "path": "bdk/power/max17050.c",
    "content": "/*\n * Fuel gauge driver for Nintendo Switch's Maxim 17050\n *\n * Copyright (c) 2011 Samsung Electronics\n * MyungJoo Ham <myungjoo.ham@samsung.com>\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n *\n * This driver is based on max17040_battery.c\n */\n\n#include \"max17050.h\"\n#include <soc/i2c.h>\n#include <soc/timer.h>\n\n/* Board default values */\n#define BOARD_CGAIN       2 /* Actual: 1.99993 */\n#define BOARD_RSENSE_MOHM 5 /* 0.005 Ohm */\n#define ADJ_RSENSE_MOHM   (BOARD_RSENSE_MOHM * BOARD_CGAIN) /* 0.01 Ohm */\n\n/* Consider RepCap which is less then 10 units below FullCAP full */\n#define FULL_THRESHOLD 10\n\n/* Status register bits */\n#define STATUS_POR_BIT BIT(1)\n#define STATUS_BST_BIT BIT(3)\n#define STATUS_VMN_BIT BIT(8)\n#define STATUS_TMN_BIT BIT(9)\n#define STATUS_SMN_BIT BIT(10)\n#define STATUS_BI_BIT  BIT(11)\n#define STATUS_VMX_BIT BIT(12)\n#define STATUS_TMX_BIT BIT(13)\n#define STATUS_SMX_BIT BIT(14)\n#define STATUS_BR_BIT  BIT(15)\n\n#define VFSOC0_LOCK   0x0000\n#define VFSOC0_UNLOCK 0x0080\n\n#define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */\n\nstatic u16 max17050_get_reg(u8 reg)\n{\n\tu16 data = 0;\n\n\ti2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, reg);\n\n\treturn data;\n}\n\nint max17050_get_version(u32 *value)\n{\n\tu16 data = max17050_get_reg(MAX17050_DevName);\n\tif (value)\n\t\t*value = data;\n\n\tif (data == 0x00AC)\n\t\treturn 0;\n\telse\n\t\treturn 1;\n}\n\nint max17050_get_property(enum MAX17050_reg reg, int *value)\n{\n\tu16 data;\n\n\tswitch (reg)\n\t{\n\tcase MAX17050_Age: // Age (percent). Based on 100% x (FullCAP Register/DesignCap).\n\t\tdata = max17050_get_reg(MAX17050_Age);\n\t\t*value = data >> 8; /* Show MSB. 1% increments */\n\t\tbreak;\n\tcase MAX17050_Cycles: // Cycle count.\n\t\t*value = max17050_get_reg(MAX17050_Cycles);\n\t\tbreak;\n\tcase MAX17050_MinVolt: // Voltage max/min\n\t\tdata = max17050_get_reg(MAX17050_MinMaxVolt);\n\t\t*value = (data & 0xff) * 20; /* Voltage MIN. Units of 20mV */\n\t\tbreak;\n\tcase MAX17050_MaxVolt: // Voltage max/min\n\t\tdata = max17050_get_reg(MAX17050_MinMaxVolt);\n\t\t*value = (data >> 8) * 20; /* Voltage MAX. Units of LSB = 20mV */\n\t\tbreak;\n\tcase MAX17050_V_empty: // Voltage min design.\n\t\tdata = max17050_get_reg(MAX17050_V_empty);\n\t\t*value = (data >> 7) * 10; /* Units of LSB = 10mV */\n\t\tbreak;\n\tcase MAX17050_VCELL: // Voltage now.\n\t\tdata = max17050_get_reg(MAX17050_VCELL);\n\t\t*value = (data >> 3) * 625 / 1000; /* Units of LSB = 0.625mV */\n\t\tbreak;\n\tcase MAX17050_AvgVCELL: // Voltage avg.\n\t\tdata = max17050_get_reg(MAX17050_AvgVCELL);\n\t\t*value = (data >> 3) * 625 / 1000; /* Units of LSB = 0.625mV */\n\t\tbreak;\n\tcase MAX17050_OCVInternal: // Voltage ocv.\n\t\tdata = max17050_get_reg(MAX17050_OCVInternal);\n\t\t*value = (data >> 3) * 625 / 1000; /* Units of LSB = 0.625mV */\n\t\tbreak;\n\tcase MAX17050_RepSOC: // Capacity %.\n\t\t*value = max17050_get_reg(MAX17050_RepSOC);\n\t\tbreak;\n\tcase MAX17050_DesignCap: // Charge full design.\n\t\tdata = max17050_get_reg(MAX17050_DesignCap);\n\t\t*value = (u32)data * 5 / ADJ_RSENSE_MOHM; /* Units of LSB = 5uVh / Rsense = 0.5mAh */\n\t\tbreak;\n\tcase MAX17050_FullCAP: // Charge full.\n\t\tdata = max17050_get_reg(MAX17050_FullCAP);\n\t\t*value = (u32)data * 5 / ADJ_RSENSE_MOHM; /* Units of LSB = 5uVh / Rsense = 0.5mAh */\n\t\tbreak;\n\tcase MAX17050_RepCap: // Charge now.\n\t\tdata = max17050_get_reg(MAX17050_RepCap);\n\t\t*value = (u32)data * 5 / ADJ_RSENSE_MOHM; /* Units of LSB = 5uVh / Rsense = 0.5mAh */\n\t\tbreak;\n\tcase MAX17050_TEMP: // Temp.\n\t\tdata = max17050_get_reg(MAX17050_TEMP);\n\t\t*value = (s16)data;\n\t\t*value = *value * 10 / 256;\n\t\tbreak;\n\tcase MAX17050_Current: // Current now.\n\t\tdata = max17050_get_reg(MAX17050_Current);\n\t\t*value = (int)(s16)data * 15625 / ADJ_RSENSE_MOHM / 10; /* Units of LSB = 1.5625uV / Rsense = 156.25uA */\n\t\tbreak;\n\tcase MAX17050_AvgCurrent: // Current avg.\n\t\tdata = max17050_get_reg(MAX17050_AvgCurrent);\n\t\t*value = (int)(s16)data * 15625 / ADJ_RSENSE_MOHM / 10; /* Units of LSB = 1.5625uV / Rsense = 156.25uA */\n\t\tbreak;\n\tdefault:\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\nstatic int _max17050_write_verify_reg(u8 reg, u16 value)\n{\n\tint retries = 8;\n\tint ret;\n\n\tdo\n\t{\n\t\tret = i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, reg, (u8 *)&value, 2);\n\t\tu16 read_value = max17050_get_reg(reg);\n\t\tif (!ret && read_value == value)\n\t\t\tbreak;\n\t} while (--retries);\n\n\treturn ret;\n}\n\nstatic void _max17050_override_por(u8 reg, u16 value)\n{\n\tif (value)\n\t\ti2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, reg, (u8 *)&value, 2);\n}\n\nstatic void _max17050_load_new_capacity_params()\n{\n\tu16 fullcap, repSoc, dq_acc, dp_acc;\n\n\tfullcap = 0x2476; // 4667mAh design capacity.\n\tdq_acc = 0x10bc;  // From a healthy fuel gauge.\n\tdp_acc = 0x5e09;  //          =||=\n\trepSoc = 0x6400;  // 100%.\n\n\t_max17050_write_verify_reg(MAX17050_RemCap, fullcap);\n\t_max17050_write_verify_reg(MAX17050_RepCap, fullcap);\n\n\t_max17050_write_verify_reg(MAX17050_dQacc, dq_acc);\n\t_max17050_write_verify_reg(MAX17050_dPacc, dp_acc);\n\n\t_max17050_write_verify_reg(MAX17050_FullCAP, fullcap);\n\t//i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_DesignCap, (u8 *)&fullcap, 2);\n\t_max17050_write_verify_reg(MAX17050_FullCAPNom, fullcap);\n\t/* Update SOC register with new SOC */\n\ti2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_RepSOC, (u8 *)&repSoc, 2);\n}\n\nstatic void _max17050_reset_vfsoc0_reg()\n{\n\tu16 lockVal = 0;\n\tu16 vfSoc = 0x6440; // >100% for fully charged battery\n\n\tlockVal = VFSOC0_UNLOCK;\n\ti2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VFSOC0Enable, (u8 *)&lockVal, 2);\n\n\t_max17050_write_verify_reg(MAX17050_VFSOC0, vfSoc);\n\n\tlockVal = VFSOC0_LOCK;\n\ti2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VFSOC0Enable, (u8 *)&lockVal, 2);\n}\n\nstatic void _max17050_update_capacity_regs()\n{\n\tu16 value = 0x2476; // Set to 4667mAh design capacity.\n\t_max17050_write_verify_reg(MAX17050_FullCAP, value);\n\t_max17050_write_verify_reg(MAX17050_FullCAPNom, value);\n\t//i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_DesignCap, config->design_cap, 2);\n}\n\nstatic void _max17050_write_config_regs()\n{\n\tu16 value = 0;\n\n\tvalue = 0x7254;\n\ti2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_CONFIG, (u8 *)&value, 2);\n\tvalue = 0x2473;\n\ti2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_LearnCFG, (u8 *)&value, 2);\n\t//i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_FilterCFG, (u8 *)&value, 2)\n\t//i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_RelaxCFG, (u8 *)&value, 2)\n\t//i2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_FullSOCThr, (u8 *)&value, 2)\n}\n\n/*\n * Block write all the override values coming from platform data.\n * This function MUST be called before the POR initialization proceedure\n * specified by maxim.\n */\nstatic void _max17050_override_por_values()\n{\n\tu16 dq_acc = 0x10bc; // From a healthy fuel gauge.\n\tu16 dp_acc = 0x5e09; //           =||=\n\n\t_max17050_override_por(MAX17050_dQacc, dq_acc);\n\t_max17050_override_por(MAX17050_dPacc, dp_acc);\n\n\t//_max17050_override_por(MAX17050_RCOMP0, config->rcomp0);  //0x58\n\t//_max17050_override_por(MAX17050_TempCo, config->tcompc0); //0x1b22\n\n\t//u16 k_empty0 = 0x439;\n\t//_max17050_override_por(map, MAX17050_K_empty0, k_empty0); // Unknown cell data\n}\n\nstatic void _max17050_set_por_bit(u16 value)\n{\n\t_max17050_write_verify_reg(MAX17050_STATUS, value);\n}\n\nvoid max17050_fix_configuration()\n{\n\t/* Init phase, set the POR bit */\n\t_max17050_set_por_bit(STATUS_POR_BIT);\n\n\t/* Override POR values */\n\t_max17050_override_por_values();\n\t/* After Power up, the MAX17050 requires 500ms in order\n\t * to perform signal debouncing and initial SOC reporting\n\t */\n\tmsleep(500);\n\n\t/* Initialize configaration */\n\t_max17050_write_config_regs();\n\n\t/* update capacity params */\n\t_max17050_update_capacity_regs();\n\n\t/* delay must be atleast 350mS to allow VFSOC\n\t * to be calculated from the new configuration\n\t */\n\tmsleep(350);\n\n\t/* reset vfsoc0 reg */\n\t_max17050_reset_vfsoc0_reg();\n\n\t/* load new capacity params */\n\t_max17050_load_new_capacity_params();\n\n\t/* Init complete, Clear the POR bit */\n\t//_max17050_set_por_bit(0); // Should we? Or let the switch to reconfigure POR?\n\n\t// Sets POR, BI, BR.\n\t_max17050_set_por_bit(0x8801);\n}\n\nvoid max17050_dump_regs(void *buf)\n{\n\tu16 *buff = (u16 *)buf;\n\n\t// Unlock model table.\n\tu16 unlock = 0x59;\n\ti2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MODELEnable1, (u8 *)&unlock, 2);\n\tunlock = 0xC4;\n\ti2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MODELEnable2, (u8 *)&unlock, 2);\n\n\t// Dump all battery fuel gauge registers.\n\tfor (u32 i = 0; i < 0x100; i++)\n\t{\n\t\tbuff[i] = max17050_get_reg(i);\n\t\tmsleep(1);\n\t}\n\n\t// Lock model table.\n\tunlock = 0;\n\ti2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MODELEnable1, (u8 *)&unlock, 2);\n\ti2c_send_buf_small(I2C_1, MAXIM17050_I2C_ADDR, MAX17050_MODELEnable2, (u8 *)&unlock, 2);\n}\n"
  },
  {
    "path": "bdk/power/max17050.h",
    "content": "/*\n * Fuel gauge driver for Nintendo Switch's Maxim 17050\n *\n * Copyright (c) 2011 Samsung Electronics\n * MyungJoo Ham <myungjoo.ham@samsung.com>\n * Copyright (c) 2018-2020 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n */\n\n#ifndef __MAX17050_H_\n#define __MAX17050_H_\n\n#include <utils/types.h>\n\n#define MAXIM17050_I2C_ADDR 0x36\n\nenum MAX17050_reg {\n\tMAX17050_STATUS\t\t= 0x00,\n\tMAX17050_VALRT_Th\t= 0x01,\n\tMAX17050_TALRT_Th\t= 0x02,\n\tMAX17050_SALRT_Th\t= 0x03,\n\tMAX17050_AtRate\t\t= 0x04,\n\tMAX17050_RepCap\t\t= 0x05,\n\tMAX17050_RepSOC\t\t= 0x06,\n\tMAX17050_Age\t\t= 0x07,\n\tMAX17050_TEMP\t\t= 0x08,\n\tMAX17050_VCELL\t\t= 0x09,\n\tMAX17050_Current\t= 0x0A,\n\tMAX17050_AvgCurrent\t= 0x0B,\n\n\tMAX17050_SOC\t\t= 0x0D,\n\tMAX17050_AvSOC\t\t= 0x0E,\n\tMAX17050_RemCap\t\t= 0x0F,\n\tMAX17050_FullCAP\t= 0x10,\n\tMAX17050_TTE\t\t= 0x11,\n\tMAX17050_QRTbl00\t= 0x12,\n\tMAX17050_FullSOCThr\t= 0x13,\n\tMAX17050_RSLOW\t\t= 0x14,\n\n\tMAX17050_AvgTA\t\t= 0x16,\n\tMAX17050_Cycles\t\t= 0x17,\n\tMAX17050_DesignCap\t= 0x18,\n\tMAX17050_AvgVCELL\t= 0x19,\n\tMAX17050_MinMaxTemp\t= 0x1A,\n\tMAX17050_MinMaxVolt\t= 0x1B,\n\tMAX17050_MinMaxCurr\t= 0x1C,\n\tMAX17050_CONFIG\t\t= 0x1D,\n\tMAX17050_ICHGTerm\t= 0x1E,\n\tMAX17050_AvCap\t\t= 0x1F,\n\tMAX17050_ManName\t= 0x20,\n\tMAX17050_DevName\t= 0x21,\n\tMAX17050_QRTbl10\t= 0x22,\n\tMAX17050_FullCAPNom\t= 0x23,\n\tMAX17050_TempNom\t= 0x24,\n\tMAX17050_TempLim\t= 0x25,\n\tMAX17050_TempHot\t= 0x26,\n\tMAX17050_AIN\t\t= 0x27,\n\tMAX17050_LearnCFG\t= 0x28,\n\tMAX17050_FilterCFG\t= 0x29,\n\tMAX17050_RelaxCFG\t= 0x2A,\n\tMAX17050_MiscCFG\t= 0x2B,\n\tMAX17050_TGAIN\t\t= 0x2C,\n\tMAX17050_TOFF\t\t= 0x2D,\n\tMAX17050_CGAIN\t\t= 0x2E,\n\tMAX17050_COFF\t\t= 0x2F,\n\n\tMAX17050_QRTbl20\t= 0x32,\n\tMAX17050_SOC_empty\t= 0x33,\n\tMAX17050_T_empty\t= 0x34,\n\tMAX17050_FullCAP0\t= 0x35,\n\tMAX17050_LAvg_empty\t= 0x36,\n\tMAX17050_FCTC\t\t= 0x37,\n\tMAX17050_RCOMP0\t\t= 0x38,\n\tMAX17050_TempCo\t\t= 0x39,\n\tMAX17050_V_empty\t= 0x3A,\n\tMAX17050_K_empty0\t= 0x3B,\n\tMAX17050_TaskPeriod\t= 0x3C,\n\tMAX17050_FSTAT\t\t= 0x3D,\n\tMAX17050_TIMER\t\t= 0x3E,\n\tMAX17050_SHDNTIMER\t= 0x3F,\n\n\tMAX17050_QRTbl30\t= 0x42,\n\n\tMAX17050_dQacc\t\t= 0x45,\n\tMAX17050_dPacc\t\t= 0x46,\n\n\tMAX17050_VFSOC0\t\t= 0x48,\n\n\tMax17050_QH0\t\t= 0x4C,\n\tMAX17050_QH\t\t\t= 0x4D,\n\tMAX17050_QL\t\t\t= 0x4E,\n\n\tMAX17050_MinVolt\t= 0x50, // Custom ID. Not to be sent to i2c.\n\tMAX17050_MaxVolt\t= 0x51, // Custom ID. Not to be sent to i2c.\n\n\tMAX17050_VFSOC0Enable\t= 0x60,\n\tMAX17050_MODELEnable1\t= 0x62,\n\tMAX17050_MODELEnable2\t= 0x63,\n\n\tMAX17050_MODELChrTbl\t= 0x80,\n\n\tMAX17050_OCV\t\t\t= 0xEE,\n\n\tMAX17050_OCVInternal\t= 0xFB,\n\n\tMAX17050_VFSOC\t\t\t= 0xFF,\n};\n\nint  max17050_get_version(u32 *value);\nint  max17050_get_property(enum MAX17050_reg reg, int *value);\nvoid max17050_fix_configuration();\nvoid max17050_dump_regs(void *buf);\n\n#endif /* __MAX17050_H_ */\n"
  },
  {
    "path": "bdk/power/max77620.h",
    "content": "/*\n * Defining registers address and its bit definitions of MAX77620 and MAX20024\n *\n * Copyright (c) 2019-2020 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n */\n\n#ifndef _MFD_MAX77620_H_\n#define _MFD_MAX77620_H_\n\n#define MAX77620_I2C_ADDR 0x3C\n\n/* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */\n#define MAX77620_REG_CNFGGLBL1      0x00\n#define  MAX77620_CNFGGLBL1_LBRSTEN           BIT(0)\n#define  MAX77620_CNFGGLBL1_LBDAC_MASK        0x0E\n#define  MAX77620_CNFGGLBL1_LBDAC_2700        (0 << 1)\n#define  MAX77620_CNFGGLBL1_LBDAC_2800        (1 << 1)\n#define  MAX77620_CNFGGLBL1_LBDAC_2900        (2 << 1)\n#define  MAX77620_CNFGGLBL1_LBDAC_3000        (3 << 1)\n#define  MAX77620_CNFGGLBL1_LBDAC_3100        (4 << 1)\n#define  MAX77620_CNFGGLBL1_LBDAC_3200        (5 << 1)\n#define  MAX77620_CNFGGLBL1_LBDAC_3300        (6 << 1)\n#define  MAX77620_CNFGGLBL1_LBDAC_3400        (7 << 1)\n#define  MAX77620_CNFGGLBL1_LBHYST_100        (0 << 4)\n#define  MAX77620_CNFGGLBL1_LBHYST_200        (1 << 4)\n#define  MAX77620_CNFGGLBL1_LBHYST_300        (2 << 4)\n#define  MAX77620_CNFGGLBL1_LBHYST_400        (3 << 4)\n#define  MAX77620_CNFGGLBL1_MPPLD             BIT(6)\n#define  MAX77620_CNFGGLBL1_LBDAC_EN          BIT(7)\n\n#define MAX77620_REG_CNFGGLBL2      0x01\n#define  MAX77620_TWD_MASK                    0x3\n#define  MAX77620_TWD_2s                      0x0\n#define  MAX77620_TWD_16s                     0x1\n#define  MAX77620_TWD_64s                     0x2\n#define  MAX77620_TWD_128s                    0x3\n#define  MAX77620_WDTEN                       BIT(2)\n#define  MAX77620_WDTSLPC                     BIT(3)\n#define  MAX77620_WDTOFFC                     BIT(4)\n#define  MAX77620_GLBL_LPM                    BIT(5)\n#define  MAX77620_I2CTWD_MASK                 0xC0\n#define  MAX77620_I2CTWD_DISABLED             0x00\n#define  MAX77620_I2CTWD_1_33ms               0x40\n#define  MAX77620_I2CTWD_35_7ms               0x80\n#define  MAX77620_I2CTWD_41_7ms               0xC0\n\n#define MAX77620_REG_CNFGGLBL3      0x02\n#define  MAX77620_WDTC_MASK                   0x3\n\n#define MAX77620_REG_CNFG1_32K      0x03\n#define  MAX77620_CNFG1_PWR_MD_32K_MASK       0x3\n#define  MAX77620_CNFG1_32K_OUT0_EN           BIT(2)\n#define  MAX77620_CNFG1_32KLOAD_MASK          0x30\n#define  MAX77620_CNFG1_32K_OK                BIT(7)\n\n#define MAX77620_REG_CNFGBBC        0x04\n#define  MAX77620_CNFGBBC_ENABLE              BIT(0)\n#define  MAX77620_CNFGBBC_CURRENT_MASK        0x06\n#define  MAX77620_CNFGBBC_CURRENT_SHIFT       1\n#define  MAX77620_CNFGBBC_VOLTAGE_MASK        0x18\n#define  MAX77620_CNFGBBC_VOLTAGE_SHIFT       3\n#define  MAX77620_CNFGBBC_LOW_CURRENT_DISABLE BIT(5)\n#define  MAX77620_CNFGBBC_RESISTOR_MASK       0xC0\n#define  MAX77620_CNFGBBC_RESISTOR_SHIFT      6\n#define  MAX77620_CNFGBBC_RESISTOR_100        (0 << MAX77620_CNFGBBC_RESISTOR_SHIFT)\n#define  MAX77620_CNFGBBC_RESISTOR_1K         (1 << MAX77620_CNFGBBC_RESISTOR_SHIFT)\n#define  MAX77620_CNFGBBC_RESISTOR_3K         (2 << MAX77620_CNFGBBC_RESISTOR_SHIFT)\n#define  MAX77620_CNFGBBC_RESISTOR_6K         (3 << MAX77620_CNFGBBC_RESISTOR_SHIFT)\n\n#define MAX77620_REG_IRQTOP         0x05\n#define MAX77620_REG_IRQTOPM        0x0D\n#define  MAX77620_IRQ_TOP_ONOFF_MASK          BIT(1)\n#define  MAX77620_IRQ_TOP_32K_MASK            BIT(2)\n#define  MAX77620_IRQ_TOP_RTC_MASK            BIT(3)\n#define  MAX77620_IRQ_TOP_GPIO_MASK           BIT(4)\n#define  MAX77620_IRQ_TOP_LDO_MASK            BIT(5)\n#define  MAX77620_IRQ_TOP_SD_MASK             BIT(6)\n#define  MAX77620_IRQ_TOP_GLBL_MASK           BIT(7)\n\n#define MAX77620_REG_INTLBT         0x06\n#define MAX77620_REG_INTENLBT       0x0E\n#define  MAX77620_IRQ_GLBLM_MASK              BIT(0)\n#define  MAX77620_IRQ_TJALRM2_MASK            BIT(1)\n#define  MAX77620_IRQ_TJALRM1_MASK            BIT(2)\n#define  MAX77620_IRQ_LBM_MASK                BIT(3)\n\n#define MAX77620_REG_IRQSD          0x07\n#define MAX77620_REG_IRQMASKSD      0x0F\n#define  MAX77620_IRQSD_PFI_SD3               BIT(4)\n#define  MAX77620_IRQSD_PFI_SD2               BIT(5)\n#define  MAX77620_IRQSD_PFI_SD1               BIT(6)\n#define  MAX77620_IRQSD_PFI_SD0               BIT(7)\n\n#define MAX77620_REG_IRQ_LVL2_L0_7  0x08 // LDO number that irq occurred.\n#define MAX77620_REG_IRQ_MSK_L0_7   0x10\n#define MAX77620_REG_IRQ_LVL2_L8    0x09 // LDO number that irq occurred. Only bit0: LDO8 is valid.\n#define MAX77620_REG_IRQ_MSK_L8     0x11\n#define MAX77620_REG_IRQ_LVL2_GPIO  0x0A // Edge detection interrupt.\n\n#define MAX77620_REG_ONOFFIRQ       0x0B\n#define MAX77620_REG_ONOFFIRQM      0x12\n#define  MAX77620_ONOFFIRQ_MRWRN              BIT(0)\n#define  MAX77620_ONOFFIRQ_EN0_1SEC           BIT(1)\n#define  MAX77620_ONOFFIRQ_EN0_F              BIT(2)\n#define  MAX77620_ONOFFIRQ_EN0_R              BIT(3)\n#define  MAX77620_ONOFFIRQ_LID_F              BIT(4)\n#define  MAX77620_ONOFFIRQ_LID_R              BIT(5)\n#define  MAX77620_ONOFFIRQ_ACOK_F             BIT(6)\n#define  MAX77620_ONOFFIRQ_ACOK_R             BIT(7)\n\n#define MAX77620_REG_NVERC          0x0C // Shutdown reason (non-volatile).\n#define  MAX77620_NVERC_SHDN                  BIT(0)\n#define  MAX77620_NVERC_WTCHDG                BIT(1)\n#define  MAX77620_NVERC_HDRST                 BIT(2)\n#define  MAX77620_NVERC_TOVLD                 BIT(3)\n#define  MAX77620_NVERC_MBLSD                 BIT(4)\n#define  MAX77620_NVERC_MBO                   BIT(5)\n#define  MAX77620_NVERC_MBU                   BIT(6)\n#define  MAX77620_NVERC_RSTIN                 BIT(7)\n\n#define MAX77620_REG_STATLBT        0x13\n#define MAX77620_REG_STATSD         0x14\n\n#define MAX77620_REG_ONOFFSTAT      0x15\n#define  MAX77620_ONOFFSTAT_LID     BIT(0)\n#define  MAX77620_ONOFFSTAT_ACOK    BIT(1)\n#define  MAX77620_ONOFFSTAT_EN0     BIT(2)\n\n/* SD and LDO Registers */\n#define MAX77620_REG_SD0            0x16\n#define MAX77620_REG_SD1            0x17\n#define MAX77620_REG_SD2            0x18\n#define MAX77620_REG_SD3            0x19\n#define MAX77620_REG_SD4            0x1A\n#define MAX77620_REG_DVSSD0         0x1B\n#define MAX77620_REG_DVSSD1         0x1C\n#define  MAX77620_SDX_VOLT_MASK               0xFF\n#define  MAX77620_SD0_VOLT_MASK               0x7F // Max is 0x40.\n#define  MAX77620_SD1_VOLT_MASK               0x7F // Max is 0x4C.\n#define  MAX77620_LDO_VOLT_MASK               0x3F\n\n#define MAX77620_REG_SD0_CFG        0x1D\n#define MAX77620_REG_SD1_CFG        0x1E\n#define MAX77620_REG_SD2_CFG        0x1F\n#define MAX77620_REG_SD3_CFG        0x20\n#define MAX77620_REG_SD4_CFG        0x21\n#define  MAX77620_SD_SR_MASK                  0xC0\n#define  MAX77620_SD_SR_SHIFT                 6\n#define  MAX77620_SD_POWER_MODE_MASK          0x30\n#define  MAX77620_SD_POWER_MODE_SHIFT         4\n#define  MAX77620_SD_CFG1_ADE_MASK            BIT(3)\n#define  MAX77620_SD_CFG1_ADE_DISABLE         0\n#define  MAX77620_SD_CFG1_ADE_ENABLE          BIT(3)\n#define  MAX77620_SD_FPWM_MASK                0x04\n#define  MAX77620_SD_FPWM_SHIFT               2\n#define  MAX77620_SD_FSRADE_MASK              0x01\n#define  MAX77620_SD_FSRADE_SHIFT             0\n#define  MAX77620_SD_CFG1_FPWM_SD_MASK        BIT(2)\n#define  MAX77620_SD_CFG1_FPWM_SD_SKIP        0\n#define  MAX77620_SD_CFG1_FPWM_SD_FPWM        BIT(2)\n#define  MAX77620_SD_CFG1_MPOK_MASK           BIT(1)\n#define  MAX77620_SD_CFG1_FSRADE_SD_MASK      BIT(0)\n#define  MAX77620_SD_CFG1_FSRADE_SD_DISABLE   0\n#define  MAX77620_SD_CFG1_FSRADE_SD_ENABLE    BIT(0)\n\n#define MAX77620_REG_SD_CFG2        0x22\n#define  MAX77620_SD_CNF2_RSVD                BIT(0)\n#define  MAX77620_SD_CNF2_ROVS_EN_SD1         BIT(1)\n#define  MAX77620_SD_CNF2_ROVS_EN_SD0         BIT(2)\n\n#define MAX77620_REG_LDO0_CFG       0x23\n#define MAX77620_REG_LDO0_CFG2      0x24\n#define MAX77620_REG_LDO1_CFG       0x25\n#define MAX77620_REG_LDO1_CFG2      0x26\n#define MAX77620_REG_LDO2_CFG       0x27\n#define MAX77620_REG_LDO2_CFG2      0x28\n#define MAX77620_REG_LDO3_CFG       0x29\n#define MAX77620_REG_LDO3_CFG2      0x2A\n#define MAX77620_REG_LDO4_CFG       0x2B\n#define MAX77620_REG_LDO4_CFG2      0x2C\n#define MAX77620_REG_LDO5_CFG       0x2D\n#define MAX77620_REG_LDO5_CFG2      0x2E\n#define MAX77620_REG_LDO6_CFG       0x2F\n#define MAX77620_REG_LDO6_CFG2      0x30\n#define MAX77620_REG_LDO7_CFG       0x31\n#define MAX77620_REG_LDO7_CFG2      0x32\n#define MAX77620_REG_LDO8_CFG       0x33\n#define MAX77620_REG_LDO8_CFG2      0x34\n/*! LDO CFG */\n#define  MAX77620_LDO_POWER_MODE_SHIFT        6\n#define  MAX77620_LDO_POWER_MODE_MASK         (3 << MAX77620_LDO_POWER_MODE_SHIFT)\n#define  MAX77620_POWER_MODE_NORMAL\t          3\n#define  MAX77620_POWER_MODE_LPM              2\n#define  MAX77620_POWER_MODE_GLPM             1\n#define  MAX77620_POWER_MODE_DISABLE          0\n/*! LDO CFG2 */\n#define  MAX77620_LDO_CFG2_SS_MASK            (1 << 0)\n#define  MAX77620_LDO_CFG2_SS_FAST            (0 << 0)\n#define  MAX77620_LDO_CFG2_SS_SLOW            (1 << 0)\n#define  MAX77620_LDO_CFG2_ADE_MASK           (1 << 1)\n#define  MAX77620_LDO_CFG2_ADE_DISABLE        (0 << 1)\n#define  MAX77620_LDO_CFG2_ADE_ENABLE         (1 << 1)\n#define  MAX77620_LDO_CFG2_MPOK_MASK          BIT(2)\n#define  MAX77620_LDO_CFG2_POK_MASK           BIT(3)\n#define  MAX77620_LDO_CFG2_COMP_SHIFT         4\n#define  MAX77620_LDO_CFG2_COMP_MASK          (3 << MAX77620_LDO_COMP_SHIFT)\n#define  MAX77620_LDO_CFG2_COMP_SLOW \t      3\n#define  MAX77620_LDO_CFG2_COMP_MID_SLOW      2\n#define  MAX77620_LDO_CFG2_COMP_MID_FAST      1\n#define  MAX77620_LDO_CFG2_COMP_FAST          0\n#define  MAX77620_LDO_CFG2_ALPM_EN_MASK       BIT(6)\n#define  MAX77620_LDO_CFG2_OVCLMP_MASK        BIT(7)\n\n#define MAX77620_REG_LDO_CFG3       0x35\n#define  MAX77620_LDO_BIAS_EN                 BIT(0)\n#define  MAX77620_TRACK4_SHIFT                5\n#define  MAX77620_TRACK4_MASK                 (1 << MAX77620_TRACK4_SHIFT)\n\n#define MAX77620_REG_GPIO0          0x36\n#define MAX77620_REG_GPIO1          0x37\n#define MAX77620_REG_GPIO2          0x38\n#define MAX77620_REG_GPIO3          0x39\n#define MAX77620_REG_GPIO4          0x3A\n#define MAX77620_REG_GPIO5          0x3B\n#define MAX77620_REG_GPIO6          0x3C\n#define MAX77620_REG_GPIO7          0x3D\n#define  MAX77620_CNFG_GPIO_DRV_MASK          (1 << 0)\n#define  MAX77620_CNFG_GPIO_DRV_PUSHPULL      (1 << 0)\n#define  MAX77620_CNFG_GPIO_DRV_OPENDRAIN     (0 << 0)\n#define  MAX77620_CNFG_GPIO_DIR_MASK          (1 << 1)\n#define  MAX77620_CNFG_GPIO_DIR_INPUT         (1 << 1)\n#define  MAX77620_CNFG_GPIO_DIR_OUTPUT        (0 << 1)\n#define  MAX77620_CNFG_GPIO_INPUT_VAL_MASK    (1 << 2)\n#define  MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK   (1 << 3)\n#define  MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH   (1 << 3)\n#define  MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW    (0 << 3)\n#define  MAX77620_CNFG_GPIO_INT_MASK          (0x3 << 4)\n#define  MAX77620_CNFG_GPIO_INT_FALLING       (1 << 4)\n#define  MAX77620_CNFG_GPIO_INT_RISING        (1 << 5)\n#define  MAX77620_CNFG_GPIO_DBNC_MASK         (0x3 << 6)\n#define  MAX77620_CNFG_GPIO_DBNC_None         (0x0 << 6)\n#define  MAX77620_CNFG_GPIO_DBNC_8ms          (0x1 << 6)\n#define  MAX77620_CNFG_GPIO_DBNC_16ms         (0x2 << 6)\n#define  MAX77620_CNFG_GPIO_DBNC_32ms         (0x3 << 6)\n#define  MAX77620_GPIO_OUTPUT_DISABLE         0\n#define  MAX77620_GPIO_OUTPUT_ENABLE          1\n\n#define MAX77620_REG_PUE_GPIO       0x3E // Gpio Pullup resistor enable.\n#define MAX77620_REG_PDE_GPIO       0x3F // Gpio Pulldown resistor enable.\n\n#define MAX77620_REG_AME_GPIO       0x40 // Gpio pinmuxing. Clear bits are Standard GPIO.\n\n#define MAX77620_REG_ONOFFCNFG1     0x41\n#define  MAX20024_ONOFFCNFG1_CLRSE            0x18\n#define  MAX77620_ONOFFCNFG1_PWR_OFF          BIT(1)\n#define  MAX77620_ONOFFCNFG1_SLPEN            BIT(2)\n#define  MAX77620_ONOFFCNFG1_MRT_SHIFT        0x3\n#define  MAX77620_ONOFFCNFG1_MRT_MASK         0x38\n#define  MAX77620_ONOFFCNFG1_RSVD             BIT(6)\n#define  MAX77620_ONOFFCNFG1_SFT_RST          BIT(7)\n\n#define MAX77620_REG_ONOFFCNFG2     0x42\n#define  MAX77620_ONOFFCNFG2_WK_EN0           BIT(0)\n#define  MAX77620_ONOFFCNFG2_WK_ALARM2        BIT(1)\n#define  MAX77620_ONOFFCNFG2_WK_ALARM1        BIT(2)\n#define  MAX77620_ONOFFCNFG2_WK_MBATT         BIT(3) // MBATT event generates a wakeup signal. use it in android/l4t?\n#define  MAX77620_ONOFFCNFG2_WK_ACOK          BIT(4)\n#define  MAX77620_ONOFFCNFG2_SLP_LPM_MSK      BIT(5)\n#define  MAX77620_ONOFFCNFG2_WD_RST_WK        BIT(6)\n#define  MAX77620_ONOFFCNFG2_SFT_RST_WK       BIT(7)\n\n/* FPS Registers */\n#define MAX77620_REG_FPS_CFG0       0x43 // FPS0.\n#define MAX77620_REG_FPS_CFG1       0x44 // FPS1.\n#define MAX77620_REG_FPS_CFG2       0x45 // FPS2.\n#define  MAX77620_FPS_ENFPS_SW_MASK           0x01\n#define  MAX77620_FPS_ENFPS_SW                0x01\n#define  MAX77620_FPS_EN_SRC_SHIFT            1\n#define  MAX77620_FPS_EN_SRC_MASK             0x06\n#define  MAX77620_FPS_TIME_PERIOD_SHIFT       3\n#define  MAX77620_FPS_TIME_PERIOD_MASK        0x38\n\n#define MAX77620_REG_FPS_LDO0       0x46\n#define MAX77620_REG_FPS_LDO1       0x47\n#define MAX77620_REG_FPS_LDO2       0x48\n#define MAX77620_REG_FPS_LDO3       0x49\n#define MAX77620_REG_FPS_LDO4       0x4A\n#define MAX77620_REG_FPS_LDO5       0x4B\n#define MAX77620_REG_FPS_LDO6       0x4C\n#define MAX77620_REG_FPS_LDO7       0x4D\n#define MAX77620_REG_FPS_LDO8       0x4E\n#define MAX77620_REG_FPS_SD0        0x4F\n#define MAX77620_REG_FPS_SD1        0x50\n#define MAX77620_REG_FPS_SD2        0x51\n#define MAX77620_REG_FPS_SD3        0x52\n#define MAX77620_REG_FPS_SD4        0x53\n#define MAX77620_REG_FPS_GPIO1      0x54\n#define MAX77620_REG_FPS_GPIO2      0x55\n#define MAX77620_REG_FPS_GPIO3      0x56\n#define MAX77620_REG_FPS_RSO        0x57\n#define  MAX77620_FPS_PD_PERIOD_SHIFT         0\n#define  MAX77620_FPS_PD_PERIOD_MASK          0x07\n#define  MAX77620_FPS_PU_PERIOD_SHIFT         3\n#define  MAX77620_FPS_PU_PERIOD_MASK          0x38\n#define  MAX77620_FPS_SRC_SHIFT               6\n#define  MAX77620_FPS_SRC_MASK                0xC0\n\n#define MAX77620_FPS_COUNT 3\n#define MAX77620_FPS_PERIOD_MIN_US 40\n#define MAX77620_FPS_PERIOD_MAX_US 2560\n\n#define MAX77620_REG_CID0           0x58\n#define MAX77620_REG_CID1           0x59\n#define MAX77620_REG_CID2           0x5A\n#define MAX77620_REG_CID3           0x5B\n#define MAX77620_REG_CID4           0x5C // OTP version.\n#define MAX77620_REG_CID5           0x5D // ES version.\n#define  MAX77620_CID_DIDO_MASK               0xF\n#define  MAX77620_CID_DIDO_SHIFT              0\n#define  MAX77620_CID_DIDM_MASK               0xF0\n#define  MAX77620_CID_DIDM_SHIFT              4\n\n/* Device Identification Metal */\n#define MAX77620_CID5_DIDM(n) (((n) >> 4) & 0xF)\n/* Device Indentification OTP */\n#define MAX77620_CID5_DIDO(n) ((n) & 0xF)\n\n#define MAX77620_REG_DVSSD4         0x5E\n#define MAX20024_REG_MAX_ADD        0x70\n\n#define MAX77620_IRQ_LVL2_GPIO_EDGE0          BIT(0)\n#define MAX77620_IRQ_LVL2_GPIO_EDGE1          BIT(1)\n#define MAX77620_IRQ_LVL2_GPIO_EDGE2          BIT(2)\n#define MAX77620_IRQ_LVL2_GPIO_EDGE3          BIT(3)\n#define MAX77620_IRQ_LVL2_GPIO_EDGE4          BIT(4)\n#define MAX77620_IRQ_LVL2_GPIO_EDGE5          BIT(5)\n#define MAX77620_IRQ_LVL2_GPIO_EDGE6          BIT(6)\n#define MAX77620_IRQ_LVL2_GPIO_EDGE7          BIT(7)\n\n/* Interrupts */\nenum {\n\tMAX77620_IRQ_TOP_GLBL,\t\t/* Low-Battery */\n\tMAX77620_IRQ_TOP_SD,\t\t/* SD power fail */\n\tMAX77620_IRQ_TOP_LDO,\t\t/* LDO power fail */\n\tMAX77620_IRQ_TOP_GPIO,\t\t/* TOP GPIO internal int to MAX77620 */\n\tMAX77620_IRQ_TOP_RTC,\t\t/* RTC */\n\tMAX77620_IRQ_TOP_32K,\t\t/* 32kHz oscillator */\n\tMAX77620_IRQ_TOP_ONOFF,\t\t/* ON/OFF oscillator */\n\tMAX77620_IRQ_LBT_MBATLOW,\t/* Thermal alarm status, > 120C */\n\tMAX77620_IRQ_LBT_TJALRM1,\t/* Thermal alarm status, > 120C */\n\tMAX77620_IRQ_LBT_TJALRM2,\t/* Thermal alarm status, > 140C */\n};\n\n/* GPIOs */\nenum {\n\tMAX77620_GPIO0,\n\tMAX77620_GPIO1,\n\tMAX77620_GPIO2,\n\tMAX77620_GPIO3,\n\tMAX77620_GPIO4,\n\tMAX77620_GPIO5,\n\tMAX77620_GPIO6,\n\tMAX77620_GPIO7,\n\tMAX77620_GPIO_NR,\n};\n\n/* FPS Source */\nenum max77620_fps_src {\n\tMAX77620_FPS_SRC_0,\n\tMAX77620_FPS_SRC_1,\n\tMAX77620_FPS_SRC_2,\n\tMAX77620_FPS_SRC_NONE,\n\tMAX77620_FPS_SRC_DEF,\n};\n\n#endif /* _MFD_MAX77620_H_ */\n"
  },
  {
    "path": "bdk/power/max7762x.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2019-2020 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <power/max7762x.h>\n#include <power/max77620.h>\n#include <power/max77812.h>\n#include <soc/fuse.h>\n#include <soc/i2c.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n\n#define REGULATOR_SD  0\n#define REGULATOR_LDO 1\n#define REGULATOR_BC0 2\n#define REGULATOR_BC1 3\n\ntypedef struct _max77620_fps_t\n{\n\tu8 fps_addr;\n\tu8 fps_src;\n\tu8 pd_period;\n\tu8 pu_period;\n} max77620_fps_t;\n\ntypedef struct _max77621_ctrl_t\n{\n\tu8 ctrl1_por;\n\tu8 ctrl1_hos;\n\tu8 ctrl2_por;\n\tu8 ctrl2_hos;\n} max77621_ctrl_t;\n\ntypedef struct _max77812_ctrl_t\n{\n\tu8 mask;\n\tu8 shift;\n\tu8 rsvd0;\n\tu8 rsvd1;\n} max77812_en_t;\n\ntypedef struct _max77620_regulator_t\n{\n\tconst char *name;\n\n\tu32 uv_step;\n\tu32 uv_min;\n\tu32 uv_default;\n\tu32 uv_max;\n\n\tu8 type;\n\tu8 volt_addr;\n\tu8 cfg_addr;\n\tu8 volt_mask;\n\n\tunion {\n\t\tmax77620_fps_t fps;\n\t\tmax77621_ctrl_t ctrl;\n\t\tmax77812_en_t enable;\n\t};\n} max77620_regulator_t;\n\nstatic const max77620_regulator_t _pmic_regulators[] = {\n\t{  \"sd0\",  12500, 600000,  625000, 1400000,  REGULATOR_SD,  MAX77620_REG_SD0,      MAX77620_REG_SD0_CFG,    MAX77620_SD0_VOLT_MASK,  {{ MAX77620_REG_FPS_SD0,  1, 7, 1 }} },\n\t{  \"sd1\",  12500, 600000, 1125000, 1237500,  REGULATOR_SD,  MAX77620_REG_SD1,      MAX77620_REG_SD1_CFG,    MAX77620_SD1_VOLT_MASK,  {{ MAX77620_REG_FPS_SD1,  0, 1, 5 }} },\n\t{  \"sd2\",  12500, 600000, 1325000, 1350000,  REGULATOR_SD,  MAX77620_REG_SD2,      MAX77620_REG_SD2_CFG,    MAX77620_SDX_VOLT_MASK,  {{ MAX77620_REG_FPS_SD2,  1, 5, 2 }} },\n\t{  \"sd3\",  12500, 600000, 1800000, 1800000,  REGULATOR_SD,  MAX77620_REG_SD3,      MAX77620_REG_SD3_CFG,    MAX77620_SDX_VOLT_MASK,  {{ MAX77620_REG_FPS_SD3,  0, 3, 3 }} },\n\t{ \"ldo0\",  25000, 800000, 1200000, 1200000,  REGULATOR_LDO, MAX77620_REG_LDO0_CFG, MAX77620_REG_LDO0_CFG2,  MAX77620_LDO_VOLT_MASK,  {{ MAX77620_REG_FPS_LDO0, 3, 7, 0 }} },\n\t{ \"ldo1\",  25000, 800000, 1050000, 1050000,  REGULATOR_LDO, MAX77620_REG_LDO1_CFG, MAX77620_REG_LDO1_CFG2,  MAX77620_LDO_VOLT_MASK,  {{ MAX77620_REG_FPS_LDO1, 3, 7, 0 }} },\n\t{ \"ldo2\",  50000, 800000, 1800000, 3300000,  REGULATOR_LDO, MAX77620_REG_LDO2_CFG, MAX77620_REG_LDO2_CFG2,  MAX77620_LDO_VOLT_MASK,  {{ MAX77620_REG_FPS_LDO2, 3, 7, 0 }} },\n\t{ \"ldo3\",  50000, 800000, 3100000, 3100000,  REGULATOR_LDO, MAX77620_REG_LDO3_CFG, MAX77620_REG_LDO3_CFG2,  MAX77620_LDO_VOLT_MASK,  {{ MAX77620_REG_FPS_LDO3, 3, 7, 0 }} },\n\t{ \"ldo4\",  12500, 800000,  850000, 1000000,  REGULATOR_LDO, MAX77620_REG_LDO4_CFG, MAX77620_REG_LDO4_CFG2,  MAX77620_LDO_VOLT_MASK,  {{ MAX77620_REG_FPS_LDO4, 0, 7, 1 }} },\n\t{ \"ldo5\",  50000, 800000, 1800000, 1800000,  REGULATOR_LDO, MAX77620_REG_LDO5_CFG, MAX77620_REG_LDO5_CFG2,  MAX77620_LDO_VOLT_MASK,  {{ MAX77620_REG_FPS_LDO5, 3, 7, 0 }} },\n\t{ \"ldo6\",  50000, 800000, 2900000, 2900000,  REGULATOR_LDO, MAX77620_REG_LDO6_CFG, MAX77620_REG_LDO6_CFG2,  MAX77620_LDO_VOLT_MASK,  {{ MAX77620_REG_FPS_LDO6, 3, 7, 0 }} },\n\t{ \"ldo7\",  50000, 800000, 1050000, 1050000,  REGULATOR_LDO, MAX77620_REG_LDO7_CFG, MAX77620_REG_LDO7_CFG2,  MAX77620_LDO_VOLT_MASK,  {{ MAX77620_REG_FPS_LDO7, 1, 4, 3 }} },\n\t{ \"ldo8\",  50000, 800000, 1050000, 2800000,  REGULATOR_LDO, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2,  MAX77620_LDO_VOLT_MASK,  {{ MAX77620_REG_FPS_LDO8, 3, 7, 0 }} },\n\n\t{ \"max77621_CPU\", 6250, 606250, 1000000, 1400000,  REGULATOR_BC0, MAX77621_REG_VOUT,    MAX77621_REG_VOUT_DVS,  MAX77621_DVC_DVS_VOLT_MASK, {{ MAX77621_CPU_CTRL1_POR_DEFAULT, MAX77621_CPU_CTRL1_HOS_DEFAULT, MAX77621_CPU_CTRL2_POR_DEFAULT, MAX77621_CPU_CTRL2_HOS_DEFAULT }} },\n\t{ \"max77621_GPU\", 6250, 606250, 1200000, 1400000,  REGULATOR_BC0, MAX77621_REG_VOUT,    MAX77621_REG_VOUT_DVS,  MAX77621_DVC_DVS_VOLT_MASK, {{ MAX77621_CPU_CTRL1_POR_DEFAULT, MAX77621_CPU_CTRL1_HOS_DEFAULT, MAX77621_CPU_CTRL2_POR_DEFAULT, MAX77621_CPU_CTRL2_HOS_DEFAULT }} },\n\t{ \"max77812_CPU\", 5000, 250000,  600000, 1525000,  REGULATOR_BC1, MAX77812_REG_M4_VOUT, MAX77812_REG_EN_CTRL,   MAX77812_BUCK_VOLT_MASK,    {{ MAX77812_EN_CTRL_EN_M4_MASK, MAX77812_EN_CTRL_EN_M4_SHIFT, 0, 0 }} },\n\t{ \"max77812_RAM\", 5000, 250000,  600000,  650000,  REGULATOR_BC1, MAX77812_REG_M3_VOUT, MAX77812_REG_EN_CTRL,   MAX77812_BUCK_VOLT_MASK,    {{ MAX77812_EN_CTRL_EN_M3_MASK, MAX77812_EN_CTRL_EN_M3_SHIFT, 0, 0 }} } // Only on PHASE211 configuration.\n\t//{ \"max77812_GPU\", 5000, 250000,  600000, 1525000,  REGULATOR_BC1, MAX77812_REG_M1_VOUT, MAX77812_REG_EN_CTRL,   MAX77812_BUCK_VOLT_MASK,    {{ MAX77812_EN_CTRL_EN_M1_MASK, MAX77812_EN_CTRL_EN_M1_SHIFT, 0, 0 }} },\n};\n\nstatic u8 _max77812_get_address()\n{\n\tstatic u8 max77812_i2c_addr = 0;\n\n\tif (max77812_i2c_addr)\n\t\treturn max77812_i2c_addr;\n\n\tmax77812_i2c_addr =\n\t\t!(FUSE(FUSE_RESERVED_ODM28_B01) & 1) ? MAX77812_PHASE31_CPU_I2C_ADDR : MAX77812_PHASE211_CPU_I2C_ADDR;\n\n\treturn max77812_i2c_addr;\n}\n\nstatic u8 _max7762x_get_i2c_address(u32 id)\n{\n\tconst max77620_regulator_t *reg = &_pmic_regulators[id];\n\n\t// Choose the correct i2c address.\n\tswitch (reg->type)\n\t{\n\tcase REGULATOR_SD:\n\tcase REGULATOR_LDO:\n\t\treturn MAX77620_I2C_ADDR;\n\tcase REGULATOR_BC0:\n\t\treturn (id == REGULATOR_CPU0 ? MAX77621_CPU_I2C_ADDR : MAX77621_GPU_I2C_ADDR);\n\tcase REGULATOR_BC1:\n\t\t{\n\t\tu8 reg_addr = _max77812_get_address();\n\t\tif (id == REGULATOR_RAM0 && reg_addr == MAX77812_PHASE31_CPU_I2C_ADDR)\n\t\t\treg_addr = 0;\n\t\treturn reg_addr;\n\t\t}\n\tdefault:\n\t\treturn 0;\n\t}\n}\n\nstatic void _max7762x_set_reg(u8 addr, u8 reg, u8 val)\n{\n\tu32 retries = 100;\n\twhile (retries)\n\t{\n\t\tif (!i2c_send_byte(I2C_5, addr, reg, val))\n\t\t\tbreak;\n\n\t\tusleep(50);\n\t\tretries--;\n\t}\n}\n\nint max77620_regulator_get_status(u32 id)\n{\n\tif (id > REGULATOR_LDO8)\n\t\treturn 0;\n\n\tconst max77620_regulator_t *reg = &_pmic_regulators[id];\n\n\t// SD power OK status.\n\tif (reg->type == REGULATOR_SD)\n\t{\n\t\tu8 mask = 1u << (7 - id);\n\t\treturn (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_STATSD) & mask) ? 0 : 1;\n\t}\n\n\t// LDO power OK status.\n\treturn (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg->cfg_addr) & MAX77620_LDO_CFG2_POK_MASK) ? 1 : 0;\n}\n\nint max77620_regulator_config_fps(u32 id)\n{\n\tif (id > REGULATOR_LDO8)\n\t\treturn 1;\n\n\tconst max77620_regulator_t *reg = &_pmic_regulators[id];\n\n\t// Set FPS configuration.\n\t_max7762x_set_reg(MAX77620_I2C_ADDR,\n\t\treg->fps.fps_addr,\n\t\t(reg->fps.fps_src   << MAX77620_FPS_SRC_SHIFT)       |\n\t\t(reg->fps.pu_period << MAX77620_FPS_PU_PERIOD_SHIFT) |\n\t\t(reg->fps.pd_period << MAX77620_FPS_PD_PERIOD_SHIFT));\n\n\treturn 0;\n}\n\nint max7762x_regulator_set_voltage(u32 id, u32 uv)\n{\n\tif (id > REGULATOR_MAX)\n\t\treturn 1;\n\n\tconst max77620_regulator_t *reg = &_pmic_regulators[id];\n\n\tif (uv < reg->uv_min || uv > reg->uv_max)\n\t\treturn 1;\n\n\tu8 addr = _max7762x_get_i2c_address(id);\n\tif (!addr)\n\t\treturn 1;\n\n\t// Calculate voltage multiplier.\n\tu32 mult = (uv + reg->uv_step - 1 - reg->uv_min) / reg->uv_step;\n\tu8 val = i2c_recv_byte(I2C_5, addr, reg->volt_addr);\n\tval = (val & ~reg->volt_mask) | (mult & reg->volt_mask);\n\n\t// Set voltage.\n\t_max7762x_set_reg(addr, reg->volt_addr, val);\n\n\t// If max77621 set DVS voltage also.\n\tif (reg->type == REGULATOR_BC0)\n\t\t_max7762x_set_reg(addr, reg->cfg_addr, MAX77621_VOUT_ENABLE_MASK | val);\n\n\t// Wait for ramp up/down delay.\n\tusleep(1000);\n\n\treturn 0;\n}\n\nint max7762x_regulator_enable(u32 id, bool enable)\n{\n\tu8 reg_addr;\n\tu8 enable_val;\n\tu8 enable_mask;\n\tu8 enable_shift;\n\n\tif (id > REGULATOR_MAX)\n\t\treturn 1;\n\n\tconst max77620_regulator_t *reg = &_pmic_regulators[id];\n\n\t// Choose the correct i2c and register addresses and mask/shift for each type.\n\tswitch (reg->type)\n\t{\n\tcase REGULATOR_SD:\n\t\treg_addr     = reg->cfg_addr;\n\t\tenable_val   = MAX77620_POWER_MODE_NORMAL;\n\t\tenable_mask  = MAX77620_SD_POWER_MODE_MASK;\n\t\tenable_shift = MAX77620_SD_POWER_MODE_SHIFT;\n\t\tbreak;\n\tcase REGULATOR_LDO:\n\t\treg_addr     = reg->volt_addr;\n\t\tenable_val   = MAX77620_POWER_MODE_NORMAL;\n\t\tenable_mask  = MAX77620_LDO_POWER_MODE_MASK;\n\t\tenable_shift = MAX77620_LDO_POWER_MODE_SHIFT;\n\t\tbreak;\n\tcase REGULATOR_BC0:\n\t\treg_addr     = reg->volt_addr;\n\t\tenable_val   = MAX77621_VOUT_ENABLE;\n\t\tenable_mask  = MAX77621_DVC_DVS_ENABLE_MASK;\n\t\tenable_shift = MAX77621_DVC_DVS_ENABLE_SHIFT;\n\t\tbreak;\n\tcase REGULATOR_BC1:\n\t\treg_addr     = reg->cfg_addr;\n\t\tenable_val   = MAX77812_EN_CTRL_ENABLE;\n\t\tenable_mask  = reg->enable.mask;\n\t\tenable_shift = reg->enable.shift;\n\t\tbreak;\n\tdefault:\n\t\treturn 1;\n\t}\n\n\tu8 addr = _max7762x_get_i2c_address(id);\n\tif (!addr)\n\t\treturn 1;\n\n\t// Read and enable/disable.\n\tu8 val = i2c_recv_byte(I2C_5, addr, reg_addr);\n\tval &= ~enable_mask;\n\n\tif (enable)\n\t\tval |= (enable_val << enable_shift);\n\n\t// Set enable.\n\t_max7762x_set_reg(addr, reg_addr, val);\n\n\t// Wait for enable/disable ramp delay.\n\tusleep(1000);\n\n\treturn 0;\n}\n\nvoid max77620_config_gpio(u32 gpio_id, bool enable)\n{\n\tif (gpio_id > 7)\n\t\treturn;\n\n\t// Configure as standard GPIO.\n\tu8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO);\n\ti2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO, val & ~BIT(gpio_id));\n\n\t// Set GPIO configuration.\n\tif (enable)\n\t\tval = MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH | MAX77620_CNFG_GPIO_DIR_OUTPUT | MAX77620_CNFG_GPIO_DRV_PUSHPULL;\n\telse\n\t\tval = MAX77620_CNFG_GPIO_DIR_INPUT | MAX77620_CNFG_GPIO_DRV_OPENDRAIN;\n\ti2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO0 + gpio_id, val);\n}\n\nvoid max77621_config_default(u32 id, bool por)\n{\n\tconst max77620_regulator_t *reg = &_pmic_regulators[id];\n\n\tif (reg->type != REGULATOR_BC0)\n\t\treturn;\n\n\tu8 addr = _max7762x_get_i2c_address(id);\n\tif (!addr)\n\t\treturn;\n\n\tif (por)\n\t{\n\t\t// Set voltage and disable power before changing the inductor.\n\t\tmax7762x_regulator_set_voltage(id, 1000000);\n\t\tmax7762x_regulator_enable(id, false);\n\n\t\t// Configure to default.\n\t\ti2c_send_byte(I2C_5, addr, MAX77621_REG_CONTROL1, reg->ctrl.ctrl1_por);\n\t\ti2c_send_byte(I2C_5, addr, MAX77621_REG_CONTROL2, reg->ctrl.ctrl2_por);\n\t}\n\telse\n\t{\n\t\ti2c_send_byte(I2C_5, addr, MAX77621_REG_CONTROL1, reg->ctrl.ctrl1_hos);\n\t\ti2c_send_byte(I2C_5, addr, MAX77621_REG_CONTROL2, reg->ctrl.ctrl2_hos);\n\t}\n}\n\nvoid max77620_config_default()\n{\n\t// Check if Erista OTP.\n\tif (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CID4) != 0x35)\n\t\treturn;\n\n\t// Set default voltages and enable regulators.\n\tfor (u32 i = REGULATOR_SD1; i <= REGULATOR_LDO8; i++)\n\t{\n\t\tmax77620_regulator_config_fps(i);\n\t\tmax7762x_regulator_set_voltage(i, _pmic_regulators[i].uv_default);\n\t\tif (_pmic_regulators[i].fps.fps_src != MAX77620_FPS_SRC_NONE)\n\t\t\tmax7762x_regulator_enable(i, true);\n\t}\n\n\t// Enable SD0 output voltage sense and disable for SD1. Additionally disable the reserved bit.\n\t_max7762x_set_reg(MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, MAX77620_SD_CNF2_ROVS_EN_SD0);\n}\n\n// Stock HOS: disabled.\nvoid max77620_low_battery_monitor_config(bool enable)\n{\n\t_max7762x_set_reg(MAX77620_I2C_ADDR, MAX77620_REG_CNFGGLBL1,\n\t\tMAX77620_CNFGGLBL1_LBDAC_EN             |\n\t\t(enable ? MAX77620_CNFGGLBL1_MPPLD : 0) |\n\t\tMAX77620_CNFGGLBL1_LBHYST_200           |\n\t\tMAX77620_CNFGGLBL1_LBDAC_2800);\n}\n"
  },
  {
    "path": "bdk/power/max7762x.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2019-2020 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _MAX7762X_H_\n#define _MAX7762X_H_\n\n#include <utils/types.h>\n\n/*\n * SDx actual min is 625 mV. Multipliers 0/1 reserved.\n * SD0 max is 1400 mV\n * SD1 max is 1550 mV\n * SD2 max is 3787.5 mV\n * SD3 max is 3787.5 mV\n */\n\n/*\n* Switch Power domains (max77620):\n* Name  | Usage         | uV step | uV min | uV default | uV max  | Init\n*-------+---------------+---------+--------+------------+---------+------------------\n*  sd0  | SoC           | 12500   | 600000 |  625000    | 1400000 | 1.125V (pkg1.1)\n*  sd1  | SDRAM         | 12500   | 600000 | 1125000    | 1125000 | 1.1V   (pkg1.1)\n*  sd2  | ldo{0-1, 7-8} | 12500   | 600000 | 1325000    | 1350000 | 1.325V (pcv)\n*  sd3  | 1.8V general  | 12500   | 600000 | 1800000    | 1800000 |\n*  ldo0 | Display Panel | 25000   | 800000 | 1200000    | 1200000 | 1.2V   (pkg1.1)\n*  ldo1 | XUSB, PCIE    | 25000   | 800000 | 1050000    | 1050000 | 1.05V  (pcv)\n*  ldo2 | SDMMC1        | 50000   | 800000 | 1800000    | 3300000 |\n*  ldo3 | GC ASIC       | 50000   | 800000 | 3100000    | 3100000 | 3.1V   (pcv)\n*  ldo4 | RTC           | 12500   | 800000 |  850000    |  850000 | 0.85V  (AO, pcv)\n*  ldo5 | GC Card       | 50000   | 800000 | 1800000    | 1800000 | 1.8V   (pcv)\n*  ldo6 | Touch, ALS    | 50000   | 800000 | 2900000    | 2900000 | 2.9V   (pcv)\n*  ldo7 | XUSB          | 50000   | 800000 | 1050000    | 1050000 | 1.05V  (pcv)\n*  ldo8 | XUSB, DP, MCU | 50000   | 800000 | 1050000    | 2800000 | 1.05V/2.8V (pcv)\n*/\n\n\n// GPIOs T210: 3: 3.3V, 5: CPU PMIC, 6: GPU PMIC, 7: DSI/VI 1.2V powered by ldo0.\n\n/*\n * OTP:  T210 - T210B01:\n * SD0:  1.0V   1.05V - SoC. EN Based on FPSSRC.\n * SD1:  1.15V  1.1V  - DRAM for T210. EN Based on FPSSRC.\n * SD2:  1.35V  1.35V\n * SD3:  1.8V   1.8V\n * All powered off?\n * LDO0:   --   --    - Display\n * LDO1: 1.05V  1.05V\n * LDO2:   --   --    - SD\n * LDO3: 3.1V   3.1V  - GC ASIC\n * LDO4: 1.0V   0.8V  - Needed for RTC domain on T210.\n * LDO5: 3.1V   3.1V\n * LDO6: 2.8V   2.9V  - Touch.\n * LDO7: 1.05V  1.0V\n * LDO8: 1.05V  1.0V\n */\n\n/*\n* MAX77620_AME_GPIO: control GPIO modes (bits 0 - 7 correspond to GPIO0 - GPIO7); 0 -> GPIO, 1 -> alt-mode\n* MAX77620_REG_GPIOx: 0x9 sets output and enable\n*/\n\n/*! MAX77620 partitions. */\n#define REGULATOR_SD0  0\n#define REGULATOR_SD1  1\n#define REGULATOR_SD2  2\n#define REGULATOR_SD3  3\n#define REGULATOR_LDO0 4\n#define REGULATOR_LDO1 5\n#define REGULATOR_LDO2 6\n#define REGULATOR_LDO3 7\n#define REGULATOR_LDO4 8\n#define REGULATOR_LDO5 9\n#define REGULATOR_LDO6 10\n#define REGULATOR_LDO7 11\n#define REGULATOR_LDO8 12\n#define REGULATOR_CPU0 13 // T210 CPU.\n#define REGULATOR_GPU0 14 // T210 CPU.\n#define REGULATOR_CPU1 15 // T210B01 CPU.\n#define REGULATOR_RAM0 16 // T210B01 RAM for PHASE211.\n//#define REGULATOR_GPU1 17 // T210B01 CPU.\n#define REGULATOR_MAX  REGULATOR_RAM0\n\n#define MAX77621_CPU_I2C_ADDR 0x1B\n#define MAX77621_GPU_I2C_ADDR 0x1C\n\n#define MAX77621_REG_VOUT     0x00\n#define MAX77621_REG_VOUT_DVS 0x01\n#define MAX77621_REG_CONTROL1 0x02\n#define MAX77621_REG_CONTROL2 0x03\n#define MAX77621_REG_CHIPID1  0x04\n#define MAX77621_REG_CHIPID2  0x05\n\n/* MAX77621_VOUT_DVC_DVS */\n#define MAX77621_DVC_DVS_VOLT_MASK    0x7F\n#define MAX77621_DVC_DVS_ENABLE_SHIFT 7\n#define MAX77621_DVC_DVS_ENABLE_MASK  (1 << MAX77621_DVC_DVS_ENABLE_SHIFT)\n\n/* MAX77621_VOUT */\n#define MAX77621_VOUT_DISABLE     0\n#define MAX77621_VOUT_ENABLE      1\n#define MAX77621_VOUT_ENABLE_MASK (MAX77621_VOUT_ENABLE << MAX77621_DVC_DVS_ENABLE_SHIFT)\n\n/* MAX77621_CONTROL1 */\n#define MAX77621_RAMP_12mV_PER_US  0x0\n#define MAX77621_RAMP_25mV_PER_US  0x1\n#define MAX77621_RAMP_50mV_PER_US  0x2\n#define MAX77621_RAMP_200mV_PER_US 0x3\n#define MAX77621_RAMP_MASK         0x3\n\n#define MAX77621_FREQSHIFT_9PER    BIT(2)\n#define MAX77621_BIAS_ENABLE       BIT(3)\n#define MAX77621_AD_ENABLE         BIT(4)\n#define MAX77621_NFSR_ENABLE       BIT(5)\n#define MAX77621_FPWM_EN_M         BIT(6)\n#define MAX77621_SNS_ENABLE        BIT(7)\n\n/* MAX77621_CONTROL2 */\n#define MAX77621_INDUCTOR_MIN_30_PER  0\n#define MAX77621_INDUCTOR_NOMINAL     1\n#define MAX77621_INDUCTOR_PLUS_30_PER 2\n#define MAX77621_INDUCTOR_PLUS_60_PER 3\n#define MAX77621_INDUCTOR_MASK        3\n\n#define MAX77621_CKKADV_TRIP_75mV_PER_US          (0  << 2)\n#define MAX77621_CKKADV_TRIP_150mV_PER_US         (1u << 2)\n#define MAX77621_CKKADV_TRIP_DISABLE              (3u << 2)\n#define MAX77621_CKKADV_TRIP_MASK                 (3u << 2)\n\n#define MAX77621_FT_ENABLE       BIT(4)\n#define MAX77621_DISCH_ENABLE    BIT(5)\n#define MAX77621_WDTMR_ENABLE    BIT(6)\n#define MAX77621_T_JUNCTION_120  BIT(7)\n\n#define MAX77621_CPU_CTRL1_POR_DEFAULT  (MAX77621_RAMP_50mV_PER_US)\n#define MAX77621_CPU_CTRL1_HOS_DEFAULT  (MAX77621_AD_ENABLE               | \\\n\t\t\t\t\t\t\t\t\t\t MAX77621_NFSR_ENABLE             | \\\n\t\t\t\t\t\t\t\t\t\t MAX77621_SNS_ENABLE              | \\\n\t\t\t\t\t\t\t\t\t\t MAX77621_RAMP_12mV_PER_US)\n#define MAX77621_CPU_CTRL2_POR_DEFAULT  (MAX77621_T_JUNCTION_120          | \\\n\t\t\t\t\t\t\t\t\t\t MAX77621_FT_ENABLE               | \\\n\t\t\t\t\t\t\t\t\t\t MAX77621_CKKADV_TRIP_DISABLE     | \\\n\t\t\t\t\t\t\t\t\t\t MAX77621_INDUCTOR_NOMINAL)\n#define MAX77621_CPU_CTRL2_HOS_DEFAULT  (MAX77621_T_JUNCTION_120          | \\\n\t\t\t\t\t\t\t\t\t\t MAX77621_WDTMR_ENABLE            | \\\n\t\t\t\t\t\t\t\t\t\t MAX77621_CKKADV_TRIP_75mV_PER_US | \\\n\t\t\t\t\t\t\t\t\t\t MAX77621_INDUCTOR_NOMINAL)\n\n#define MAX77621_CTRL_HOS_CFG 0\n#define MAX77621_CTRL_POR_CFG 1\n\nint  max77620_regulator_get_status(u32 id);\nint  max77620_regulator_config_fps(u32 id);\nint  max7762x_regulator_set_voltage(u32 id, u32 uv);\nint  max7762x_regulator_enable(u32 id, bool enable);\nvoid max77620_config_gpio(u32 id, bool enable);\nvoid max77620_config_default();\nvoid max77620_low_battery_monitor_config(bool enable);\n\nvoid max77621_config_default(u32 id, bool por);\n\n#endif\n"
  },
  {
    "path": "bdk/power/max77812.h",
    "content": "/*\n * Copyright (c) 2020 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _MAX77812_H_\n#define _MAX77812_H_\n\n#define MAX77812_PHASE31_CPU_I2C_ADDR  0x31 // High power GPU. 2 Outputs: 3-phase M1 + 1-phase M4.\n#define MAX77812_PHASE211_CPU_I2C_ADDR 0x33 // Low  power GPU. 3 Outputs: 2-phase M1 + 1-phase M3 + 1-phase M4.\n\n#define MAX77812_REG_RSET\t\t\t0x00\n#define MAX77812_REG_INT_SRC\t\t0x01\n#define MAX77812_REG_INT_SRC_M\t\t0x02\n#define MAX77812_REG_TOPSYS_INT\t\t0x03\n#define MAX77812_REG_TOPSYS_INT_M\t0x04\n#define MAX77812_REG_TOPSYS_STAT\t0x05\n#define MAX77812_REG_EN_CTRL\t\t0x06\n#define  MAX77812_EN_CTRL_ENABLE      1\n#define  MAX77812_EN_CTRL_EN_M1_SHIFT 0\n#define  MAX77812_EN_CTRL_EN_M1_MASK  (1 << MAX77812_EN_CTRL_EN_M1_SHIFT)\n#define  MAX77812_EN_CTRL_EN_M2_SHIFT 2\n#define  MAX77812_EN_CTRL_EN_M2_MASK  (1 << MAX77812_EN_CTRL_EN_M2_SHIFT)\n#define  MAX77812_EN_CTRL_EN_M3_SHIFT 4\n#define  MAX77812_EN_CTRL_EN_M3_MASK  (1 << MAX77812_EN_CTRL_EN_M3_SHIFT)\n#define  MAX77812_EN_CTRL_EN_M4_SHIFT 6\n#define  MAX77812_EN_CTRL_EN_M4_MASK  (1 << MAX77812_EN_CTRL_EN_M4_SHIFT)\n#define MAX77812_REG_STUP_DLY2\t\t0x07\n#define MAX77812_REG_STUP_DLY3\t\t0x08\n#define MAX77812_REG_STUP_DLY4\t\t0x09\n#define MAX77812_REG_SHDN_DLY1\t\t0x0A\n#define MAX77812_REG_SHDN_DLY2\t\t0x0B\n#define MAX77812_REG_SHDN_DLY3\t\t0x0C\n#define MAX77812_REG_SHDN_DLY4\t\t0x0D\n#define MAX77812_REG_WDTRSTB_DEB\t0x0E\n#define MAX77812_REG_GPI_FUNC\t\t0x0F\n#define MAX77812_REG_GPI_DEB1\t\t0x10\n#define MAX77812_REG_GPI_DEB2\t\t0x11\n#define MAX77812_REG_GPI_PD_CTRL\t0x12\n#define MAX77812_REG_PROT_CFG\t\t0x13\n#define MAX77812_REG_VERSION\t\t0x14\n#define MAX77812_REG_I2C_CFG\t\t0x15\n#define MAX77812_REG_BUCK_INT\t\t0x20\n#define MAX77812_REG_BUCK_INT_M\t\t0x21\n#define MAX77812_REG_BUCK_STAT\t\t0x22\n#define MAX77812_REG_M1_VOUT\t\t0x23 // GPU.\n#define MAX77812_REG_M2_VOUT\t\t0x24\n#define MAX77812_REG_M3_VOUT\t\t0x25 // DRAM on PHASE211.\n#define MAX77812_REG_M4_VOUT\t\t0x26 // CPU.\n#define MAX77812_REG_M1_VOUT_D\t\t0x27\n#define MAX77812_REG_M2_VOUT_D\t\t0x28\n#define MAX77812_REG_M3_VOUT_D\t\t0x29\n#define MAX77812_REG_M4_VOUT_D\t\t0x2A\n#define MAX77812_REG_M1_VOUT_S\t\t0x2B\n#define MAX77812_REG_M2_VOUT_S\t\t0x2C\n#define MAX77812_REG_M3_VOUT_S\t\t0x2D\n#define MAX77812_REG_M4_VOUT_S\t\t0x2E\n#define MAX77812_REG_M1_CFG\t\t\t0x2F // HOS: M1_ILIM - 7.2A/4.8A.\n#define MAX77812_REG_M2_CFG\t\t\t0x30 // HOS: M2_ILIM - 7.2A/4.8A.\n#define MAX77812_REG_M3_CFG\t\t\t0x31 // HOS: M3_ILIM - 7.2A/4.8A.\n#define MAX77812_REG_M4_CFG\t\t\t0x32 // HOS: M4_ILIM - 7.2A/4.8A.\n#define MAX77812_REG_GLB_CFG1\t\t0x33 // HOS: B_SD_SR/B_SS_SR - 5mV/us.\n#define MAX77812_REG_GLB_CFG2\t\t0x34 // HOS: B_RD_SR/B_RU_SR - 5mV/us\n#define MAX77812_REG_GLB_CFG3\t\t0x35\n\n/*! Protected area and settings only for MAX77812_ES2_VERSION */\n#define MAX77812_REG_GLB_CFG4\t\t0x36 // QS: 0xBB.\n#define MAX77812_REG_GLB_CFG5\t\t0x37 // QS: 0x39. ES2: Set to 0x3E.\n#define MAX77812_REG_GLB_CFG6\t\t0x38 // QS: 0x88. ES2: Set to 0x90.\n#define MAX77812_REG_GLB_CFG7\t\t0x39 // QS: 0x04.\n#define MAX77812_REG_GLB_CFG8\t\t0x3A // QS: 0x3A. ES2: Set to 0x3A.\n\n#define MAX77812_REG_PROT_ACCESS\t0xFD // 0x00: Lock, 0x5A: Unlock.\n#define MAX77812_REG_UNKNOWN\t\t0xFE\n\n#define MAX77812_REG_EN_CTRL_MASK(n)\t\tBIT(n)\n#define MAX77812_START_SLEW_RATE_MASK\t\t0x07\n#define MAX77812_SHDN_SLEW_RATE_MASK\t\t0x70\n#define MAX77812_RAMPUP_SLEW_RATE_MASK\t\t0x07\n#define MAX77812_RAMPDOWN_SLEW_RATE_MASK\t0x70\n#define MAX77812_SLEW_RATE_SHIFT\t\t\t4\n\n#define MAX77812_OP_ACTIVE_DISCHARGE_MASK\tBIT(7)\n#define MAX77812_PEAK_CURRENT_LMT_MASK\t\t0x70\n#define MAX77812_SWITCH_FREQ_MASK\t\t\t0x0C\n#define MAX77812_FORCED_PWM_MASK\t\t\tBIT(1)\n#define MAX77812_SLEW_RATE_CNTRL_MASK\t\tBIT(0)\n#define MAX77812_START_SHD_DELAY_MASK\t\t0x1F\n#define MAX77812_VERSION_MASK\t\t\t\t0x07\n#define MAX77812_ES2_VERSION\t\t\t\t0x04\n#define MAX77812_QS_VERSION\t\t\t\t\t0x05\n\n#define MAX77812_BUCK_VOLT_MASK\t\t\t\t0xFF\n\n#endif\n"
  },
  {
    "path": "bdk/power/regulator_5v.c",
    "content": "/*\n * Copyright (c) 2019-2023 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <soc/fuse.h>\n#include <soc/gpio.h>\n#include <soc/hw_init.h>\n#include <soc/pinmux.h>\n#include <soc/pmc.h>\n#include <soc/t210.h>\n#include <utils/types.h>\n\nstatic u8 reg_5v_dev = 0;\nstatic bool usb_src = false;\n\nvoid regulator_5v_enable(u8 dev)\n{\n\tbool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210;\n\n\t// The power supply selection from battery or USB is automatic.\n\tif (!reg_5v_dev)\n\t{\n\t\t// Fan and Rail power from battery 5V regulator EN.\n\t\tPINMUX_AUX(PINMUX_AUX_SATA_LED_ACTIVE) = 1;\n\t\tgpio_direction_output(GPIO_PORT_A, GPIO_PIN_5, GPIO_HIGH);\n\n\t\t// Only Icosa has USB 5V VBUS rails.\n\t\tif (tegra_t210)\n\t\t{\n\t\t\t// Fan and Rail power from USB 5V VBUS EN.\n\t\t\tPINMUX_AUX(PINMUX_AUX_USB_VBUS_EN0) = PINMUX_LPDR | 1;\n\t\t\tgpio_direction_output(GPIO_PORT_CC, GPIO_PIN_4, GPIO_LOW);\n\t\t}\n\n\t\t// Make sure GPIO IO power is enabled.\n\t\tPMC(APBDEV_PMC_NO_IOPOWER) &= ~PMC_NO_IOPOWER_GPIO;\n\t\t(void)PMC(APBDEV_PMC_NO_IOPOWER); // Commit write.\n\n\t\t// Inform GPIO IO pads that we switched to 1.8V.\n\t\tPMC(APBDEV_PMC_PWR_DET_VAL) &= ~PMC_PWR_DET_33V_GPIO;\n\t\t(void)PMC(APBDEV_PMC_PWR_DET_VAL); // Commit write.\n\n\t\tusb_src = false;\n\t}\n\treg_5v_dev |= dev;\n}\n\nvoid regulator_5v_disable(u8 dev)\n{\n\tbool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210;\n\n\treg_5v_dev &= ~dev;\n\n\tif (!reg_5v_dev)\n\t{\n\t\t// Rail power from battery 5V regulator.\n\t\tgpio_write(GPIO_PORT_A, GPIO_PIN_5, GPIO_LOW);\n\n\t\t// Only Icosa has USB 5V VBUS rails.\n\t\tif (tegra_t210)\n\t\t{\n\t\t\t// Rail power from USB 5V VBUS.\n\t\t\tgpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_LOW);\n\t\t\tusb_src = false;\n\n\t\t}\n\t}\n}\n\nbool regulator_5v_get_dev_enabled(u8 dev)\n{\n\treturn (reg_5v_dev & dev);\n}\n\nvoid regulator_5v_usb_src_enable(bool enable)\n{\n\t// Only for Icosa.\n\tif (hw_get_chip_id() != GP_HIDREV_MAJOR_T210)\n\t\treturn;\n\n\tif (enable && !usb_src)\n\t{\n\t\tgpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_HIGH);\n\t\tusb_src = true;\n\t}\n\telse if (!enable && usb_src)\n\t{\n\t\tgpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_LOW);\n\t\tusb_src = false;\n\t}\n}\n"
  },
  {
    "path": "bdk/power/regulator_5v.h",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _REGULATOR_5V_H_\n#define _REGULATOR_5V_H_\n\n#include <utils/types.h>\n\nenum\n{\n\tREGULATOR_5V_FAN  = BIT(0),\n\tREGULATOR_5V_JC_R = BIT(1),\n\tREGULATOR_5V_JC_L = BIT(2),\n\tREGULATOR_5V_ALL  = 0xFF\n};\n\nvoid regulator_5v_enable(u8 dev);\nvoid regulator_5v_disable(u8 dev);\nbool regulator_5v_get_dev_enabled(u8 dev);\nvoid regulator_5v_usb_src_enable(bool enable);\n\n#endif"
  },
  {
    "path": "bdk/rtc/max77620-rtc.c",
    "content": "/*\n * PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC\n *\n * Copyright (c) 2018-2025 CTCaer\n * Copyright (c) 2019 shchmue\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <rtc/max77620-rtc.h>\n#include <soc/i2c.h>\n#include <soc/pmc.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n\nbool auto_dst     = false;\nint  epoch_offset = 0;\n\nvoid max77620_rtc_prep_read()\n{\n\ti2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE);\n}\n\nvoid max77620_rtc_get_time(rtc_time_t *time)\n{\n\tu8 val = 0;\n\n\t// Update RTC regs from RTC clock.\n\ti2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE);\n\n\t// Get control reg config.\n\tval = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_CONTROL_REG);\n\t// TODO: Make also sure it's binary format?\n\n\t// Get time.\n\ttime->sec  = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG)  & 0x7F;\n\ttime->min  = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG)  & 0x7F;\n\tu8 hour    = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG) & 0x1F;\n\ttime->hour = hour & 0x1F;\n\n\tif (!(val & MAX77620_RTC_24H))\n\t{\n\t\ttime->hour = hour & 0xF;\n\t\tif (hour & MAX77620_RTC_HOUR_PM_MASK)\n\t\t\ttime->hour += 12;\n\t}\n\n\t// Get day of week. 1: Monday to 7: Sunday.\n\ttime->weekday = 0;\n\tval = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_WEEKDAY_REG) & 0x7F;\n\tfor (int i = 0; i < 8; i++)\n\t{\n\t\ttime->weekday++;\n\t\tif (val & 1)\n\t\t\tbreak;\n\t\tval >>= 1;\n\t}\n\n\t// Get date.\n\ttime->day   = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DAY_REG) & 0x1F;\n\ttime->month = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MONTH_REG) & 0xF) - 1;\n\ttime->month++; // Normally minus 1, but everything else expects 1 as January.\n\ttime->year  = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_YEAR_REG) & 0x7F) + 2000;\n}\n\nvoid max77620_rtc_stop_alarm()\n{\n\tu8 val = 0;\n\n\t// Update RTC regs from RTC clock.\n\ti2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE);\n\tmsleep(16);\n\n\t// Stop alarm for both ALARM1 and ALARM2. Horizon uses ALARM2.\n\tfor (int i = 0; i < (MAX77620_RTC_NR_TIME_REGS * 2); i++)\n\t{\n\t\tval = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_SEC_REG + i);\n\t\tval &= ~MAX77620_RTC_ALARM_EN_MASK;\n\t\ti2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_SEC_REG + i, val);\n\t}\n\n\t// Update RTC clock from RTC regs.\n\ti2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_WRITE_UPDATE);\n}\n\nvoid max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time)\n{\n\tu32 tmp, edays, year, month, day;\n\n\t// Set time.\n\ttime->sec  = epoch % 60;\n\tepoch /= 60;\n\ttime->min  = epoch % 60;\n\tepoch /= 60;\n\ttime->hour = epoch % 24;\n\tepoch /= 24;\n\n\t// Calculate base date values.\n\ttmp = (u32)(((u64)4 * epoch + 102032) / 146097 + 15);\n\ttmp = (u32)((u64)epoch + 2442113 + tmp - (tmp >> 2));\n\n\tyear = (20 * tmp - 2442) / 7305;\n\tedays = tmp - 365 * year - (year >> 2);\n\tmonth = edays * 1000 / 30601;\n\tday = edays - month * 30 - month * 601 / 1000;\n\n\t// Month/Year offset.\n\tif (month < 14)\n\t{\n\t\tyear -= 4716;\n\t\tmonth--;\n\t}\n\telse\n\t{\n\t\tyear  -= 4715;\n\t\tmonth -= 13;\n\t}\n\n\t// Set date.\n\ttime->year = year;\n\ttime->month = month;\n\ttime->day = day;\n\n\t// Set weekday.\n\ttime->weekday = (day + 4) % 7;\n}\n\nu32 max77620_rtc_date_to_epoch(const rtc_time_t *time)\n{\n\tu32 year, month, epoch;\n\n\t//Year\n\tyear = time->year;\n\t//Month of year\n\tmonth = time->month;\n\n\t// Month/Year offset.\n\tif (month < 3)\n\t{\n\t\tmonth += 12;\n\t\tyear--;\n\t}\n\n\tepoch  = (365 * year) + (year >> 2) - (year / 100) + (year / 400); // Years to days.\n\n\tepoch += (30 * month) + (3 * (month + 1) / 5) + time->day; // Months to days.\n\tepoch -= 719561; // Epoch time is 1/1/1970.\n\n\tepoch *= 86400; // Days to seconds.\n\tepoch += (3600 * time->hour) + (60 * time->min) + time->sec; // Add hours, minutes and seconds.\n\n\treturn epoch;\n}\n\nvoid max77620_rtc_get_time_adjusted(rtc_time_t *time)\n{\n\tmax77620_rtc_get_time(time);\n\tif (epoch_offset)\n\t{\n\t\tu32 epoch = (u32)((s64)max77620_rtc_date_to_epoch(time) + epoch_offset);\n\n\t\t// Adjust for DST between 28 march and 28 october. Good enough to cover all years as week info is not valid.\n\t\tu16 md = (time->month << 8) | time->day;\n\t\tif (auto_dst && md >= 0x31C && md < 0xA1C)\n\t\t\tepoch += 3600;\n\n\t\tmax77620_rtc_epoch_to_date(epoch, time);\n\t}\n}\n\nvoid max77620_rtc_set_auto_dst(bool enable)\n{\n\tauto_dst = enable;\n}\n\nvoid max77620_rtc_set_epoch_offset(int offset)\n{\n\tepoch_offset = offset;\n}\n\nvoid max77620_rtc_set_reboot_reason(rtc_reboot_reason_t *rr)\n{\n\tmax77620_rtc_stop_alarm();\n\n\t// Set reboot reason.\n\ti2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_YEAR_REG, rr->enc.val1);\n\ti2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM2_YEAR_REG, rr->enc.val2);\n\n\t// Set reboot reason magic.\n\ti2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_WEEKDAY_REG, RTC_REBOOT_REASON_MAGIC);\n\ti2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM2_WEEKDAY_REG, RTC_REBOOT_REASON_MAGIC);\n\n\t// Update RTC clock from RTC regs.\n\ti2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_WRITE_UPDATE);\n\tmsleep(16);\n}\n\nbool max77620_rtc_get_reboot_reason(rtc_reboot_reason_t *rr)\n{\n\tu8 magic[2];\n\n\t// Get reboot reason magic.\n\tmagic[0] = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_WEEKDAY_REG);\n\tmagic[1] = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM2_WEEKDAY_REG);\n\n\t// Magic must be correct and match on both registers.\n\tif (magic[0] != RTC_REBOOT_REASON_MAGIC || magic[0] != magic[1])\n\t\treturn false;\n\n\t// Reboot reason setter is expected to have updated the actual regs already.\n\trr->enc.val1 = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_YEAR_REG);\n\trr->enc.val2 = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM2_YEAR_REG);\n\n\t// Clear magic and update actual regs.\n\ti2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_WEEKDAY_REG, 0);\n\ti2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM2_WEEKDAY_REG, 0);\n\ti2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_WRITE_UPDATE);\n\n\t// Return reboot reason. False if [config] was selected.\n\treturn true;\n}\n"
  },
  {
    "path": "bdk/rtc/max77620-rtc.h",
    "content": "/*\n * PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC\n *\n * Copyright (c) 2018-2022 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _MFD_MAX77620_RTC_H_\n#define _MFD_MAX77620_RTC_H_\n\n#include <utils/types.h>\n\n#define MAX77620_RTC_I2C_ADDR       0x68\n\n#define MAX77620_RTC_NR_TIME_REGS   7\n\n#define MAX77620_RTC_RTCINT_REG     0x00\n#define MAX77620_RTC_RTCINTM_REG    0x01\n#define MAX77620_RTC_CONTROLM_REG   0x02\n#define MAX77620_RTC_CONTROL_REG    0x03\n#define  MAX77620_RTC_BIN_FORMAT    BIT(0)\n#define  MAX77620_RTC_24H           BIT(1)\n\n#define MAX77620_RTC_UPDATE0_REG    0x04\n#define  MAX77620_RTC_WRITE_UPDATE  BIT(0)\n#define  MAX77620_RTC_READ_UPDATE   BIT(4)\n\n#define MAX77620_RTC_UPDATE1_REG    0x05\n#define MAX77620_RTC_RTCSMPL_REG    0x06\n\n#define MAX77620_RTC_SEC_REG        0x07\n#define MAX77620_RTC_MIN_REG        0x08\n#define MAX77620_RTC_HOUR_REG       0x09\n#define  MAX77620_RTC_HOUR_PM_MASK  BIT(6)\n#define MAX77620_RTC_WEEKDAY_REG    0x0A\n#define MAX77620_RTC_MONTH_REG      0x0B\n#define MAX77620_RTC_YEAR_REG       0x0C\n#define MAX77620_RTC_DAY_REG        0x0D\n\n#define MAX77620_ALARM1_SEC_REG     0x0E\n#define MAX77620_ALARM1_MIN_REG     0x0F\n#define MAX77620_ALARM1_HOUR_REG    0x10\n#define MAX77620_ALARM1_WEEKDAY_REG 0x11\n#define MAX77620_ALARM1_MONTH_REG   0x12\n#define MAX77620_ALARM1_YEAR_REG    0x13\n#define MAX77620_ALARM1_DATE_REG    0x14\n#define MAX77620_ALARM2_SEC_REG     0x15\n#define MAX77620_ALARM2_MIN_REG     0x16\n#define MAX77620_ALARM2_HOUR_REG    0x17\n#define MAX77620_ALARM2_WEEKDAY_REG 0x18\n#define MAX77620_ALARM2_MONTH_REG   0x19\n#define MAX77620_ALARM2_YEAR_REG    0x1A\n#define MAX77620_ALARM2_DATE_REG    0x1B\n#define  MAX77620_RTC_ALARM_EN_MASK\tBIT(7)\n\ntypedef struct _rtc_time_t {\n\tu8  weekday;\n\tu8  sec;\n\tu8  min;\n\tu8  hour;\n\tu8  day;\n\tu8  month;\n\tu16 year;\n} rtc_time_t;\n\n#define RTC_REBOOT_REASON_MAGIC 0x77 // 7-bit reg.\n\nenum {\n\tREBOOT_REASON_NOP   = 0, // Use [config].\n\tREBOOT_REASON_SELF  = 1, // Use autoboot_idx/autoboot_list.\n\tREBOOT_REASON_MENU  = 2, // Force menu.\n\tREBOOT_REASON_UMS   = 3, // Force selected UMS partition.\n\tREBOOT_REASON_REC   = 4, // Set PMC_SCRATCH0_MODE_RECOVERY and reboot to self.\n\tREBOOT_REASON_PANIC = 5  // Inform bootloader that panic occured if T210B01.\n};\n\ntypedef struct _rtc_rr_decoded_t\n{\n\tu16 reason:4;\n\tu16 autoboot_idx:4;\n\tu16 autoboot_list:1;\n\tu16 ums_idx:3;\n} rtc_rr_decoded_t;\n\ntypedef struct _rtc_rr_encoded_t\n{\n\tu16 val1:6; // 6-bit reg.\n\tu16 val2:6; // 6-bit reg.\n} rtc_rr_encoded_t;\n\ntypedef struct _rtc_reboot_reason_t\n{\n\tunion {\n\t\trtc_rr_decoded_t dec;\n\t\trtc_rr_encoded_t enc;\n\t};\n} rtc_reboot_reason_t;\n\nvoid max77620_rtc_prep_read();\nvoid max77620_rtc_get_time(rtc_time_t *time);\nvoid max77620_rtc_get_time_adjusted(rtc_time_t *time);\nvoid max77620_rtc_set_epoch_offset(int offset);\nvoid max77620_rtc_set_auto_dst(bool enable);\nvoid max77620_rtc_stop_alarm();\nvoid max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time);\nu32  max77620_rtc_date_to_epoch(const rtc_time_t *time);\nvoid max77620_rtc_set_reboot_reason(rtc_reboot_reason_t *rr);\nbool max77620_rtc_get_reboot_reason(rtc_reboot_reason_t *rr);\n\n#endif /* _MFD_MAX77620_RTC_H_ */\n"
  },
  {
    "path": "bdk/sec/se.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include \"se.h\"\n#include <memory_map.h>\n#include <soc/bpmp.h>\n#include <soc/hw_init.h>\n#include <soc/pmc.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n\ntypedef struct _se_ll_t\n{\n\tu32 num;\n\tu32 addr;\n\tu32 size;\n} se_ll_t;\n\nse_ll_t ll_src, ll_dst; // Must be u32 aligned.\nse_ll_t *ll_src_ptr, *ll_dst_ptr;\n\nstatic void _se_ls_1bit(void *buf)\n{\n\tu8 *block = (u8 *)buf;\n\tu32 carry = 0;\n\n\tfor (int i = SE_AES_BLOCK_SIZE - 1; i >= 0; i--)\n\t{\n\t\tu8 b = block[i];\n\t\tblock[i] = (b << 1) | carry;\n\t\tcarry = b >> 7;\n\t}\n\n\tif (carry)\n\t\tblock[SE_AES_BLOCK_SIZE - 1] ^= 0x87;\n}\n\nstatic void _se_ls_1bit_le(void *buf)\n{\n\tu32 *block = (u32 *)buf;\n\tu32 carry = 0;\n\n\tfor (u32 i = 0; i < 4; i++)\n\t{\n\t\tu32 b = block[i];\n\t\tblock[i] = (b << 1) | carry;\n\t\tcarry = b >> 31;\n\t}\n\n\tif (carry)\n\t\tblock[0x0] ^= 0x87;\n}\n\nstatic void _se_ll_set(se_ll_t *ll, u32 addr, u32 size)\n{\n\tll->num  = 0;\n\tll->addr = addr;\n\tll->size = size & 0xFFFFFF;\n}\n\nstatic int _se_op_wait()\n{\n\tbool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210;\n\n\t// Wait for operation to be done.\n\twhile (!(SE(SE_INT_STATUS_REG) & SE_INT_OP_DONE))\n\t\t;\n\n\t// Check for errors.\n\tif ((SE(SE_INT_STATUS_REG) & SE_INT_ERR_STAT)                          ||\n\t\t(SE(SE_STATUS_REG) & SE_STATUS_STATE_MASK) != SE_STATUS_STATE_IDLE ||\n\t\t(SE(SE_ERR_STATUS_REG) != 0)\n\t   )\n\t{\n\t\treturn 1;\n\t}\n\n\t// WAR: Coherency flushing.\n\tif (ll_dst_ptr)\n\t{\n\t\t// Ensure data is out from SE.\n\t\tif (tegra_t210)\n\t\t\tusleep(15); // Worst case scenario.\n\t\telse\n\t\t{\n\t\t\t// T210B01 has a status bit for that.\n\t\t\tu32 retries = 500000;\n\t\t\twhile (SE(SE_STATUS_REG) & SE_STATUS_MEM_IF_BUSY)\n\t\t\t{\n\t\t\t\tif (!retries)\n\t\t\t\t\treturn 1;\n\t\t\t\tusleep(1);\n\t\t\t\tretries--;\n\t\t\t}\n\t\t}\n\n\t\t// Ensure data is out from AHB.\n\t\tu32 retries = 500000;\n\t\twhile (AHB_GIZMO(AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID) & MEM_WRQUE_SE_MST_ID)\n\t\t{\n\t\t\tif (!retries)\n\t\t\t\treturn 1;\n\t\t\tusleep(1);\n\t\t\tretries--;\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nstatic int _se_execute_finalize()\n{\n\tint res = _se_op_wait();\n\n\t// Invalidate data after OP is done.\n\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);\n\n\treturn res;\n}\n\nstatic int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size, bool is_oneshot)\n{\n\tif (dst_size > SE_LL_MAX_SIZE || src_size > SE_LL_MAX_SIZE)\n\t\treturn 1;\n\n\tll_src_ptr = NULL;\n\tll_dst_ptr = NULL;\n\n\tif (src)\n\t{\n\t\tll_src_ptr = &ll_src;\n\t\t_se_ll_set(ll_src_ptr, (u32)src, src_size);\n\t}\n\n\tif (dst)\n\t{\n\t\tll_dst_ptr = &ll_dst;\n\t\t_se_ll_set(ll_dst_ptr, (u32)dst, dst_size);\n\t}\n\n\t// Set linked list pointers.\n\tSE(SE_IN_LL_ADDR_REG)  = (u32)ll_src_ptr;\n\tSE(SE_OUT_LL_ADDR_REG) = (u32)ll_dst_ptr;\n\n\t// Clear status.\n\tSE(SE_ERR_STATUS_REG) = SE(SE_ERR_STATUS_REG);\n\tSE(SE_INT_STATUS_REG) = SE(SE_INT_STATUS_REG);\n\n\t// Flush data before starting OP.\n\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_CLEAN_WAY, false);\n\n\tSE(SE_OPERATION_REG) = op;\n\n\tif (is_oneshot)\n\t\treturn _se_execute_finalize();\n\n\treturn 0;\n}\n\nstatic int _se_execute_oneshot(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size)\n{\n\treturn _se_execute(op, dst, dst_size, src, src_size, true);\n}\n\nstatic int _se_execute_aes_oneshot(void *dst, const void *src, u32 size)\n{\n\t// Set optional memory interface.\n\tif (dst >= (void *)DRAM_START && src >= (void *)DRAM_START)\n\t\tSE(SE_CRYPTO_CONFIG_REG) |= SE_CRYPTO_MEMIF(MEMIF_MCCIF);\n\n\tu32 size_aligned = ALIGN_DOWN(size, SE_AES_BLOCK_SIZE);\n\tu32 size_residue = size % SE_AES_BLOCK_SIZE;\n\tint res = 0;\n\n\t// Handle initial aligned message.\n\tif (size_aligned)\n\t{\n\t\tSE(SE_CRYPTO_LAST_BLOCK_REG) = (size >> 4) - 1;\n\n\t\tres = _se_execute_oneshot(SE_OP_START, dst, size_aligned, src, size_aligned);\n\t}\n\n\t// Handle leftover partial message.\n\tif (!res && size_residue)\n\t{\n\t\t// Copy message to a block sized buffer in case it's partial.\n\t\tu32 block[SE_AES_BLOCK_SIZE / sizeof(u32)] = {0};\n\t\tmemcpy(block, src + size_aligned, size_residue);\n\n\t\t// Use updated IV for CBC and OFB. Ignored on others.\n\t\tSE(SE_CRYPTO_CONFIG_REG) |= SE_CRYPTO_IV_SEL(IV_UPDATED);\n\n\t\tSE(SE_CRYPTO_LAST_BLOCK_REG) = (SE_AES_BLOCK_SIZE >> 4) - 1;\n\n\t\tres = _se_execute_oneshot(SE_OP_START, block, SE_AES_BLOCK_SIZE, block, SE_AES_BLOCK_SIZE);\n\n\t\t// Copy result back.\n\t\tmemcpy(dst + size_aligned, block, size_residue);\n\t}\n\n\treturn res;\n}\n\nstatic void _se_aes_counter_set(const void *ctr)\n{\n\tu32 data[SE_AES_IV_SIZE / sizeof(u32)];\n\tmemcpy(data, ctr, SE_AES_IV_SIZE);\n\n\tfor (u32 i = 0; i < SE_CRYPTO_LINEAR_CTR_REG_COUNT; i++)\n\t\tSE(SE_CRYPTO_LINEAR_CTR_REG + sizeof(u32) * i) = data[i];\n}\n\nvoid se_rsa_acc_ctrl(u32 rs, u32 flags)\n{\n\tif (flags & SE_RSA_KEY_TBL_DIS_KEY_ACCESS_FLAG)\n\t\tSE(SE_RSA_KEYTABLE_ACCESS_REG + sizeof(u32) * rs) =\n\t\t\t(((flags >> 4) & SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG) | (flags & SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG)) ^\n\t\t\t\tSE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_USE_FLAG;\n\tif (flags & SE_RSA_KEY_LOCK_FLAG)\n\t\tSE(SE_RSA_SECURITY_PERKEY_REG) &= ~BIT(rs);\n}\n\nvoid se_key_acc_ctrl(u32 ks, u32 flags)\n{\n\tif (flags & SE_KEY_TBL_DIS_KEY_ACCESS_FLAG)\n\t\tSE(SE_CRYPTO_KEYTABLE_ACCESS_REG + sizeof(u32) * ks) = ~flags;\n\tif (flags & SE_KEY_LOCK_FLAG)\n\t\tSE(SE_CRYPTO_SECURITY_PERKEY_REG) &= ~BIT(ks);\n}\n\nu32 se_key_acc_ctrl_get(u32 ks)\n{\n\treturn SE(SE_CRYPTO_KEYTABLE_ACCESS_REG + sizeof(u32) * ks);\n}\n\nvoid se_aes_key_set(u32 ks, const void *key, u32 size)\n{\n\tu32 data[SE_AES_MAX_KEY_SIZE / sizeof(u32)];\n\tmemcpy(data, key, size);\n\n\tfor (u32 i = 0; i < (size / sizeof(u32)); i++)\n\t{\n\t\t// QUAD KEYS_4_7 bit is automatically set by PKT macro.\n\t\tSE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_QUAD(KEYS_0_3) | SE_KEYTABLE_PKT(i);\n\t\tSE(SE_CRYPTO_KEYTABLE_DATA_REG) = data[i];\n\t}\n}\n\nvoid se_aes_iv_set(u32 ks, const void *iv, u32 size)\n{\n\tu32 data[SE_AES_MAX_KEY_SIZE / sizeof(u32)];\n\tmemcpy(data, iv, size);\n\n\tfor (u32 i = 0; i < (size / sizeof(u32)); i++)\n\t{\n\t\t// QUAD UPDATED_IV bit is automatically set by PKT macro.\n\t\tSE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_QUAD(ORIGINAL_IV) | SE_KEYTABLE_PKT(i);\n\t\tSE(SE_CRYPTO_KEYTABLE_DATA_REG) = data[i];\n\t}\n}\n\nvoid se_aes_key_get(u32 ks, void *key, u32 size)\n{\n\tu32 data[SE_AES_MAX_KEY_SIZE / sizeof(u32)];\n\n\tfor (u32 i = 0; i < (size / sizeof(u32)); i++)\n\t{\n\t\t// QUAD KEYS_4_7 bit is automatically set by PKT macro.\n\t\tSE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_QUAD(KEYS_0_3) | SE_KEYTABLE_PKT(i);\n\t\tdata[i] = SE(SE_CRYPTO_KEYTABLE_DATA_REG);\n\t}\n\n\tmemcpy(key, data, size);\n}\n\nvoid se_aes_key_clear(u32 ks)\n{\n\tfor (u32 i = 0; i < (SE_AES_MAX_KEY_SIZE / sizeof(u32)); i++)\n\t{\n\t\t// QUAD KEYS_4_7 bit is automatically set by PKT macro.\n\t\tSE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_QUAD(KEYS_0_3) | SE_KEYTABLE_PKT(i);\n\t\tSE(SE_CRYPTO_KEYTABLE_DATA_REG) = 0;\n\t}\n}\n\nvoid se_aes_iv_clear(u32 ks)\n{\n\tfor (u32 i = 0; i < (SE_AES_MAX_KEY_SIZE / sizeof(u32)); i++)\n\t{\n\t\t// QUAD UPDATED_IV bit is automatically set by PKT macro.\n\t\tSE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_QUAD(ORIGINAL_IV) | SE_KEYTABLE_PKT(i);\n\t\tSE(SE_CRYPTO_KEYTABLE_DATA_REG) = 0;\n\t}\n}\n\nint se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *seed)\n{\n\tSE(SE_CONFIG_REG)              = SE_CONFIG_DEC_MODE(MODE_KEY128)   | SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_KEYTABLE);\n\tSE(SE_CRYPTO_CONFIG_REG)       = SE_CRYPTO_KEY_INDEX(ks_src)       | SE_CRYPTO_CORE_SEL(CORE_DECRYPT);\n\tSE(SE_CRYPTO_LAST_BLOCK_REG)   = (SE_AES_BLOCK_SIZE >> 4) - 1;\n\tSE(SE_CRYPTO_KEYTABLE_DST_REG) = SE_KEYTABLE_DST_KEY_INDEX(ks_dst) | SE_KEYTABLE_DST_WORD_QUAD(KEYS_0_3);\n\n\treturn _se_execute_oneshot(SE_OP_START, NULL, 0, seed, SE_KEY_128_SIZE);\n}\n\nint se_aes_crypt_ecb(u32 ks, int enc, void *dst, const void *src, u32 size)\n{\n\tif (enc)\n\t{\n\t\tSE(SE_CONFIG_REG)        = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_AES_ENC)   | SE_CONFIG_DST(DST_MEMORY);\n\t\tSE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks)         | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) |\n\t\t\t\t\t\t\t\t   SE_CRYPTO_XOR_POS(XOR_BYPASS);\n\t}\n\telse\n\t{\n\t\tSE(SE_CONFIG_REG)        = SE_CONFIG_DEC_MODE(MODE_KEY128) | SE_CONFIG_DEC_ALG(ALG_AES_DEC)   | SE_CONFIG_DST(DST_MEMORY);\n\t\tSE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks)         | SE_CRYPTO_CORE_SEL(CORE_DECRYPT) |\n\t\t\t\t\t\t\t\t   SE_CRYPTO_XOR_POS(XOR_BYPASS);\n\t}\n\n\treturn _se_execute_aes_oneshot(dst, src, size);\n}\n\nint se_aes_crypt_cbc(u32 ks, int enc, void *dst, const void *src, u32 size)\n{\n\tif (enc)\n\t{\n\t\tSE(SE_CONFIG_REG)        = SE_CONFIG_ENC_MODE(MODE_KEY128)  | SE_CONFIG_ENC_ALG(ALG_AES_ENC)      | SE_CONFIG_DST(DST_MEMORY);\n\t\tSE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks)          | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) |\n\t\t\t\t\t\t\t\t   SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_XOR_POS(XOR_TOP);\n\t}\n\telse\n\t{\n\t\tSE(SE_CONFIG_REG)        = SE_CONFIG_DEC_MODE(MODE_KEY128)  | SE_CONFIG_DEC_ALG(ALG_AES_DEC)       | SE_CONFIG_DST(DST_MEMORY);\n\t\tSE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks)          | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVMEM) |\n\t\t\t\t\t\t\t\t   SE_CRYPTO_CORE_SEL(CORE_DECRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM);\n\t}\n\n\treturn _se_execute_aes_oneshot(dst, src, size);\n}\n\nint se_aes_crypt_ofb(u32 ks, void *dst, const void *src, u32 size)\n{\n\tSE(SE_SPARE_REG)         = SE_INPUT_NONCE_LE;\n\tSE(SE_CONFIG_REG)        = SE_CONFIG_ENC_MODE(MODE_KEY128)  | SE_CONFIG_ENC_ALG(ALG_AES_ENC)      | SE_CONFIG_DST(DST_MEMORY);\n\tSE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks)          | SE_CRYPTO_INPUT_SEL(INPUT_AESOUT) |\n\t\t\t\t\t\t\t   SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM);\n\n\treturn _se_execute_aes_oneshot(dst, src, size);\n}\n\nint se_aes_crypt_ctr(u32 ks, void *dst, const void *src, u32 size, void *ctr)\n{\n\tSE(SE_SPARE_REG)         = SE_INPUT_NONCE_LE;\n\tSE(SE_CONFIG_REG)        = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_AES_ENC)     | SE_CONFIG_DST(DST_MEMORY);\n\tSE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks)         | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT)   |\n\t\t\t\t\t\t\t   SE_CRYPTO_XOR_POS(XOR_BOTTOM)   | SE_CRYPTO_INPUT_SEL(INPUT_LNR_CTR) |\n\t\t\t\t\t\t\t   SE_CRYPTO_CTR_CNTN(1);\n\n\t_se_aes_counter_set(ctr);\n\n\treturn _se_execute_aes_oneshot(dst, src, size);\n}\n\nint se_aes_crypt_xts_sec(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, void *dst, void *src, u32 secsize)\n{\n\tu32 tmp[SE_AES_BLOCK_SIZE / sizeof(u32)];\n\tu8 *tweak = (u8 *)tmp;\n\tu8 *pdst = (u8 *)dst;\n\tu8 *psrc = (u8 *)src;\n\n\t// Generate tweak.\n\tfor (int i = SE_AES_BLOCK_SIZE - 1; i >= 0; i--)\n\t{\n\t\ttweak[i] = sec & 0xFF;\n\t\tsec >>= 8;\n\t}\n\tif (se_aes_crypt_ecb(tweak_ks, ENCRYPT, tweak, tweak, SE_AES_BLOCK_SIZE))\n\t\treturn 1;\n\n\t// We are assuming a 0x10-aligned sector size in this implementation.\n\tfor (u32 i = 0; i < secsize / SE_AES_BLOCK_SIZE; i++)\n\t{\n\t\tfor (u32 j = 0; j < SE_AES_BLOCK_SIZE; j++)\n\t\t\tpdst[j] = psrc[j] ^ tweak[j];\n\n\t\tif (se_aes_crypt_ecb(crypt_ks, enc, pdst, pdst, SE_AES_BLOCK_SIZE))\n\t\t\treturn 1;\n\n\t\tfor (u32 j = 0; j < SE_AES_BLOCK_SIZE; j++)\n\t\t\tpdst[j] = pdst[j] ^ tweak[j];\n\n\t\t_se_ls_1bit(tweak);\n\t\tpsrc += SE_AES_BLOCK_SIZE;\n\t\tpdst += SE_AES_BLOCK_SIZE;\n\t}\n\n\treturn 0;\n}\n\nint se_aes_crypt_xts_sec_nx(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, u8 *tweak, bool regen_tweak, u32 tweak_exp, void *dst, void *src, u32 sec_size)\n{\n\tu32 *pdst = (u32 *)dst;\n\tu32 *psrc = (u32 *)src;\n\tu32 *ptweak = (u32 *)tweak;\n\n\tif (regen_tweak)\n\t{\n\t\tfor (int i = SE_AES_BLOCK_SIZE - 1; i >= 0; i--)\n\t\t{\n\t\t\ttweak[i] = sec & 0xFF;\n\t\t\tsec >>= 8;\n\t\t}\n\t\tif (se_aes_crypt_ecb(tweak_ks, ENCRYPT, tweak, tweak, SE_AES_BLOCK_SIZE))\n\t\t\treturn 1;\n\t}\n\n\t// tweak_exp allows using a saved tweak to reduce _se_ls_1bit_le calls.\n\tfor (u32 i = 0; i < (tweak_exp << 5); i++)\n\t\t_se_ls_1bit_le(tweak);\n\n\tu8 orig_tweak[SE_KEY_128_SIZE] __attribute__((aligned(4)));\n\tmemcpy(orig_tweak, tweak, SE_KEY_128_SIZE);\n\n\t// We are assuming a 16 sector aligned size in this implementation.\n\tfor (u32 i = 0; i < (sec_size >> 4); i++)\n\t{\n\t\tfor (u32 j = 0; j < (SE_AES_BLOCK_SIZE / sizeof(u32)); j++)\n\t\t\tpdst[j] = psrc[j] ^ ptweak[j];\n\n\t\t_se_ls_1bit_le(tweak);\n\t\tpsrc += sizeof(u32);\n\t\tpdst += sizeof(u32);\n\t}\n\n\tif (se_aes_crypt_ecb(crypt_ks, enc, dst, dst, sec_size))\n\t\treturn 1;\n\n\tpdst = (u32 *)dst;\n\tptweak = (u32 *)orig_tweak;\n\tfor (u32 i = 0; i < (sec_size >> 4); i++)\n\t{\n\t\tfor (u32 j = 0; j < (SE_AES_BLOCK_SIZE / sizeof(u32)); j++)\n\t\t\tpdst[j] = pdst[j] ^ ptweak[j];\n\n\t\t_se_ls_1bit_le(orig_tweak);\n\t\tpdst += sizeof(u32);\n\t}\n\n\treturn 0;\n}\n\nint se_aes_crypt_xts(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, void *dst, void *src, u32 secsize, u32 num_secs)\n{\n\tu8 *pdst = (u8 *)dst;\n\tu8 *psrc = (u8 *)src;\n\n\tfor (u32 i = 0; i < num_secs; i++)\n\t\tif (se_aes_crypt_xts_sec(tweak_ks, crypt_ks, enc, sec + i, pdst + secsize * i, psrc + secsize * i, secsize))\n\t\t\treturn 1;\n\n\treturn 0;\n}\n\nstatic void _se_sha_hash_256_get_hash(void *hash)\n{\n\t// Copy output hash.\n\tu32 hash32[SE_SHA_256_SIZE / sizeof(u32)];\n\tfor (u32 i = 0; i < (SE_SHA_256_SIZE / sizeof(u32)); i++)\n\t\thash32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG + sizeof(u32) * i));\n\tmemcpy(hash, hash32, SE_SHA_256_SIZE);\n}\n\nstatic int _se_sha_hash_256(void *hash, u64 total_size, const void *src, u32 src_size, bool is_oneshot)\n{\n\t// Src size of 0 is not supported, so return null string sha256.\n\tif (!src_size)\n\t{\n\t\tconst u8 null_hash[SE_SHA_256_SIZE] = {\n\t\t\t0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24,\n\t\t\t0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55\n\t\t};\n\t\tmemcpy(hash, null_hash, SE_SHA_256_SIZE);\n\t\treturn 0;\n\t}\n\n\t// Increase leftover size if not last message. (Engine will always stop at src_size.)\n\tu32 msg_left = src_size;\n\tif (total_size < src_size)\n\t\tmsg_left++;\n\n\t// Setup config for SHA256.\n\tSE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG);\n\n\t// Set total size: BITS(total_size), up to 2 EB.\n\tSE(SE_SHA_MSG_LENGTH_0_REG) = (u32)(total_size << 3);\n\tSE(SE_SHA_MSG_LENGTH_1_REG) = (u32)(total_size >> 29);\n\tSE(SE_SHA_MSG_LENGTH_2_REG) = 0;\n\tSE(SE_SHA_MSG_LENGTH_3_REG) = 0;\n\n\t// Set leftover size: BITS(src_size).\n\tSE(SE_SHA_MSG_LEFT_0_REG) = (u32)(msg_left << 3);\n\tSE(SE_SHA_MSG_LEFT_1_REG) = (u32)(msg_left >> 29);\n\tSE(SE_SHA_MSG_LEFT_2_REG) = 0;\n\tSE(SE_SHA_MSG_LEFT_3_REG) = 0;\n\n\t// Set config based on init or partial continuation.\n\tif (total_size == src_size || !total_size)\n\t\tSE(SE_SHA_CONFIG_REG) = SHA_INIT_HASH;\n\telse\n\t\tSE(SE_SHA_CONFIG_REG) = SHA_CONTINUE;\n\n\t// Trigger the operation. src vs total size decides if it's partial.\n\tint res = _se_execute(SE_OP_START, NULL, 0, src, src_size, is_oneshot);\n\n\tif (!res && is_oneshot)\n\t\t_se_sha_hash_256_get_hash(hash);\n\n\treturn res;\n}\n\nint se_sha_hash_256_async(void *hash, const void *src, u32 size)\n{\n\treturn _se_sha_hash_256(hash, size, src, size, false);\n}\n\nint se_sha_hash_256_oneshot(void *hash, const void *src, u32 size)\n{\n\treturn _se_sha_hash_256(hash, size, src, size, true);\n}\n\nint se_sha_hash_256_partial_start(void *hash, const void *src, u32 size, bool is_oneshot)\n{\n\t// Check if aligned SHA256 block size.\n\tif (size % SE_SHA2_MIN_BLOCK_SIZE)\n\t\treturn 1;\n\n\treturn _se_sha_hash_256(hash, 0, src, size, is_oneshot);\n}\n\nint se_sha_hash_256_partial_update(void *hash, const void *src, u32 size, bool is_oneshot)\n{\n\t// Check if aligned to SHA256 block size.\n\tif (size % SE_SHA2_MIN_BLOCK_SIZE)\n\t\treturn 1;\n\n\treturn _se_sha_hash_256(hash, size - 1, src, size, is_oneshot);\n}\n\nint se_sha_hash_256_partial_end(void *hash, u64 total_size, const void *src, u32 src_size, bool is_oneshot)\n{\n\treturn _se_sha_hash_256(hash, total_size, src, src_size, is_oneshot);\n}\n\nint se_sha_hash_256_finalize(void *hash)\n{\n\tint res = _se_execute_finalize();\n\n\t_se_sha_hash_256_get_hash(hash);\n\n\treturn res;\n}\n\nint se_rng_pseudo(void *dst, u32 size)\n{\n\t// Setup config for SP 800-90 PRNG.\n\tSE(SE_CONFIG_REG)        = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG)    | SE_CONFIG_DST(DST_MEMORY);\n\tSE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_XOR_POS(XOR_BYPASS)   | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);\n\tSE(SE_RNG_CONFIG_REG)    = SE_RNG_CONFIG_SRC(SRC_ENTROPY)  | SE_RNG_CONFIG_MODE(MODE_NORMAL);\n\tSE(SE_RNG_SRC_CONFIG_REG) |= SE_RNG_SRC_CONFIG_ENTR_SRC(RO_ENTR_ENABLE); // DRBG. Depends on ENTROPY clock.\n\tSE(SE_RNG_RESEED_INTERVAL_REG) = 4096;\n\n\tu32 size_aligned = ALIGN_DOWN(size, SE_RNG_BLOCK_SIZE);\n\tu32 size_residue = size % SE_RNG_BLOCK_SIZE;\n\tint res = 0;\n\n\t// Handle initial aligned message.\n\tif (size_aligned)\n\t{\n\t\tSE(SE_CRYPTO_LAST_BLOCK_REG) = (size >> 4) - 1;\n\n\t\tres = _se_execute_oneshot(SE_OP_START, dst, size_aligned, NULL, 0);\n\t}\n\n\t// Handle leftover partial message.\n\tif (!res && size_residue)\n\t{\n\t\t// Copy message to a block sized buffer in case it's partial.\n\t\tu32 block[SE_RNG_BLOCK_SIZE / sizeof(u32)] = {0};\n\n\t\tSE(SE_CRYPTO_LAST_BLOCK_REG) = (SE_AES_BLOCK_SIZE >> 4) - 1;\n\n\t\tres = _se_execute_oneshot(SE_OP_START, block, SE_RNG_BLOCK_SIZE, NULL, 0);\n\n\t\t// Copy result back.\n\t\tmemcpy(dst + size_aligned, block, size_residue);\n\t}\n\n\treturn res;\n}\n\nvoid se_aes_ctx_get_keys(u8 *buf, u8 *keys, u32 keysize)\n{\n\tu8 *aligned_buf = (u8 *)ALIGN((u32)buf, 0x40);\n\n\t// Set Secure Random Key.\n\tSE(SE_CONFIG_REG)        = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG)       | SE_CONFIG_DST(DST_SRK);\n\tSE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(0)          | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);\n\tSE(SE_RNG_CONFIG_REG)    = SE_RNG_CONFIG_SRC(SRC_ENTROPY)  | SE_RNG_CONFIG_MODE(MODE_FORCE_RESEED);\n\tSE(SE_CRYPTO_LAST_BLOCK) = 0;\n\t_se_execute_oneshot(SE_OP_START, NULL, 0, NULL, 0);\n\n\t// Save AES keys.\n\tSE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);\n\n\tfor (u32 i = 0; i < SE_AES_KEYSLOT_COUNT; i++)\n\t{\n\t\tSE(SE_CONTEXT_SAVE_CONFIG_REG) = SE_CONTEXT_SRC(AES_KEYTABLE) | SE_KEYTABLE_DST_KEY_INDEX(i) |\n\t\t\t\t\t\t\t\t\t\t SE_CONTEXT_AES_KEY_INDEX(0)  | SE_CONTEXT_AES_WORD_QUAD(KEYS_0_3);\n\n\t\tSE(SE_CRYPTO_LAST_BLOCK) = 0;\n\t\t_se_execute_oneshot(SE_OP_CTX_SAVE, aligned_buf, SE_AES_BLOCK_SIZE, NULL, 0);\n\t\tmemcpy(keys + i * keysize, aligned_buf, SE_AES_BLOCK_SIZE);\n\n\t\tif (keysize > SE_KEY_128_SIZE)\n\t\t{\n\t\t\tSE(SE_CONTEXT_SAVE_CONFIG_REG) = SE_CONTEXT_SRC(AES_KEYTABLE) | SE_KEYTABLE_DST_KEY_INDEX(i) |\n\t\t\t\t\t\t\t\t\t\t\t SE_CONTEXT_AES_KEY_INDEX(0)  | SE_CONTEXT_AES_WORD_QUAD(KEYS_4_7);\n\n\t\t\tSE(SE_CRYPTO_LAST_BLOCK) = 0;\n\t\t\t_se_execute_oneshot(SE_OP_CTX_SAVE, aligned_buf, SE_AES_BLOCK_SIZE, NULL, 0);\n\t\t\tmemcpy(keys + i * keysize + SE_AES_BLOCK_SIZE, aligned_buf, SE_AES_BLOCK_SIZE);\n\t\t}\n\t}\n\n\t// Save SRK to PMC secure scratches.\n\tSE(SE_CONTEXT_SAVE_CONFIG_REG) = SE_CONTEXT_SRC(SRK);\n\tSE(SE_CRYPTO_LAST_BLOCK)       = 0;\n\t_se_execute_oneshot(SE_OP_CTX_SAVE, NULL, 0, NULL, 0);\n\n\t// End context save.\n\tSE(SE_CONFIG_REG) = 0;\n\t_se_execute_oneshot(SE_OP_CTX_SAVE, NULL, 0, NULL, 0);\n\n\t// Get SRK.\n\tu32 srk[4];\n\tsrk[0] = PMC(APBDEV_PMC_SECURE_SCRATCH4);\n\tsrk[1] = PMC(APBDEV_PMC_SECURE_SCRATCH5);\n\tsrk[2] = PMC(APBDEV_PMC_SECURE_SCRATCH6);\n\tsrk[3] = PMC(APBDEV_PMC_SECURE_SCRATCH7);\n\n\t// Decrypt context.\n\tse_aes_key_set(3, srk, SE_KEY_128_SIZE);\n\tse_aes_crypt_cbc(3, DECRYPT, keys, keys, SE_AES_KEYSLOT_COUNT * keysize);\n\tse_aes_key_clear(3);\n}\n\nint se_aes_hash_cmac(u32 ks, void *hash, const void *src, u32 size)\n{\n\tu32 tmp1[SE_KEY_128_SIZE / sizeof(u32)] = {0};\n\tu32 tmp2[SE_AES_BLOCK_SIZE / sizeof(u32)] = {0};\n\tu8 *subkey = (u8 *)tmp1;\n\tu8 *last_block = (u8 *)tmp2;\n\n\t// Generate sub key (CBC with zeroed IV, basically ECB).\n\tse_aes_iv_clear(ks);\n\tif (se_aes_crypt_cbc(ks, ENCRYPT, subkey, subkey, SE_KEY_128_SIZE))\n\t\treturn 1;\n\n\t// Generate K1 subkey.\n\t_se_ls_1bit(subkey);\n\tif (size & 0xF)\n\t\t_se_ls_1bit(subkey); // Convert to K2.\n\n\t// Switch to hash register. The rest of the config is already set.\n\tSE(SE_CONFIG_REG)        |= SE_CONFIG_DST(DST_HASHREG);\n\tSE(SE_CRYPTO_CONFIG_REG) |= SE_CRYPTO_HASH(HASH_ENABLE);\n\n\t// Initial blocks.\n\tu32 num_blocks = (size + 0xF) >> 4;\n\tif (num_blocks > 1)\n\t{\n\t\tSE(SE_CRYPTO_LAST_BLOCK_REG) = num_blocks - 2;\n\n\t\tif (_se_execute_oneshot(SE_OP_START, NULL, 0, src, size))\n\t\t\treturn 1;\n\n\t\t// Use updated IV for next OP as a continuation.\n\t\tSE(SE_CRYPTO_CONFIG_REG) |= SE_CRYPTO_IV_SEL(IV_UPDATED);\n\t}\n\n\t// Last block.\n\tif (size & 0xF)\n\t{\n\t\tmemcpy(last_block, src + (size & (~0xF)), size & 0xF);\n\t\tlast_block[size & 0xF] = 0x80;\n\t}\n\telse if (size >= SE_AES_BLOCK_SIZE)\n\t\tmemcpy(last_block, src + size - SE_AES_BLOCK_SIZE, SE_AES_BLOCK_SIZE);\n\n\tfor (u32 i = 0; i < SE_KEY_128_SIZE; i++)\n\t\tlast_block[i] ^= subkey[i];\n\n\tSE(SE_CRYPTO_LAST_BLOCK_REG) = (SE_AES_BLOCK_SIZE >> 4) - 1;\n\n\tif (_se_execute_oneshot(SE_OP_START, NULL, 0, last_block, SE_AES_BLOCK_SIZE))\n\t\treturn 1;\n\n\t// Copy output hash.\n\tu32 *hash32 = (u32 *)hash;\n\tfor (u32 i = 0; i < (SE_AES_CMAC_DIGEST_SIZE / sizeof(u32)); i++)\n\t\thash32[i] = SE(SE_HASH_RESULT_REG + sizeof(u32) * i);\n\n\treturn 0;\n}\n"
  },
  {
    "path": "bdk/sec/se.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2019-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _SE_H_\n#define _SE_H_\n\n#include \"se_t210.h\"\n#include <utils/types.h>\n\nvoid se_rsa_acc_ctrl(u32 rs, u32 flags);\nvoid se_key_acc_ctrl(u32 ks, u32 flags);\nu32  se_key_acc_ctrl_get(u32 ks);\n\n/*! AES Key Management Functions */\nvoid se_aes_key_set(u32 ks, const void *key, u32 size);\nvoid se_aes_iv_set(u32 ks, const void *iv, u32 size);\nvoid se_aes_key_get(u32 ks, void *key, u32 size);\nvoid se_aes_key_clear(u32 ks);\nvoid se_aes_iv_clear(u32 ks);\nint  se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *seed);\nvoid se_aes_ctx_get_keys(u8 *buf, u8 *keys, u32 keysize);\n/*! Encryption Functions */\nint  se_aes_crypt_ecb(u32 ks, int enc, void *dst, const void *src, u32 size);\nint  se_aes_crypt_cbc(u32 ks, int enc, void *dst, const void *src, u32 size);\nint  se_aes_crypt_ofb(u32 ks, void *dst, const void *src, u32 size);\nint  se_aes_crypt_ctr(u32 ks, void *dst, const void *src, u32 size, void *ctr);\nint  se_aes_crypt_xts_sec(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, void *dst, void *src, u32 secsize);\nint  se_aes_crypt_xts_sec_nx(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, u8 *tweak, bool regen_tweak, u32 tweak_exp, void *dst, void *src, u32 sec_size);\nint  se_aes_crypt_xts(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, void *dst, void *src, u32 secsize, u32 num_secs);\n/*! Hashing Functions */\nint  se_sha_hash_256_async(void *hash, const void *src, u32 size);\nint  se_sha_hash_256_oneshot(void *hash, const void *src, u32 size);\nint  se_sha_hash_256_partial_start(void *hash, const void *src, u32 size, bool is_oneshot);\nint  se_sha_hash_256_partial_update(void *hash, const void *src, u32 size, bool is_oneshot);\nint  se_sha_hash_256_partial_end(void *hash, u64 total_size, const void *src, u32 src_size, bool is_oneshot);\nint  se_sha_hash_256_finalize(void *hash);\nint  se_aes_hash_cmac(u32 ks, void *hash, const void *src, u32 size);\n/*! Random Functions */\nint  se_rng_pseudo(void *dst, u32 size);\n\n#endif\n"
  },
  {
    "path": "bdk/sec/se_t210.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _SE_T210_H\n#define _SE_T210_H\n\n#include <utils/types.h>\n\n#define SE_CRYPTO_QUEUE_LENGTH 50\n#define SE_MAX_SRC_SG_COUNT    50\n#define SE_MAX_DST_SG_COUNT    50\n\n#define SE_AES_KEYSLOT_COUNT   16\n#define SE_RSA_KEYSLOT_COUNT   2\n\n#define SE_AES_BLOCK_SIZE   16\n#define SE_AES_IV_SIZE      16\n#define SE_AES_MIN_KEY_SIZE 16\n#define SE_AES_MAX_KEY_SIZE 32\n#define SE_KEY_128_SIZE     16\n#define SE_KEY_192_SIZE     24\n#define SE_KEY_256_SIZE     32\n#define SE_SHA_192_SIZE     24\n#define SE_SHA_256_SIZE     32\n#define SE_SHA_384_SIZE     48\n#define SE_SHA_512_SIZE     64\n#define SE_RNG_BLOCK_SIZE   16\n#define SE_RNG_IV_SIZE      16\n#define SE_RNG_DT_SIZE      16\n#define SE_RNG_KEY_SIZE     16\n#define SE_RNG_SEED_SIZE (SE_RNG_IV_SIZE + SE_RNG_KEY_SIZE + SE_RNG_DT_SIZE)\n\n#define SE_AES_CMAC_DIGEST_SIZE 16\n#define SE_RSA512_DIGEST_SIZE   64\n#define SE_RSA1024_DIGEST_SIZE  128\n#define SE_RSA1536_DIGEST_SIZE  192\n#define SE_RSA2048_DIGEST_SIZE  256\n\n#define SE_SHA2_MIN_BLOCK_SIZE 64\n#define SE_SHA2_MAX_BLOCK_SIZE 128\n\n#define SE_LL_MAX_SIZE ALIGN_DOWN(0xFFFFFF, SE_SHA2_MAX_BLOCK_SIZE)\n\n#define  DECRYPT   0\n#define  ENCRYPT   1\n\n/* SE register definitions */\n#define SE_SE_SECURITY_REG 0x000\n#define  SE_HARD_SETTING   BIT(0)\n#define  SE_ENG_DIS        BIT(1)\n#define  SE_PERKEY_SETTING BIT(2)\n#define  SE_SOFT_SETTING   BIT(16)\n\n#define SE_TZRAM_SECURITY_REG 0x004\n#define  SE_TZRAM_HARD_SETTING BIT(0)\n#define  SE_TZRAM_ENG_DIS      BIT(1)\n\n#define SE_OPERATION_REG 0x008\n#define  SE_OP_ABORT       0\n#define  SE_OP_START       1\n#define  SE_OP_RESTART_OUT 2\n#define  SE_OP_CTX_SAVE    3\n#define  SE_OP_RESTART_IN  4\n\n#define SE_INT_ENABLE_REG\t0x00C\n#define SE_INT_STATUS_REG\t0x010\n#define  SE_INT_IN_LL_BUF_RD  BIT(0)\n#define  SE_INT_IN_DONE       BIT(1)\n#define  SE_INT_OUT_LL_BUF_WR BIT(2)\n#define  SE_INT_OUT_DONE      BIT(3)\n#define  SE_INT_OP_DONE       BIT(4)\n#define  SE_INT_RESEED_NEEDED BIT(5)\n#define  SE_INT_ERR_STAT      BIT(16)\n\n#define SE_CONFIG_REG 0x014\n#define  DST_MEMORY      0\n#define  DST_HASHREG     1\n#define  DST_KEYTABLE    2\n#define  DST_SRK         3\n#define  DST_RSAREG      4\n#define  SE_CONFIG_DST(x)      ((x) << 2)\n#define  ALG_NOP         0\n#define  ALG_AES_DEC     1\n#define  SE_CONFIG_DEC_ALG(x)  ((x) << 8)\n#define  ALG_NOP         0\n#define  ALG_AES_ENC     1\n#define  ALG_RNG         2\n#define  ALG_SHA         3\n#define  ALG_RSA         4\n#define  SE_CONFIG_ENC_ALG(x)  ((x) << 12)\n#define  MODE_KEY128     0\n#define  MODE_KEY192     1\n#define  MODE_KEY256     2\n#define  MODE_SHA1       0\n#define  MODE_SHA224     4\n#define  MODE_SHA256     5\n#define  MODE_SHA384     6\n#define  MODE_SHA512     7\n#define  SE_CONFIG_DEC_MODE(x) ((x) << 16)\n#define  SE_CONFIG_ENC_MODE(x) ((x) << 24)\n\n#define SE_IN_LL_ADDR_REG        0x018\n#define SE_IN_CUR_BYTE_ADDR_REG  0x01C\n#define SE_IN_CUR_LL_ID_REG      0x020\n#define SE_OUT_LL_ADDR_REG       0x024\n#define SE_OUT_CUR_BYTE_ADDR_REG 0x028\n#define SE_OUT_CUR_LL_ID_REG     0x02C\n\n#define SE_HASH_RESULT_REG 0x030\n#define  SE_HASH_RESULT_REG_COUNT 16\n\n#define SE_CONTEXT_SAVE_CONFIG_REG 0x070\n#define  KEYS_0_3        0\n#define  KEYS_4_7        1\n#define  ORIGINAL_IV     2\n#define  UPDATED_IV      3\n#define  SE_CONTEXT_AES_WORD_QUAD(x)    ((x) << 0)\n#define  SE_CONTEXT_AES_KEY_INDEX(x)    ((x) << 8)\n#define  KEYS_0_3        0\n#define  KEYS_4_7        1\n#define  KEYS_8_11       2\n#define  KEYS_12_15      3\n#define  SE_CONTEXT_RSA_WORD_QUAD(x)    ((x) << 12)\n#define  SLOT0_EXPONENT  0\n#define  SLOT0_MODULUS   1\n#define  SLOT1_EXPONENT  2\n#define  SLOT1_MODULUS   3\n#define  SE_CONTEXT_RSA_KEY_INDEX(x)    ((x) << 16)\n#define  STICKY_0_3      0\n#define  STICKY_4_7      1\n#define  SE_CONTEXT_STICKY_WORD_QUAD(x) ((x) << 24)\n#define  STICKY_BITS     0\n#define  RSA_KEYTABLE    1\n#define  AES_KEYTABLE    2\n#define  MEM             4\n#define  SRK             6\n#define SE_CONTEXT_SRC(x)               ((x) << 29)\n\n#define SE_CTX_SAVE_AUTO_T210B01_REG 0x074\n#define  SE_CTX_SAVE_AUTO_ENABLE\t\tBIT(0)\n#define  SE_CTX_SAVE_AUTO_LOCK          BIT(8)\n#define  SE_CTX_SAVE_AUTO_CURR_CNT_MASK (0x3FF << 16)\n\n#define SE_CRYPTO_LAST_BLOCK 0x080\n\n#define SE_SHA_CONFIG_REG 0x200\n#define  SHA_CONTINUE  0\n#define  SHA_INIT_HASH 1\n\n#define SE_SHA_MSG_LENGTH_0_REG 0x204\n#define SE_SHA_MSG_LENGTH_1_REG 0x208\n#define SE_SHA_MSG_LENGTH_2_REG 0x20C\n#define SE_SHA_MSG_LENGTH_3_REG 0x210\n#define SE_SHA_MSG_LEFT_0_REG   0x214\n#define SE_SHA_MSG_LEFT_1_REG   0x218\n#define SE_SHA_MSG_LEFT_2_REG   0x21C\n#define SE_SHA_MSG_LEFT_3_REG   0x220\n\n#define SE_CRYPTO_SECURITY_PERKEY_REG 0x280\n#define  SE_KEY_LOCK_FLAG   0x80\n#define SE_CRYPTO_KEYTABLE_ACCESS_REG 0x284\n#define  SE_CRYPTO_KEYTABLE_ACCESS_REG_COUNT 16\n#define  SE_KEY_TBL_DIS_KEYREAD_FLAG    BIT(0)\n#define  SE_KEY_TBL_DIS_KEYUPDATE_FLAG  BIT(1)\n#define  SE_KEY_TBL_DIS_OIVREAD_FLAG    BIT(2)\n#define  SE_KEY_TBL_DIS_OIVUPDATE_FLAG  BIT(3)\n#define  SE_KEY_TBL_DIS_UIVREAD_FLAG    BIT(4)\n#define  SE_KEY_TBL_DIS_UIVUPDATE_FLAG  BIT(5)\n#define  SE_KEY_TBL_DIS_KEYUSE_FLAG     BIT(6)\n#define  SE_KEY_TBL_DIS_KEY_ACCESS_FLAG 0x7F\n\n#define SE_CRYPTO_CONFIG_REG 0x304\n#define  HASH_DISABLE   0\n#define  HASH_ENABLE    1\n#define  SE_CRYPTO_HASH(x)          ((x) << 0)\n#define  XOR_BYPASS     0\n#define  XOR_TOP        2\n#define  XOR_BOTTOM     3\n#define  SE_CRYPTO_XOR_POS(x)       ((x) << 1)\n#define  INPUT_MEMORY   0\n#define  INPUT_RANDOM   1\n#define  INPUT_AESOUT   2\n#define  INPUT_LNR_CTR  3\n#define  SE_CRYPTO_INPUT_SEL(x)     ((x) << 3)\n#define  VCTRAM_MEM     0\n#define  VCTRAM_AESOUT  2\n#define  VCTRAM_PREVMEM 3\n#define  SE_CRYPTO_VCTRAM_SEL(x)    ((x) << 5)\n#define  IV_ORIGINAL    0\n#define  IV_UPDATED     1\n#define  SE_CRYPTO_IV_SEL(x)        ((x) << 7)\n#define  CORE_DECRYPT   0\n#define  CORE_ENCRYPT   1\n#define  SE_CRYPTO_CORE_SEL(x)      ((x) << 8)\n#define  SE_CRYPTO_KEYSCH_BYPASS BIT(10)\n#define  SE_CRYPTO_CTR_CNTN(x)      ((x) << 11)\n#define  SE_CRYPTO_KEY_INDEX(x)     ((x) << 24)\n#define  MEMIF_AHB      0\n#define  MEMIF_MCCIF    1\n#define  SE_CRYPTO_MEMIF(x)         ((x) << 31)\n\n#define SE_CRYPTO_LINEAR_CTR_REG 0x308\n#define  SE_CRYPTO_LINEAR_CTR_REG_COUNT 4\n\n#define SE_CRYPTO_LAST_BLOCK_REG 0x318\n\n#define SE_CRYPTO_KEYTABLE_ADDR_REG 0x31C\n#define  SE_KEYTABLE_PKT(x)         ((x) << 0)\n#define  KEYS_0_3        0\n#define  KEYS_4_7        1\n#define  ORIGINAL_IV     2\n#define  UPDATED_IV      3\n#define  SE_KEYTABLE_QUAD(x)        ((x) << 2)\n#define  SE_KEYTABLE_SLOT(x)        ((x) << 4)\n\n#define SE_CRYPTO_KEYTABLE_DATA_REG 0x320\n\n#define SE_CRYPTO_KEYTABLE_DST_REG 0x330\n#define  KEYS_0_3        0\n#define  KEYS_4_7        1\n#define  ORIGINAL_IV     2\n#define  UPDATED_IV      3\n#define  SE_KEYTABLE_DST_WORD_QUAD(x) ((x) << 0)\n#define  SE_KEYTABLE_DST_KEY_INDEX(x) ((x) << 8)\n\n#define SE_RNG_CONFIG_REG 0x340\n#define  MODE_NORMAL 0\n#define  MODE_FORCE_INSTANTION 1\n#define  MODE_FORCE_RESEED     2\n#define  SE_RNG_CONFIG_MODE(x)        ((x) << 0)\n#define  SRC_NONE        0\n#define  SRC_ENTROPY     1\n#define  SRC_LFSR        2\n#define  SE_RNG_CONFIG_SRC(x)         ((x) << 2)\n\n#define SE_RNG_SRC_CONFIG_REG\t0x344\n#define  RO_ENTR_LOCK_DISABLE  0\n#define  RO_ENTR_LOCK_ENABLE   1\n#define  SE_RNG_SRC_CONFIG_ENTR_SRC_LOCK(x) ((x) << 0)\n#define  RO_ENTR_DISABLE       0\n#define  RO_ENTR_ENABLE        1\n#define  SE_RNG_SRC_CONFIG_ENTR_SRC(x)      ((x) << 1)\n#define  RO_HW_DIS_CYA_DISABLE 0\n#define  RO_HW_DIS_CYA_ENABLE  1\n#define  SE_RNG_SRC_CONFIG_HW_DIS_CYA(x)    ((x) << 2)\n#define  SE_RNG_SRC_CONFIG_ENTR_SUBSMPL(x)  ((x) << 4)\n#define  SE_RNG_SRC_CONFIG_ENTR_DATA_FLUSH  BIT(8)\n\n#define SE_RNG_RESEED_INTERVAL_REG 0x348\n\n#define SE_RSA_CONFIG 0x400\n#define  RSA_KEY_SLOT_ONE 0\n#define  RSA_KEY_SLOT_TW0 1\n#define  RSA_KEY_SLOT(x)            ((x) << 24)\n\n#define SE_RSA_KEY_SIZE_REG 0x404\n#define  RSA_KEY_WIDTH_512  0\n#define  RSA_KEY_WIDTH_1024 1\n#define  RSA_KEY_WIDTH_1536 2\n#define  RSA_KEY_WIDTH_2048 3\n\n#define SE_RSA_EXP_SIZE_REG 0x408\n\n#define SE_RSA_SECURITY_PERKEY_REG 0x40C\n#define  SE_RSA_KEY_LOCK_FLAG               0x80\n#define SE_RSA_KEYTABLE_ACCESS_REG 0x410\n#define  SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG    BIT(0)\n#define  SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG  BIT(1)\n#define  SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG     BIT(2)\n#define  SE_RSA_KEY_TBL_DIS_KEY_ACCESS_FLAG 0x7F\n#define  SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG      (SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG | SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG)\n#define  SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_USE_FLAG  (SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG | SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG | SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG)\n\n#define SE_RSA_KEYTABLE_ADDR_REG 0x420\n#define  SE_RSA_KEYTABLE_PKT(x)        ((x) << 0)\n#define  RSA_KEY_TYPE_EXP       0\n#define  RSA_KEY_TYPE_MOD       1\n#define  SE_RSA_KEYTABLE_TYPE(x)       ((x) << 6)\n#define  RSA_KEY_NUM(x)                ((x) << 7)\n#define  RSA_KEY_INPUT_MODE_REG 0\n#define  RSA_KEY_INPUT_MODE_DMA 1\n#define  SE_RSA_KEYTABLE_INPUT_MODE(x) ((x) << 8)\n#define  RSA_KEY_READ           0\n#define  RSA_KEY_WRITE          1\n#define  SE_RSA_KEY_OP(x)              ((x) << 10)\n\n#define SE_RSA_KEYTABLE_DATA_REG 0x424\n\n#define SE_RSA_OUTPUT_REG 0x428\n#define  SE_RSA_OUTPUT_REG_COUNT 64\n\n#define SE_STATUS_REG 0x800\n#define  SE_STATUS_STATE_IDLE     0\n#define  SE_STATUS_STATE_BUSY     1\n#define  SE_STATUS_STATE_WAIT_OUT 2\n#define  SE_STATUS_STATE_WAIT_IN  3\n#define  SE_STATUS_STATE_MASK     3\n#define  SE_STATUS_MEM_IF_IDLE    (0 << 2)\n#define  SE_STATUS_MEM_IF_BUSY    BIT(2)\n\n#define SE_ERR_STATUS_REG 0x804\n#define  SE_ERR_STATUS_SE_NS_ACCESS    BIT(0)\n#define  SE_ERR_STATUS_BUSY_REG_WR     BIT(1)\n#define  SE_ERR_STATUS_DST             BIT(2)\n#define  SE_ERR_STATUS_SRK_USAGE_LIMIT BIT(3)\n#define  SE_ERR_STATUS_TZRAM_NS_ACCESS BIT(24)\n#define  SE_ERR_STATUS_TZRAM_ADDRESS   BIT(25)\n\n#define SE_MISC_REG 0x808\n#define  SE_ENTROPY_NEXT_192BIT BIT(0)\n#define  SE_ENTROPY_VN_BYPASS   BIT(1)\n#define  SE_CLK_OVR_ON          BIT(2)\n\n#define SE_SPARE_REG 0x80C\n#define  SE_INPUT_NONCE_LE BIT(0)\n\n#endif\n"
  },
  {
    "path": "bdk/sec/tsec.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2024 CTCaer\n * Copyright (c) 2018 balika011\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include \"tsec.h\"\n#include \"tsec_t210.h\"\n#include <memory_map.h>\n#include <mem/heap.h>\n#include <mem/mc.h>\n#include <mem/smmu.h>\n#include <sec/se_t210.h>\n#include <soc/bpmp.h>\n#include <soc/clock.h>\n#include <soc/kfuse.h>\n#include <soc/pmc.h>\n#include <soc/t210.h>\n#include <soc/timer.h>\n\n// #include <gfx_utils.h>\n\n#define PKG11_MAGIC 0x31314B50\n\n#define TSEC_HOS_KB_620 6\n\nstatic int _tsec_dma_wait_idle()\n{\n\tu32 timeout = get_tmr_ms() + 10000;\n\n\twhile (!(TSEC(TSEC_DMATRFCMD) & TSEC_DMATRFCMD_IDLE))\n\t\tif (get_tmr_ms() > timeout)\n\t\t\treturn 1;\n\n\treturn 0;\n}\n\nstatic int _tsec_dma_pa_to_internal_100(int not_imem, int i_offset, int pa_offset)\n{\n\tu32 cmd;\n\n\tif (not_imem)\n\t\tcmd = TSEC_DMATRFCMD_SIZE_256B; // DMA 256 bytes\n\telse\n\t\tcmd = TSEC_DMATRFCMD_IMEM;      // DMA IMEM (Instruction memmory)\n\n\tTSEC(TSEC_DMATRFMOFFS)  = i_offset;\n\tTSEC(TSEC_DMATRFFBOFFS) = pa_offset;\n\tTSEC(TSEC_DMATRFCMD)    = cmd;\n\n\treturn _tsec_dma_wait_idle();\n}\n\nint tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt)\n{\n\tint res = 0;\n\tu8 *fwbuf = NULL;\n\tu32 type = tsec_ctxt->type;\n\tu32 *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec;\n\tu32 *pkg11_magic_off;\n\tvoid *ptb;\n\n\tbpmp_mmu_disable();\n\tbpmp_clk_rate_relaxed(true);\n\n\t// Enable clocks.\n\tclock_enable_tsec();\n\tclock_enable_sor_safe();\n\tclock_enable_sor0();\n\tclock_enable_sor1();\n\tclock_enable_kfuse();\n\tkfuse_wait_ready();\n\n\t// Disable AHB aperture.\n\tmc_disable_ahb_redirect();\n\n\tif (type == TSEC_FW_TYPE_NEW)\n\t{\n\t\t// Disable all CCPLEX core rails.\n\t\tpmc_domain_pwrgate_set(POWER_RAIL_CE0, DISABLE);\n\t\tpmc_domain_pwrgate_set(POWER_RAIL_CE1, DISABLE);\n\t\tpmc_domain_pwrgate_set(POWER_RAIL_CE2, DISABLE);\n\t\tpmc_domain_pwrgate_set(POWER_RAIL_CE3, DISABLE);\n\n\t\t// Enable AHB aperture and set it to full mmio.\n\t\tmc_enable_ahb_redirect(0);\n\t}\n\n\t// Configure Falcon.\n\tTSEC(TSEC_DMACTL) = 0;\n\tTSEC(TSEC_IRQMSET) =\n\t\tTSEC_IRQMSET_EXT(0xFF) |\n\t\tTSEC_IRQMSET_WDTMR     |\n\t\tTSEC_IRQMSET_HALT      |\n\t\tTSEC_IRQMSET_EXTERR    |\n\t\tTSEC_IRQMSET_SWGEN0    |\n\t\tTSEC_IRQMSET_SWGEN1;\n\tTSEC(TSEC_IRQDEST) =\n\t\tTSEC_IRQDEST_EXT(0xFF) |\n\t\tTSEC_IRQDEST_HALT      |\n\t\tTSEC_IRQDEST_EXTERR    |\n\t\tTSEC_IRQDEST_SWGEN0    |\n\t\tTSEC_IRQDEST_SWGEN1;\n\tTSEC(TSEC_ITFEN) = TSEC_ITFEN_CTXEN | TSEC_ITFEN_MTHDEN;\n\tif (_tsec_dma_wait_idle())\n\t{\n\t\tres = -1;\n\t\tgoto out;\n\t}\n\n\t// Load firmware or emulate memio environment for newer TSEC fw.\n\tif (type == TSEC_FW_TYPE_EMU)\n\t\tTSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8;\n\telse\n\t{\n\t\tfwbuf = (u8 *)malloc(SZ_16K);\n\t\tu8 *fwbuf_aligned = (u8 *)ALIGN((u32)fwbuf, 0x100);\n\t\tmemcpy(fwbuf_aligned, tsec_ctxt->fw, tsec_ctxt->size);\n\n\t\tTSEC(TSEC_DMATRFBASE) = (u32)fwbuf_aligned >> 8;\n\t}\n\n\tfor (u32 addr = 0; addr < tsec_ctxt->size; addr += 0x100)\n\t{\n\t\tif (_tsec_dma_pa_to_internal_100(false, addr, addr))\n\t\t{\n\t\t\tres = -2;\n\t\t\tgoto out_free;\n\t\t}\n\t}\n\n\tif (type == TSEC_FW_TYPE_EMU)\n\t{\n\t\t// Init SMMU translation for TSEC.\n\t\tptb = smmu_domain_init(MC_SMMU_TSEC_ASID, 1);\n\t\tsmmu_init();\n\n\t\t// Enable SMMU.\n\t\tsmmu_enable();\n\n\t\t// Clock reset controller.\n\t\tcar = smmu_page_zalloc(1);\n\t\tmemcpy(car, (void *)CLOCK_BASE, SZ_PAGE);\n\t\tcar[CLK_RST_CONTROLLER_CLK_SOURCE_TSEC / 4] = CLK_SRC_DIV(2);\n\t\tsmmu_map(ptb, CLOCK_BASE, (u32)car, 1, SMMU_WRITE | SMMU_READ | SMMU_NS);\n\n\t\t// Fuse driver.\n\t\tfuse = smmu_page_zalloc(1);\n\t\tmemcpy((void *)&fuse[0x800/4], (void *)FUSE_BASE, SZ_1K);\n\t\tfuse[0x82C / 4] = 0;\n\t\tfuse[0x9E0 / 4] = (1 << (TSEC_HOS_KB_620 + 2)) - 1;\n\t\tfuse[0x9E4 / 4] = (1 << (TSEC_HOS_KB_620 + 2)) - 1;\n\t\tsmmu_map(ptb, (FUSE_BASE - 0x800), (u32)fuse, 1, SMMU_READ | SMMU_NS);\n\n\t\t// Power management controller.\n\t\tpmc = smmu_page_zalloc(1);\n\t\tsmmu_map(ptb, RTC_BASE, (u32)pmc, 1, SMMU_READ | SMMU_NS);\n\n\t\t// Flow control.\n\t\tflowctrl = smmu_page_zalloc(1);\n\t\tsmmu_map(ptb, FLOW_CTLR_BASE, (u32)flowctrl, 1, SMMU_WRITE | SMMU_NS);\n\n\t\t// Security engine.\n\t\tse = smmu_page_zalloc(1);\n\t\tmemcpy(se, (void *)SE_BASE, SZ_PAGE);\n\t\tsmmu_map(ptb, SE_BASE, (u32)se, 1, SMMU_READ | SMMU_WRITE | SMMU_NS);\n\n\t\t// Memory controller.\n\t\tmc = smmu_page_zalloc(1);\n\t\tmemcpy(mc, (void *)MC_BASE, SZ_PAGE);\n\t\tmc[MC_IRAM_BOM / 4] = 0;\n\t\tmc[MC_IRAM_TOM / 4] = DRAM_START;\n\t\tsmmu_map(ptb, MC_BASE, (u32)mc, 1, SMMU_READ | SMMU_NS);\n\n\t\t// IRAM\n\t\tiram = smmu_page_zalloc(0x30);\n\t\tmemcpy(iram, tsec_ctxt->pkg1, 0x30000);\n\t\t// PKG1.1 magic offset.\n\t\tpkg11_magic_off = (u32 *)(iram + ((tsec_ctxt->pkg11_off + 0x20) / sizeof(u32)));\n\t\tsmmu_map(ptb, 0x40010000, (u32)iram, 0x30, SMMU_READ | SMMU_WRITE | SMMU_NS);\n\n\t\t// Exception vectors\n\t\tevec = smmu_page_zalloc(1);\n\t\tsmmu_map(ptb, EXCP_VEC_BASE, (u32)evec, 1, SMMU_READ | SMMU_WRITE | SMMU_NS);\n\t}\n\n\t// Execute firmware.\n\tHOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA;\n\tTSEC(TSEC_MAILBOX1) = 0;\n\tTSEC(TSEC_MAILBOX0) = 1; // Set HOS key version.\n\tTSEC(TSEC_BOOTVEC)  = 0;\n\tTSEC(TSEC_CPUCTL)   = TSEC_CPUCTL_STARTCPU;\n\n\tif (type == TSEC_FW_TYPE_EMU)\n\t{\n\t\tu32 k = se[SE_CRYPTO_KEYTABLE_DATA_REG / 4];\n\t\tu32 timeout = get_tmr_us() + 125000;\n\t\tu32 key[16] = {0};\n\t\tu32 kidx = 0;\n\n\t\twhile (*pkg11_magic_off != PKG11_MAGIC)\n\t\t{\n\t\t\tsmmu_flush_all();\n\n\t\t\tif (k != se[SE_CRYPTO_KEYTABLE_DATA_REG / 4])\n\t\t\t{\n\t\t\t\tk = se[SE_CRYPTO_KEYTABLE_DATA_REG / 4];\n\t\t\t\tkey[kidx++] = k;\n\t\t\t}\n\n\t\t\t// Failsafe.\n\t\t\tif ((u32)get_tmr_us() > timeout)\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif (kidx != 8)\n\t\t{\n\t\t\tres = -6;\n\t\t\tsmmu_domain_deinit(MC_SMMU_TSEC_ASID, 1);\n\n\t\t\tgoto out_free;\n\t\t}\n\n\t\t// Give some extra time to make sure PKG1.1 is decrypted.\n\t\tmsleep(50);\n\n\t\tmemcpy(tsec_keys, &key, 0x20);\n\t\tmemcpy(tsec_ctxt->pkg1, iram, 0x30000);\n\n\t\tsmmu_domain_deinit(MC_SMMU_TSEC_ASID, 1);\n\n\t\t// for (int i = 0; i < kidx; i++)\n\t\t// \tgfx_printf(\"key %08X\\n\", key[i]);\n\n\t\t// gfx_printf(\"cpuctl (%08X) mbox (%08X)\\n\", TSEC(TSEC_CPUCTL), TSEC(TSEC_MAILBOX1));\n\n\t\t// u32 errst = MC(MC_ERR_STATUS);\n\t\t// gfx_printf(\" MC %08X %08X %08X\\n\", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR));\n\t\t// gfx_printf(\" type: %02X\\n\", errst >> 28);\n\t\t// gfx_printf(\" smmu: %02X\\n\", (errst >> 25) & 3);\n\t\t// gfx_printf(\" dir:  %s\\n\", (errst >> 16) & 1 ? \"W\" : \"R\");\n\t\t// gfx_printf(\" cid:  %02x\\n\", errst & 0xFF);\n\t}\n\telse\n\t{\n\t\tif (_tsec_dma_wait_idle())\n\t\t{\n\t\t\tres = -3;\n\t\t\tgoto out_free;\n\t\t}\n\n\t\tu32 timeout = get_tmr_ms() + 2000;\n\t\twhile (!TSEC(TSEC_MAILBOX1))\n\t\t{\n\t\t\tif (get_tmr_ms() > timeout)\n\t\t\t{\n\t\t\t\tres = -4;\n\t\t\t\tgoto out_free;\n\t\t\t}\n\t\t}\n\n\t\tif (TSEC(TSEC_MAILBOX1) != 0xB0B0B0B0)\n\t\t{\n\t\t\tres = -5;\n\t\t\tgoto out_free;\n\t\t}\n\n\t\t// Fetch result.\n\t\tHOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0;\n\t\tu32 buf[4];\n\t\tbuf[0] = SOR1(SOR_DP_HDCP_BKSV_LSB);\n\t\tbuf[1] = SOR1(SOR_TMDS_HDCP_BKSV_LSB);\n\t\tbuf[2] = SOR1(SOR_TMDS_HDCP_CN_MSB);\n\t\tbuf[3] = SOR1(SOR_TMDS_HDCP_CN_LSB);\n\t\tSOR1(SOR_DP_HDCP_BKSV_LSB)   = 0;\n\t\tSOR1(SOR_TMDS_HDCP_BKSV_LSB) = 0;\n\t\tSOR1(SOR_TMDS_HDCP_CN_MSB)   = 0;\n\t\tSOR1(SOR_TMDS_HDCP_CN_LSB)   = 0;\n\n\t\tmemcpy(tsec_keys, &buf, SE_KEY_128_SIZE);\n\t}\n\nout_free:\n\tfree(fwbuf);\n\nout:\n\t// Disable clocks.\n\tclock_disable_kfuse();\n\tclock_disable_sor1();\n\tclock_disable_sor0();\n\tclock_disable_sor_safe();\n\tclock_disable_tsec();\n\tbpmp_mmu_enable();\n\tbpmp_clk_rate_relaxed(false);\n\n\t// Re-enable AHB aperture.\n\tmc_enable_ahb_redirect(1);\n\n\treturn res;\n}\n"
  },
  {
    "path": "bdk/sec/tsec.h",
    "content": "/*\n* Copyright (c) 2018 naehrwert\n* Copyright (c) 2018-2024 CTCaer\n*\n* This program is free software; you can redistribute it and/or modify it\n* under the terms and conditions of the GNU General Public License,\n* version 2, as published by the Free Software Foundation.\n*\n* This program is distributed in the hope it will be useful, but WITHOUT\n* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n* more details.\n*\n* You should have received a copy of the GNU General Public License\n* along with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n#ifndef _TSEC_H_\n#define _TSEC_H_\n\n#include <utils/types.h>\n\nenum tsec_fw_type\n{\n\t// Retail Hovi Keygen.\n\tTSEC_FW_TYPE_OLD = 0, // 1.0.0 - 6.1.0.\n\tTSEC_FW_TYPE_EMU = 1, // 6.2.0 emulated environment.\n\tTSEC_FW_TYPE_NEW = 2, // 7.0.0+.\n};\n\ntypedef struct _tsec_ctxt_t\n{\n\tvoid *fw;\n\tu32 size;\n\tu32 type;\n\tvoid *pkg1;\n\tu32 pkg11_off;\n} tsec_ctxt_t;\n\nint tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt);\n\n#endif\n"
  },
  {
    "path": "bdk/sec/tsec_t210.h",
    "content": "/*\n* Copyright (c) 2018-2023 CTCaer\n*\n* This program is free software; you can redistribute it and/or modify it\n* under the terms and conditions of the GNU General Public License,\n* version 2, as published by the Free Software Foundation.\n*\n* This program is distributed in the hope it will be useful, but WITHOUT\n* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n* more details.\n*\n* You should have received a copy of the GNU General Public License\n* along with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n#ifndef _TSEC_T210_H_\n#define _TSEC_T210_H_\n\n#define TSEC_MAILBOX0      0x1040\n#define TSEC_MAILBOX1      0x1044\n#define TSEC_ITFEN         0x1048\n#define  TSEC_ITFEN_CTXEN         BIT(0)\n#define  TSEC_ITFEN_MTHDEN        BIT(1)\n#define TSEC_IRQMSET       0x1010\n#define  TSEC_IRQMSET_WDTMR       BIT(1)\n#define  TSEC_IRQMSET_HALT        BIT(4)\n#define  TSEC_IRQMSET_EXTERR      BIT(5)\n#define  TSEC_IRQMSET_SWGEN0      BIT(6)\n#define  TSEC_IRQMSET_SWGEN1      BIT(7)\n#define  TSEC_IRQMSET_EXT(val)    (((val) & 0xFF) << 8)\n#define TSEC_IRQDEST       0x101C\n#define  TSEC_IRQDEST_HALT        BIT(4)\n#define  TSEC_IRQDEST_EXTERR      BIT(5)\n#define  TSEC_IRQDEST_SWGEN0      BIT(6)\n#define  TSEC_IRQDEST_SWGEN1      BIT(7)\n#define  TSEC_IRQDEST_EXT(val)    (((val) & 0xFF) << 8)\n#define TSEC_CPUCTL       0x1100\n#define  TSEC_CPUCTL_STARTCPU     BIT(1)\n#define TSEC_BOOTVEC      0x1104\n#define TSEC_DMACTL       0x110C\n#define TSEC_DMATRFBASE   0x1110\n#define TSEC_DMATRFMOFFS  0x1114\n#define TSEC_DMATRFCMD    0x1118\n#define  TSEC_DMATRFCMD_IDLE      BIT(1)\n#define  TSEC_DMATRFCMD_IMEM      BIT(4)\n#define  TSEC_DMATRFCMD_SIZE_256B (6 << 8)\n#define TSEC_DMATRFFBOFFS 0x111C\n\n#endif\n"
  },
  {
    "path": "bdk/soc/actmon.c",
    "content": "/*\n * Activity Monitor driver for Tegra X1\n *\n * Copyright (c) 2021 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include \"actmon.h\"\n#include \"clock.h\"\n#include \"t210.h\"\n\n/* Global registers */\n#define ACTMON_GLB_STATUS          0x0\n#define  ACTMON_MCCPU_MON_ACT      BIT(8)\n#define  ACTMON_MCALL_MON_ACT      BIT(9)\n#define  ACTMON_CPU_FREQ_MON_ACT   BIT(10)\n#define  ACTMON_APB_MON_ACT        BIT(12)\n#define  ACTMON_AHB_MON_ACT        BIT(13)\n#define  ACTMON_BPMP_MON_ACT       BIT(14)\n#define  ACTMON_CPU_MON_ACT        BIT(15)\n#define  ACTMON_MCCPU_INTR         BIT(25)\n#define  ACTMON_MCALL_INTR         BIT(26)\n#define  ACTMON_CPU_FREQ_INTR      BIT(27)\n#define  ACTMON_APB_INTR           BIT(28)\n#define  ACTMON_AHB_INTR           BIT(29)\n#define  ACTMON_BPMP_INTR          BIT(30)\n#define  ACTMON_CPU_INTR           BIT(31)\n#define ACTMON_GLB_PERIOD_CTRL     0x4\n#define  ACTMON_GLB_PERIOD_USEC    BIT(8)\n#define  ACTMON_GLB_PERIOD_SAMPLE(n) (((n) - 1) & 0xFF)\n\n/* Device Registers */\n#define ACTMON_DEV_BASE            ACTMON_BASE + 0x80\n#define  ACTMON_DEV_SIZE           0x40\n/* CTRL */\n#define  ACTMON_DEV_CTRL_K_VAL(k)                       (((k) & 7) << 10)\n#define  ACTMON_DEV_CTRL_ENB_PERIODIC                   BIT(18)\n#define  ACTMON_DEV_CTRL_AT_END_EN                      BIT(19)\n#define  ACTMON_DEV_CTRL_AVG_BELOW_WMARK_EN             BIT(20)\n#define  ACTMON_DEV_CTRL_AVG_ABOVE_WMARK_EN             BIT(21)\n#define  ACTMON_DEV_CTRL_WHEN_OVERFLOW_EN               BIT(22)\n#define  ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_NUM(n) (((n) & 7) << 23)\n#define  ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_NUM(n) (((n) & 7) << 26)\n#define  ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN     BIT(29)\n#define  ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN     BIT(30)\n#define  ACTMON_DEV_CTRL_ENB                            BIT(31)\n/* INTR_STATUS */\n#define  ACTMON_DEV_ISTS_AVG_ABOVE_WMARK   BIT(24)\n#define  ACTMON_DEV_ISTS_AVG_BELOW_WMARK   BIT(25)\n#define  ACTMON_DEV_ISTS_WHEN_OVERFLOW     BIT(26)\n#define  ACTMON_DEV_ISTS_AT_END            BIT(29)\n#define  ACTMON_DEV_ISTS_CONSECUTIVE_LOWER BIT(30)\n#define  ACTMON_DEV_ISTS_CONSECUTIVE_UPPER BIT(31)\n\n/* Histogram Registers */\n#define ACTMON_HISTOGRAM_CONFIG    0x300\n#define  ACTMON_HIST_CFG_ACTIVE                   BIT(0)\n#define  ACTMON_HIST_CFG_LINEAR_MODE              BIT(1)\n#define  ACTMON_HIST_CFG_NO_UNDERFLOW_BUCKET      BIT(2)\n#define  ACTMON_HIST_CFG_STALL_ON_SINGLE_SATURATE BIT(3)\n#define  ACTMON_HIST_CFG_SHIFT(s)                 (((s) & 0x1F) << 4)\n#define  ACTMON_HIST_CFG_SOURCE(s)                (((s) & 0xF) << 12)\n#define ACTMON_HISTOGRAM_CTRL      0x304\n#define  ACTMON_HIST_CTRL_CLEAR_ALL               BIT(0)\n#define ACTMON_HISTOGRAM_DATA_BASE 0x380\n#define  ACTMON_HISTOGRAM_DATA_NUM 32\n\n#define ACTMON_FREQ      19200000\n#define ACTMON_PERIOD_MS 20\n#define DEV_COUNT_WEIGHT 5\n\ntypedef struct _actmon_dev_reg_t\n{\n\tvu32 ctrl;\n\tvu32 upper_wnark;\n\tvu32 lower_wmark;\n\tvu32 init_avg;\n\tvu32 avg_upper_wmark;\n\tvu32 avg_lower_wmark;\n\tvu32 count_weight;\n\tvu32 count;\n\tvu32 avg_count;\n\tvu32 intr_status;\n\tvu32 ctrl2;\n\tvu32 rsvd[5];\n} actmon_dev_reg_t;\n\nvoid actmon_hist_enable(actmon_hist_src_t src)\n{\n\tACTMON(ACTMON_HISTOGRAM_CONFIG) = ACTMON_HIST_CFG_SOURCE(src) | ACTMON_HIST_CFG_ACTIVE;\n\tACTMON(ACTMON_HISTOGRAM_CTRL) = ACTMON_HIST_CTRL_CLEAR_ALL;\n}\n\nvoid actmon_hist_disable()\n{\n\tACTMON(ACTMON_HISTOGRAM_CONFIG) = 0;\n}\n\nvoid actmon_hist_get(u32 *histogram)\n{\n\tif (histogram)\n\t{\n\t\tfor (u32 i = 0; i < ACTMON_HISTOGRAM_DATA_NUM; i++)\n\t\t\thistogram[i] = ACTMON(ACTMON_HISTOGRAM_DATA_BASE + i * sizeof(u32));\n\t}\n}\n\nvoid actmon_dev_enable(actmon_dev_t dev)\n{\n\tactmon_dev_reg_t *regs = (actmon_dev_reg_t *)(ACTMON_DEV_BASE + (dev * ACTMON_DEV_SIZE));\n\n\tregs->init_avg = ACTMON_FREQ * ACTMON_PERIOD_MS * DEV_COUNT_WEIGHT / 100;\n\tregs->count_weight = DEV_COUNT_WEIGHT;\n\n\tregs->ctrl = ACTMON_DEV_CTRL_ENB | ACTMON_DEV_CTRL_ENB_PERIODIC | ACTMON_DEV_CTRL_K_VAL(7); // 128 samples average.\n}\n\nvoid actmon_dev_disable(actmon_dev_t dev)\n{\n\tactmon_dev_reg_t *regs = (actmon_dev_reg_t *)(ACTMON_DEV_BASE + (dev * ACTMON_DEV_SIZE));\n\n\tregs->ctrl = 0;\n}\n\nu32 actmon_dev_get_load(actmon_dev_t dev)\n{\n\tactmon_dev_reg_t *regs = (actmon_dev_reg_t *)(ACTMON_DEV_BASE + (dev * ACTMON_DEV_SIZE));\n\n\t// Get load-based sampling. 1 decimal point precision.\n\tu32 load = regs->count * 100 / (ACTMON_FREQ / (ACTMON_PERIOD_MS * DEV_COUNT_WEIGHT));\n\n\treturn load;\n}\n\nu32 actmon_dev_get_load_avg(actmon_dev_t dev)\n{\n\tactmon_dev_reg_t *regs = (actmon_dev_reg_t *)(ACTMON_DEV_BASE + (dev * ACTMON_DEV_SIZE));\n\n\t// Get load-based sampling. 1 decimal point precision.\n\tu32 avg_load = regs->avg_count * 100 / (ACTMON_FREQ / (ACTMON_PERIOD_MS * DEV_COUNT_WEIGHT));\n\n\treturn avg_load;\n}\n\nvoid atmon_dev_all_disable()\n{\n\t// TODO: do a global reset?\n}\n\nvoid actmon_init()\n{\n\tclock_enable_actmon();\n\n\t// Set period.\n\tACTMON(ACTMON_GLB_PERIOD_CTRL) = ACTMON_GLB_PERIOD_SAMPLE(ACTMON_PERIOD_MS);\n}\n\nvoid actmon_end()\n{\n\tclock_disable_actmon();\n}"
  },
  {
    "path": "bdk/soc/actmon.h",
    "content": "/*\n * Activity Monitor driver for Tegra X1\n *\n * Copyright (c) 2021 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef __ACTMON_H_\n#define __ACTMON_H_\n\n#include <utils/types.h>\n\ntypedef enum _actmon_dev_t\n{\n\tACTMON_DEV_CPU,\n\tACTMON_DEV_BPMP,\n\tACTMON_DEV_AHB,\n\tACTMON_DEV_APB,\n\tACTMON_DEV_CPU_FREQ,\n\tACTMON_DEV_MC_ALL,\n\tACTMON_DEV_MC_CPU,\n\n\tACTMON_DEV_NUM,\n} actmon_dev_t;\n\ntypedef enum _actmon_hist_src_t\n{\n\tACTMON_HIST_SRC_NONE     = 0,\n\tACTMON_HIST_SRC_AHB      = 1,\n\tACTMON_HIST_SRC_APB      = 2,\n\tACTMON_HIST_SRC_BPMP     = 3,\n\tACTMON_HIST_SRC_CPU      = 4,\n\tACTMON_HIST_SRC_MC_ALL   = 5,\n\tACTMON_HIST_SRC_MC_CPU   = 6,\n\tACTMON_HIST_SRC_CPU_FREQ = 7,\n\tACTMON_HIST_SRC_NA       = 8,\n\tACTMON_HIST_SRC_APB_MMIO = 9,\n} actmon_hist_src_t;\n\nvoid actmon_hist_enable(actmon_hist_src_t src);\nvoid actmon_hist_disable();\nvoid actmon_hist_get(u32 *histogram);\nvoid actmon_dev_enable(actmon_dev_t dev);\nvoid actmon_dev_disable(actmon_dev_t dev);\nu32  actmon_dev_get_load(actmon_dev_t dev);\nu32  actmon_dev_get_load_avg(actmon_dev_t dev);\nvoid atmon_dev_all_disable();\nvoid actmon_init();\nvoid actmon_end();\n\n#endif"
  },
  {
    "path": "bdk/soc/bpmp.c",
    "content": "/*\n * BPMP-Lite Cache/MMU and Frequency driver for Tegra X1\n *\n * Copyright (c) 2019-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <soc/bpmp.h>\n#include <soc/clock.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n#include <memory_map.h>\n\n#define BPMP_MMU_CACHE_LINE_SIZE        0x20\n\n#define BPMP_CACHE_CONFIG               0x0\n#define  CFG_ENABLE_CACHE               BIT(0)\n#define  CFG_ENABLE_SKEW_ASSOC          BIT(1)\n#define  CFG_DISABLE_RANDOM_ALLOC       BIT(2)\n#define  CFG_FORCE_WRITE_THROUGH        BIT(3)\n#define  CFG_NEVER_ALLOCATE             BIT(6)\n#define  CFG_ENABLE_INTERRUPT           BIT(7)\n#define  CFG_MMU_TAG_MODE(x)            ((x) << 8)\n#define   TAG_MODE_PARALLEL             0\n#define   TAG_MODE_TAG_FIRST            1\n#define   TAG_MODE_MMU_FIRST            2\n#define  CFG_DISABLE_WRITE_BUFFER       BIT(10)\n#define  CFG_DISABLE_READ_BUFFER        BIT(11)\n#define  CFG_ENABLE_HANG_DETECT         BIT(12)\n#define  CFG_FULL_LINE_DIRTY            BIT(13)\n#define  CFG_TAG_CHK_ABRT_ON_ERR        BIT(14)\n#define  CFG_TAG_CHK_CLR_ERR            BIT(15)\n#define  CFG_DISABLE_SAMELINE           BIT(16)\n#define  CFG_OBS_BUS_EN                 BIT(31)\n\n#define BPMP_CACHE_LOCK                 0x4\n#define  LOCK_LINE(x)                   BIT((x))\n\n#define BPMP_CACHE_SIZE                 0xC\n#define BPMP_CACHE_LFSR                 0x10\n\n#define BPMP_CACHE_TAG_STATUS           0x14\n#define  TAG_STATUS_TAG_CHECK_ERROR     BIT(0)\n#define  TAG_STATUS_CONFLICT_ADDR_MASK  0xFFFFFFE0\n\n#define BPMP_CACHE_CLKEN_OVERRIDE       0x18\n#define  CLKEN_OVERRIDE_WR_MCCIF_CLKEN  BIT(0)\n#define  CLKEN_OVERRIDE_RD_MCCIF_CLKEN  BIT(1)\n\n#define BPMP_CACHE_MAINT_ADDR           0x20\n#define BPMP_CACHE_MAINT_DATA           0x24\n\n#define BPMP_CACHE_MAINT_REQ            0x28\n#define  MAINT_REQ_WAY_BITMAP(x)        ((x) << 8)\n\n#define BPMP_CACHE_INT_MASK             0x40\n#define BPMP_CACHE_INT_CLEAR            0x44\n#define BPMP_CACHE_INT_RAW_EVENT        0x48\n#define BPMP_CACHE_INT_STATUS           0x4C\n#define  INT_MAINT_DONE                 BIT(0)\n#define  INT_MAINT_ERROR                BIT(1)\n\n#define BPMP_CACHE_RB_CFG               0x80\n#define BPMP_CACHE_WB_CFG               0x84\n\n#define BPMP_CACHE_MMU_FALLBACK_ENTRY   0xA0\n#define BPMP_CACHE_MMU_SHADOW_COPY_MASK 0xA4\n\n#define BPMP_CACHE_MMU_CFG              0xAC\n#define  MMU_CFG_BLOCK_MAIN_ENTRY_WR    BIT(0)\n#define  MMU_CFG_SEQ_EN                 BIT(1)\n#define  MMU_CFG_TLB_EN                 BIT(2)\n#define  MMU_CFG_SEG_CHECK_ALL_ENTRIES  BIT(3)\n#define  MMU_CFG_ABORT_STORE_LAST       BIT(4)\n#define  MMU_CFG_CLR_ABORT              BIT(5)\n\n#define BPMP_CACHE_MMU_CMD              0xB0\n#define  MMU_CMD_NOP                    0\n#define  MMU_CMD_INIT                   1\n#define  MMU_CMD_COPY_SHADOW            2\n\n#define BPMP_CACHE_MMU_ABORT_STAT       0xB4\n#define  ABORT_STAT_UNIT_MASK           0x7\n#define  ABORT_STAT_UNIT_NONE           0\n#define  ABORT_STAT_UNIT_CACHE          1\n#define  ABORT_STAT_UNIT_SEQ            2\n#define  ABORT_STAT_UNIT_TLB            3\n#define  ABORT_STAT_UNIT_SEG            4\n#define  ABORT_STAT_UNIT_FALLBACK       5\n#define  ABORT_STAT_OVERLAP             BIT(3)\n#define  ABORT_STAT_ENTRY               (0x1F << 4)\n#define  ABORT_STAT_TYPE_MASK           (3 << 16)\n#define  ABORT_STAT_TYPE_EXE            (0 << 16)\n#define  ABORT_STAT_TYPE_RD             (1 << 16)\n#define  ABORT_STAT_TYPE_WR             (2 << 16)\n#define  ABORT_STAT_SIZE                (3 << 18)\n#define  ABORT_STAT_SEQ                 BIT(20)\n#define  ABORT_STAT_PROT                BIT(21)\n\n#define BPMP_CACHE_MMU_ABORT_ADDR       0xB8\n#define BPMP_CACHE_MMU_ACTIVE_ENTRIES   0xBC\n\n#define BPMP_MMU_SHADOW_ENTRY_BASE      (BPMP_CACHE_BASE + 0x400)\n#define BPMP_MMU_MAIN_ENTRY_BASE        (BPMP_CACHE_BASE + 0x800)\n#define  MMU_EN_CACHED                  BIT(0)\n#define  MMU_EN_EXEC                    BIT(1)\n#define  MMU_EN_READ                    BIT(2)\n#define  MMU_EN_WRITE                   BIT(3)\n\nstatic const bpmp_mmu_entry_t mmu_entries[] =\n{\n\t{ DRAM_START, 0xFFFFFFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true },\n\t{ IRAM_BASE,  0x4003FFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true }\n};\n\nvoid bpmp_mmu_maintenance(u32 op, bool force)\n{\n\tif (!force && !(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE))\n\t\treturn;\n\n\tBPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = INT_MAINT_DONE;\n\n\t// This is a blocking operation.\n\tBPMP_CACHE_CTRL(BPMP_CACHE_MAINT_REQ) = MAINT_REQ_WAY_BITMAP(0xF) | op;\n\n\twhile (!(BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT) & INT_MAINT_DONE))\n\t\t;\n\n\tBPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT);\n}\n\nvoid bpmp_mmu_set_entry(int idx, const bpmp_mmu_entry_t *entry, bool apply)\n{\n\tif (idx > 31)\n\t\treturn;\n\n\tvolatile bpmp_mmu_entry_t *mmu_entry = (bpmp_mmu_entry_t *)(BPMP_MMU_SHADOW_ENTRY_BASE + sizeof(bpmp_mmu_entry_t) * idx);\n\n\tif (entry->enable)\n\t{\n\t\tmmu_entry->start_addr = ALIGN(entry->start_addr, BPMP_MMU_CACHE_LINE_SIZE);\n\t\tmmu_entry->end_addr   = ALIGN_DOWN(entry->end_addr, BPMP_MMU_CACHE_LINE_SIZE);\n\t\tmmu_entry->attr       = entry->attr;\n\n\t\tBPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) |= BIT(idx);\n\n\t\tif (apply)\n\t\t\tBPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW;\n\t}\n}\n\nvoid bpmp_mmu_enable()\n{\n\tif (BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE)\n\t\treturn;\n\n\t// Init BPMP MMU.\n\tBPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD)            = MMU_CMD_INIT;\n\tBPMP_CACHE_CTRL(BPMP_CACHE_MMU_FALLBACK_ENTRY) = MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC; // RWX for non-defined regions.\n\tBPMP_CACHE_CTRL(BPMP_CACHE_MMU_CFG)            = MMU_CFG_SEQ_EN | MMU_CFG_TLB_EN | MMU_CFG_ABORT_STORE_LAST;\n\n\t// Init BPMP MMU entries.\n\tBPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) = 0;\n\tfor (u32 idx = 0; idx < ARRAY_SIZE(mmu_entries); idx++)\n\t\tbpmp_mmu_set_entry(idx, &mmu_entries[idx], false);\n\n\tBPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW;\n\n\t// Invalidate cache.\n\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, true);\n\n\t// Enable cache.\n\tBPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = CFG_ENABLE_CACHE | CFG_FORCE_WRITE_THROUGH |\n\t\tCFG_MMU_TAG_MODE(TAG_MODE_PARALLEL) | CFG_TAG_CHK_ABRT_ON_ERR;\n\n\t// HW bug. Invalidate cache again.\n\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);\n}\n\nvoid bpmp_mmu_disable()\n{\n\tif (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE))\n\t\treturn;\n\n\t// Clean and invalidate cache.\n\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);\n\n\t// Disable cache.\n\tBPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0;\n}\n\n\n/*\n * CLK_RST_CONTROLLER_SCLK_BURST_POLICY:\n * 0 = CLKM\n * 1 = PLLC_OUT1\n * 2 = PLLC4_OUT3\n * 3 = PLLP_OUT0\n * 4 = PLLP_OUT2\n * 5 = PLLC4_OUT1\n * 6 = CLK_S\n * 7 = PLLC4_OUT2\n */\n\nbpmp_freq_t bpmp_fid_current = BPMP_CLK_NORMAL;\n\nvoid bpmp_clk_rate_relaxed(bool enable)\n{\n\t// This is a glitch-free way to reduce the SCLK timings.\n\tif (enable)\n\t{\n\t\t// Restore to PLLP source during PLLC configuration.\n\t\tCLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003330; // PLLP_OUT.\n\t\t(void)CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY);\n\t\tusleep(100); // Wait a bit for clock source change.\n\t\tCLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // S1:H1:P3.\n\t\t(void)CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE);\n\t}\n\telse if (bpmp_fid_current)\n\t{\n\t\t// Restore to PLLC_OUT1.\n\t\tCLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // S1:H1:P4.\n\t\tCLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003310; // PLLC_OUT1 and CLKM for idle.\n\t\t(void)CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY);\n\t\tusleep(100); // Wait a bit for clock source change.\n\t}\n}\n\n// APB clock affects RTC, PWM, MEMFETCH, APE, USB, SOR PWM,\n// I2C host, DC/DSI/DISP. UART gives extra stress.\n// 92: 100% success ratio. 93-94: 595-602MHz has 99% success ratio. 95: 608MHz less.\n// APB clock max is supposed to be 204 MHz though.\nstatic const u8 pll_divn[] = {\n\t0,   // BPMP_CLK_NORMAL:      408MHz  0% - 136MHz APB.\n\t85,  // BPMP_CLK_HIGH_BOOST:  544MHz 33% - 136MHz APB.\n\t88,  // BPMP_CLK_HIGH2_BOOST: 563MHz 38% - 141MHz APB.\n\t90,  // BPMP_CLK_SUPER_BOOST: 576MHz 41% - 144MHz APB.\n\t92,  // BPMP_CLK_HYPER_BOOST: 589MHz 44% - 147MHz APB.\n\t// Do not use for public releases!\n\t//95   // BPMP_CLK_DEV_BOOST: 608MHz 49% - 152MHz APB.\n};\n\nvoid bpmp_clk_rate_get()\n{\n\tbool clk_src_is_pllp = ((CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) >> 4) & 7) == 3;\n\n\tif (clk_src_is_pllp)\n\t\tbpmp_fid_current = BPMP_CLK_NORMAL;\n\telse\n\t{\n\t\tbpmp_fid_current = BPMP_CLK_HIGH_BOOST;\n\n\t\tu8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF;\n\t\tfor (u32 i = 1; i < sizeof(pll_divn); i++)\n\t\t{\n\t\t\tif (pll_divn[i] == pll_divn_curr)\n\t\t\t{\n\t\t\t\tbpmp_fid_current = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid bpmp_clk_rate_set(bpmp_freq_t fid)\n{\n\tif (fid >= BPMP_CLK_NUM)\n\t\tfid = BPMP_CLK_NUM - 1;\n\n\tif (bpmp_fid_current == fid)\n\t\treturn;\n\n\tbpmp_fid_current = fid;\n\n\t// Use default SCLK / HCLK / PCLK clocks.\n\tbpmp_clk_rate_relaxed(true);\n\n\tif (fid)\n\t{\n\t\t// Configure and enable PLLC.\n\t\tclock_enable_pllc(pll_divn[fid]);\n\n\t\t// Set new source and SCLK / HCLK / PCLK dividers.\n\t\tbpmp_clk_rate_relaxed(false);\n\t}\n\telse\n\t{\n\t\t// Disable PLLC to save power.\n\t\tclock_disable_pllc();\n\t}\n}\n\n// State is reset to RUN on any clock or source set via SW.\nvoid bpmp_state_set(bpmp_state_t state)\n{\n\tu32 cfg = CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & ~0xF0000000u;\n\tCLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = cfg | (state << 28u);\n}\n\n// The following functions halt BPMP to reduce power while sleeping.\n// They are not as accurate as RTC at big values but they guarantee time+ delay.\nvoid bpmp_usleep(u32 us)\n{\n\tu32 delay;\n\n\t// Each iteration takes 1us.\n\twhile (us)\n\t{\n\t\tdelay = (us > HALT_MAX_CNT) ? HALT_MAX_CNT : us;\n\t\tus -= delay;\n\n\t\tFLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_MODE_WAITEVENT | HALT_USEC | delay;\n\t}\n}\n\nvoid bpmp_msleep(u32 ms)\n{\n\tu32 delay;\n\n\t// Iteration time is variable. ~200 - 1000us.\n\twhile (ms)\n\t{\n\t\tdelay = (ms > HALT_MAX_CNT) ? HALT_MAX_CNT : ms;\n\t\tms -= delay;\n\n\t\tFLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_MODE_WAITEVENT | HALT_MSEC | delay;\n\t}\n}\n\nvoid bpmp_halt()\n{\n\tFLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_MODE_WAITEVENT | HALT_JTAG;\n}\n"
  },
  {
    "path": "bdk/soc/bpmp.h",
    "content": "/*\n * BPMP-Lite Cache/MMU and Frequency driver for Tegra X1\n *\n * Copyright (c) 2019-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _BPMP_H_\n#define _BPMP_H_\n\n#include <utils/types.h>\n\ntypedef enum\n{\n\tBPMP_MMU_MAINT_NOP                =  0,\n\tBPMP_MMU_MAINT_CLEAN_PHY          =  1,\n\tBPMP_MMU_MAINT_INVALID_PHY        =  2,\n\tBPMP_MMU_MAINT_CLEAN_INVALID_PHY  =  3,\n\tBPMP_MMU_MAINT_CLEAN_LINE         =  9,\n\tBPMP_MMU_MAINT_INVALID_LINE       = 10,\n\tBPMP_MMU_MAINT_CLEAN_INVALID_LINE = 11,\n\tBPMP_MMU_MAINT_CLEAN_WAY          = 17,\n\tBPMP_MMU_MAINT_INVALID_WAY        = 18,\n\tBPMP_MMU_MAINT_CLN_INV_WAY        = 19\n} bpmp_maintenance_t;\n\ntypedef struct _bpmp_mmu_entry_t\n{\n\tu32 start_addr;\n\tu32 end_addr;\n\tu32 attr;\n\tu32 enable;\n} bpmp_mmu_entry_t;\n\ntypedef enum\n{\n\tBPMP_CLK_NORMAL,      // 408MHz  0% - 136MHz APB.\n\tBPMP_CLK_HIGH_BOOST,  // 544MHz 33% - 136MHz APB.\n\tBPMP_CLK_HIGH2_BOOST, // 563MHz 38% - 141MHz APB.\n\tBPMP_CLK_SUPER_BOOST, // 576MHz 41% - 144MHz APB.\n\tBPMP_CLK_HYPER_BOOST, // 589MHz 44% - 147MHz APB.\n\t//BPMP_CLK_DEV_BOOST, // 608MHz 49% - 152MHz APB.\n\tBPMP_CLK_NUM\n} bpmp_freq_t;\n\ntypedef enum\n{\n\tBPMP_STATE_STANDBY = 0, // 32KHz.\n\tBPMP_STATE_IDLE    = 1,\n\tBPMP_STATE_RUN     = 2,\n\n\tBPMP_STATE_IRQ     = BIT(2),\n\tBPMP_STATE_FIQ     = BIT(3),\n} bpmp_state_t;\n\n#define BPMP_CLK_BIN0_BOOST    BPMP_CLK_HYPER_BOOST\n#define BPMP_CLK_BIN1_BOOST    BPMP_CLK_SUPER_BOOST\n#define BPMP_CLK_BIN2_BOOST    BPMP_CLK_HIGH2_BOOST\n#define BPMP_CLK_BIN3_BOOST    BPMP_CLK_HIGH_BOOST\n\n#define BPMP_CLK_LOWEST_BOOST  BPMP_CLK_BIN3_BOOST\n#define BPMP_CLK_LOWER_BOOST   BPMP_CLK_BIN1_BOOST\n#define BPMP_CLK_DEFAULT_BOOST BPMP_CLK_BIN0_BOOST\n\nvoid bpmp_mmu_maintenance(u32 op, bool force);\nvoid bpmp_mmu_set_entry(int idx, const bpmp_mmu_entry_t *entry, bool apply);\nvoid bpmp_mmu_enable();\nvoid bpmp_mmu_disable();\nvoid bpmp_clk_rate_relaxed(bool enable);\nvoid bpmp_clk_rate_get();\nvoid bpmp_clk_rate_set(bpmp_freq_t fid);\nvoid bpmp_state_set(bpmp_state_t state);\nvoid bpmp_usleep(u32 us);\nvoid bpmp_msleep(u32 ms);\nvoid bpmp_halt();\n\n#endif\n"
  },
  {
    "path": "bdk/soc/ccplex.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2024 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <memory_map.h>\n#include <soc/ccplex.h>\n#include <soc/hw_init.h>\n#include <soc/i2c.h>\n#include <soc/clock.h>\n#include <soc/pmc.h>\n#include <soc/t210.h>\n#include <power/max77620.h>\n#include <power/max7762x.h>\n#include <power/max77812.h>\n#include <utils/util.h>\n\n#define CCPLEX_FLOWCTRL_POWERGATING 0\n\nstatic void _ccplex_enable_power_t210()\n{\n\t// Configure GPIO5 and enable output in order to power CPU pmic.\n\tmax77620_config_gpio(5, MAX77620_GPIO_OUTPUT_ENABLE);\n\n\t// Configure CPU pmic.\n\t// 1-3.x: MAX77621_NFSR_ENABLE.\n\t// 1.0.0-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL.\n\tmax77621_config_default(REGULATOR_CPU0, MAX77621_CTRL_HOS_CFG);\n\n\t// Set voltage and enable cluster power.\n\tmax7762x_regulator_set_voltage(REGULATOR_CPU0, 950000);\n\tmax7762x_regulator_enable(REGULATOR_CPU0, true);\n}\n\nstatic void _ccplex_enable_power_t210b01()\n{\n\t// Set voltage and enable cluster power.\n\tmax7762x_regulator_set_voltage(REGULATOR_CPU1, 800000);\n\tmax7762x_regulator_enable(REGULATOR_CPU1, true);\n}\n\nstatic void _ccplex_disable_power()\n{\n\t// Disable cluster power.\n\tif (hw_get_chip_id() == GP_HIDREV_MAJOR_T210)\n\t{\n\t\tmax7762x_regulator_enable(REGULATOR_CPU0, false);\n\t\ti2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 0);\n\t}\n\telse\n\t\tmax7762x_regulator_enable(REGULATOR_CPU1, false);\n}\n\nvoid ccplex_boot_cpu0(u32 entry, bool lock)\n{\n\t// Set ACTIVE_CLUSER to FAST.\n\tFLOW_CTLR(FLOW_CTLR_BPMP_CLUSTER_CONTROL) &= ~CLUSTER_CTRL_ACTIVE_SLOW;\n\n\tif (hw_get_chip_id() == GP_HIDREV_MAJOR_T210)\n\t\t_ccplex_enable_power_t210();\n\telse\n\t\t_ccplex_enable_power_t210b01();\n\n\tclock_enable_pllx();\n\n\t// Configure MSELECT source and enable clock to 102MHz.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT) = (0 << 29) | CLK_SRC_DIV(4);\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET)      = BIT(CLK_V_MSELECT);\n\n\t// Configure initial CPU clock frequency and enable clock.\n\tCLOCK(CLK_RST_CONTROLLER_CCLK_BURST_POLICY)  = 0x20008888; // PLLX_OUT0_LJ.\n\tCLOCK(CLK_RST_CONTROLLER_SUPER_CCLK_DIVIDER) = BIT(31);    // SUPER_CDIV_ENB.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET)      = BIT(CLK_V_CPUG);\n\n\tclock_enable_coresight();\n\n\t// CAR2PMC_CPU_ACK_WIDTH should be set to 0.\n\tCLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000;\n\n\t// Enable CPU main rail.\n\tpmc_domain_pwrgate_set(POWER_RAIL_CRAIL, ENABLE);\n\t// Enable cluster 0 non-CPU rail.\n\tpmc_domain_pwrgate_set(POWER_RAIL_C0NC,  ENABLE);\n\t// Enable CPU0 rail.\n\tpmc_domain_pwrgate_set(POWER_RAIL_CE0,   ENABLE);\n\n\t// Request and wait for RAM repair. Needed for the Fast cluster.\n\tFLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = RAM_REPAIR_REQ;\n\twhile (!(FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) & RAM_REPAIR_STS))\n\t\t;\n\n\tEXCP_VEC(EVP_CPU_RESET_VECTOR) = 0;\n\n\t// Set reset vector.\n\tSB(SB_AA64_RESET_LOW)  = entry | SB_AA64_RST_AARCH64_MODE_EN;\n\tSB(SB_AA64_RESET_HIGH) = 0;\n\n\t// Non-secure reset vector write disable.\n\tif (lock)\n\t{\n\t\tSB(SB_CSR) = SB_CSR_NS_RST_VEC_WR_DIS;\n\t\t(void)SB(SB_CSR);\n\t}\n\n\t// Tighten up the security aperture.\n\t// MC(MC_TZ_SECURITY_CTRL) = TZ_SEC_CTRL_CPU_STRICT_TZ_APERTURE_CHECK;\n\n\t// Clear MSELECT reset.\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_V_CLR)      = BIT(CLK_V_MSELECT);\n\t// Clear NONCPU reset.\n\tCLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = BIT(29); // CLR_NONCPURESET.\n\t// Clear CPU0 reset.\n\t// < 5.x: 0x411F000F, Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset.\n\tCLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = BIT(30) | BIT(24) | BIT(16) | BIT(0);\n}\n\nvoid ccplex_powergate_cpu0()\n{\n#if CCPLEX_FLOWCTRL_POWERGATING\n\t// Halt CPU0.\n\tFLOW_CTLR(FLOW_CTLR_HALT_CPU0_EVENTS) = HALT_MODE_STOP_UNTIL_IRQ;\n\n\t// Powergate cluster via flow control without waiting for WFI.\n\tFLOW_CTLR(FLOW_CTLR_CPU0_CSR) = CSR_INTR_FLAG | CSR_EVENT_FLAG | CSR_ENABLE_EXT_CPU_RAIL | CSR_WAIT_WFI_NONE | CSR_ENABLE;\n\n\t// Wait for the rail power off to finish.\n\twhile((FLOW_CTLR(FLOW_CTLR_CPU_PWR_CSR) & CPU_PWR_RAIL_STS_MASK) != CPU_PWR_RAIL_OFF);\n\n\t// Set CPU0 to waitevent.\n\tFLOW_CTLR(FLOW_CTLR_HALT_CPU0_EVENTS) = HALT_MODE_WAITEVENT;\n#endif\n\n\t// Set CPU0 POR and CORE, CX0, L2, and DBG reset.\n\tCLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET) = BIT(30) | BIT(24) | BIT(16) | BIT(0);\n\t// Set NONCPU reset.\n\tCLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET) = BIT(29);\n\n\t// Disable CE0.\n\tpmc_domain_pwrgate_set(POWER_RAIL_CE0,   DISABLE);\n\t// Disable cluster 0 non-CPU.\n\tpmc_domain_pwrgate_set(POWER_RAIL_C0NC,  DISABLE);\n\t// Disable CPU rail.\n\tpmc_domain_pwrgate_set(POWER_RAIL_CRAIL, DISABLE);\n\n\tclock_disable_coresight();\n\n\t// Clear out MSELECT and CPU clocks.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_CLR) = BIT(CLK_V_CPUG);\n\n\t_ccplex_disable_power();\n}\n"
  },
  {
    "path": "bdk/soc/ccplex.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _CCPLEX_H_\n#define _CCPLEX_H_\n\n#include <utils/types.h>\n\nvoid ccplex_boot_cpu0(u32 entry, bool lock);\nvoid ccplex_powergate_cpu0();\n\n#endif\n"
  },
  {
    "path": "bdk/soc/clock.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <soc/bpmp.h>\n#include <soc/clock.h>\n#include <soc/hw_init.h>\n#include <soc/pmc.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n#include <storage/sdmmc.h>\n\n#define RST_DEV_L_SET CLK_RST_CONTROLLER_RST_DEV_L_SET\n#define RST_DEV_H_SET CLK_RST_CONTROLLER_RST_DEV_H_SET\n#define RST_DEV_U_SET CLK_RST_CONTROLLER_RST_DEV_U_SET\n#define RST_DEV_V_SET CLK_RST_CONTROLLER_RST_DEV_V_SET\n#define RST_DEV_W_SET CLK_RST_CONTROLLER_RST_DEV_W_SET\n#define RST_DEV_X_SET CLK_RST_CONTROLLER_RST_DEV_X_SET\n#define RST_DEV_Y_SET CLK_RST_CONTROLLER_RST_DEV_Y_SET\n\n#define CLK_ENB_L_SET CLK_RST_CONTROLLER_CLK_ENB_L_SET\n#define CLK_ENB_H_SET CLK_RST_CONTROLLER_CLK_ENB_H_SET\n#define CLK_ENB_U_SET CLK_RST_CONTROLLER_CLK_ENB_U_SET\n#define CLK_ENB_V_SET CLK_RST_CONTROLLER_CLK_ENB_V_SET\n#define CLK_ENB_W_SET CLK_RST_CONTROLLER_CLK_ENB_W_SET\n#define CLK_ENB_X_SET CLK_RST_CONTROLLER_CLK_ENB_X_SET\n#define CLK_ENB_Y_SET CLK_RST_CONTROLLER_CLK_ENB_Y_SET\n\n#define RST_DEV_H_CLR CLK_RST_CONTROLLER_RST_DEV_H_CLR\n#define CLK_ENB_H_CLR CLK_RST_CONTROLLER_CLK_ENB_H_CLR\n\ntypedef struct _clk_rst_mgd_t\n{\n\tu16 reset;  // Reset  SET.\n\tu16 enable; // Enable SET.\n\tu16 source;\n\tu8  index;\n} clk_rst_mgd_t;\n\ntypedef struct _clock_osc_t\n{\n\tu32 freq;\n\tu16 min;\n\tu16 max;\n} clock_osc_t;\n\nstatic const clock_osc_t _clock_osc_cnt[] = {\n\t{ 12000, 706,  757  },\n\t{ 13000, 766,  820  },\n\t{ 16800, 991,  1059 },\n\t{ 19200, 1133, 1210 },\n\t{ 26000, 1535, 1638 },\n\t{ 38400, 2268, 2418 },\n\t{ 48000, 2836, 3023 }\n};\n\n/*\n * T210 rare HW Errata\n * A fraction of T210 silicon has an undocumented HW Errata on SDMMC clock state machine.\n * Specifically on enable when using the combo registers. Using SET/CLR variants is mandatory.\n */\nstatic const clk_rst_mgd_t _clock_sdmmc[] = {\n\t{ RST_DEV_L_SET, CLK_ENB_L_SET, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1, CLK_L_SDMMC1 },\n\t{ RST_DEV_L_SET, CLK_ENB_L_SET, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2, CLK_L_SDMMC2 },\n\t{ RST_DEV_U_SET, CLK_ENB_U_SET, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3, CLK_U_SDMMC3 },\n\t{ RST_DEV_L_SET, CLK_ENB_L_SET, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4, CLK_L_SDMMC4 },\n};\n\n/* clk_rst_t: reset, enable, source, index, clk_src, clk_div */\n\nstatic const clk_rst_t _clock_uart[] = {\n\t{ RST_DEV_L_SET, CLK_ENB_L_SET, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA,   CLK_L_UARTA,   0, CLK_SRC_DIV(2) },\n\t{ RST_DEV_L_SET, CLK_ENB_L_SET, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB,   CLK_L_UARTB,   0, CLK_SRC_DIV(2) },\n\t{ RST_DEV_H_SET, CLK_ENB_H_SET, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC,   CLK_H_UARTC,   0, CLK_SRC_DIV(2) },\n\t{ RST_DEV_U_SET, CLK_ENB_U_SET, CLK_RST_CONTROLLER_CLK_SOURCE_UARTD,   CLK_U_UARTD,   0, CLK_SRC_DIV(2) },\n\t{ RST_DEV_Y_SET, CLK_ENB_Y_SET, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, CLK_Y_UARTAPE, 0, CLK_SRC_DIV(2) }\n};\n\n// I2C Fout = Fin / (TLOW + THIGH + 2) / FM_DIV). Default parameters - TLOW: 4, THIGH: 2, DEBOUNCE: 0, FM_DIV: 6.\nstatic const clk_rst_t _clock_i2c[] = {\n\t{ RST_DEV_L_SET, CLK_ENB_L_SET, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, CLK_L_I2C1, 6, CLK_I2C_SRC_DIV(4) }, //  4.8 MHz -> 100 KHz\n\t{ RST_DEV_H_SET, CLK_ENB_H_SET, CLK_RST_CONTROLLER_CLK_SOURCE_I2C2, CLK_H_I2C2, 6, CLK_I2C_SRC_DIV(1) }, // 19.2 MHz -> 400 KHz\n\t{ RST_DEV_U_SET, CLK_ENB_U_SET, CLK_RST_CONTROLLER_CLK_SOURCE_I2C3, CLK_U_I2C3, 6, CLK_I2C_SRC_DIV(1) }, // 19.2 MHz -> 400 KHz\n\t{ RST_DEV_V_SET, CLK_ENB_V_SET, CLK_RST_CONTROLLER_CLK_SOURCE_I2C4, CLK_V_I2C4, 6, CLK_I2C_SRC_DIV(4) }, //  4.8 MHz -> 100 KHz\n\t{ RST_DEV_H_SET, CLK_ENB_H_SET, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, CLK_H_I2C5, 6, CLK_I2C_SRC_DIV(1) }, // 19.2 MHz -> 400 KHz\n\t{ RST_DEV_X_SET, CLK_ENB_X_SET, CLK_RST_CONTROLLER_CLK_SOURCE_I2C6, CLK_X_I2C6, 6, CLK_I2C_SRC_DIV(4) }  //  4.8 MHz -> 100 KHz\n};\n\nstatic clk_rst_t _clock_se = {\n\tRST_DEV_V_SET, CLK_ENB_V_SET, CLK_RST_CONTROLLER_CLK_SOURCE_SE,          CLK_V_SE,          0, CLK_SRC_DIV(1)   // 408 MHz. Max: 627.2 MHz.\n};\nstatic clk_rst_t _clock_tzram = {\n\tRST_DEV_V_SET, CLK_ENB_V_SET, CLK_NO_SOURCE,                             CLK_V_TZRAM,       0, 0\n};\nstatic clk_rst_t _clock_host1x = { // Has idle divisor.\n\tRST_DEV_L_SET, CLK_ENB_L_SET, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X,      CLK_L_HOST1X,      4, CLK_SRC_DIV(2.5) // 163.2MHz. Max: 408 MHz.\n};\nstatic clk_rst_t _clock_tsec = {\n\tRST_DEV_U_SET, CLK_ENB_U_SET, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC,        CLK_U_TSEC,        0, CLK_SRC_DIV(2)   // 204 MHz. Max: 408 MHz.\n};\nstatic clk_rst_t _clock_nvdec = {\n\tRST_DEV_Y_SET, CLK_ENB_Y_SET, CLK_RST_CONTROLLER_CLK_SOURCE_NVDEC,       CLK_Y_NVDEC,       4, CLK_SRC_DIV(1)   // 408 MHz. Max: 716.8/979.2 MHz.\n};\nstatic clk_rst_t _clock_nvjpg = {\n\tRST_DEV_Y_SET, CLK_ENB_Y_SET, CLK_RST_CONTROLLER_CLK_SOURCE_NVJPG,       CLK_Y_NVJPG,       4, CLK_SRC_DIV(1)   // 408 MHz. Max: 627.2/652.8 MHz.\n};\nstatic clk_rst_t _clock_vic = { // Has idle divisor.\n\tRST_DEV_X_SET, CLK_ENB_X_SET, CLK_RST_CONTROLLER_CLK_SOURCE_VIC,         CLK_X_VIC,         2, CLK_SRC_DIV(1)   // 408 MHz. Max: 627.2/652.8 MHz.\n};\nstatic clk_rst_t _clock_sor_safe = {\n\tRST_DEV_Y_SET, CLK_ENB_Y_SET, CLK_NO_SOURCE,                             CLK_Y_SOR_SAFE,    0, 0                // 24 MHz.\n};\nstatic clk_rst_t _clock_sor0 = {\n\tRST_DEV_X_SET, CLK_ENB_X_SET, CLK_NOT_USED,                              CLK_X_SOR0,        0, 0                // 24 MHz (safe).\n};\nstatic clk_rst_t _clock_sor1 = {\n\tRST_DEV_X_SET, CLK_ENB_X_SET, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1,        CLK_X_SOR1,        0, CLK_SRC_DIV(2)   // 204 MHz.\n};\nstatic clk_rst_t _clock_kfuse = {\n\tRST_DEV_H_SET, CLK_ENB_H_SET, CLK_NO_SOURCE,                             CLK_H_KFUSE,       0, 0\n};\nstatic clk_rst_t _clock_cl_dvfs =\t{\n\tRST_DEV_W_SET, CLK_ENB_W_SET, CLK_NO_SOURCE,                             CLK_W_DVFS,        0, 0\n};\nstatic clk_rst_t _clock_coresight = {\n\tRST_DEV_U_SET, CLK_ENB_U_SET, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE,       CLK_U_CSITE,       0, CLK_SRC_DIV(3)   // 136 MHz.\n};\nstatic clk_rst_t _clock_pwm = {\n\tRST_DEV_L_SET, CLK_ENB_L_SET, CLK_RST_CONTROLLER_CLK_SOURCE_PWM,         CLK_L_PWM,         6, CLK_SRC_DIV(3)   // Fref: 6.4MHz. HOS: PLLP / 54 = 7.55MHz.\n};\nstatic clk_rst_t _clock_sdmmc_legacy_tm = {\n\tRST_DEV_Y_SET, CLK_ENB_Y_SET, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM, CLK_Y_SDMMC_LEGACY_TM, 4, CLK_SRC_DIV(34) // 12MHz.\n};\nstatic clk_rst_t _clock_apbdma = {\n\tRST_DEV_H_SET, CLK_ENB_H_SET, CLK_NO_SOURCE,                             CLK_H_APBDMA,      0, 0                // Max: 204 MHz.\n};\nstatic clk_rst_t _clock_ahbdma = {\n\tRST_DEV_H_SET, CLK_ENB_H_SET, CLK_NO_SOURCE,                             CLK_H_AHBDMA,      0, 0                // Max: 408 MHz.\n};\nstatic clk_rst_t _clock_actmon = {\n\tRST_DEV_V_SET, CLK_ENB_V_SET, CLK_RST_CONTROLLER_CLK_SOURCE_ACTMON,      CLK_V_ACTMON,      6, CLK_SRC_DIV(1)   // 19.2 MHz.\n};\nstatic clk_rst_t _clock_extperiph1 = {\n\tRST_DEV_V_SET, CLK_ENB_V_SET, CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH1,  CLK_V_EXTPERIPH1,  0, CLK_SRC_DIV(1)\n};\nstatic clk_rst_t _clock_extperiph2 = {\n\tRST_DEV_V_SET, CLK_ENB_V_SET, CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH2,  CLK_V_EXTPERIPH2,  2, CLK_SRC_DIV(102) // 4.0 MHz\n};\n\nvoid clock_enable(const clk_rst_t *clk)\n{\n\tconst u32 module = BIT(clk->index);\n\n\t// Put clock into reset.\n\tCLOCK(clk->reset) = module;\n\n\t// Disable.\n\tCLOCK(clk->enable + CLK_CLR_OFFSET) = module;\n\n\t// Configure clock source if required.\n\tif (clk->source)\n\t\tCLOCK(clk->source) = (clk->clk_src << 29u) | clk->clk_div;\n\n\t// Enable.\n\tCLOCK(clk->enable) = module;\n\tusleep(2);\n\n\t// Take clock off reset.\n\tCLOCK(clk->reset + CLK_CLR_OFFSET) = module;\n\n\t// Commit changes.\n\t(void)CLOCK(clk->reset);\n}\n\nvoid clock_disable(const clk_rst_t *clk)\n{\n\tconst u32 module = BIT(clk->index);\n\n\t// Put clock into reset.\n\tCLOCK(clk->reset) = module;\n\n\t// Disable.\n\tCLOCK(clk->enable + CLK_CLR_OFFSET) = module;\n}\n\nvoid clock_enable_fuse(bool enable)\n{\n\t// Enable Fuse registers visibility.\n\tCLOCK(CLK_RST_CONTROLLER_MISC_CLK_ENB) = (CLOCK(CLK_RST_CONTROLLER_MISC_CLK_ENB) & 0xEFFFFFFF) | ((enable & 1) << 28);\n}\n\nvoid clock_enable_uart(u32 idx)\n{\n\t// Ease the stress to APB.\n\tbpmp_clk_rate_relaxed(true);\n\n\tclock_enable(&_clock_uart[idx]);\n\n\t// Restore sys clock.\n\tbpmp_clk_rate_relaxed(false);\n}\n\nvoid clock_disable_uart(u32 idx)\n{\n\tclock_disable(&_clock_uart[idx]);\n}\n\n#define UART_SRC_CLK_DIV_EN BIT(24)\n\nint clock_uart_use_src_div(u32 idx, u32 baud)\n{\n\tu32 clk_src = CLOCK(_clock_uart[idx].source) & 0xE0000000;\n\n\tif (baud == 3000000)\n\t\tCLOCK(_clock_uart[idx].source) = clk_src | UART_SRC_CLK_DIV_EN | CLK_SRC_DIV(8.5);\n\telse if (baud == 1000000)\n\t\tCLOCK(_clock_uart[idx].source) = clk_src | UART_SRC_CLK_DIV_EN | CLK_SRC_DIV(25.5);\n\telse\n\t{\n\t\tCLOCK(_clock_uart[idx].source) = clk_src | CLK_SRC_DIV(2);\n\n\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n\nvoid clock_enable_i2c(u32 idx)\n{\n\t// Ease the stress to APB.\n\tbpmp_clk_rate_relaxed(true);\n\n\tclock_enable(&_clock_i2c[idx]);\n\n\t// Restore sys clock.\n\tbpmp_clk_rate_relaxed(false);\n}\n\nvoid clock_disable_i2c(u32 idx)\n{\n\tclock_disable(&_clock_i2c[idx]);\n}\n\nvoid clock_enable_se()\n{\n\tclock_enable(&_clock_se);\n\n\t// Lock clock to always enabled if T210B01.\n\tif (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01)\n\t\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SE) |= BIT(8);\n}\n\nvoid clock_enable_tzram()\n{\n\tclock_enable(&_clock_tzram);\n}\n\nvoid clock_enable_host1x()\n{\n\tclock_enable(&_clock_host1x);\n\n\t// Set idle frequency to 81.6 MHz.\n\t// CLOCK(_clock_host1x.clk_src) |= CLK_SRC_DIV(5) << 8;\n}\n\nvoid clock_disable_host1x()\n{\n\tclock_disable(&_clock_host1x);\n}\n\nvoid clock_enable_tsec()\n{\n\tclock_enable(&_clock_tsec);\n}\n\nvoid clock_disable_tsec()\n{\n\tclock_disable(&_clock_tsec);\n}\n\nvoid clock_enable_nvdec()\n{\n\tclock_enable(&_clock_nvdec);\n}\n\nvoid clock_disable_nvdec()\n{\n\tclock_disable(&_clock_nvdec);\n}\n\nvoid clock_enable_nvjpg()\n{\n\tclock_enable(&_clock_nvjpg);\n}\n\nvoid clock_disable_nvjpg()\n{\n\tclock_disable(&_clock_nvjpg);\n}\n\nvoid clock_enable_vic()\n{\n\t// Ease the stress to APB.\n\tbpmp_clk_rate_relaxed(true);\n\n\tclock_enable(&_clock_vic);\n\n\t// Set idle frequency to 136 MHz.\n\t// CLOCK(_clock_vic.clk_src) |= CLK_SRC_DIV(3) << 8;\n\n\t// Restore sys clock.\n\tbpmp_clk_rate_relaxed(false);\n}\n\nvoid clock_disable_vic()\n{\n\tclock_disable(&_clock_vic);\n}\n\nvoid clock_enable_sor_safe()\n{\n\tclock_enable(&_clock_sor_safe);\n}\n\nvoid clock_disable_sor_safe()\n{\n\tclock_disable(&_clock_sor_safe);\n}\n\nvoid clock_enable_sor0()\n{\n\tclock_enable(&_clock_sor0);\n}\n\nvoid clock_disable_sor0()\n{\n\tclock_disable(&_clock_sor0);\n}\n\nvoid clock_enable_sor1()\n{\n\tclock_enable(&_clock_sor1);\n}\n\nvoid clock_disable_sor1()\n{\n\tclock_disable(&_clock_sor1);\n}\n\nvoid clock_enable_kfuse()\n{\n\tCLOCK(RST_DEV_H_SET) = BIT(CLK_H_KFUSE);\n\tCLOCK(CLK_ENB_H_CLR) = BIT(CLK_H_KFUSE);\n\tCLOCK(CLK_ENB_H_SET) = BIT(CLK_H_KFUSE);\n\tusleep(10); // Wait 10us to prevent glitching.\n\n\tCLOCK(RST_DEV_H_CLR) = BIT(CLK_H_KFUSE);\n\tusleep(20); // Wait 20us for KFUSE HW to init.\n}\n\nvoid clock_disable_kfuse()\n{\n\tclock_disable(&_clock_kfuse);\n}\n\nvoid clock_enable_cl_dvfs()\n{\n\tclock_enable(&_clock_cl_dvfs);\n}\n\nvoid clock_disable_cl_dvfs()\n{\n\tclock_disable(&_clock_cl_dvfs);\n}\n\nvoid clock_enable_coresight()\n{\n\tclock_enable(&_clock_coresight);\n}\n\nvoid clock_disable_coresight()\n{\n\tclock_disable(&_clock_coresight);\n}\n\nvoid clock_enable_pwm()\n{\n\t// Ease the stress to APB.\n\tbpmp_clk_rate_relaxed(true);\n\n\tclock_enable(&_clock_pwm);\n\n\t// Restore sys clock.\n\tbpmp_clk_rate_relaxed(false);\n}\n\nvoid clock_disable_pwm()\n{\n\tclock_disable(&_clock_pwm);\n}\n\nvoid clock_enable_apbdma()\n{\n\tclock_enable(&_clock_apbdma);\n}\n\nvoid clock_disable_apbdma()\n{\n\tclock_disable(&_clock_apbdma);\n}\n\nvoid clock_enable_ahbdma()\n{\n\tclock_enable(&_clock_ahbdma);\n}\n\nvoid clock_disable_ahbdma()\n{\n\tclock_disable(&_clock_ahbdma);\n}\n\nvoid clock_enable_actmon()\n{\n\tclock_enable(&_clock_actmon);\n}\n\nvoid clock_disable_actmon()\n{\n\tclock_disable(&_clock_actmon);\n}\n\nvoid clock_enable_extperiph1()\n{\n\tclock_enable(&_clock_extperiph1);\n\n\tPMC(APBDEV_PMC_CLK_OUT_CNTRL) |= PMC_CLK_OUT_CNTRL_CLK1_SRC_SEL(OSC_CAR) | PMC_CLK_OUT_CNTRL_CLK1_FORCE_EN;\n\tusleep(5);\n}\n\nvoid clock_disable_extperiph1()\n{\n\tPMC(APBDEV_PMC_CLK_OUT_CNTRL) &= ~((PMC_CLK_OUT_CNTRL_CLK1_SRC_SEL(OSC_CAR)) | PMC_CLK_OUT_CNTRL_CLK1_FORCE_EN);\n\tclock_disable(&_clock_extperiph1);\n}\n\nvoid clock_enable_extperiph2()\n{\n\tclock_enable(&_clock_extperiph2);\n\n\tPMC(APBDEV_PMC_CLK_OUT_CNTRL) |= PMC_CLK_OUT_CNTRL_CLK2_SRC_SEL(OSC_CAR) | PMC_CLK_OUT_CNTRL_CLK2_FORCE_EN;\n\tusleep(5);\n}\n\nvoid clock_disable_extperiph2()\n{\n\tPMC(APBDEV_PMC_CLK_OUT_CNTRL) &= ~((PMC_CLK_OUT_CNTRL_CLK2_SRC_SEL(OSC_CAR)) | PMC_CLK_OUT_CNTRL_CLK2_FORCE_EN);\n\tclock_disable(&_clock_extperiph2);\n}\n\nstatic void _clock_pll_wait_lock(u32 base, u32 max_delay)\n{\n\tfor (u32 i = 0; i < max_delay; i++)\n\t{\n\t\tif (CLOCK(base) & PLL_BASE_LOCK)\n\t\t\tbreak;\n\t\tusleep(1);\n\t}\n\n\tusleep(2);\n}\n\nvoid clock_enable_plld(u32 divp, u32 divn, bool lowpower, bool tegra_t210)\n{\n\tu32 plld_div = (divp << 20) | (divn << 11) | 1;\n\n\t// N divider is fractional, so N = DIVN + 1/2 + PLLD_SDM_DIN/8192.\n\tu32 misc = BIT(21) | BIT(19) | BIT(18) | BIT(16) | 0xFC00; // Clock enable and PLLD_SDM_DIN: -1024 -> DIVN + 0.375.\n\tif (lowpower && tegra_t210)\n\t\tmisc = BIT(21) | BIT(19) | BIT(18) | BIT(16) | 0x0AAA; // Clock enable and PLLD_SDM_DIN:  2730 -> DIVN + 0.833.\n\n\t// Set DISP1 clock source.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DISP1) = 2 << 29u; // PLLD_OUT0.\n\n\t// Set dividers and enable PLLD.\n\tCLOCK(CLK_RST_CONTROLLER_PLLD_BASE)  = PLL_BASE_ENABLE | PLL_BASE_LOCK | plld_div;\n\tCLOCK(CLK_RST_CONTROLLER_PLLD_MISC1) = tegra_t210 ? 0x20 : 0; // Keep default PLLD_SETUP.\n\n\t// Set PLLD_SDM_DIN and enable (T210) PLLD to DSI pads.\n\tCLOCK(CLK_RST_CONTROLLER_PLLD_MISC) = misc;\n\n\t// Wait for PLL to stabilize.\n\t_clock_pll_wait_lock(CLK_RST_CONTROLLER_PLLD_BASE, 1000);\n}\n\nvoid clock_enable_pllx()\n{\n\t// Configure and enable PLLX if disabled.\n\tif (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & PLL_BASE_ENABLE))  // PLLX_ENABLE.\n\t{\n\t\tCLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= ~PLLX_MISC3_IDDQ; // Disable IDDQ.\n\t\tusleep(2);\n\n\t\t// Set div configuration.\n\t\tconst u32 pllx_div_cfg = (2 << 20) | (156 << 8) | 2; // P div: 2 (3), N div: 156, M div: 2. 998.4 MHz.\n\n\t\t// Bypass dividers.\n\t\tCLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = PLL_BASE_BYPASS | pllx_div_cfg;\n\t\t// Disable bypass\n\t\tCLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = pllx_div_cfg;\n\t\t// Set PLLX_LOCK_ENABLE.\n\t\tCLOCK(CLK_RST_CONTROLLER_PLLX_MISC) |= PLLX_MISC_LOCK_EN;\n\t\t// Enable PLLX.\n\t\tCLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = PLL_BASE_ENABLE | pllx_div_cfg;\n\t}\n\n\t// Wait for PLL to stabilize.\n\t_clock_pll_wait_lock(CLK_RST_CONTROLLER_PLLX_BASE, 300);\n}\n\nvoid clock_enable_pllc(u32 divn)\n{\n\tu32 enabled = CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLL_BASE_ENABLE;\n\tu8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF;\n\n\t// Check if already enabled and configured.\n\tif (enabled && (pll_divn_curr == divn))\n\t\treturn;\n\n\t// WAR: Disable first to avoid HPLL overshoot.\n\tif (enabled)\n\t\tclock_disable_pllc();\n\n\t// Take PLLC out of reset (misc) and set misc2 parameters.\n\tCLOCK(CLK_RST_CONTROLLER_PLLC_MISC)    = (0x8000 << 4); // PLLC_EXT_FRU.\n\tCLOCK(CLK_RST_CONTROLLER_PLLC_MISC_2) |= 0xF << 8;      // PLLC_FLL_LD_MEM.\n\n\t// Disable PLL and IDDQ in case they are on.\n\tCLOCK(CLK_RST_CONTROLLER_PLLC_BASE)   &= ~PLL_BASE_ENABLE;\n\tCLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) &= ~PLLC_MISC1_IDDQ;\n\tusleep(10);\n\n\t// Set PLLC dividers.\n\tCLOCK(CLK_RST_CONTROLLER_PLLC_BASE) = (divn << 10) | 6; // DIVM: 6, DIVP: 1.\n\n\t// Enable PLLC and wait for Phase and Frequency lock.\n\tCLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLL_BASE_ENABLE;\n\t_clock_pll_wait_lock(CLK_RST_CONTROLLER_PLLC_BASE, 300);\n\n\t// Disable PLLC_OUT1, enable reset and set div to 1.\n\tCLOCK(CLK_RST_CONTROLLER_PLLC_OUT) = 0;\n\n\t// Enable PLLC_OUT1 and bring it out of reset.\n\tCLOCK(CLK_RST_CONTROLLER_PLLC_OUT) |= PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR;\n\tmsleep(1); // Wait a bit for PLL to stabilize.\n}\n\nvoid clock_disable_pllc()\n{\n\t// Disable PLLC and PLLC_OUT1.\n\tCLOCK(CLK_RST_CONTROLLER_PLLC_OUT)    &= ~PLLC_OUT1_RSTN_CLR;\n\tCLOCK(CLK_RST_CONTROLLER_PLLC_MISC)    = PLLC_MISC_RESET;\n\tCLOCK(CLK_RST_CONTROLLER_PLLC_BASE)   &= ~PLL_BASE_ENABLE;\n\tCLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) |= PLLC_MISC1_IDDQ;\n\tCLOCK(CLK_RST_CONTROLLER_PLLC_MISC_2) &= ~(0xFF << 8); // PLLC_FLL_LD_MEM.\n\tusleep(10);\n}\n\n#define PLLC4_ENABLED BIT(31)\n#define PLLC4_IN_USE  (~PLLC4_ENABLED)\n\nu32 pllc4_enabled = 0;\n\nstatic void _clock_enable_pllc4(u32 mask)\n{\n\tpllc4_enabled |= mask;\n\n\tif (pllc4_enabled & PLLC4_ENABLED)\n\t\treturn;\n\n\t// Enable Phase and Frequency lock detection.\n\tCLOCK(CLK_RST_CONTROLLER_PLLC4_MISC) = PLLC4_MISC_EN_LCKDET;\n\n\t// Disable PLL and IDDQ in case they are on.\n\tCLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLL_BASE_ENABLE;\n\tCLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLLC4_BASE_IDDQ;\n\tusleep(10);\n\n\t// Set PLLC4 dividers.\n\tCLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) = (0 << 19) | (104 << 8) | 4; // DIVP: 1, DIVN: 104, DIVM: 4. 998MHz OUT0, 199MHz OUT2.\n\n\t// Enable PLLC4 and wait for Phase and Frequency lock.\n\tCLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) |= PLL_BASE_ENABLE;\n\t_clock_pll_wait_lock(CLK_RST_CONTROLLER_PLLC4_BASE, 300 + 700);\n\n\tpllc4_enabled |= PLLC4_ENABLED;\n}\n\nstatic void _clock_disable_pllc4(u32 mask)\n{\n\tpllc4_enabled &= ~mask;\n\n\t// Check if currently in use or disabled.\n\tif ((pllc4_enabled & PLLC4_IN_USE) || !(pllc4_enabled & PLLC4_ENABLED))\n\t\treturn;\n\n\t// Disable PLLC4.\n\tusleep(100); // Wait at least 100us to prevent glitching.\n\tCLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLL_BASE_ENABLE;\n\tCLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) |= PLLC4_BASE_IDDQ;\n\tusleep(10);\n\n\tpllc4_enabled = 0;\n}\n\nvoid clock_enable_pllu()\n{\n\t// Configure PLLU.\n\tCLOCK(CLK_RST_CONTROLLER_PLLU_MISC) |= BIT(29); // Disable reference clock.\n\tu32 pllu_cfg = (CLOCK(CLK_RST_CONTROLLER_PLLU_BASE) & 0xFFE00000) | BIT(24) | (1 << 16) | (0x19 << 8) | 2;\n\tCLOCK(CLK_RST_CONTROLLER_PLLU_BASE) = pllu_cfg;\n\tCLOCK(CLK_RST_CONTROLLER_PLLU_BASE) = pllu_cfg | PLL_BASE_ENABLE; // Enable.\n\n\t// Wait for PLL to stabilize.\n\t_clock_pll_wait_lock(CLK_RST_CONTROLLER_PLLU_BASE, 1000);\n\tusleep(8);\n\n\t// Enable PLLU USB/HSIC/ICUSB/48M.\n\tCLOCK(CLK_RST_CONTROLLER_PLLU_BASE) |= 0x2E00000;\n}\n\nvoid clock_disable_pllu()\n{\n\tCLOCK(CLK_RST_CONTROLLER_PLLU_BASE) &= ~0x2E00000; // Disable PLLU USB/HSIC/ICUSB/48M.\n\tCLOCK(CLK_RST_CONTROLLER_PLLU_BASE) &= ~BIT(30);   // Disable PLLU.\n\tCLOCK(CLK_RST_CONTROLLER_PLLU_MISC) &= ~BIT(29);   // Enable reference clock.\n}\n\nvoid clock_enable_utmipll()\n{\n\t// Set UTMIPLL dividers and config based on OSC and enable it to 960 MHz.\n\tCLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG0) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG0) & 0xFF0000FF) | (25 << 16) | (1 << 8); // 38.4Mhz * (25 / 1) = 960 MHz.\n\tCLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) & 0xFF00003F) | (24 << 18); // Set delay count for 38.4Mhz osc crystal.\n\tCLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) &  0x7FFA000) | (1 << 15) | 375;\n\n\t// Wait for UTMIPLL to stabilize.\n\tu32 retries = 10; // Wait 20us\n\twhile (!(CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) & UTMIPLL_LOCK) && retries)\n\t{\n\t\tusleep(1);\n\t\tretries--;\n\t}\n}\n\nstatic int _clock_sdmmc_in_reset(u32 id)\n{\n\tconst clk_rst_mgd_t *clk = &_clock_sdmmc[id];\n\n\treturn CLOCK(clk->reset) & BIT(clk->index);\n}\n\nstatic void _clock_sdmmc_set_reset(u32 id)\n{\n\tconst clk_rst_mgd_t *clk = &_clock_sdmmc[id];\n\n\tCLOCK(clk->reset) = BIT(clk->index);\n}\n\nstatic void _clock_sdmmc_clr_reset(u32 id)\n{\n\tconst clk_rst_mgd_t *clk = &_clock_sdmmc[id];\n\n\tCLOCK(clk->reset + CLK_CLR_OFFSET) = BIT(clk->index);\n}\n\nstatic int _clock_sdmmc_is_enabled(u32 id)\n{\n\tconst clk_rst_mgd_t *clk = &_clock_sdmmc[id];\n\n\treturn CLOCK(clk->enable) & BIT(clk->index);\n}\n\nstatic void _clock_sdmmc_set_enable(u32 id)\n{\n\tconst clk_rst_mgd_t *clk = &_clock_sdmmc[id];\n\n\tCLOCK(clk->enable) = BIT(clk->index);\n}\n\nstatic void _clock_sdmmc_clr_enable(u32 id)\n{\n\tconst clk_rst_mgd_t *clk = &_clock_sdmmc[id];\n\n\tCLOCK(clk->enable + CLK_CLR_OFFSET) = BIT(clk->index);\n}\n\nstatic void _clock_sdmmc_config_legacy_tm()\n{\n\tconst clk_rst_t *clk = &_clock_sdmmc_legacy_tm;\n\n\tif (!(CLOCK(clk->enable) & BIT(clk->index)))\n\t\tclock_enable(clk);\n}\n\ntypedef struct _clock_sdmmc_t\n{\n\tu32 clock;\n\tu32 pclock;\n} clock_sdmmc_t;\n\nstatic clock_sdmmc_t _clock_sdmmc_table[4] = { 0 };\n\n#define SDMMC_CLOCK_SRC_PLLP_OUT0      0x0\n#define SDMMC_CLOCK_SRC_PLLC4_OUT2     0x3\n#define SDMMC_CLOCK_SRC_PLLC4_OUT0     0x7\n#define SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ 0x1\n\nstatic int _clock_sdmmc_config_clock_host(u32 *pclock, u32 id, u32 clock)\n{\n\tu32 divisor = 0;\n\tu32 source  = SDMMC_CLOCK_SRC_PLLP_OUT0;\n\n\tif (id > SDMMC_4)\n\t\treturn 1;\n\n\t// Get IO clock divisor.\n\tswitch (clock)\n\t{\n\tcase 25000:\n\t\t*pclock = 24728;\n\t\tdivisor = CLK_SRC_DIV(16.5);\n\t\tbreak;\n\n\tcase 26000:\n\t\t*pclock = 25500;\n\t\tdivisor = CLK_SRC_DIV(16);\n\t\tbreak;\n\n\tcase 50000:\n\t\t*pclock = 48000;\n\t\tdivisor = CLK_SRC_DIV(8.5);\n\t\tbreak;\n\n\tcase 52000:\n\t\t*pclock = 51000;\n\t\tdivisor = CLK_SRC_DIV(8);\n\t\tbreak;\n\n\tcase 82000:\n\t\t*pclock = 81600;\n\t\tdivisor = CLK_SRC_DIV(5);\n\t\tbreak;\n\n\tcase 100000:\n\t\tsource = SDMMC_CLOCK_SRC_PLLC4_OUT2;\n\t\t*pclock = 99840;\n\t\tdivisor = CLK_SRC_DIV(2);\n\t\tbreak;\n\n\tcase 164000:\n\t\t*pclock = 163200;\n\t\tdivisor = CLK_SRC_DIV(2.5);\n\t\tbreak;\n\n\tcase 200000:\n\t\tswitch (id)\n\t\t{\n\t\tcase SDMMC_1:\n\t\tcase SDMMC_3:\n\t\t\tsource = SDMMC_CLOCK_SRC_PLLC4_OUT2;\n\t\t\tbreak;\n\t\tcase SDMMC_2:\n\t\tcase SDMMC_4:\n\t\t\tsource = SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ; // CLK RST divisor is ignored.\n\t\t\tbreak;\n\t\t}\n\t\t*pclock = 199680;\n\t\tdivisor = CLK_SRC_DIV(1);\n\t\tbreak;\n\n#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT\n\tcase 400000:\n\t\tsource = SDMMC_CLOCK_SRC_PLLC4_OUT0;\n\t\t*pclock = 399360;\n\t\tdivisor = CLK_SRC_DIV(2.5);\n\t\tbreak;\n#endif\n\t}\n\n\t_clock_sdmmc_table[id].clock  = clock;\n\t_clock_sdmmc_table[id].pclock = *pclock;\n\n\t// Enable PLLC4 if in use by any SDMMC.\n\tif (source != SDMMC_CLOCK_SRC_PLLP_OUT0)\n\t\t_clock_enable_pllc4(BIT(id));\n\n\t// Set SDMMC legacy timeout clock.\n\t_clock_sdmmc_config_legacy_tm();\n\n\t// Set SDMMC clock.\n\tconst clk_rst_mgd_t *clk = &_clock_sdmmc[id];\n\tCLOCK(clk->source) = (source << 29u) | divisor;\n\n\treturn 0;\n}\n\nvoid clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 clock)\n{\n\tif (_clock_sdmmc_table[id].clock == clock)\n\t{\n\t\t*pclock = _clock_sdmmc_table[id].pclock;\n\t}\n\telse\n\t{\n\t\t// Ease the stress to APB.\n\t\tif (id == SDMMC_1)\n\t\t\tbpmp_clk_rate_relaxed(true);\n\n\t\tint is_enabled = _clock_sdmmc_is_enabled(id);\n\t\tif (is_enabled)\n\t\t\t_clock_sdmmc_clr_enable(id);\n\n\t\t_clock_sdmmc_config_clock_host(pclock, id, clock);\n\n\t\tif (is_enabled)\n\t\t\t_clock_sdmmc_set_enable(id);\n\n\t\t// Commit changes.\n\t\t_clock_sdmmc_in_reset(id);\n\n\t\t// Restore sys clock.\n\t\tif (id == SDMMC_1)\n\t\t\tbpmp_clk_rate_relaxed(false);\n\t}\n}\n\nvoid clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type)\n{\n\t// Get Card clock divisor.\n\tswitch (type)\n\t{\n\tcase SDHCI_TIMING_MMC_ID:     // Actual card clock: 386.36 KHz.\n\t\t*pclock = 26000;\n\t\t*pdivisor = 66;\n\t\tbreak;\n\n\tcase SDHCI_TIMING_MMC_LS26:\n\t\t*pclock = 26000;\n\t\t*pdivisor = 1;\n\t\tbreak;\n\n\tcase SDHCI_TIMING_MMC_HS52:\n\t\t*pclock = 52000;\n\t\t*pdivisor = 1;\n\t\tbreak;\n\n\tcase SDHCI_TIMING_MMC_HS200:\n\tcase SDHCI_TIMING_MMC_HS400:\n\tcase SDHCI_TIMING_UHS_SDR104:\n\t\t*pclock = 200000;\n\t\t*pdivisor = 1;\n\t\tbreak;\n\n\tcase SDHCI_TIMING_SD_ID:      // Actual card clock: 386.38 KHz.\n\t\t*pclock = 25000;\n\t\t*pdivisor = 64;\n\t\tbreak;\n\n\tcase SDHCI_TIMING_SD_DS12:\n\tcase SDHCI_TIMING_UHS_SDR12:\n\t\t*pclock = 25000;\n\t\t*pdivisor = 1;\n\t\tbreak;\n\n\tcase SDHCI_TIMING_SD_HS25:\n\tcase SDHCI_TIMING_UHS_SDR25:\n\t\t*pclock = 50000;\n\t\t*pdivisor = 1;\n\t\tbreak;\n\n\tcase SDHCI_TIMING_UHS_SDR50:\n\t\t*pclock = 100000;\n\t\t*pdivisor = 1;\n\t\tbreak;\n\n\tcase SDHCI_TIMING_UHS_SDR82:\n\t\t*pclock = 164000;\n\t\t*pdivisor = 1;\n\t\tbreak;\n\n\tcase SDHCI_TIMING_UHS_DDR50:  // Actual card clock: 40.80 MHz.\n\t\t*pclock = 82000;\n\t\t*pdivisor = 2;\n\t\tbreak;\n\n\tcase SDHCI_TIMING_MMC_HS100:  // Actual card clock: 99.84 MHz.\n\t\t*pclock = 200000;\n\t\t*pdivisor = 2;\n\t\tbreak;\n\n#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT\n\tcase SDHCI_TIMING_UHS_DDR200: // Actual card clock: 199.68 KHz.\n\t\t*pclock = 400000;\n\t\t*pdivisor = 2;\n\t\tbreak;\n#endif\n\t}\n}\n\nint clock_sdmmc_is_active(u32 id)\n{\n\treturn !_clock_sdmmc_in_reset(id) && _clock_sdmmc_is_enabled(id);\n}\n\nvoid clock_sdmmc_enable(u32 id, u32 clock)\n{\n\tu32 pclock = 0;\n\n\t// Ease the stress to APB.\n\tif (id == SDMMC_1)\n\t\tbpmp_clk_rate_relaxed(true);\n\n\t_clock_sdmmc_clr_enable(id);\n\t_clock_sdmmc_set_reset(id);\n\t_clock_sdmmc_config_clock_host(&pclock, id, clock);\n\t_clock_sdmmc_set_enable(id);\n\n\t// Commit changes and wait 100 cycles for reset and for clocks to stabilize.\n\t_clock_sdmmc_in_reset(id);\n\tusleep((100 * 1000 + pclock - 1) / pclock);\n\n\t_clock_sdmmc_clr_reset(id);\n\t_clock_sdmmc_in_reset(id);\n\n\t// Restore sys clock.\n\tif (id == SDMMC_1)\n\t\tbpmp_clk_rate_relaxed(false);\n}\n\nvoid clock_sdmmc_disable(u32 id)\n{\n\t_clock_sdmmc_set_reset(id);\n\t_clock_sdmmc_clr_enable(id);\n\t_clock_sdmmc_in_reset(id);\n\t_clock_disable_pllc4(BIT(id));\n}\n\nu32 clock_get_osc_freq()\n{\n\tCLOCK(CLK_RST_CONTROLLER_OSC_FREQ_DET) = OSC_FREQ_DET_TRIG | (2 - 1); // 2 periods of 32.76KHz window.\n\twhile (CLOCK(CLK_RST_CONTROLLER_OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_BUSY)\n\t\t;\n\tu32 cnt = (CLOCK(CLK_RST_CONTROLLER_OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_CNT);\n\tCLOCK(CLK_RST_CONTROLLER_OSC_FREQ_DET) = 0;\n\n\t// Return frequency in KHz.\n\tfor (u32 i = 0; i < ARRAY_SIZE(_clock_osc_cnt); i++)\n\t\tif (cnt >= _clock_osc_cnt[i].min && cnt <= _clock_osc_cnt[i].max)\n\t\t\treturn _clock_osc_cnt[i].freq;\n\n\treturn 0;\n}\n\nu32 clock_get_dev_freq(clock_pto_id_t id)\n{\n\tconst u32 pto_win = 16;\n\tconst u32 pto_osc = 32768;\n\n\tu32 val = ((id & PTO_SRC_SEL_MASK) << PTO_SRC_SEL_SHIFT) | PTO_DIV_SEL_DIV1 | PTO_CLK_ENABLE | (pto_win - 1);\n\tCLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val;\n\t(void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL);\n\tusleep(2);\n\n\tCLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val | PTO_CNT_RST;\n\t(void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL);\n\tusleep(2);\n\n\tCLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val;\n\t(void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL);\n\tusleep(2);\n\n\tCLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = val | PTO_CNT_EN;\n\t(void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL);\n\tusleep((1000000 * pto_win / pto_osc) + 12 + 2);\n\n\twhile (CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_STATUS) & PTO_CLK_CNT_BUSY)\n\t\t;\n\n\tu32 cnt = CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_STATUS) & PTO_CLK_CNT;\n\n\tCLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL) = 0;\n\t(void)CLOCK(CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL);\n\tusleep(2);\n\n\tu32 freq_khz = (u64)cnt * pto_osc / pto_win / 1000;\n\n\treturn freq_khz;\n}\n\n"
  },
  {
    "path": "bdk/soc/clock.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _CLOCK_H_\n#define _CLOCK_H_\n\n#include <utils/types.h>\n\n/*! Clock registers. */\n#define CLK_RST_CONTROLLER_RST_SOURCE 0x0\n#define CLK_RST_CONTROLLER_RST_DEVICES_L 0x4\n#define CLK_RST_CONTROLLER_RST_DEVICES_H 0x8\n#define CLK_RST_CONTROLLER_RST_DEVICES_U 0xC\n#define CLK_RST_CONTROLLER_CLK_OUT_ENB_L 0x10\n#define CLK_RST_CONTROLLER_CLK_OUT_ENB_H 0x14\n#define CLK_RST_CONTROLLER_CLK_OUT_ENB_U 0x18\n#define CLK_RST_CONTROLLER_CCLK_BURST_POLICY 0x20\n#define CLK_RST_CONTROLLER_SUPER_CCLK_DIVIDER 0x24\n#define CLK_RST_CONTROLLER_SCLK_BURST_POLICY 0x28\n#define CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER 0x2C\n#define CLK_RST_CONTROLLER_CLK_SYSTEM_RATE 0x30\n#define CLK_RST_CONTROLLER_MISC_CLK_ENB 0x48\n#define CLK_RST_CONTROLLER_OSC_CTRL 0x50\n#define CLK_RST_CONTROLLER_OSC_FREQ_DET 0x58\n#define CLK_RST_CONTROLLER_OSC_FREQ_DET_STATUS 0x5C\n#define CLK_RST_CONTROLLER_PTO_CLK_CNT_CNTL 0x60\n#define CLK_RST_CONTROLLER_PTO_CLK_CNT_STATUS 0x64\n#define CLK_RST_CONTROLLER_PLLC_BASE 0x80\n#define CLK_RST_CONTROLLER_PLLC_OUT 0x84\n#define CLK_RST_CONTROLLER_PLLC_MISC 0x88\n#define CLK_RST_CONTROLLER_PLLC_MISC_1 0x8C\n#define CLK_RST_CONTROLLER_PLLM_BASE 0x90\n#define CLK_RST_CONTROLLER_PLLM_MISC1 0x98\n#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C\n#define CLK_RST_CONTROLLER_PLLP_BASE 0xA0\n#define CLK_RST_CONTROLLER_PLLP_OUTB 0xA8\n#define CLK_RST_CONTROLLER_PLLA_BASE 0xB0\n#define CLK_RST_CONTROLLER_PLLA_OUT 0xB4\n#define CLK_RST_CONTROLLER_PLLA_MISC1 0xB8\n#define CLK_RST_CONTROLLER_PLLA_MISC 0xBC\n#define CLK_RST_CONTROLLER_PLLU_BASE 0xC0\n#define CLK_RST_CONTROLLER_PLLU_OUTA 0xC4\n#define CLK_RST_CONTROLLER_PLLU_MISC 0xCC\n#define CLK_RST_CONTROLLER_PLLD_BASE 0xD0\n#define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8\n#define CLK_RST_CONTROLLER_PLLD_MISC 0xDC\n#define CLK_RST_CONTROLLER_PLLX_BASE 0xE0\n#define CLK_RST_CONTROLLER_PLLX_MISC 0xE4\n#define CLK_RST_CONTROLLER_PLLE_BASE 0xE8\n#define CLK_RST_CONTROLLER_PLLE_MISC 0xEC\n#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA 0xF8\n#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB 0xFC\n#define CLK_RST_CONTROLLER_CLK_SOURCE_I2S2 0x100\n#define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110\n#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124\n#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128\n#define CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 0x138\n#define CLK_RST_CONTROLLER_CLK_SOURCE_VI 0x148\n#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1 0x150\n#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2 0x154\n#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4 0x164\n#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA 0x178\n#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB 0x17C\n#define CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X 0x180\n#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C2 0x198\n#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C\n#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC 0x1A0\n#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C3 0x1B8\n#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC\n#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTD 0x1C0\n#define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4\n#define CLK_RST_CONTROLLER_CLK_SOURCE_I2S1 0x1D8\n#define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4\n#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280\n#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284\n#define CLK_RST_CONTROLLER_CLK_ENB_X_CLR 0x288\n#define CLK_RST_CONTROLLER_RST_DEVICES_X 0x28C\n#define CLK_RST_CONTROLLER_RST_DEV_X_SET 0x290\n#define CLK_RST_CONTROLLER_RST_DEV_X_CLR 0x294\n#define CLK_RST_CONTROLLER_CLK_OUT_ENB_Y 0x298\n#define CLK_RST_CONTROLLER_CLK_ENB_Y_SET 0x29C\n#define CLK_RST_CONTROLLER_CLK_ENB_Y_CLR 0x2A0\n#define CLK_RST_CONTROLLER_RST_DEVICES_Y 0x2A4\n#define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2A8\n#define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2AC\n#define CLK_RST_CONTROLLER_RST_DEV_L_SET 0x300\n#define CLK_RST_CONTROLLER_RST_DEV_L_CLR 0x304\n#define CLK_RST_CONTROLLER_RST_DEV_H_SET 0x308\n#define CLK_RST_CONTROLLER_RST_DEV_H_CLR 0x30C\n#define CLK_RST_CONTROLLER_RST_DEV_U_SET 0x310\n#define CLK_RST_CONTROLLER_RST_DEV_U_CLR 0x314\n#define CLK_RST_CONTROLLER_CLK_ENB_L_SET 0x320\n#define CLK_RST_CONTROLLER_CLK_ENB_L_CLR 0x324\n#define CLK_RST_CONTROLLER_CLK_ENB_H_SET 0x328\n#define CLK_RST_CONTROLLER_CLK_ENB_H_CLR 0x32C\n#define CLK_RST_CONTROLLER_CLK_ENB_U_SET 0x330\n#define CLK_RST_CONTROLLER_CLK_ENB_U_CLR 0x334\n#define CLK_RST_CONTROLLER_RST_DEVICES_V 0x358\n#define CLK_RST_CONTROLLER_RST_DEVICES_W 0x35C\n#define CLK_RST_CONTROLLER_CLK_OUT_ENB_V 0x360\n#define CLK_RST_CONTROLLER_CLK_OUT_ENB_W 0x364\n#define CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2 0x388\n#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC 0x3A0\n#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4\n#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4\n#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C4 0x3C4\n#define CLK_RST_CONTROLLER_CLK_SOURCE_AHUB 0x3D0\n#define CLK_RST_CONTROLLER_CLK_SOURCE_ACTMON 0x3E8\n#define CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH1 0x3EC\n#define CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH2 0x3F0\n#define CLK_RST_CONTROLLER_CLK_SOURCE_SYS 0x400\n#define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410\n#define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C\n#define CLK_RST_CONTROLLER_RST_DEV_V_SET 0x430\n#define CLK_RST_CONTROLLER_RST_DEV_V_CLR 0x434\n#define CLK_RST_CONTROLLER_RST_DEV_W_SET 0x438\n#define CLK_RST_CONTROLLER_RST_DEV_W_CLR 0x43C\n#define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440\n#define CLK_RST_CONTROLLER_CLK_ENB_V_CLR 0x444\n#define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448\n#define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C\n#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450\n#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR 0x454\n#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG0 0x480\n#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG1 0x484\n#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG2 0x488\n#define CLK_RST_CONTROLLER_PLLE_AUX 0x48C\n#define CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S0 0x4A0\n#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG3 0x4C0\n#define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518\n#define CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0 0x52C\n#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554\n#define CLK_RST_CONTROLLER_SPARE_REG0 0x55C\n#define CLK_RST_CONTROLLER_PLLC4_BASE 0x5A4\n#define CLK_RST_CONTROLLER_PLLC4_MISC 0x5A8\n#define CLK_RST_CONTROLLER_PLLC_MISC_2 0x5D0\n#define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4\n#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8\n#define CLK_RST_CONTROLLER_PLLMB_MISC1 0x5EC\n#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_FS 0x608\n#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_CORE_DEV 0x60C\n#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_SS 0x610\n#define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620\n#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C6 0x65C\n#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL 0x664\n#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL 0x66C\n#define CLK_RST_CONTROLLER_CLK_SOURCE_VIC 0x678\n#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM 0x694\n#define CLK_RST_CONTROLLER_CLK_SOURCE_NVDEC 0x698\n#define CLK_RST_CONTROLLER_CLK_SOURCE_NVJPG 0x69C\n#define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0\n#define CLK_RST_CONTROLLER_CLK_SOURCE_APE 0x6C0\n#define CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK 0x6CC\n#define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704\n#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE 0x710\n\n#define CLK_NO_SOURCE 0x0\n#define CLK_NOT_USED  0x0\n\n#define CLK_CLR_OFFSET 0x4\n\n/*! PLL control and status bits */\n#define PLL_BASE_LOCK        BIT(27)\n#define PLL_BASE_REF_DIS     BIT(29)\n#define PLL_BASE_ENABLE      BIT(30)\n#define PLL_BASE_BYPASS      BIT(31)\n\n#define PLLX_MISC_LOCK_EN    BIT(18)\n#define PLLX_MISC3_IDDQ      BIT(3)\n\n#define PLLA_OUT0_RSTN_CLR   BIT(0)\n#define PLLA_OUT0_CLKEN      BIT(1)\n#define PLLA_BASE_IDDQ       BIT(25)\n\n#define PLLC_OUT1_RSTN_CLR   BIT(0)\n#define PLLC_OUT1_CLKEN      BIT(1)\n#define PLLC_MISC1_IDDQ      BIT(27)\n#define PLLC_MISC_RESET      BIT(30)\n\n#define PLLC4_OUT3_RSTN_CLR  BIT(0)\n#define PLLC4_OUT3_CLKEN     BIT(1)\n#define PLLC4_BASE_IDDQ      BIT(18)\n#define PLLC4_MISC_EN_LCKDET BIT(30)\n\n#define UTMIPLL_LOCK         BIT(31)\n\n/*! Clock source */\n#define CLK_SRC_DIV(d)     ((d) ? ((u32)(((d) - 1) * 2)) : 0)\n#define CLK_I2C_SRC_DIV(d) ((d) ? ((u32)(((d) - 1))) : 0)\n\n/*! PTO_CLK_CNT */\n#define PTO_REF_CLK_WIN_CFG_MASK 0xF\n#define PTO_REF_CLK_WIN_CFG_16P  0xF\n#define PTO_CNT_EN               BIT(9)\n#define PTO_CNT_RST              BIT(10)\n#define PTO_CLK_ENABLE           BIT(13)\n#define PTO_SRC_SEL_SHIFT        14\n#define PTO_SRC_SEL_MASK         0x1FF\n#define PTO_DIV_SEL_MASK         (3 << 23)\n#define PTO_DIV_SEL_GATED        (0 << 23)\n#define PTO_DIV_SEL_DIV1         (1 << 23)\n#define PTO_DIV_SEL_DIV4_RISING  (2 << 23)\n#define PTO_DIV_SEL_DIV4_FALLING (3 << 23)\n#define PTO_DIV_SEL_CPU_EARLY    (0 << 23)\n#define PTO_DIV_SEL_CPU_LATE     (1 << 23)\n\n#define PTO_CLK_CNT_BUSY         BIT(31)\n#define PTO_CLK_CNT              0xFFFFFF\n\n/*! OSC_FREQ_DET */\n#define OSC_REF_CLK_WIN_CFG_MASK 0xF\n#define OSC_FREQ_DET_TRIG        BIT(31)\n\n#define OSC_FREQ_DET_BUSY        BIT(31)\n#define OSC_FREQ_DET_CNT         0xFFFF\n\n/*! PTO IDs. */\ntypedef enum _clock_pto_id_t\n{\n\tCLK_PTO_PCLK_SYS          = 0x06,\n\tCLK_PTO_HCLK_SYS          = 0x07,\n\tCLK_PTO_DMIC1             = 0x08,\n\tCLK_PTO_DMIC2             = 0x09,\n\tCLK_PTO_HDMI_SLOWCLK_DIV2 = 0x0A,\n\tCLK_PTO_JTAG_REG          = 0x0B,\n\tCLK_PTO_UTMIP_240_A       = 0x0C,\n\tCLK_PTO_UTMIP_240_B       = 0x0D,\n\n\tCLK_PTO_CCLK_G            = 0x12,\n\tCLK_PTO_CCLK_G_DIV2       = 0x13,\n\tCLK_PTO_MIPIBIF           = 0x14,\n\n\tCLK_PTO_SPI1              = 0x17,\n\tCLK_PTO_SPI2              = 0x18,\n\tCLK_PTO_SPI3              = 0x19,\n\tCLK_PTO_SPI4              = 0x1A,\n\tCLK_PTO_MAUD              = 0x1B,\n\tCLK_PTO_SCLK              = 0x1C,\n\n\tCLK_PTO_SDMMC1            = 0x20,\n\tCLK_PTO_SDMMC2            = 0x21,\n\tCLK_PTO_SDMMC3            = 0x22,\n\tCLK_PTO_SDMMC4            = 0x23,\n\tCLK_PTO_EMC               = 0x24,\n\n\tCLK_PTO_DMIC3             = 0x2A,\n\tCLK_PTO_CCLK_LP           = 0x2B,\n\tCLK_PTO_CCLK_LP_DIV2      = 0x2C,\n\n\tCLK_PTO_MSELECT           = 0x2F,\n\n\tCLK_PTO_VI_SENSOR2        = 0x33,\n\tCLK_PTO_VI_SENSOR         = 0x34,\n\tCLK_PTO_VIC               = 0x35,\n\tCLK_PTO_VIC_SKIP          = 0x36,\n\tCLK_PTO_ISP_SKIP          = 0x37,\n\tCLK_PTO_ISPB_SE2_SKIP     = 0x38,\n\tCLK_PTO_NVDEC_SKIP        = 0x39,\n\tCLK_PTO_NVENC_SKIP        = 0x3A,\n\tCLK_PTO_NVJPG_SKIP        = 0x3B,\n\tCLK_PTO_TSEC_SKIP         = 0x3C,\n\tCLK_PTO_TSECB_SKIP        = 0x3D,\n\tCLK_PTO_SE_SKIP           = 0x3E,\n\tCLK_PTO_VI_SKIP           = 0x3F,\n\n\tCLK_PTO_PLLX_OBS          = 0x40,\n\tCLK_PTO_PLLC_OBS          = 0x41,\n\tCLK_PTO_PLLM_OBS          = 0x42,\n\tCLK_PTO_PLLP_OBS          = 0x43,\n\tCLK_PTO_PLLA_OBS          = 0x44,\n\tCLK_PTO_PLLMB_OBS         = 0x45,\n\tCLK_PTO_SATA_OOB          = 0x46,\n\n\tCLK_PTO_FCPU_DVFS_DIV12_CPU = 0x48,\n\n\tCLK_PTO_EQOS_AXI          = 0x4C,\n\tCLK_PTO_EQOS_PTP_REF      = 0x4D,\n\tCLK_PTO_EQOS_TX           = 0x4E,\n\tCLK_PTO_EQOS_RX           = 0x4F,\n\n\tCLK_PTO_CILAB             = 0x52,\n\tCLK_PTO_CILCD             = 0x53,\n\n\tCLK_PTO_CILEF             = 0x55,\n\tCLK_PTO_PLLA1_PTO_OBS     = 0x56,\n\tCLK_PTO_PLLC4_PTO_OBS     = 0x57,\n\n\tCLK_PTO_PLLC2_PTO_OBS     = 0x59,\n\tCLK_PTO_PLLC3_PTO_OBS     = 0x5B,\n\n\tCLK_PTO_DSIA_LP           = 0x62,\n\tCLK_PTO_DSIB_LP           = 0x63,\n\tCLK_PTO_ISP               = 0x64,\n\tCLK_PTO_PEX_PAD           = 0x65,\n\n\tCLK_PTO_MC                = 0x6A,\n\n\tCLK_PTO_ACTMON            = 0x6B,\n\tCLK_PTO_CSITE             = 0x6C,\n\tCLK_PTO_VI_I2C            = 0x6D,\n\n\tCLK_PTO_HOST1X            = 0x6F,\n\n\tCLK_PTO_QSPI_2X           = 0x71,\n\tCLK_PTO_NVDEC             = 0x72,\n\tCLK_PTO_NVJPG             = 0x73,\n\tCLK_PTO_SE                = 0x74,\n\tCLK_PTO_SOC_THERM         = 0x75,\n\n\tCLK_PTO_TSEC              = 0x77,\n\tCLK_PTO_TSECB             = 0x78,\n\tCLK_PTO_VI                = 0x79,\n\tCLK_PTO_LA                = 0x7A,\n\tCLK_PTO_SCLK_SKIP         = 0x7B,\n\n\tCLK_PTO_ADSP_SKIP         = 0x7C,\n\tCLK_PTO_QSPI              = 0x7D,\n\n\tCLK_PTO_SDMMC2_SHAPER     = 0x7E,\n\tCLK_PTO_SDMMC4_SHAPER     = 0x7F,\n\tCLK_PTO_I2S1              = 0x80,\n\tCLK_PTO_I2S2              = 0x81,\n\tCLK_PTO_I2S3              = 0x82,\n\tCLK_PTO_I2S4              = 0x83,\n\tCLK_PTO_I2S5              = 0x84,\n\tCLK_PTO_AHUB              = 0x85,\n\tCLK_PTO_APE               = 0x86,\n\n\tCLK_PTO_DVFS_SOC          = 0x88,\n\tCLK_PTO_DVFS_REF          = 0x89,\n\tCLK_PTO_ADSP_CLK          = 0x8A,\n\tCLK_PTO_ADSP_DIV2_CLK     = 0x8B,\n\n\tCLK_PTO_SPDIF_OUT         = 0x8F,\n\tCLK_PTO_SPDIF_IN          = 0x90,\n\tCLK_PTO_UART_FST_MIPI_CAL = 0x91,\n\tCLK_PTO_SYS2HSIO_SATA_CLK = 0x92,\n\tCLK_PTO_PWM               = 0x93,\n\tCLK_PTO_I2C1              = 0x94,\n\tCLK_PTO_I2C2              = 0x95,\n\tCLK_PTO_I2C3              = 0x96,\n\tCLK_PTO_I2C4              = 0x97,\n\tCLK_PTO_I2C5              = 0x98,\n\tCLK_PTO_I2C6              = 0x99,\n\tCLK_PTO_I2C_SLOW          = 0x9A,\n\tCLK_PTO_UARTAPE           = 0x9B,\n\n\tCLK_PTO_EXTPERIPH1        = 0x9D,\n\tCLK_PTO_EXTPERIPH2        = 0x9E,\n\tCLK_PTO_EXTPERIPH3        = 0x9F,\n\tCLK_PTO_ENTROPY           = 0xA0,\n\tCLK_PTO_UARTA             = 0xA1,\n\tCLK_PTO_UARTB             = 0xA2,\n\tCLK_PTO_UARTC             = 0xA3,\n\tCLK_PTO_UARTD             = 0xA4,\n\tCLK_PTO_OWR               = 0xA5,\n\tCLK_PTO_TSENSOR           = 0xA6,\n\tCLK_PTO_HDA2CODEC_2X      = 0xA7,\n\tCLK_PTO_HDA               = 0xA8,\n\tCLK_PTO_EMC_LATENCY       = 0xA9,\n\tCLK_PTO_EMC_DLL           = 0xAA,\n\tCLK_PTO_SDMMC_LEGACY_TM   = 0xAB,\n\tCLK_PTO_DBGAPB            = 0xAC,\n\n\tCLK_PTO_SOR0              = 0xC0,\n\tCLK_PTO_SOR1              = 0xC1,\n\tCLK_PTO_HDMI              = 0xC2,\n\n\tCLK_PTO_DISP2             = 0xC4,\n\tCLK_PTO_DISP1             = 0xC5,  // Branches: 0xD5, 0xE5, 0xF5.\n\n\tCLK_PTO_PLLD_OBS          = 0xCA,  // Branches: 0xDA, 0xEA, 0xFA.\n\tCLK_PTO_PLLD2_PTO_OBS     = 0xCC,\n\tCLK_PTO_PLLDP_OBS         = 0xCE,\n\tCLK_PTO_PLLE_OBS          = 0x10A,\n\tCLK_PTO_PLLU_OBS          = 0x10C, // Branches: 0x14C 0x18C 0x1CC.\n\tCLK_PTO_PLLREFE_OBS       = 0x10E,\n\n\tCLK_PTO_XUSB_FALCON       = 0x110, // Branches: 0x150 0x190 0x1D0.\n\tCLK_PTO_XUSB_CLK480M_HSIC = 0x111, // Branches: 0x151 0x191 0x1D1.\n\tCLK_PTO_USB_L0_RX         = 0x112,\n\tCLK_PTO_USB_L3_RX         = 0x113,\n\tCLK_PTO_USB_RX            = 0x114,\n\tCLK_PTO_USB3_L0_TXCLKREF  = 0x115,\n\tCLK_PTO_PEX_TXCLKREF_SWITCH_TMS  = 0x116,\n\tCLK_PTO_PEX_TXCLKREF_SWITCH_GRP0 = 0x117,\n\tCLK_PTO_PEX_TXCLKREF_SWITCH_GRP1 = 0x118,\n\tCLK_PTO_PEX_TXCLKREF_SWITCH_GRP2 = 0x119,\n\tCLK_PTO_PEX_L4_RX         = 0x11A,\n\tCLK_PTO_PEX_TXCLKREF      = 0x11B,\n\tCLK_PTO_PEX_TXCLKREF_DIV2 = 0x11C,\n\tCLK_PTO_PEX_TXCLKREF2     = 0x11D,\n\tCLK_PTO_PEX_L0_RX         = 0x11E,\n\tCLK_PTO_PEX_L1_RX         = 0x11F,\n\tCLK_PTO_PEX_L2_RX         = 0x120,\n\tCLK_PTO_PEX_L3_RX         = 0x121,\n\tCLK_PTO_SATA_TXCLKREF     = 0x122,\n\tCLK_PTO_SATA_TXCLKREF_DIV2 = 0x123,\n\tCLK_PTO_USB_L5_RX         = 0x124,\n\tCLK_PTO_SATA_TX           = 0x125,\n\tCLK_PTO_SATA_L0_RX        = 0x126,\n\n\tCLK_PTO_USB3_L1_TXCLKREF  = 0x129,\n\tCLK_PTO_USB3_L7_TXCLKREF  = 0x12A,\n\tCLK_PTO_USB3_L7_RX        = 0x12B,\n\tCLK_PTO_USB3_TX           = 0x12C,\n\tCLK_PTO_UTMIP_PLL_PAD     = 0x12D, // Branches: 0x16D 0x1AD 0x1ED.\n\n\tCLK_PTO_XUSB_FS           = 0x136, // Branches: 0x176 0x1B6 0x1F6.\n\tCLK_PTO_XUSB_SS_HOST_DEV  = 0x137, // Branches: 0x177 0x1B7 0x1F7.\n\tCLK_PTO_XUSB_CORE_HOST    = 0x138, // Branches: 0x178 0x1B8 0x1F8.\n\tCLK_PTO_XUSB_CORE_DEV     = 0x139, // Branches: 0x179 0x1B9 0x1F9.\n\n\tCLK_PTO_USB3_L2_TXCLKREF  = 0x13C,\n\tCLK_PTO_USB3_L3_TXCLKREF  = 0x13D,\n\tCLK_PTO_USB_L4_RX         = 0x13E,\n\tCLK_PTO_USB_L6_RX         = 0x13F,\n\n\t/*\n\t * PLL need PTO enabled in MISC registers.\n\t * Normal div is 2 so result is multiplied with it.\n\t */\n\tCLK_PTO_PLLC_DIV2    = 0x01,\n\tCLK_PTO_PLLM_DIV2    = 0x02,\n\tCLK_PTO_PLLP_DIV2    = 0x03,\n\tCLK_PTO_PLLA_DIV2    = 0x04,\n\tCLK_PTO_PLLX_DIV2    = 0x05,\n\n\tCLK_PTO_PLLMB_DIV2   = 0x25,\n\n\tCLK_PTO_PLLC4_DIV2   = 0x51,\n\n\tCLK_PTO_PLLA1_DIV2   = 0x55,\n\tCLK_PTO_PLLC2_DIV2   = 0x58,\n\tCLK_PTO_PLLC3_DIV2   = 0x5A,\n\n\tCLK_PTO_PLLD_DIV2    = 0xCB,  // Branches: 0xDB, 0xEB, 0xFB.\n\tCLK_PTO_PLLD2_DIV2   = 0xCD,\n\tCLK_PTO_PLLDP_DIV2   = 0xCF,\n\n\tCLK_PTO_PLLE_DIV2    = 0x10B,\n\n\tCLK_PTO_PLLU_DIV2    = 0x10D, // Branches: 0x14D 0x18D 0x1CD.\n\n\tCLK_PTO_PLLREFE_DIV2 = 0x10F,\n} clock_pto_id_t;\n\n/*\n * CLOCK Peripherals:\n * L   0 -  31\n * H  32 -  63\n * U  64 -  95\n * V  96 - 127\n * W 128 - 159\n * X 160 - 191\n * Y 192 - 223\n */\n\nenum CLK_L_DEV\n{\n\tCLK_L_CPU             =  0, // Deprecated.\n\tCLK_L_BPMP            =  1, // Only reset.\n\tCLK_L_SYS             =  2, // Only reset.\n\tCLK_L_ISPB            =  3,\n\tCLK_L_RTC             =  4, // Only enable.\n\tCLK_L_TMR             =  5,\n\tCLK_L_UARTA           =  6,\n\tCLK_L_UARTB           =  7,\n\tCLK_L_GPIO            =  8,\n\tCLK_L_SDMMC2          =  9,\n\tCLK_L_SPDIF           = 10, // Only enable.\n\tCLK_L_I2S2            = 11, // Only enable.\n\tCLK_L_I2C1            = 12,\n\tCLK_L_SDMMC1          = 14,\n\tCLK_L_SDMMC4          = 15,\n\tCLK_L_TWC             = 16, // 3-Wire Controller. Deprecated.\n\tCLK_L_PWM             = 17,\n\tCLK_L_I2S3            = 18, // Only enable.\n\tCLK_L_VI              = 20,\n\tCLK_L_USBD            = 22,\n\tCLK_L_ISP             = 23,\n\tCLK_L_DISP2           = 26,\n\tCLK_L_DISP1           = 27,\n\tCLK_L_HOST1X          = 28,\n\tCLK_L_I2S1            = 30, // Only enable.\n\tCLK_L_BPMP_CACHE_CTRL = 31, // Controller.\n};\n\nenum CLK_H_DEV\n{\n\tCLK_H_MEM      =  0, // MC.\n\tCLK_H_AHBDMA   =  1,\n\tCLK_H_APBDMA   =  2,\n\tCLK_H_STAT_MON =  5,\n\tCLK_H_PMC      =  6, // Only enable.\n\tCLK_H_FUSE     =  7,\n\tCLK_H_KFUSE    =  8,\n\tCLK_H_SPI1     =  9,\n\tCLK_H_SPI2     = 12,\n\tCLK_H_XIO      = 13, // Misc IO. Deprecated?\n\tCLK_H_SPI3     = 14,\n\tCLK_H_I2C5     = 15,\n\tCLK_H_DSI      = 16,\n\tCLK_H_CSI      = 20,\n\tCLK_H_I2C2     = 22,\n\tCLK_H_UARTC    = 23,\n\tCLK_H_MIPI_CAL = 24,\n\tCLK_H_EMC      = 25,\n\tCLK_H_USB2     = 26,\n\tCLK_H_BSEV     = 31,\n};\n\nenum CLK_U_DEV\n{\n\t//CLK_U_SPEEDO         =  0, // RESERVED. Old speedo ring oscillator.\n\tCLK_U_UARTD          =  1,\n\tCLK_U_I2C3           =  3,\n\tCLK_U_SPI4           =  4,\n\tCLK_U_SDMMC3         =  5,\n\tCLK_U_PCIE           =  6,\n\tCLK_U_OWR            =  7, // 1-Wire Controller. Deprecated.\n\tCLK_U_AFI            =  8,\n\tCLK_U_CSITE          =  9,\n\tCLK_U_PCIEXCLK       = 10, // Only reset.\n\tCLK_U_LA             = 12, // DFD.\n\tCLK_U_SOC_THERM      = 14,\n\tCLK_U_DTV            = 15, // Deprecated.\n\tCLK_U_I2C_SLOW       = 17,\n\tCLK_U_DSIB           = 18,\n\tCLK_U_TSEC           = 19,\n\tCLK_U_IRAMA          = 20, // Only enable.\n\tCLK_U_IRAMB          = 21, // Only enable.\n\tCLK_U_IRAMC          = 22, // Only enable.\n\tCLK_U_IRAMD          = 23, // EMUCIF ON RESET\n\tCLK_U_BPMP_CACHE_RAM = 24, // Only enable.\n\tCLK_U_XUSB_HOST      = 25,\n\tCLK_U_SUS_OUT        = 28, // Only enable. VI  MCLK. Deprecated?\n\tCLK_U_DEV2_OUT       = 29, // Only enable. DAP MCLK. Deprecated?\n\tCLK_U_DEV1_OUT       = 30, // Only enable. DAP MCLK. Deprecated?\n\tCLK_U_XUSB_DEV       = 31,\n};\n\nenum CLK_V_DEV\n{\n\tCLK_V_CPUG          = 0,\n\tCLK_V_CPULP         = 1, // Reserved.\n\tCLK_V_MSELECT       = 3,\n\tCLK_V_TSENSOR       = 4, // Only enable.\n\tCLK_V_I2S4          = 5, // Only enable.\n\tCLK_V_I2S5          = 6, // Only enable.\n\tCLK_V_I2C4          = 7,\n\tCLK_V_AHUB          = 10, // AUDIO. Only enable.\n\tCLK_V_APB2APE       = 11, // APBIF. Only enable.\n\tCLK_V_HDA2CODEC_2X  = 15,\n\tCLK_V_ATOMICS       = 16,\n\tCLK_V_SPDIF_DOUBLER = 22, // Only enable.\n\tCLK_V_ACTMON        = 23,\n\tCLK_V_EXTPERIPH1    = 24,\n\tCLK_V_EXTPERIPH2    = 25,\n\tCLK_V_EXTPERIPH3    = 26,\n\tCLK_V_SATA_OOB      = 27, // Only on T210.\n\tCLK_V_SATA          = 28, // Only on T210.\n\tCLK_V_HDA           = 29,\n\tCLK_V_TZRAM         = 30,\n\tCLK_V_SE            = 31,\n};\n\nenum CLK_W_DEV\n{\n\tCLK_W_HDA2HDMICODEC =  0,\n\tCLK_W_SATACOLD      =  1, // Enable reserved. Unused.\n\tCLK_W_PCIERX0       =  2, // Reset reserved.\n\tCLK_W_PCIERX1       =  3, // Reset reserved.\n\tCLK_W_PCIERX2       =  4, // Reset reserved.\n\tCLK_W_PCIERX3       =  5, // Reset reserved.\n\tCLK_W_PCIERX4       =  6, // Reset reserved.\n\tCLK_W_PCIERX5       =  7, // Reset reserved.\n\tCLK_W_CEC           =  8,\n\tCLK_W_PCIE2_IOBIST  =  9, // Reset reserved.\n\tCLK_W_EMC_IOBIST    = 10, // Reset reserved.\n\tCLK_W_SATA_IOBIST   = 12, // Reset reserved.\n\tCLK_W_MIPI_IOBIST   = 13, // Reset reserved.\n\tCLK_W_XUSB_PADCTL   = 14, // Only reset.\n\tCLK_W_XUSB          = 15, // Only enable.\n\tCLK_W_CILAB         = 16, // Only enable.\n\tCLK_W_CILCD         = 17, // Only enable.\n\tCLK_W_CILEF         = 18, // Only enable.\n\tCLK_W_DSIA_LP       = 19, // Only enable.\n\tCLK_W_DSIB_LP       = 20, // Only enable.\n\tCLK_W_ENTROPY       = 21,\n\tCLK_W_DP2           = 24, // HIDDEN.\n\tCLK_W_DVFS          = 27,\n\tCLK_W_XUSB_SS       = 28,\n\tCLK_W_EMC_LATENCY   = 29, // Only enable.\n\tCLK_W_MC1           = 30, // Only enable.\n};\n\nenum CLK_X_DEV\n{\n\tCLK_X_SPARE             =  0,\n\tCLK_X_DMIC1             =  1, // Only enable.\n\tCLK_X_DMIC2             =  2, // Only enable.\n\tCLK_X_ETR               =  3, // DFD.\n\tCLK_X_CAM_MCLK          =  4, // Only enable.\n\tCLK_X_CAM_MCLK2         =  5, // Only enable.\n\tCLK_X_I2C6              =  6,\n\tCLK_X_MC_CAPA           =  7, // MC Clients daisy chain 1. Only enable.\n\tCLK_X_MC_CBPA           =  8, // MC Clients daisy chain 2. Only enable.\n\tCLK_X_MC_CPU            =  9, // MC CPU.      Only enable.\n\tCLK_X_MC_BBC            = 10, // MC Backbone. Only enable.\n\tCLK_X_VIM2_CLK          = 11, // Only enable.\n\tCLK_X_MIPIBIF           = 13,\n\tCLK_X_EMC_DLL           = 14, // Only enable.\n\tCLK_X_UART_FST_MIPI_CAL = 17, // Only enable.\n\tCLK_X_VIC               = 18,\n\tCLK_X_DPAUX             = 21,\n\tCLK_X_SOR0              = 22,\n\tCLK_X_SOR1              = 23,\n\tCLK_X_GPU               = 24,\n\tCLK_X_DBGAPB            = 25, // Only enable.\n\tCLK_X_HPLL_ADSP         = 26, // Only enable.\n\tCLK_X_PLLP_ADSP         = 27, // Only enable.\n\tCLK_X_PLLA_ADSP         = 28, // Only enable.\n\tCLK_X_PLLG_REF          = 29, // Only enable.\n\tCLK_X_EQOS              = 30, // T210B01 only.\n};\n\nenum CLK_Y_DEV\n{\n\tCLK_Y_SPARE1          =  0,\n\tCLK_Y_SDMMC_LEGACY_TM =  1, // Only enable.\n\tCLK_Y_NVDEC           =  2,\n\tCLK_Y_NVJPG           =  3,\n\tCLK_Y_AXIAP           =  4, // DFD.\n\tCLK_Y_DMIC3           =  5, // Only enable.\n\tCLK_Y_APE             =  6,\n\tCLK_Y_ADSP            =  7,\n\tCLK_Y_MC_CDPA         =  8, // MC Clients daisy chain 4. Only enable.\n\tCLK_Y_MC_CCPA         =  9, // MC Clients daisy chain 3. Only enable.\n\tCLK_Y_MAUD            = 10, // Only enable.\n\tCLK_Y_SATA_USB_UPHY   = 12, // Only reset.\n\tCLK_Y_PEX_USB_UPHY    = 13, // Only reset.\n\tCLK_Y_TSECB           = 14,\n\tCLK_Y_DPAUX1          = 15,\n\tCLK_Y_VI_I2C          = 16,\n\tCLK_Y_HSIC_TRK        = 17, // Only enable.\n\tCLK_Y_USB2_TRK        = 18, // Only enable.\n\tCLK_Y_QSPI            = 19,\n\tCLK_Y_UARTAPE         = 20, // Only enable.\n\tCLK_Y_ADSPINTF        = 21, // Only reset.\n\tCLK_Y_ADSPPERIPH      = 22, // Only reset.\n\tCLK_Y_ADSPDBG         = 23, // Only reset.\n\tCLK_Y_ADSPWDT         = 24, // Only reset.\n\tCLK_Y_ADSPSCU         = 25, // Only reset.\n\tCLK_Y_ADSPNEON        = 26,\n\tCLK_Y_NVENC           = 27,\n\tCLK_Y_IQC2            = 28, // Only enable. (Audio.)\n\tCLK_Y_IQC1            = 29, // Only enable. (Audio.)\n\tCLK_Y_SOR_SAFE        = 30, // Only enable.\n\tCLK_Y_PLLP_OUT_CPU    = 31, // Only enable.\n};\n\n/*! Generic clock descriptor. */\ntypedef struct _clk_rst_t\n{\n\tu16 reset;  // Reset  SET.\n\tu16 enable; // Enable SET.\n\tu16 source;\n\tu8 index:5;\n\tu8 clk_src:3;\n\tu8 clk_div;\n} clk_rst_t;\n\n/*! Generic clock enable/disable. */\nvoid clock_enable(const clk_rst_t *clk);\nvoid clock_disable(const clk_rst_t *clk);\n\n/*! Clock control for specific hardware portions. */\nvoid clock_enable_fuse(bool enable);\nvoid clock_enable_uart(u32 idx);\nvoid clock_disable_uart(u32 idx);\nint  clock_uart_use_src_div(u32 idx, u32 baud);\nvoid clock_enable_i2c(u32 idx);\nvoid clock_disable_i2c(u32 idx);\nvoid clock_enable_se();\nvoid clock_enable_tzram();\nvoid clock_enable_host1x();\nvoid clock_disable_host1x();\nvoid clock_enable_tsec();\nvoid clock_disable_tsec();\nvoid clock_enable_nvdec();\nvoid clock_disable_nvdec();\nvoid clock_enable_nvjpg();\nvoid clock_disable_nvjpg();\nvoid clock_enable_vic();\nvoid clock_disable_vic();\nvoid clock_enable_sor_safe();\nvoid clock_disable_sor_safe();\nvoid clock_enable_sor0();\nvoid clock_disable_sor0();\nvoid clock_enable_sor1();\nvoid clock_disable_sor1();\nvoid clock_enable_kfuse();\nvoid clock_disable_kfuse();\nvoid clock_enable_cl_dvfs();\nvoid clock_disable_cl_dvfs();\nvoid clock_enable_coresight();\nvoid clock_disable_coresight();\nvoid clock_enable_pwm();\nvoid clock_disable_pwm();\nvoid clock_enable_apbdma();\nvoid clock_disable_apbdma();\nvoid clock_enable_ahbdma();\nvoid clock_disable_ahbdma();\nvoid clock_enable_actmon();\nvoid clock_disable_actmon();\nvoid clock_enable_extperiph1();\nvoid clock_disable_extperiph1();\nvoid clock_enable_extperiph2();\nvoid clock_disable_extperiph2();\n\nvoid clock_enable_plld(u32 divp, u32 divn, bool lowpower, bool tegra_t210);\nvoid clock_enable_pllx();\nvoid clock_enable_pllc(u32 divn);\nvoid clock_disable_pllc();\nvoid clock_enable_pllu();\nvoid clock_disable_pllu();\nvoid clock_enable_utmipll();\n\nvoid clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 clock);\nvoid clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type);\nint  clock_sdmmc_is_active(u32 id);\nvoid clock_sdmmc_enable(u32 id, u32 clock);\nvoid clock_sdmmc_disable(u32 id);\n\nu32 clock_get_osc_freq();\nu32 clock_get_dev_freq(clock_pto_id_t id);\n\n#endif\n"
  },
  {
    "path": "bdk/soc/fuse.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018 shuffle2\n * Copyright (c) 2018 balika011\n * Copyright (c) 2019-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <mem/heap.h>\n#include <sec/se.h>\n#include <sec/se_t210.h>\n#include <soc/clock.h>\n#include <soc/fuse.h>\n#include <soc/hw_init.h>\n#include <soc/pmc.h>\n#include <soc/t210.h>\n#include <soc/timer.h>\n#include <utils/types.h>\n\nstatic const u32 evp_thunk_template[] = {\n\t0xe92d0007, //   STMFD   SP!, {R0-R2}\n\t0xe1a0200e, //   MOV     R2, LR\n\t0xe2422002, //   SUB     R2, R2, #2\n\t0xe5922000, //   LDR     R2, [R2]\n\t0xe20220ff, //   AND     R2, R2, #0xFF\n\t0xe1a02082, //   MOV     R2, R2,LSL#1\n\t0xe59f001c, //   LDR     R0, =evp_thunk_template\n\t0xe59f101c, //   LDR     R1, =thunk_end\n\t0xe0411000, //   SUB     R1, R1, R0\n\t0xe59f0018, //   LDR     R0, =iram_evp_thunks\n\t0xe0800001, //   ADD     R0, R0, R1\n\t0xe0822000, //   ADD     R2, R2, R0\n\t0xe3822001, //   ORR     R2, R2, #1\n\t0xe8bd0003, //   LDMFD   SP!, {R0,R1}\n\t0xe12fff12, //   BX      R2\n\t// idx: 15:\n\t0x001007b0, // off_1007EC DCD evp_thunk_template\n\t0x001007f8, // off_1007F0 DCD thunk_end\n\t0x40004c30, // off_1007F4 DCD iram_evp_thunks\n\t// thunk_end is here\n};\n\nstatic const u32 evp_thunk_func_offsets_t210b01[] = {\n\t0x0010022c, // off_100268 DCD evp_thunk_template\n\t0x00100174, // off_10026C DCD thunk_end\n\t0x40004164, // off_100270 DCD iram_evp_thunks\n\t// thunk_end is here\n};\n\n// treated as 12bit values\nstatic const u32 hash_vals[] = {1, 2, 4, 8, 0, 3, 5, 6, 7, 9, 10, 11};\n\nvoid fuse_disable_program()\n{\n\tFUSE(FUSE_DISABLEREGPROGRAM) = 1;\n}\n\nu32 fuse_read_odm(u32 idx)\n{\n\treturn FUSE(FUSE_RESERVED_ODMX(idx));\n}\n\nu32 fuse_read_odm_keygen_rev()\n{\n\tbool has_new_keygen;\n\n\t// Check if it has new keygen.\n\tif (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01)\n\t\thas_new_keygen = true;\n\telse\n\t\thas_new_keygen = (fuse_read_odm(4) & 0x800) && fuse_read_odm(0) == 0x8E61ECAE && fuse_read_odm(1) == 0xF2BA3BB2;\n\n\tif (has_new_keygen)\n\t\treturn (fuse_read_odm(2) & 0x1F);\n\n\treturn 0;\n}\n\nstatic bool _dramid_8gb = false;\n\nvoid fuse_force_8gb_dramid()\n{\n\t// Override fuse DRAM ID with a 8GB ID.\n\t_dramid_8gb = true;\n}\n\nu32 fuse_read_dramid(bool raw_id)\n{\n\tbool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210;\n\tu32  odm4       = fuse_read_odm(4);\n\n\tu32 dramid = (odm4 & 0xF8) >> 3;\n\n\t// Get extended dram id info.\n\tif (!tegra_t210)\n\t\tdramid |= (odm4 & 0x7000) >> 7;\n\n\tif (raw_id)\n\t\treturn dramid;\n\n\tif (tegra_t210)\n\t{\n\t\tif (dramid > 7)\n\t\t\tdramid = 0;\n\n\t\tif (_dramid_8gb)\n\t\t\tdramid = 7;\n\t}\n\telse\n\t{\n\t\tif (dramid > 34)\n\t\t\tdramid = 8;\n\n\t\tif (_dramid_8gb)\n\t\t\tdramid = 28;\n\t}\n\n\treturn dramid;\n}\n\nu32 fuse_read_hw_state()\n{\n\tif ((fuse_read_odm(4) & 3) != 3)\n\t\treturn FUSE_NX_HW_STATE_PROD;\n\telse\n\t\treturn FUSE_NX_HW_STATE_DEV;\n}\n\nu32 fuse_read_hw_type()\n{\n\tif (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01)\n\t{\n\t\tswitch ((fuse_read_odm(4) & 0xF0000) >> 16)\n\t\t{\n\t\tcase 2:\n\t\t\treturn FUSE_NX_HW_TYPE_HOAG;\n\t\tcase 4:\n\t\t\treturn FUSE_NX_HW_TYPE_AULA;\n\t\tcase 1:\n\t\tdefault:\n\t\t\treturn FUSE_NX_HW_TYPE_IOWA;\n\t\t}\n\t}\n\n\treturn FUSE_NX_HW_TYPE_ICOSA;\n}\n\nint fuse_set_sbk()\n{\n\tif (FUSE(FUSE_PRIVATE_KEY0) != 0xFFFFFFFF)\n\t{\n\t\t// Read SBK from fuses.\n\t\tu32 sbk[4] = {\n\t\t\tFUSE(FUSE_PRIVATE_KEY0),\n\t\t\tFUSE(FUSE_PRIVATE_KEY1),\n\t\t\tFUSE(FUSE_PRIVATE_KEY2),\n\t\t\tFUSE(FUSE_PRIVATE_KEY3)\n\t\t};\n\n\t\t// Set SBK to slot 14.\n\t\tse_aes_key_set(14, sbk, SE_KEY_128_SIZE);\n\n\t\t// Lock SBK from being read.\n\t\tse_key_acc_ctrl(14, SE_KEY_TBL_DIS_KEYREAD_FLAG);\n\n\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n\nvoid fuse_wait_idle()\n{\n\twhile (((FUSE(FUSE_CTRL) >> 16) & 0x1F) != FUSE_STATUS_IDLE)\n\t\t;\n}\n\nvoid fuse_sense()\n{\n\tclock_enable_fuse(false);\n\n\tFUSE(FUSE_CTRL) = (FUSE(FUSE_CTRL) & (~FUSE_CMD_MASK)) | FUSE_SENSE;\n\tusleep(1);\n\n\tfuse_wait_idle();\n\n\tFUSE(FUSE_PRIV2INTFC) = FUSE_PRIV2INTFC_SKIP_RECORDS | FUSE_PRIV2INTFC_START_DATA;\n\tusleep(1);\n\n\twhile (!(FUSE(FUSE_CTRL) & BIT(30)) || ((FUSE(FUSE_CTRL) >> 16) & 0x1F) != FUSE_STATUS_IDLE)\n\t\t;\n\n\n  \tclock_enable_fuse(true);\n}\n\nu32 fuse_read(u32 addr)\n{\n\tFUSE(FUSE_ADDR) = addr;\n\tFUSE(FUSE_CTRL) = (FUSE(FUSE_CTRL) & ~FUSE_CMD_MASK) | FUSE_READ;\n\n\tfuse_wait_idle();\n\n\treturn FUSE(FUSE_RDATA);\n}\n\nu32 fuse_read_array(u32 *words)\n{\n\tu32 array_size = (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01) ?\n\t\t\t\t\t FUSE_ARRAY_WORDS_NUM_B01 : FUSE_ARRAY_WORDS_NUM;\n\n\tfor (u32 i = 0; i < array_size; i++)\n\t\twords[i] = fuse_read(i);\n\n\treturn array_size;\n}\n\nstatic u32 _parity32_even(const u32 *words, u32 count)\n{\n\tu32 acc = words[0];\n\tfor (u32 i = 1; i < count; i++)\n\t\tacc ^= words[i];\n\n\tu32 lo = ((acc & 0xffff) ^ (acc >> 16)) & 0xff;\n\tu32 hi = ((acc & 0xffff) ^ (acc >> 16)) >> 8;\n\tu32 x = hi ^ lo;\n\tlo = ((x & 0xf) ^ (x >> 4)) & 3;\n\thi = ((x & 0xf) ^ (x >> 4)) >> 2;\n\tx = hi ^ lo;\n\n\treturn (x & 1) ^ (x >> 1);\n}\n\nstatic int _patch_hash_one(u32 *word)\n{\n\tu32 bits20_31 = *word & 0xfff00000;\n\tu32 parity_bit = _parity32_even(&bits20_31, 1);\n\tu32 hash = 0;\n\n\tfor (u32 i = 0; i < 12; i++)\n\t{\n\t\tif (*word & (1 << (20 + i)))\n\t\t\thash ^= hash_vals[i];\n\t}\n\n\tif (hash == 0)\n\t{\n\t\tif (parity_bit == 0)\n\t\t\treturn 0;\n\n\t\t*word ^= 1 << 24;\n\n\t\treturn 1;\n\t}\n\n\tif (parity_bit == 0)\n\t\treturn 3;\n\n\tfor (u32 i = 0; i < ARRAY_SIZE(hash_vals); i++)\n\t{\n\t\tif (hash_vals[i] == hash)\n\t\t{\n\t\t\t*word ^= 1 << (20 + i);\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\treturn 2;\n}\n\nstatic int _patch_hash_multi(u32 *words, u32 count)\n{\n\tu32 parity_bit = _parity32_even(words, count);\n\tu32 bits0_14 = words[0] & 0x7fff;\n\tu32 bit15 = words[0] & 0x8000;\n\tu32 bits16_19 = words[0] & 0xf0000;\n\n\tu32 hash = 0;\n\twords[0] = bits16_19;\n\tfor (u32 i = 0; i < count; i++)\n\t{\n\t\tu32 w = words[i];\n\t\tif (w)\n\t\t{\n\t\t\tfor (u32 bitpos = 0; bitpos < 32; bitpos++)\n\t\t\t{\n\t\t\t\tif ((w >> bitpos) & 1)\n\t\t\t\t\thash ^= 0x4000 + i * 32 + bitpos;\n\t\t\t}\n\t\t}\n\t}\n\thash ^= bits0_14;\n\t// stupid but this is what original code does.\n\t// equivalent to original words[0] &= 0xfff00000\n\twords[0] = bits16_19 ^ bit15 ^ bits0_14;\n\n\tif (hash == 0)\n\t{\n\t\tif (parity_bit == 0)\n\t\t\treturn 0;\n\n\t\twords[0] ^= 0x8000;\n\t\treturn 1;\n\t}\n\tif (parity_bit == 0)\n\t\treturn 3;\n\n\tu32 bitcount = hash - 0x4000;\n\tif (bitcount < 16 || bitcount >= count * 32)\n\t{\n\t\tu32 num_set = 0;\n\t\tfor (u32 bitpos = 0; bitpos < 15; bitpos++)\n\t\t{\n\t\t\tif ((hash >> bitpos) & 1)\n\t\t\t\tnum_set++;\n\t\t}\n\t\tif (num_set != 1)\n\t\t\treturn 2;\n\n\t\twords[0] ^= hash;\n\t\treturn 1;\n\t}\n\twords[bitcount / 32] ^= 1 << (hash & 0x1f);\n\treturn 1;\n}\n\nint fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))\n{\n\tu32 words[80];\n\tu32 word_count;\n\tu32 word_addr;\n\tu32 word0;\n\tu32 total_read = 0;\n\n\tword_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);\n\tword_count &= 0x7F;\n\tword_addr = FUSE_ARRAY_WORDS_NUM - 1;\n\n\twhile (word_count)\n\t{\n\t\ttotal_read += word_count;\n\t\tif (total_read >= ARRAY_SIZE(words))\n\t\t\tbreak;\n\n\t\tfor (u32 i = 0; i < word_count; i++)\n\t\t{\n\t\t\twords[i] = fuse_read(word_addr--);\n\t\t\t// Parse extra T210B01 fuses when the difference is reached.\n\t\t\tif (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01 &&\n\t\t\t\tword_addr == ((FUSE_ARRAY_WORDS_NUM - 1) -\n\t\t\t\t\t\t\t  (FUSE_ARRAY_WORDS_NUM_B01 - FUSE_ARRAY_WORDS_NUM) / sizeof(u32)))\n\t\t\t{\n\t\t\t\tword_addr = FUSE_ARRAY_WORDS_NUM_B01 - 1;\n\t\t\t}\n\t\t}\n\n\t\tword0 = words[0];\n\t\tif (_patch_hash_multi(words, word_count) >= 2)\n\t\t\treturn 1;\n\n\t\tu32 ipatch_count = (words[0] >> 16) & 0xF;\n\t\tif (ipatch_count)\n\t\t{\n\t\t\tfor (u32 i = 0; i < ipatch_count; i++)\n\t\t\t{\n\t\t\t\tu32 word = words[i + 1];\n\t\t\t\tu32 addr = (word >> 16) * 2;\n\t\t\t\tu32 data = word & 0xFFFF;\n\n\t\t\t\tipatch(addr, data);\n\t\t\t}\n\t\t}\n\n\t\twords[0] = word0;\n\t\tif ((word0 >> 25) == 0)\n\t\t\tbreak;\n\n\t\tif (_patch_hash_one(&word0) >= 2)\n\t\t\treturn 3;\n\n\t\tword_count = word0 >> 25;\n\t}\n\n\treturn 0;\n}\n\nint fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)\n{\n\tu32 words[80];\n\tu32 word_count;\n\tu32 word_addr;\n\tu32 word0;\n\tu32 total_read = 0;\n\tint evp_thunk_written = 0;\n\tvoid *evp_thunk_dst_addr = 0;\n\tbool t210b01 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01;\n\tu32 *evp_thunk_tmp = (u32 *)malloc(sizeof(evp_thunk_template));\n\n\tmemcpy(evp_thunk_tmp, evp_thunk_template, sizeof(evp_thunk_template));\n\tmemset(iram_evp_thunks, 0, *iram_evp_thunks_len);\n\n\tif (t210b01)\n\t\tmemcpy(&evp_thunk_tmp[15], evp_thunk_func_offsets_t210b01, sizeof(evp_thunk_func_offsets_t210b01));\n\n\tword_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);\n\tword_count &= 0x7F;\n\tword_addr = FUSE_ARRAY_WORDS_NUM - 1;\n\n\twhile (word_count)\n\t{\n\t\ttotal_read += word_count;\n\t\tif (total_read >= ARRAY_SIZE(words))\n\t\t\tbreak;\n\n\t\tfor (u32 i = 0; i < word_count; i++)\n\t\t{\n\t\t\twords[i] = fuse_read(word_addr--);\n\t\t\t// Parse extra T210B01 fuses when the difference is reached.\n\t\t\tif (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01 &&\n\t\t\t\tword_addr == ((FUSE_ARRAY_WORDS_NUM - 1) -\n\t\t\t\t\t\t\t  (FUSE_ARRAY_WORDS_NUM_B01 - FUSE_ARRAY_WORDS_NUM) / sizeof(u32)))\n\t\t\t{\n\t\t\t\tword_addr = FUSE_ARRAY_WORDS_NUM_B01 - 1;\n\t\t\t}\n\t\t}\n\n\t\tword0 = words[0];\n\t\tif (_patch_hash_multi(words, word_count) >= 2)\n\t\t{\n\t\t\tfree(evp_thunk_tmp);\n\t\t\treturn 1;\n\t\t}\n\n\t\tu32 ipatch_count = (words[0] >> 16) & 0xF;\n\t\tu32 insn_count = word_count - ipatch_count - 1;\n\t\tif (insn_count)\n\t\t{\n\t\t\tif (!evp_thunk_written)\n\t\t\t{\n\t\t\t\tevp_thunk_dst_addr = (void *)iram_evp_thunks;\n\n\t\t\t\tmemcpy(evp_thunk_dst_addr, (void *)evp_thunk_tmp, sizeof(evp_thunk_template));\n\t\t\t\tevp_thunk_dst_addr += sizeof(evp_thunk_template);\n\t\t\t\tevp_thunk_written = 1;\n\t\t\t\t*iram_evp_thunks_len = sizeof(evp_thunk_template);\n\n\t\t\t\t//write32(TEGRA_EXCEPTION_VECTORS_BASE + 0x208, iram_evp_thunks);\n\t\t\t}\n\n\t\t\tu32 thunk_patch_len = insn_count * sizeof(u32);\n\t\t\tmemcpy(evp_thunk_dst_addr, &words[ipatch_count + 1], thunk_patch_len);\n\t\t\tevp_thunk_dst_addr += thunk_patch_len;\n\t\t\t*iram_evp_thunks_len += thunk_patch_len;\n\t\t}\n\n\t\twords[0] = word0;\n\t\tif ((word0 >> 25) == 0)\n\t\t\tbreak;\n\n\t\tif (_patch_hash_one(&word0) >= 2)\n\t\t{\n\t\t\tfree(evp_thunk_tmp);\n\t\t\treturn 3;\n\t\t}\n\n\t\tword_count = word0 >> 25;\n\t}\n\n\tfree(evp_thunk_tmp);\n\n\treturn 0;\n}\n\nbool fuse_check_patched_rcm()\n{\n\t// Check if XUSB in use or Tegra X1+.\n\tif (FUSE(FUSE_RESERVED_SW) & (1<<7) || hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01)\n\t\treturn true;\n\n\t// Check if RCM is ipatched.\n\tu32 word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE) & 0x7F;\n\tu32 word_addr = FUSE_ARRAY_WORDS_NUM - 1;\n\n\twhile (word_count)\n\t{\n\t\tu32 word0 = fuse_read(word_addr);\n\t\tu32 ipatch_count = (word0 >> 16) & 0xF;\n\n\t\tfor (u32 i = 0; i < ipatch_count; i++)\n\t\t{\n\t\t\tu32 word = fuse_read(word_addr - (i + 1));\n\t\t\tu32 addr = (word >> 16) * 2;\n\t\t\tif (addr == 0x769A)\n\t\t\t\treturn true;\n\t\t}\n\n\t\tword_addr -= word_count;\n\t\tword_count = word0 >> 25;\n\t}\n\n\treturn false;\n}\n"
  },
  {
    "path": "bdk/soc/fuse.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018 shuffle2\n * Copyright (c) 2018 balika011\n * Copyright (c) 2019-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _FUSE_H_\n#define _FUSE_H_\n\n#include <utils/types.h>\n\n/*! Fuse registers. */\n#define FUSE_CTRL                             0x0\n#define FUSE_ADDR                             0x4\n#define FUSE_RDATA                            0x8\n#define FUSE_WDATA                            0xC\n#define FUSE_TIME_RD1                         0x10\n#define FUSE_TIME_RD2                         0x14\n#define FUSE_TIME_PGM1                        0x18\n#define FUSE_TIME_PGM2                        0x1C\n#define FUSE_PRIV2INTFC                       0x20\n#define  FUSE_PRIV2INTFC_START_DATA            BIT(0)\n#define  FUSE_PRIV2INTFC_SKIP_RECORDS          BIT(1)\n#define FUSE_FUSEBYPASS                       0x24\n#define FUSE_PRIVATEKEYDISABLE                0x28\n#define  FUSE_PRIVKEY_DISABLE                  BIT(0)\n#define  FUSE_PRIVKEY_TZ_STICKY_BIT            BIT(4)\n#define FUSE_DISABLEREGPROGRAM                0x2C\n#define FUSE_WRITE_ACCESS_SW                  0x30\n#define FUSE_PWR_GOOD_SW                      0x34\n#define FUSE_PRIV2RESHIFT                     0x3C\n#define FUSE_FUSETIME_RD0                     0x40\n#define FUSE_FUSETIME_RD1                     0x44\n#define FUSE_FUSETIME_RD2                     0x48\n#define FUSE_FUSETIME_RD3                     0x4C\n#define FUSE_PRIVATE_KEY0_NONZERO             0x80\n#define FUSE_PRIVATE_KEY1_NONZERO             0x84\n#define FUSE_PRIVATE_KEY2_NONZERO             0x88\n#define FUSE_PRIVATE_KEY3_NONZERO             0x8C\n#define FUSE_PRIVATE_KEY4_NONZERO             0x90\n\n/*! Fuse Cached registers */\n#define FUSE_RESERVED_ODM8_B01                0x98 // FUSE_READ_TZ Group 0.\n#define FUSE_RESERVED_ODM9_B01                0x9C // FUSE_READ_TZ Group 0.\n#define FUSE_RESERVED_ODM10_B01               0xA0 // FUSE_READ_TZ Group 0.\n#define FUSE_RESERVED_ODM11_B01               0xA4 // FUSE_READ_TZ Group 0.\n#define FUSE_RESERVED_ODM12_B01               0xA8 // FUSE_READ_TZ Group 1? Is value -1?\n#define FUSE_RESERVED_ODM13_B01               0xAC // FUSE_READ_TZ Group 1? Is value -1?\n#define FUSE_RESERVED_ODM14_B01               0xB0 // FUSE_READ_TZ Group 1? Is value -1?\n#define FUSE_RESERVED_ODM15_B01               0xB4 // FUSE_READ_TZ Group 1? Is value -1?\n#define FUSE_RESERVED_ODM16_B01               0xB8 // FUSE_READ_TZ Group 2? Is value -1?\n#define FUSE_RESERVED_ODM17_B01               0xBC // FUSE_READ_TZ Group 2? Is value -1?\n#define FUSE_RESERVED_ODM18_B01               0xC0 // FUSE_READ_TZ Group 2.\n#define FUSE_RESERVED_ODM19_B01               0xC4 // FUSE_READ_TZ Group 2.\n#define FUSE_RESERVED_ODM20_B01               0xC8 // FUSE_READ_TZ Group 3.\n#define FUSE_RESERVED_ODM21_B01               0xCC // FUSE_READ_TZ Group 3.\n#define FUSE_KEK00_B01                        0xD0\n#define FUSE_KEK01_B01                        0xD4\n#define FUSE_KEK02_B01                        0xD8\n#define FUSE_KEK03_B01                        0xDC\n#define FUSE_BEK00_B01                        0xE0\n#define FUSE_BEK01_B01                        0xE4\n#define FUSE_BEK02_B01                        0xE8\n#define FUSE_BEK03_B01                        0xEC\n#define FUSE_OPT_RAM_RTSEL_TSMCSP_PO4SVT_B01  0xF0\n#define FUSE_OPT_RAM_WTSEL_TSMCSP_PO4SVT_B01  0xF4\n#define FUSE_OPT_RAM_RTSEL_TSMCPDP_PO4SVT_B01 0xF8\n#define FUSE_OPT_RAM_MTSEL_TSMCPDP_PO4SVT_B01 0xFC\n\n#define FUSE_PRODUCTION_MODE                  0x100\n#define FUSE_JTAG_SECUREID_VALID              0x104\n#define FUSE_ODM_LOCK                         0x108\n#define FUSE_OPT_OPENGL_EN                    0x10C\n#define FUSE_SKU_INFO                         0x110\n#define FUSE_CPU_SPEEDO_0_CALIB               0x114\n#define FUSE_CPU_IDDQ_CALIB                   0x118\n\n#define FUSE_RESERVED_ODM22_B01               0x11C // FUSE_READ_TZ Group 3.\n#define FUSE_RESERVED_ODM23_B01               0x120 // FUSE_READ_TZ Group 3.\n#define FUSE_RESERVED_ODM24_B01               0x124 // FUSE_READ_TZ Group 4.\n\n#define FUSE_OPT_FT_REV                       0x128\n#define FUSE_CPU_SPEEDO_1_CALIB               0x12C\n#define FUSE_CPU_SPEEDO_2_CALIB               0x130\n#define FUSE_SOC_SPEEDO_0_CALIB               0x134\n#define FUSE_SOC_SPEEDO_1_CALIB               0x138\n#define FUSE_SOC_SPEEDO_2_CALIB               0x13C\n#define FUSE_SOC_IDDQ_CALIB                   0x140\n\n#define FUSE_RESERVED_ODM25_B01               0x144 // FUSE_READ_TZ Group 4.\n\n#define FUSE_FA                               0x148\n#define FUSE_RESERVED_PRODUCTION              0x14C\n#define FUSE_HDMI_LANE0_CALIB                 0x150\n#define FUSE_HDMI_LANE1_CALIB                 0x154\n#define FUSE_HDMI_LANE2_CALIB                 0x158\n#define FUSE_HDMI_LANE3_CALIB                 0x15C\n#define FUSE_ENCRYPTION_RATE                  0x160\n#define FUSE_PUBLIC_KEY0                      0x164\n#define FUSE_PUBLIC_KEY1                      0x168\n#define FUSE_PUBLIC_KEY2                      0x16C\n#define FUSE_PUBLIC_KEY3                      0x170\n#define FUSE_PUBLIC_KEY4                      0x174\n#define FUSE_PUBLIC_KEY5                      0x178\n#define FUSE_PUBLIC_KEY6                      0x17C\n#define FUSE_PUBLIC_KEY7                      0x180\n#define FUSE_TSENSOR1_CALIB                   0x184 // CPU1.\n#define FUSE_TSENSOR2_CALIB                   0x188 // CPU2.\n\n#define FUSE_OPT_SECURE_SCC_DIS_B01           0x18C\n\n#define FUSE_OPT_CP_REV                       0x190 // FUSE style revision - ATE. 0x101 0x100\n#define FUSE_OPT_PFG                          0x194\n#define FUSE_TSENSOR0_CALIB                   0x198 // CPU0.\n#define FUSE_FIRST_BOOTROM_PATCH_SIZE         0x19C\n#define FUSE_SECURITY_MODE                    0x1A0\n#define FUSE_PRIVATE_KEY0                     0x1A4\n#define FUSE_PRIVATE_KEY1                     0x1A8\n#define FUSE_PRIVATE_KEY2                     0x1AC\n#define FUSE_PRIVATE_KEY3                     0x1B0\n#define FUSE_PRIVATE_KEY4                     0x1B4\n#define FUSE_ARM_JTAG_DIS                     0x1B8\n#define FUSE_BOOT_DEVICE_INFO                 0x1BC\n#define FUSE_RESERVED_SW                      0x1C0\n#define FUSE_OPT_VP9_DISABLE                  0x1C4\n\n#define FUSE_RESERVED_ODM0                    0x1C8\n#define FUSE_RESERVED_ODM1                    0x1CC\n#define FUSE_RESERVED_ODM2                    0x1D0\n#define FUSE_RESERVED_ODM3                    0x1D4\n#define FUSE_RESERVED_ODM4                    0x1D8\n#define FUSE_RESERVED_ODM5                    0x1DC\n#define FUSE_RESERVED_ODM6                    0x1E0\n#define FUSE_RESERVED_ODM7                    0x1E4\n\n#define FUSE_OBS_DIS                          0x1E8\n\n#define FUSE_OPT_NVJTAG_PROTECTION_ENABLE_B01 0x1EC\n\n#define FUSE_USB_CALIB                        0x1F0\n#define FUSE_SKU_DIRECT_CONFIG                0x1F4\n#define FUSE_KFUSE_PRIVKEY_CTRL               0x1F8\n#define FUSE_PACKAGE_INFO                     0x1FC // 1: MID, 2: DSC.\n#define FUSE_OPT_VENDOR_CODE                  0x200\n#define FUSE_OPT_FAB_CODE                     0x204\n#define FUSE_OPT_LOT_CODE_0                   0x208\n#define FUSE_OPT_LOT_CODE_1                   0x20C\n#define FUSE_OPT_WAFER_ID                     0x210\n#define FUSE_OPT_X_COORDINATE                 0x214\n#define FUSE_OPT_Y_COORDINATE                 0x218\n#define FUSE_OPT_SEC_DEBUG_EN                 0x21C\n#define FUSE_OPT_OPS_RESERVED                 0x220\n#define FUSE_SATA_CALIB                       0x224\n\n#define FUSE_SPARE_REGISTER_ODM_B01           0x224\n\n#define FUSE_GPU_IDDQ_CALIB\t                  0x228\n#define FUSE_TSENSOR3_CALIB                   0x22C // CPU3.\n#define FUSE_CLOCK_BONDOUT0                   0x230\n#define FUSE_CLOCK_BONDOUT1                   0x234\n\n#define FUSE_RESERVED_ODM26_B01               0x238 // FUSE_READ_TZ Group 4.\n#define FUSE_RESERVED_ODM27_B01               0x23C // FUSE_READ_TZ Group 4.\n#define FUSE_RESERVED_ODM28_B01               0x240 // MAX77812 phase configuration. FUSE_READ_TZ Group 5.\n\n#define FUSE_OPT_SAMPLE_TYPE                  0x244\n#define FUSE_OPT_SUBREVISION                  0x248 // \"\", \"p\", \"q\", \"r\". e.g: A01p.\n#define FUSE_OPT_SW_RESERVED_0                0x24C\n#define FUSE_OPT_SW_RESERVED_1                0x250\n#define FUSE_TSENSOR4_CALIB                   0x254 // GPU.\n#define FUSE_TSENSOR5_CALIB                   0x258 // MEM0.\n#define FUSE_TSENSOR6_CALIB                   0x25C // MEM1.\n#define FUSE_TSENSOR7_CALIB                   0x260 // PLLX.\n#define FUSE_OPT_PRIV_SEC_DIS                 0x264\n#define FUSE_PKC_DISABLE                      0x268\n\n#define FUSE_BOOT_SECURITY_INFO_B01           0x268\n#define FUSE_OPT_RAM_RTSEL_TSMCSP_PO4HVT_B01  0x26C\n#define FUSE_OPT_RAM_WTSEL_TSMCSP_PO4HVT_B01  0x270\n#define FUSE_OPT_RAM_RTSEL_TSMCPDP_PO4HVT_B01 0x274\n#define FUSE_OPT_RAM_MTSEL_TSMCPDP_PO4HVT_B01 0x278\n\n#define FUSE_FUSE2TSEC_DEBUG_DISABLE          0x27C\n#define FUSE_TSENSOR_COMMON                   0x280\n#define FUSE_OPT_CP_BIN                       0x284\n#define FUSE_OPT_GPU_DISABLE                  0x288\n#define FUSE_OPT_FT_BIN                       0x28C\n#define FUSE_OPT_DONE_MAP                     0x290\n\n#define FUSE_RESERVED_ODM29_B01               0x294 // FUSE_READ_TZ Group 5? Is value -1?\n\n#define FUSE_APB2JTAG_DISABLE                 0x298\n#define FUSE_ODM_INFO                         0x29C // Debug features disable.\n#define FUSE_ARM_CRYPT_DE_FEATURE             0x2A8\n\n#define FUSE_OPT_RAM_WTSEL_TSMCPDP_PO4SVT_B01 0x2B0\n#define FUSE_OPT_RAM_RCT_TSMCDP_PO4SVT_B01    0x2B4\n#define FUSE_OPT_RAM_WCT_TSMCDP_PO4SVT_B01    0x2B8\n#define FUSE_OPT_RAM_KP_TSMCDP_PO4SVT_B01     0x2BC\n\n#define FUSE_WOA_SKU_FLAG                     0x2C0\n#define FUSE_ECO_RESERVE_1                    0x2C4\n#define FUSE_GCPLEX_CONFIG_FUSE               0x2C8\n#define  FUSE_GPU_VPR_AUTO_FETCH_DIS          BIT(0)\n#define  FUSE_GPU_VPR_ENABLED                 BIT(1)\n#define  FUSE_GPU_WPR_ENABLED                 BIT(2)\n#define FUSE_PRODUCTION_MONTH                 0x2CC\n#define FUSE_RAM_REPAIR_INDICATOR             0x2D0\n#define FUSE_TSENSOR9_CALIB                   0x2D4 // AOTAG.\n#define FUSE_VMIN_CALIBRATION                 0x2DC\n#define FUSE_AGING_SENSOR_CALIBRATION         0x2E0\n#define FUSE_DEBUG_AUTHENTICATION             0x2E4\n#define FUSE_SECURE_PROVISION_INDEX           0x2E8\n#define FUSE_SECURE_PROVISION_INFO            0x2EC\n#define FUSE_OPT_GPU_DISABLE_CP1              0x2F0\n#define FUSE_SPARE_ENDIS                      0x2F4\n#define FUSE_ECO_RESERVE_0                    0x2F8 // AID.\n#define FUSE_RESERVED_CALIB0                  0x304 // GPCPLL ADC Calibration.\n#define FUSE_RESERVED_CALIB1                  0x308\n#define FUSE_OPT_GPU_TPC0_DISABLE             0x30C\n#define FUSE_OPT_GPU_TPC0_DISABLE_CP1         0x310\n#define FUSE_OPT_CPU_DISABLE                  0x314\n#define FUSE_OPT_CPU_DISABLE_CP1              0x318\n#define FUSE_TSENSOR10_CALIB                  0x31C\n#define FUSE_TSENSOR10_CALIB_AUX              0x320\n#define FUSE_OPT_RAM_SVOP_DP                  0x324\n#define FUSE_OPT_RAM_SVOP_PDP                 0x328\n#define FUSE_OPT_RAM_SVOP_REG                 0x32C\n#define FUSE_OPT_RAM_SVOP_SP                  0x330\n#define FUSE_OPT_RAM_SVOP_SMPDP               0x334\n\n#define FUSE_OPT_RAM_WTSEL_TSMCPDP_PO4HVT_B01 0x324\n#define FUSE_OPT_RAM_RCT_TSMCDP_PO4HVT_B01    0x328\n#define FUSE_OPT_RAM_WCT_TSMCDP_PO4HVT_B01    0x32c\n#define FUSE_OPT_RAM_KP_TSMCDP_PO4HVT_B01     0x330\n#define FUSE_OPT_RAM_SVOP_SP_B01              0x334\n\n#define FUSE_OPT_GPU_TPC0_DISABLE_CP2         0x338\n#define FUSE_OPT_GPU_TPC1_DISABLE             0x33C\n#define FUSE_OPT_GPU_TPC1_DISABLE_CP1         0x340\n#define FUSE_OPT_GPU_TPC1_DISABLE_CP2         0x344\n#define FUSE_OPT_CPU_DISABLE_CP2              0x348\n#define FUSE_OPT_GPU_DISABLE_CP2              0x34C\n#define FUSE_USB_CALIB_EXT                    0x350\n#define FUSE_RESERVED_FIELD                   0x354 // RMA.\n#define FUSE_SPARE_REALIGNMENT_REG            0x37C\n#define FUSE_SPARE_BIT_0                      0x380\n//...\n#define FUSE_SPARE_BIT_31                     0x3FC\n\n/*! Fuse commands. */\n#define FUSE_IDLE     0x0\n#define FUSE_READ     0x1\n#define FUSE_WRITE    0x2\n#define FUSE_SENSE    0x3\n#define FUSE_CMD_MASK 0x3\n\n/*! Fuse status. */\n#define FUSE_STATUS_RESET                   0\n#define FUSE_STATUS_POST_RESET              1\n#define FUSE_STATUS_LOAD_ROW0               2\n#define FUSE_STATUS_LOAD_ROW1               3\n#define FUSE_STATUS_IDLE                    4\n#define FUSE_STATUS_READ_SETUP              5\n#define FUSE_STATUS_READ_STROBE             6\n#define FUSE_STATUS_SAMPLE_FUSES            7\n#define FUSE_STATUS_READ_HOLD               8\n#define FUSE_STATUS_FUSE_SRC_SETUP          9\n#define FUSE_STATUS_WRITE_SETUP             10\n#define FUSE_STATUS_WRITE_ADDR_SETUP        11\n#define FUSE_STATUS_WRITE_PROGRAM           12\n#define FUSE_STATUS_WRITE_ADDR_HOLD         13\n#define FUSE_STATUS_FUSE_SRC_HOLD           14\n#define FUSE_STATUS_LOAD_RIR                15\n#define FUSE_STATUS_READ_BEFORE_WRITE_SETUP 16\n#define FUSE_STATUS_READ_DEASSERT_PD        17\n\n/*! Fuse cache registers. */\n#define FUSE_RESERVED_ODMX(x) (0x1C8 + 4 * (x))\n\n#define FUSE_ARRAY_WORDS_NUM     192\n#define FUSE_ARRAY_WORDS_NUM_B01 256\n\nenum\n{\n\tFUSE_NX_HW_TYPE_ICOSA,\n\tFUSE_NX_HW_TYPE_IOWA,\n\tFUSE_NX_HW_TYPE_HOAG,\n\tFUSE_NX_HW_TYPE_AULA\n};\n\nenum\n{\n\tFUSE_NX_HW_STATE_PROD,\n\tFUSE_NX_HW_STATE_DEV\n};\n\nvoid fuse_disable_program();\nu32  fuse_read_odm(u32 idx);\nu32  fuse_read_odm_keygen_rev();\nvoid fuse_force_8gb_dramid();\nu32  fuse_read_dramid(bool raw_id);\nu32  fuse_read_hw_state();\nu32  fuse_read_hw_type();\nint  fuse_set_sbk();\nvoid fuse_wait_idle();\nvoid fuse_sense();\nu32  fuse_read(u32 addr);\nint  fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value));\nint  fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len);\nu32  fuse_read_array(u32 *words);\nbool fuse_check_patched_rcm();\n\n#endif\n"
  },
  {
    "path": "bdk/soc/gpio.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2019-2023 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <soc/gpio.h>\n#include <soc/t210.h>\n\n#define GPIO_BANK_IDX(port)              ((port) >> 2)\n#define GPIO_PORT_OFFSET(port)           ((GPIO_BANK_IDX(port) << 8) + (((port) % 4) << 2))\n\n#define GPIO_CNF_OFFSET(port)            (0x00 + GPIO_PORT_OFFSET(port))\n#define GPIO_OE_OFFSET(port)             (0x10 + GPIO_PORT_OFFSET(port))\n#define GPIO_OUT_OFFSET(port)            (0x20 + GPIO_PORT_OFFSET(port))\n#define GPIO_IN_OFFSET(port)             (0x30 + GPIO_PORT_OFFSET(port))\n#define GPIO_INT_STA_OFFSET(port)        (0x40 + GPIO_PORT_OFFSET(port))\n#define GPIO_INT_ENB_OFFSET(port)        (0x50 + GPIO_PORT_OFFSET(port))\n#define GPIO_INT_LVL_OFFSET(port)        (0x60 + GPIO_PORT_OFFSET(port))\n#define GPIO_INT_CLR_OFFSET(port)        (0x70 + GPIO_PORT_OFFSET(port))\n\n#define GPIO_CNF_MASKED_OFFSET(port)     (0x80 + GPIO_PORT_OFFSET(port))\n#define GPIO_OE_MASKED_OFFSET(port)      (0x90 + GPIO_PORT_OFFSET(port))\n#define GPIO_OUT_MASKED_OFFSET(port)     (0xA0 + GPIO_PORT_OFFSET(port))\n#define GPIO_INT_STA_MASKED_OFFSET(port) (0xC0 + GPIO_PORT_OFFSET(port))\n#define GPIO_INT_ENB_MASKED_OFFSET(port) (0xD0 + GPIO_PORT_OFFSET(port))\n#define GPIO_INT_LVL_MASKED_OFFSET(port) (0xE0 + GPIO_PORT_OFFSET(port))\n\n#define GPIO_DB_CTRL_OFFSET(port)        (0xB0 + GPIO_PORT_OFFSET(port))\n#define GPIO_DB_CNT_OFFSET(port)         (0xF0 + GPIO_PORT_OFFSET(port))\n\n#define GPIO_IRQ_BANK1 32\n#define GPIO_IRQ_BANK2 33\n#define GPIO_IRQ_BANK3 34\n#define GPIO_IRQ_BANK4 35\n#define GPIO_IRQ_BANK5 55\n#define GPIO_IRQ_BANK6 87\n#define GPIO_IRQ_BANK7 89\n#define GPIO_IRQ_BANK8 125\n\nstatic u8 gpio_bank_irq_ids[8] = {\n\tGPIO_IRQ_BANK1, GPIO_IRQ_BANK2, GPIO_IRQ_BANK3, GPIO_IRQ_BANK4,\n\tGPIO_IRQ_BANK5, GPIO_IRQ_BANK6, GPIO_IRQ_BANK7, GPIO_IRQ_BANK8\n};\n\nvoid gpio_config(u32 port, u32 pins, int mode)\n{\n\tconst u32 offset = GPIO_CNF_OFFSET(port);\n\n\tif (mode)\n\t\tGPIO(offset) |= pins;\n\telse\n\t\tGPIO(offset) &= ~pins;\n\n\t(void)GPIO(offset); // Commit the write.\n}\n\nvoid gpio_output_enable(u32 port, u32 pins, int enable)\n{\n\tconst u32 port_offset = GPIO_OE_OFFSET(port);\n\n\tif (enable)\n\t\tGPIO(port_offset) |= pins;\n\telse\n\t\tGPIO(port_offset) &= ~pins;\n\n\t(void)GPIO(port_offset); // Commit the write.\n}\n\nvoid gpio_write(u32 port, u32 pins, int high)\n{\n\tconst u32 port_offset = GPIO_OUT_OFFSET(port);\n\n\tif (high)\n\t\tGPIO(port_offset) |= pins;\n\telse\n\t\tGPIO(port_offset) &= ~pins;\n\n\t(void)GPIO(port_offset); // Commit the write.\n}\n\nvoid gpio_direction_input(u32 port, u32 pins)\n{\n\tgpio_config(port, pins, GPIO_MODE_GPIO);\n\tgpio_output_enable(port, pins, GPIO_OUTPUT_DISABLE);\n}\n\nvoid gpio_direction_output(u32 port, u32 pins, int high)\n{\n\tgpio_config(port, pins, GPIO_MODE_GPIO);\n\tgpio_write(port, pins, high);\n\tgpio_output_enable(port, pins, GPIO_OUTPUT_ENABLE);\n}\n\nint gpio_read(u32 port, u32 pins)\n{\n\tconst u32 port_offset = GPIO_IN_OFFSET(port);\n\n\treturn (GPIO(port_offset) & pins) ? 1 : 0;\n}\n\nvoid gpio_set_debounce(u32 port, u32 pins, u32 ms)\n{\n\tconst u32 db_ctrl_offset = GPIO_DB_CTRL_OFFSET(port);\n\tconst u32 db_cnt_offset  = GPIO_DB_CNT_OFFSET(port);\n\n\tif (ms)\n\t{\n\t\tif (ms > 255)\n\t\t\tms = 255;\n\n\t\t// Debounce time affects all pins of the same port.\n\t\tGPIO(db_cnt_offset)  = ms;\n\t\tGPIO(db_ctrl_offset) = (pins << 8) | pins;\n\t}\n\telse\n\t\tGPIO(db_ctrl_offset) = (pins << 8) | 0;\n\n\t(void)GPIO(db_ctrl_offset); // Commit the write.\n}\n\nstatic void _gpio_interrupt_clear(u32 port, u32 pins)\n{\n\tconst u32 port_offset = GPIO_INT_CLR_OFFSET(port);\n\n\tGPIO(port_offset) |= pins;\n\n\t(void)GPIO(port_offset); // Commit the write.\n}\n\nint gpio_interrupt_status(u32 port, u32 pins)\n{\n\tconst u32 port_offset  = GPIO_INT_STA_OFFSET(port);\n\tconst u32 enabled_mask = GPIO(GPIO_INT_ENB_OFFSET(port)) & pins;\n\n\tint status = ((GPIO(port_offset) & pins) && enabled_mask) ? 1 : 0;\n\n\t// Clear the interrupt status.\n\tif (status)\n\t\t_gpio_interrupt_clear(port, pins);\n\n\treturn status;\n}\n\nvoid gpio_interrupt_enable(u32 port, u32 pins, int enable)\n{\n\tconst u32 port_offset = GPIO_INT_ENB_OFFSET(port);\n\n\t// Clear any possible stray interrupt.\n\t_gpio_interrupt_clear(port, pins);\n\n\tif (enable)\n\t\tGPIO(port_offset) |= pins;\n\telse\n\t\tGPIO(port_offset) &= ~pins;\n\n\t(void)GPIO(port_offset); // Commit the write.\n}\n\nvoid gpio_interrupt_level(u32 port, u32 pins, int high, int edge, int delta)\n{\n\tconst u32 port_offset = GPIO_INT_LVL_OFFSET(port);\n\n\tu32 val = GPIO(port_offset);\n\n\tif (high)\n\t\tval |= pins;\n\telse\n\t\tval &= ~pins;\n\n\tif (edge)\n\t\tval |= pins << 8;\n\telse\n\t\tval &= ~(pins << 8);\n\n\tif (delta)\n\t\tval |= pins << 16;\n\telse\n\t\tval &= ~(pins << 16);\n\n\tGPIO(port_offset) = val;\n\n\t(void)GPIO(port_offset); // Commit the write.\n\n\t// Clear any possible stray interrupt.\n\t_gpio_interrupt_clear(port, pins);\n}\n\nu32 gpio_get_bank_irq_id(u32 port)\n{\n\tconst u32 bank_idx = GPIO_BANK_IDX(port);\n\n\treturn gpio_bank_irq_ids[bank_idx];\n}\n"
  },
  {
    "path": "bdk/soc/gpio.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2019-2023 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _GPIO_H_\n#define _GPIO_H_\n\n#include <utils/types.h>\n\n#define GPIO_MODE_SPIO 0\n#define GPIO_MODE_GPIO 1\n\n#define GPIO_OUTPUT_DISABLE 0\n#define GPIO_OUTPUT_ENABLE 1\n\n#define GPIO_IRQ_DISABLE 0\n#define GPIO_IRQ_ENABLE 1\n\n#define GPIO_LOW 0\n#define GPIO_HIGH 1\n#define GPIO_FALLING 0\n#define GPIO_RISING 1\n\n#define GPIO_LEVEL 0\n#define GPIO_EDGE 1\n\n#define GPIO_CONFIGURED_EDGE 0\n#define GPIO_ANY_EDGE_CHANGE 1\n\n/*! GPIO pins (0-7 for each port). */\n#define GPIO_PIN_0 BIT(0)\n#define GPIO_PIN_1 BIT(1)\n#define GPIO_PIN_2 BIT(2)\n#define GPIO_PIN_3 BIT(3)\n#define GPIO_PIN_4 BIT(4)\n#define GPIO_PIN_5 BIT(5)\n#define GPIO_PIN_6 BIT(6)\n#define GPIO_PIN_7 BIT(7)\n\n/*! GPIO ports (A-EE). */\n#define GPIO_PORT_A 0\n#define GPIO_PORT_B 1\n#define GPIO_PORT_C 2\n#define GPIO_PORT_D 3\n#define GPIO_PORT_E 4\n#define GPIO_PORT_F 5\n#define GPIO_PORT_G 6\n#define GPIO_PORT_H 7\n#define GPIO_PORT_I 8\n#define GPIO_PORT_J 9\n#define GPIO_PORT_K 10\n#define GPIO_PORT_L 11\n#define GPIO_PORT_M 12\n#define GPIO_PORT_N 13\n#define GPIO_PORT_O 14\n#define GPIO_PORT_P 15\n#define GPIO_PORT_Q 16\n#define GPIO_PORT_R 17\n#define GPIO_PORT_S 18\n#define GPIO_PORT_T 19\n#define GPIO_PORT_U 20\n#define GPIO_PORT_V 21\n#define GPIO_PORT_W 22\n#define GPIO_PORT_X 23\n#define GPIO_PORT_Y 24\n#define GPIO_PORT_Z 25\n#define GPIO_PORT_AA 26\n#define GPIO_PORT_BB 27\n#define GPIO_PORT_CC 28\n#define GPIO_PORT_DD 29\n#define GPIO_PORT_EE 30\n\nvoid gpio_config(u32 port, u32 pins, int mode);\nvoid gpio_output_enable(u32 port, u32 pins, int enable);\nvoid gpio_direction_input(u32 port, u32 pins);\nvoid gpio_direction_output(u32 port, u32 pins, int high);\nvoid gpio_write(u32 port, u32 pins, int high);\nint  gpio_read(u32 port, u32 pins);\nvoid gpio_set_debounce(u32 port, u32 pins, u32 ms);\nint  gpio_interrupt_status(u32 port, u32 pins);\nvoid gpio_interrupt_enable(u32 port, u32 pins, int enable);\nvoid gpio_interrupt_level(u32 port, u32 pins, int high, int edge, int delta);\nu32  gpio_get_bank_irq_id(u32 port);\n\n#endif\n"
  },
  {
    "path": "bdk/soc/hw_init.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <soc/hw_init.h>\n#include <display/di.h>\n#include <display/vic.h>\n#include <input/joycon.h>\n#include <input/touch.h>\n#include <sec/se.h>\n#include <sec/se_t210.h>\n#include <soc/bpmp.h>\n#include <soc/clock.h>\n#include <soc/fuse.h>\n#include <soc/gpio.h>\n#include <soc/i2c.h>\n#include <soc/pinmux.h>\n#include <soc/pmc.h>\n#include <soc/uart.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n#include <mem/mc.h>\n#include <mem/minerva.h>\n#include <mem/sdram.h>\n#include <power/bq24193.h>\n#include <power/max77620.h>\n#include <power/max7762x.h>\n#include <power/regulator_5v.h>\n#include <storage/sd.h>\n#include <storage/sdmmc.h>\n#include <thermal/fan.h>\n#include <thermal/tmp451.h>\n#include <utils/util.h>\n\nu32 hw_rst_status;\nu32 hw_rst_reason;\n\nu32 hw_get_chip_id()\n{\n\tif (((APB_MISC(APB_MISC_GP_HIDREV) >> 4) & 0xF) >= GP_HIDREV_MAJOR_T210B01)\n\t\treturn GP_HIDREV_MAJOR_T210B01;\n\telse\n\t\treturn GP_HIDREV_MAJOR_T210;\n}\n\n/*\n * CLK_OSC - 38.4 MHz crystal.\n * CLK_M   - 19.2 MHz (osc/2).\n * CLK_S   - 32.768 KHz (from PMIC).\n * SCLK    - 204MHz init (-> 408MHz -> OC).\n * HCLK    - 204MHz init (-> 408MHz -> OC).\n * PCLK    - 68MHz  init (-> 136MHz -> OC/4).\n */\n\nstatic void _config_oscillators()\n{\n\tCLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4; // Set CLK_M_DIVISOR to 2.\n\tSYSCTR0(SYSCTR0_CNTFID0)             = 19200000;   // Set counter frequency.\n\tTMR(TIMERUS_USEC_CFG)                = 0x45F;      // For 19.2MHz clk_m.\n\tCLOCK(CLK_RST_CONTROLLER_OSC_CTRL)   = 0x50000071; // Set OSC to 38.4MHz and drive strength.\n\n\tPMC(APBDEV_PMC_OSC_EDPD_OVER)  = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE; // Set LP0 OSC drive strength.\n\tPMC(APBDEV_PMC_OSC_EDPD_OVER)  = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | PMC_OSC_EDPD_OVER_OSC_CTRL_OVER;\n\tPMC(APBDEV_PMC_CNTRL2)         = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | PMC_CNTRL2_HOLD_CKE_LOW_EN;\n\tAPB_MISC(APB_MISC_GP_ASDBGREG) = (APB_MISC(APB_MISC_GP_ASDBGREG) & 0xFCFFFFFF) | (2 << 24); // CFG2TMC_RAM_SVOP_PDP.\n\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10;       // Set HCLK div to 2 and PCLK div to 1.\n\tCLOCK(CLK_RST_CONTROLLER_PLLMB_BASE)     &= 0xBFFFFFFF; // PLLMB disable.\n\n\tPMC(APBDEV_PMC_TSC_MULT) = (PMC(APBDEV_PMC_TSC_MULT) & 0xFFFF0000) | 0x249F; // 0x249F = 19200000 * (16 / 32.768 kHz).\n\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SYS)     = 0;          // Set BPMP/SCLK div to 1.\n\tCLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY)  = 0x20004444; // Set BPMP/SCLK source to Run and PLLP_OUT2 (204MHz).\n\tCLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000; // Enable SUPER_SDIV to 1.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE)    = 2;          // Set HCLK div to 1 and PCLK div to 3.\n}\n\nvoid hw_config_arbiter(bool reset)\n{\n\tif (reset)\n\t{\n\t\tARB_PRI(ARB_PRIO_CPU_PRIORITY) = 0x0040090;\n\t\tARB_PRI(ARB_PRIO_COP_PRIORITY) = 0x12024C2;\n\t\tARB_PRI(ARB_PRIO_VCP_PRIORITY) = 0x2201209;\n\t\tARB_PRI(ARB_PRIO_DMA_PRIORITY) = 0x320365B;\n\t}\n\telse\n\t{\n\t\tARB_PRI(ARB_PRIO_CPU_PRIORITY) = 0x12412D1;\n\t\tARB_PRI(ARB_PRIO_COP_PRIORITY) = 0x0000000;\n\t\tARB_PRI(ARB_PRIO_VCP_PRIORITY) = 0x220244A;\n\t\tARB_PRI(ARB_PRIO_DMA_PRIORITY) = 0x320369B;\n\t}\n}\n\n// The uart is skipped for Copper, Hoag and Calcio. Used in Icosa, Iowa and Aula.\nstatic void _config_gpios(bool nx_hoag)\n{\n\t// Clamp inputs when tristated.\n\tAPB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0;\n\n\tif (!nx_hoag)\n\t{\n\t\t// Turn Joy-Con detect on. (GPIO mode and input logic for UARTB/C TX pins.)\n\t\tPINMUX_AUX(PINMUX_AUX_UART2_TX) = 0;\n\t\tPINMUX_AUX(PINMUX_AUX_UART3_TX) = 0;\n\t\tgpio_direction_input(GPIO_PORT_G, GPIO_PIN_0);\n\t\tgpio_direction_input(GPIO_PORT_D, GPIO_PIN_1);\n\t}\n\n\t// Set Joy-Con IsAttached pinmux. Shared with UARTB/UARTC TX.\n\tPINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;\n\tPINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;\n\n\t// Configure Joy-Con IsAttached pins. Shared with UARTB/UARTC TX.\n\tgpio_direction_input(GPIO_PORT_E, GPIO_PIN_6);\n\tgpio_direction_input(GPIO_PORT_H, GPIO_PIN_6);\n\n\tpinmux_config_i2c(I2C_1);\n\tpinmux_config_i2c(I2C_5);\n\tpinmux_config_uart(UART_A);\n\n\t// Configure volume up/down as inputs.\n\tgpio_direction_input(GPIO_PORT_X, GPIO_PIN_6 | GPIO_PIN_7);\n\n\t// Configure HOME as input. (Shared with UARTB RTS).\n\tPINMUX_AUX(PINMUX_AUX_BUTTON_HOME) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;\n\tgpio_direction_input(GPIO_PORT_Y, GPIO_PIN_1);\n\n\t// Power button can be configured for hoag here. Only SKU where it's connected.\n}\n\nstatic void _config_pmc_scratch()\n{\n\tPMC(APBDEV_PMC_SCRATCH20)  &= 0xFFF3FFFF; // Unset Debug console from Customer Option.\n\tPMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE; // Unset WDT_DURING_BR.\n\tPMC(APBDEV_PMC_SECURE_SCRATCH21) |= PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT;\n}\n\nstatic void _mbist_workaround_bl()\n{\n\t/*\n\t * DFT MBIST HW Errata for T210.\n\t * RAM Data corruption observed when MBIST_EN from DFT (Tegra X1 Si Errata)\n\t *\n\t * The MBIST_EN signals from the DFT logic can impact the functional logic of\n\t * internal rams after power-on since they are driven by non-resetable flops.\n\t * That can be worked around by enabling and then disabling the related clocks.\n\t *\n\t * The bootrom patches, already handle the LVL2 SLCG war by enabling all clocks\n\t * and all LVL2 CLK overrides (power saving disable).\n\t * The Bootloader then handles the IP block SLCG part and also restores the\n\t * state for the clocks/lvl2 slcg.\n\t * After these, per domain MBIST WAR is needed every time a domain gets\n\t * unpowergated if it was previously powergated.\n\t *\n\t * Affected power domains: all except IRAM and CCPLEX.\n\t */\n\n\t// Set mux output to SOR1 clock switch (for VI).\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) & ~BIT(14)) | BIT(15);\n\t// Enable PLLD and set csi to PLLD for test pattern generation (for VI).\n\tCLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= PLL_BASE_ENABLE | BIT(23);\n\n\t// Make sure Audio clocks are enabled before accessing I2S.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET) = BIT(CLK_V_AHUB);\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_Y_SET) = BIT(CLK_Y_APE);\n\n\t// Clear per-clock resets for APE/VIC/HOST1X/DISP1.\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = BIT(CLK_Y_APE);\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_X_CLR) = BIT(CLK_X_VIC);\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_HOST1X) | BIT(CLK_L_DISP1);\n\tusleep(2);\n\n\t// Set I2S to master to enable clocks and set SLCG overrides.\n\tfor (u32 i2s_idx = 0; i2s_idx < 5; i2s_idx++)\n\t{\n\t\tI2S(I2S_CTRL + (i2s_idx << 8u)) |= I2S_CTRL_MASTER_EN;\n\t\tI2S(I2S_CG   + (i2s_idx << 8u))  = I2S_CG_SLCG_DISABLE;\n\t}\n\t// Set SLCG overrides for DISPA and VIC.\n\tDISPLAY_A(DC_COM_DSC_TOP_CTL) |= BIT(2); // DSC_SLCG_OVERRIDE.\n\tVIC(VIC_THI_SLCG_OVERRIDE_LOW_A) = 0xFFFFFFFF;\n\n\t// Wait a bit for MBIST_EN to get unstuck (1 cycle min).\n\tusleep(2);\n\n\t// Reset SLCG to automatic mode.\n\t// for (u32 i2s_idx = 0; i2s_idx < 5; i2s_idx++)\n\t// \tI2S(I2S_CG   + (i2s_idx << 8u)) = I2S_CG_SLCG_ENABLE;\n\t// DISPLAY_A(DC_COM_DSC_TOP_CTL) &= ~BIT(2); // DSC_SLCG_OVERRIDE.\n\t// VIC(VIC_THI_SLCG_OVERRIDE_LOW_A) = 0;\n\n\t// Set per-clock reset for APE/VIC/HOST1X/DISP1.\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = BIT(CLK_Y_APE);\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_HOST1X) | BIT(CLK_L_DISP1);\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = BIT(CLK_X_VIC);\n\n\t// Disable all unneeded clocks that were enabled in bootrom.\n\t// CLK L Devices.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = BIT(CLK_H_PMC) |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_H_FUSE);\n\t// CLK H Devices.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = BIT(CLK_L_RTC)  |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_L_TMR)  |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_L_GPIO) |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_L_BPMP_CACHE_CTRL);\n\t// CLK U Devices.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = BIT(CLK_U_CSITE) |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_U_IRAMA) |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_U_IRAMB) |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_U_IRAMC) |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_U_IRAMD) |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_U_BPMP_CACHE_RAM);\n\t// CLK V Devices.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = BIT(CLK_V_MSELECT)       |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_V_APB2APE)       |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_V_SPDIF_DOUBLER) |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_V_SE);\n\t// CLK W Devices.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = BIT(CLK_W_PCIERX0) |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_W_PCIERX1) |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_W_PCIERX2) |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_W_PCIERX3) |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_W_PCIERX4) |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_W_PCIERX5) |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_W_ENTROPY) |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_W_MC1);\n\t// CLK X Devices.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = BIT(CLK_X_MC_CAPA)  |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_X_MC_CBPA)  |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_X_MC_CPU)   |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_X_MC_BBC)   |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_X_GPU)      |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_X_DBGAPB)   |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_X_PLLG_REF);\n\t// CLK Y Devices.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = BIT(CLK_Y_MC_CDPA) |\n\t\t\t\t\t\t\t\t\t\t\t  BIT(CLK_Y_MC_CCPA);\n\n\t// Reset clock gate overrides to automatic mode.\n\tCLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA) = 0;\n\tCLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB) = 0;\n\tCLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC) = 0;\n\tCLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = 0;\n\tCLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE) = 0;\n\n\t// Set child clock sources.\n\tCLOCK(CLK_RST_CONTROLLER_PLLD_BASE)        &= 0x1F7FFFFF; // Disable PLLD and set reference clock and csi clock.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1)  &= ~(BIT(15) | BIT(14)); // Set SOR1 to automatic muxing of safe clock (24MHz) or SOR1 clk switch.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI)     = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI)     & 0x1FFFFFFF) | (4 << 29u); // Set clock source to PLLP_OUT.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | (4 << 29u); // Set clock source to PLLP_OUT.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC)  = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC)  & 0x1FFFFFFF) | (4 << 29u); // Set clock source to PLLP_OUT.\n}\n\nstatic void _config_se_brom()\n{\n\t// Enable Fuse visibility.\n\tclock_enable_fuse(true);\n\n\t// Try to set SBK from fuses. If patched, skip.\n\tfuse_set_sbk();\n\n\t// Make SBK unreadable.\n\t//FUSE(FUSE_PRIVATEKEYDISABLE) = FUSE_PRIVKEY_TZ_STICKY_BIT | FUSE_PRIVKEY_DISABLE;\n\n\t// Lock SSK (although it's not set and unused anyways).\n\t// se_key_acc_ctrl(15, SE_KEY_TBL_DIS_KEYREAD_FLAG);\n\n\t// This memset needs to happen here, else TZRAM will behave weirdly later on.\n\tmemset((void *)TZRAM_BASE, 0, TZRAM_SIZE);\n\tPMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_ENABLE;\n\n\t// Clear SE interrupts.\n\tSE(SE_INT_STATUS_REG) = SE_INT_OP_DONE | SE_INT_OUT_DONE | SE_INT_OUT_LL_BUF_WR | SE_INT_IN_DONE | SE_INT_IN_LL_BUF_RD;\n\n\t// Save reset reason.\n\thw_rst_status = PMC(APBDEV_PMC_SCRATCH200);\n\thw_rst_reason = PMC(APBDEV_PMC_RST_STATUS) & PMC_RST_STATUS_MASK;\n\n\t// Clear the boot reason to avoid problems later.\n\tPMC(APBDEV_PMC_SCRATCH200) = 0;\n\tPMC(APBDEV_PMC_RST_STATUS) = PMC_RST_STATUS_POR;\n\tAPB_MISC(APB_MISC_PP_STRAPPING_OPT_A) = (APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) & 0xF0) | (7 << 10);\n}\n\nstatic void _config_regulators(bool tegra_t210, bool nx_hoag)\n{\n\t// Set RTC/AO domain to POR voltage.\n\tif (tegra_t210)\n\t\tmax7762x_regulator_set_voltage(REGULATOR_LDO4, 1000000);\n\n\t// Disable low battery shutdown monitor.\n\tmax77620_low_battery_monitor_config(false);\n\n\t// Power on all relevant rails in case we came out of warmboot. Only keep MEM/MEM_COMP and SDMMC1 states.\n\tPMC(APBDEV_PMC_NO_IOPOWER) &= PMC_NO_IOPOWER_MEM_COMP | PMC_NO_IOPOWER_SDMMC1 | PMC_NO_IOPOWER_MEM;\n\n\t// Make sure SDMMC1 IO/Core are powered off.\n\tmax7762x_regulator_enable(REGULATOR_LDO2, false);\n\tgpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_LOW);\n\tPMC(APBDEV_PMC_NO_IOPOWER) |= PMC_NO_IOPOWER_SDMMC1;\n\t(void)PMC(APBDEV_PMC_NO_IOPOWER);\n\tsd_power_cycle_time_start = get_tmr_ms();\n\n\t// Disable backup battery charger.\n\ti2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, MAX77620_CNFGBBC_RESISTOR_1K);\n\n\t// Set PWR delay for forced shutdown off to 6s.\n\ti2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_RSVD | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT));\n\n\tif (tegra_t210)\n\t{\n\t\t// Configure all Flexible Power Sequencers for MAX77620.\n\t\ti2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0, (7 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (0 << MAX77620_FPS_EN_SRC_SHIFT));\n\t\ti2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1, (7 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (1 << MAX77620_FPS_EN_SRC_SHIFT));\n\t\ti2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG2, (7 << MAX77620_FPS_TIME_PERIOD_SHIFT));\n\t\tmax77620_regulator_config_fps(REGULATOR_LDO4);\n\t\tmax77620_regulator_config_fps(REGULATOR_LDO8);\n\t\tmax77620_regulator_config_fps(REGULATOR_SD0);\n\t\tmax77620_regulator_config_fps(REGULATOR_SD1);\n\t\tmax77620_regulator_config_fps(REGULATOR_SD3);\n\n\t\t// Set GPIO3 to FPS0 for SYS 3V3 EN. Enabled when FPS0 is enabled.\n\t\ti2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3, (4 << MAX77620_FPS_PU_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT));\n\n\t\t// Set vdd_core voltage to 1.125V.\n\t\tmax7762x_regulator_set_voltage(REGULATOR_SD0, 1125000);\n\n\t\t// Power down CPU/GPU regulators after L4T warmboot.\n\t\tmax77620_config_gpio(5, MAX77620_GPIO_OUTPUT_DISABLE);\n\t\tmax77620_config_gpio(6, MAX77620_GPIO_OUTPUT_DISABLE);\n\n\t\t// Set POR configuration.\n\t\tmax77621_config_default(REGULATOR_CPU0, MAX77621_CTRL_POR_CFG);\n\t\tmax77621_config_default(REGULATOR_GPU0, MAX77621_CTRL_POR_CFG);\n\t}\n\telse\n\t{\n\t\t// Tegra X1+ set vdd_core voltage to 1.05V.\n\t\tmax7762x_regulator_set_voltage(REGULATOR_SD0, 1050000);\n\n\t\t// Power on SD2 regulator for supplying LDO0/1/8.\n\t\tmax7762x_regulator_set_voltage(REGULATOR_SD2, 1325000);\n\n\t\t// Set slew rate and enable SD2 regulator.\n\t\ti2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD2_CFG, (1 << MAX77620_SD_SR_SHIFT)                                  |\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  (MAX77620_POWER_MODE_NORMAL << MAX77620_SD_POWER_MODE_SHIFT) |\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  MAX77620_SD_CFG1_FSRADE_SD_ENABLE);\n\n\t\t// Enable LDO8 on HOAG as it also powers I2C1 IO pads.\n\t\tif (nx_hoag)\n\t\t{\n\t\t\tmax7762x_regulator_set_voltage(REGULATOR_LDO8, 2800000);\n\t\t\tmax7762x_regulator_enable(REGULATOR_LDO8, true);\n\t\t}\n\t}\n}\n\nvoid hw_init()\n{\n\t// Get Chip ID and SKU.\n\tbool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210;\n\tbool nx_hoag = fuse_read_hw_type() == FUSE_NX_HW_TYPE_HOAG;\n\n\t// Bootrom stuff we might skipped by going through rcm.\n\t_config_se_brom();\n\n\t// Unset APB2JTAG_OVERRIDE_EN and OBS_OVERRIDE_EN.\n\tSYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F;\n\tPMC(APBDEV_PMC_SCRATCH49) &= 0xFFFFFFFC;\n\n\t// Perform the bootloader part of the Memory Built-In Self Test WAR if T210.\n\tif (tegra_t210)\n\t\t_mbist_workaround_bl();\n\n\t// Make sure PLLP_OUT3/4 is set to 408 MHz and enabled.\n\tCLOCK(CLK_RST_CONTROLLER_PLLP_OUTB) = 0x30003;\n\n\t// Enable Security Engine clock.\n\tclock_enable_se();\n\n\t// Enable Fuse visibility.\n\tclock_enable_fuse(true);\n\n\t// Disable Fuse programming.\n\tfuse_disable_program();\n\n\t// Enable clocks to Memory controllers and disable AHB redirect.\n\tmc_enable();\n\n\t// Initialize counters, CLKM, BPMP and other clocks based on 38.4MHz oscillator.\n\t_config_oscillators();\n\n\t// Initialize pin configuration.\n\t_config_gpios(nx_hoag);\n\n\t// Enable CL-DVFS clock unconditionally to avoid issues with I2C5 sharing.\n\tclock_enable_cl_dvfs();\n\n\t// Enable clocks to I2C1 and I2CPWR.\n\tclock_enable_i2c(I2C_1);\n\tclock_enable_i2c(I2C_5);\n\n\t// Enable clock to TZRAM.\n\tclock_enable_tzram();\n\n\t// Initialize I2C5, mandatory for PMIC.\n\ti2c_init(I2C_5);\n\n\t// Initialize various regulators based on Erista/Mariko platform.\n\t_config_regulators(tegra_t210, nx_hoag);\n\n\t// Initialize I2C1 for various power related devices.\n\ti2c_init(I2C_1);\n\n\t_config_pmc_scratch(); // Missing from 4.x+\n\n\t// Set BPMP/SCLK to PLLP_OUT (408MHz).\n\tCLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333;\n\n\t// Disable T210B01 TZRAM power-gating and lock the reg.\n\tif (!tegra_t210)\n\t{\n\t\t// This is not actually needed since it's done by bootrom. The read locks are extra.\n\t\tPMC(APBDEV_PMC_TZRAM_PWR_CNTRL_B01)      &= ~PMC_TZRAM_PWR_CNTRL_SD;\n\t\tPMC(APBDEV_PMC_TZRAM_NON_SEC_DISABLE_B01) = PMC_TZRAM_DISABLE_REG_WRITE | PMC_TZRAM_DISABLE_REG_READ;\n\t\tPMC(APBDEV_PMC_TZRAM_SEC_DISABLE_B01)     = PMC_TZRAM_DISABLE_REG_WRITE | PMC_TZRAM_DISABLE_REG_READ;\n\t}\n\n\t// Set arbiter.\n\thw_config_arbiter(false);\n\n\t// Initialize External memory controller and configure DRAM parameters.\n\tsdram_init();\n\n\tbpmp_mmu_enable();\n\n\t// Enable HOST1X used by every display module (DC, VIC, NVDEC, NVENC, TSEC, etc).\n\tclock_enable_host1x();\n\n#ifdef DEBUG_UART_PORT\n\t// Setup debug uart port.\n\t#if   (DEBUG_UART_PORT == UART_B)\n\t\tgpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);\n\t#elif (DEBUG_UART_PORT == UART_C)\n\t\tgpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);\n\t#endif\n\tpinmux_config_uart(DEBUG_UART_PORT);\n\tclock_enable_uart(DEBUG_UART_PORT);\n\tuart_init(DEBUG_UART_PORT, DEBUG_UART_BAUDRATE, UART_AO_TX_AO_RX);\n\tuart_invert(DEBUG_UART_PORT, DEBUG_UART_INVERT, UART_INVERT_TXD);\n#endif\n}\n\nvoid hw_deinit(bool keep_display)\n{\n\t// Seamless display or display power off.\n\tif (!keep_display)\n\t{\n\t\tdisplay_end();\n\t\tclock_disable_host1x();\n\t}\n\n\t// Scale down BPMP clock.\n\tbpmp_clk_rate_set(BPMP_CLK_NORMAL);\n\n#ifdef BDK_HW_EXTRA_DEINIT\n\t// Disable temperature sensor, touchscreen, 5V regulators, Joy-Con and VIC.\n\tvic_end();\n\ttmp451_end();\n\tfan_set_duty(0);\n\ttouch_power_off();\n\tjc_deinit();\n\tregulator_5v_disable(REGULATOR_5V_ALL);\n#endif\n\n\t// Set DRAM clock to 204MHz.\n\tminerva_deinit();\n\n\t// Flush/disable MMU cache.\n\tbpmp_mmu_disable();\n\n\t// Reset arbiter.\n\thw_config_arbiter(true);\n\n\t// Re-enable clocks to Audio Processing Engine as a workaround to rerunning mbist war.\n\tif (hw_get_chip_id() == GP_HIDREV_MAJOR_T210)\n\t{\n\t\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET) = BIT(CLK_V_AHUB);\n\t\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_Y_SET) = BIT(CLK_Y_APE);\n\t}\n}\n"
  },
  {
    "path": "bdk/soc/hw_init.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _HW_INIT_H_\n#define _HW_INIT_H_\n\n#include <utils/types.h>\n\nextern u32 hw_rst_status;\nextern u32 hw_rst_reason;\n\nvoid hw_init();\nvoid hw_deinit(bool keep_display);\nvoid hw_config_arbiter(bool reset);\nu32  hw_get_chip_id();\n\n#endif\n"
  },
  {
    "path": "bdk/soc/i2c.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <soc/i2c.h>\n#include <soc/t210.h>\n#include <soc/timer.h>\n\n#define I2C_PACKET_PROT_I2C  BIT(4)\n#define I2C_HEADER_CONT_XFER BIT(15)\n#define I2C_HEADER_REP_START BIT(16)\n#define I2C_HEADER_IE_ENABLE BIT(17)\n#define I2C_HEADER_READ      BIT(19)\n\n#define I2C_CNFG              (0x00 / 4)\n#define  CMD1_WRITE           (0 << 6)\n#define  CMD1_READ            BIT(6)\n#define  NORMAL_MODE_GO       BIT(9)\n#define  PACKET_MODE_GO       BIT(10)\n#define  NEW_MASTER_FSM       BIT(11)\n#define  DEBOUNCE_CNT_4T      (2 << 12)\n\n#define I2C_CMD_ADDR0         (0x04 / 4)\n#define  ADDR0_WRITE          0\n#define  ADDR0_READ           1\n\n#define I2C_CMD_DATA1         (0x0C / 4)\n#define I2C_CMD_DATA2         (0x10 / 4)\n\n#define I2C_STATUS            (0x1C / 4)\n#define  I2C_STATUS_NOACK     (0xF << 0)\n#define  I2C_STATUS_BUSY      BIT(8)\n\n#define I2C_TX_FIFO           (0x50 / 4)\n#define I2C_RX_FIFO           (0x54 / 4)\n\n#define I2C_PACKET_TRANSFER_STATUS (0x58 / 4)\n#define  PKT_TRANSFER_COMPLETE BIT(24)\n\n#define I2C_FIFO_CONTROL      (0x5C / 4)\n#define  RX_FIFO_FLUSH        BIT(0)\n#define  TX_FIFO_FLUSH        BIT(1)\n\n#define I2C_FIFO_STATUS       (0x60 / 4)\n#define  RX_FIFO_FULL_CNT     (0xF << 0)\n#define  TX_FIFO_EMPTY_CNT    (0xF << 4)\n\n#define I2C_INT_EN            (0x64 / 4)\n#define I2C_INT_STATUS        (0x68 / 4)\n#define I2C_INT_SOURCE        (0x70 / 4)\n#define  RX_FIFO_DATA_REQ     BIT(0)\n#define  TX_FIFO_DATA_REQ     BIT(1)\n#define  ARB_LOST             BIT(2)\n#define  NO_ACK               BIT(3)\n#define  RX_FIFO_UNDER        BIT(4)\n#define  TX_FIFO_OVER         BIT(5)\n#define  ALL_PACKETS_COMPLETE BIT(6)\n#define  PACKET_COMPLETE      BIT(7)\n#define  BUS_CLEAR_DONE       BIT(11)\n\n#define I2C_CLK_DIVISOR       (0x6C / 4)\n\n#define I2C_BUS_CLEAR_CONFIG  (0x84 / 4)\n#define  BC_ENABLE            BIT(0)\n#define  BC_TERMINATE         BIT(1)\n\n#define I2C_BUS_CLEAR_STATUS  (0x88 / 4)\n\n#define I2C_CONFIG_LOAD       (0x8C / 4)\n#define  MSTR_CONFIG_LOAD     BIT(0)\n#define  TIMEOUT_CONFIG_LOAD  BIT(2)\n\n/* I2C_1, 2, 3, 4, 5 and 6. */\nstatic const u16 _i2c_base_offsets[6] = { 0x0, 0x400, 0x500, 0x700, 0x1000, 0x1100 };\n\nstatic void _i2c_load_cfg_wait(vu32 *base)\n{\n\tbase[I2C_CONFIG_LOAD] = BIT(5) | TIMEOUT_CONFIG_LOAD | MSTR_CONFIG_LOAD;\n\tfor (u32 i = 0; i < 20; i++)\n\t{\n\t\tif (!(base[I2C_CONFIG_LOAD] & MSTR_CONFIG_LOAD))\n\t\t\tbreak;\n\t\tusleep(1);\n\t}\n}\n\nstatic int _i2c_send_normal(u32 i2c_idx, u32 dev_addr, const u8 *buf, u32 size)\n{\n\tif (size > 8)\n\t\treturn 1;\n\n\tu32 tmp = 0;\n\n\tvu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]);\n\n\t// Set device address and send mode.\n\tbase[I2C_CMD_ADDR0] = dev_addr << 1 | ADDR0_WRITE;\n\n\tif (size > 4)\n\t{\n\t\tmemcpy(&tmp, buf, 4);\n\t\tbase[I2C_CMD_DATA1] = tmp; //Set value.\n\t\ttmp = 0;\n\t\tmemcpy(&tmp, buf + 4, size - 4);\n\t\tbase[I2C_CMD_DATA2] = tmp;\n\t}\n\telse\n\t{\n\t\tmemcpy(&tmp, buf, size);\n\t\tbase[I2C_CMD_DATA1] = tmp; //Set value.\n\t}\n\n\t// Set size and send mode.\n\tbase[I2C_CNFG] = ((size - 1) << 1) | DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_WRITE;\n\n\t// Load configuration.\n\t_i2c_load_cfg_wait(base);\n\n\t// Initiate transaction on normal mode.\n\tbase[I2C_CNFG] = (base[I2C_CNFG] & ~NORMAL_MODE_GO) | NORMAL_MODE_GO;\n\n\tu32 timeout = get_tmr_ms() + 100; // Actual for max 8 bytes at 100KHz is 0.74ms.\n\twhile (base[I2C_STATUS] & I2C_STATUS_BUSY)\n\t{\n\t\tif (get_tmr_ms() > timeout)\n\t\t\treturn 1;\n\t}\n\n\tif (base[I2C_STATUS] & I2C_STATUS_NOACK)\n\t\treturn 1;\n\n\treturn 0;\n}\n\nstatic int _i2c_recv_normal(u32 i2c_idx, u8 *buf, u32 size, u32 dev_addr)\n{\n\tif (size > 8)\n\t\treturn 1;\n\n\tvu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]);\n\n\t// Set device address and recv mode.\n\tbase[I2C_CMD_ADDR0] = (dev_addr << 1) | ADDR0_READ;\n\n\t// Set size and recv mode.\n\tbase[I2C_CNFG] = ((size - 1) << 1) | DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_READ;\n\n\t// Load configuration.\n\t_i2c_load_cfg_wait(base);\n\n\t// Initiate transaction on normal mode.\n\tbase[I2C_CNFG] = (base[I2C_CNFG] & ~NORMAL_MODE_GO) | NORMAL_MODE_GO;\n\n\tu32 timeout = get_tmr_ms() + 100; // Actual for max 8 bytes at 100KHz is 0.74ms.\n\twhile (base[I2C_STATUS] & I2C_STATUS_BUSY)\n\t{\n\t\tif (get_tmr_ms() > timeout)\n\t\t\treturn 1;\n\t}\n\n\tif (base[I2C_STATUS] & I2C_STATUS_NOACK)\n\t\treturn 1;\n\n\tu32 tmp = base[I2C_CMD_DATA1]; // Get LS value.\n\tif (size > 4)\n\t{\n\t\tmemcpy(buf, &tmp, 4);\n\t\ttmp = base[I2C_CMD_DATA2]; // Get MS value.\n\t\tmemcpy(buf + 4, &tmp, size - 4);\n\t}\n\telse\n\t\tmemcpy(buf, &tmp, size);\n\n\treturn 0;\n}\n\nstatic int _i2c_send_packet(u32 i2c_idx, const u8 *buf, u32 size, u32 dev_addr)\n{\n\tif (size > 32)\n\t\treturn 1;\n\n\tint res = 0;\n\n\tvu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]);\n\n\t// Set device address and send mode.\n\tbase[I2C_CMD_ADDR0] = (dev_addr << 1) | ADDR0_WRITE;\n\n\t// Set recv mode.\n\tbase[I2C_CNFG] = DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_WRITE;\n\n\t// Set and flush FIFO.\n\tbase[I2C_FIFO_CONTROL] = RX_FIFO_FLUSH | TX_FIFO_FLUSH;\n\n\t// Load configuration.\n\t_i2c_load_cfg_wait(base);\n\n\t// Initiate transaction on packet mode.\n\tbase[I2C_CNFG] = (base[I2C_CNFG] & ~NORMAL_MODE_GO) | PACKET_MODE_GO;\n\n\t// Send header with request.\n\tbase[I2C_TX_FIFO] = I2C_PACKET_PROT_I2C;\n\tbase[I2C_TX_FIFO] = size - 1;\n\tbase[I2C_TX_FIFO] = I2C_HEADER_IE_ENABLE | I2C_HEADER_CONT_XFER | (dev_addr << 1);\n\n\t// Send data.\n\tu32 rem = size;\n\twhile (rem)\n\t{\n\t\tu32 len = MIN(rem, sizeof(u32));\n\t\tu32 word = 0;\n\t\tmemcpy(&word, buf, len);\n\t\tbase[I2C_TX_FIFO] = word;\n\t\tbuf += len;\n\t\trem -= len;\n\t}\n\n\tu32 timeout = get_tmr_ms() + 200;\n\twhile (((base[I2C_PACKET_TRANSFER_STATUS] >> 4) & 0xFFF) != (size - 1))\n\t{\n\t\tif (get_tmr_ms() > timeout)\n\t\t{\n\t\t\tres = 1;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Check if no reply.\n\tif (base[I2C_STATUS] & I2C_STATUS_NOACK)\n\t\tres = 1;\n\n\t// Wait for STOP and disable packet mode.\n\tusleep(20);\n\tbase[I2C_CNFG] &= ~(PACKET_MODE_GO | NORMAL_MODE_GO);\n\n\treturn res;\n}\n\nint i2c_xfer_packet(u32 i2c_idx, u32 dev_addr, const u8 *tx_buf, u32 tx_size, u8 *rx_buf, u32 rx_size)\n{\n\t// Max 32 bytes TX/RX fifo.\n\tif (tx_size > 20 || rx_size > 32) // Header included.\n\t\treturn 1;\n\n\tint res = 0;\n\n\tvu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]);\n\n\t// Set device address and recv mode.\n\tbase[I2C_CMD_ADDR0] = (dev_addr << 1) | ADDR0_READ;\n\n\t// Set recv mode.\n\tbase[I2C_CNFG] = DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_READ;\n\n\t// Set and flush FIFO.\n\tbase[I2C_FIFO_CONTROL] = RX_FIFO_FLUSH | TX_FIFO_FLUSH;\n\n\t// Load configuration.\n\t_i2c_load_cfg_wait(base);\n\n\t// Initiate transaction on packet mode.\n\tbase[I2C_CNFG] = (base[I2C_CNFG] & ~NORMAL_MODE_GO) | PACKET_MODE_GO;\n\n\t// Send header with send request.\n\tbase[I2C_TX_FIFO] = I2C_PACKET_PROT_I2C;\n\tbase[I2C_TX_FIFO] = tx_size - 1;\n\tbase[I2C_TX_FIFO] = I2C_HEADER_REP_START | (dev_addr << 1);\n\n\t// Send data.\n\tu32 tx_rem = tx_size;\n\twhile (tx_rem)\n\t{\n\t\tu32 len = MIN(tx_rem, sizeof(u32));\n\t\tu32 word = 0;\n\t\tmemcpy(&word, tx_buf, len);\n\t\tbase[I2C_TX_FIFO] = word;\n\t\ttx_buf += len;\n\t\ttx_rem -= len;\n\t}\n\n\tu32 timeout = get_tmr_ms() + 200;\n\twhile (((base[I2C_PACKET_TRANSFER_STATUS] >> 4) & 0xFFF) != (tx_size - 1))\n\t{\n\t\tif (get_tmr_ms() > timeout)\n\t\t{\n\t\t\tres = 1;\n\t\t\tgoto out;\n\t\t}\n\t}\n\n\t// Send header with receive request\n\tbase[I2C_TX_FIFO] = I2C_PACKET_PROT_I2C;\n\tbase[I2C_TX_FIFO] = rx_size - 1;\n\tbase[I2C_TX_FIFO] = I2C_HEADER_READ | (dev_addr << 1);\n\n\t// Receive data.\n\ttimeout = get_tmr_ms() + 200;\n\twhile (rx_size)\n\t{\n\t\tif (base[I2C_FIFO_STATUS] & RX_FIFO_FULL_CNT)\n\t\t{\n\t\t\tu32 len = MIN(rx_size, sizeof(u32));\n\t\t\tu32 word = base[I2C_RX_FIFO];\n\t\t\tmemcpy(rx_buf, &word, len);\n\t\t\trx_buf  += len;\n\t\t\trx_size -= len;\n\t\t}\n\n\t\tif (get_tmr_ms() > timeout)\n\t\t{\n\t\t\tres = 1;\n\t\t\tbreak;\n\t\t}\n\t}\n\nout:\n\t// Check if no reply.\n\tif (base[I2C_STATUS] & I2C_STATUS_NOACK)\n\t\tres = 1;\n\n\t// Wait for STOP and disable packet mode.\n\tusleep(20);\n\tbase[I2C_CNFG] &= ~(PACKET_MODE_GO | NORMAL_MODE_GO);\n\n\treturn res;\n}\n\nvoid i2c_init(u32 i2c_idx)\n{\n\tvu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]);\n\n\tbase[I2C_CLK_DIVISOR] = (5 << 16) | 1; // SF mode Div: 6, HS mode div: 2.\n\tbase[I2C_BUS_CLEAR_CONFIG] = (9 << 16) | BC_TERMINATE | BC_ENABLE;\n\n\t// Load configuration.\n\t_i2c_load_cfg_wait(base);\n\n\tfor (u32 i = 0; i < 10; i++)\n\t{\n\t\tif (base[I2C_INT_STATUS] & BUS_CLEAR_DONE)\n\t\t\tbreak;\n\t\tusleep(25);\n\t}\n\n\t(vu32)base[I2C_BUS_CLEAR_STATUS];\n\tbase[I2C_INT_STATUS] = base[I2C_INT_STATUS];\n}\n\nint i2c_send_buf_big(u32 i2c_idx, u32 dev_addr, const u8 *buf, u32 size)\n{\n\treturn _i2c_send_packet(i2c_idx, buf, size, dev_addr);\n}\n\nint i2c_recv_buf_big(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg)\n{\n\treturn i2c_xfer_packet(i2c_idx, dev_addr, (u8 *)&reg, 1, buf, size);\n}\n\nint i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, const u8 *buf, u32 size)\n{\n\tif (size > 7)\n\t\treturn 1;\n\n\tu8 tmp[8];\n\ttmp[0] = reg;\n\tmemcpy(tmp + 1, buf, size);\n\n\treturn _i2c_send_normal(i2c_idx, dev_addr, tmp, size + 1);\n}\n\nint i2c_recv_buf_small(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg)\n{\n\tint res = _i2c_send_normal(i2c_idx, dev_addr, (u8 *)&reg, 1);\n\tif (!res)\n\t\tres = _i2c_recv_normal(i2c_idx, buf, size, dev_addr);\n\treturn res;\n}\n\nint i2c_send_byte(u32 i2c_idx, u32 dev_addr, u32 reg, u8 val)\n{\n\treturn i2c_send_buf_small(i2c_idx, dev_addr, reg, &val, 1);\n}\n\nu8 i2c_recv_byte(u32 i2c_idx, u32 dev_addr, u32 reg)\n{\n\tu8 tmp = 0;\n\ti2c_recv_buf_small(&tmp, 1, i2c_idx, dev_addr, reg);\n\treturn tmp;\n}\n\n"
  },
  {
    "path": "bdk/soc/i2c.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2020-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _I2C_H_\n#define _I2C_H_\n\n#include <utils/types.h>\n\n#define I2C_1 0\n#define I2C_2 1\n#define I2C_3 2\n#define I2C_4 3\n#define I2C_5 4\n#define I2C_6 5\n\nvoid i2c_init(u32 i2c_idx);\nint i2c_xfer_packet(u32 i2c_idx, u32 dev_addr, const u8 *tx_buf, u32 tx_size, u8 *rx_buf, u32 rx_size);\nint i2c_send_buf_big(u32 i2c_idx, u32 dev_addr, const u8 *buf, u32 size);\nint i2c_recv_buf_big(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg);\nint i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, const u8 *buf, u32 size);\nint i2c_recv_buf_small(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg);\nint i2c_send_byte(u32 i2c_idx, u32 dev_addr, u32 reg, u8 val);\nu8  i2c_recv_byte(u32 i2c_idx, u32 dev_addr, u32 reg);\n\n#endif\n"
  },
  {
    "path": "bdk/soc/irq.c",
    "content": "/*\n * BPMP-Lite IRQ driver for Tegra X1\n *\n * Copyright (c) 2019-2024 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include \"irq.h\"\n#include <soc/timer.h>\n#include <soc/t210.h>\n#include <gfx_utils.h>\n#include <mem/heap.h>\n\n//#define DPRINTF(...) gfx_printf(__VA_ARGS__)\n#define DPRINTF(...)\n\nextern void excp_reset();\nextern void irq_disable();\nextern void irq_enable_cpu_irq_exceptions();\nextern void irq_disable_cpu_irq_exceptions();\n\ntypedef struct _irq_ctxt_t\n{\n\tu32  irq;\n\tint  (*handler)(u32 irq, void *data);\n\tvoid *data;\n\tu32  flags;\n} irq_ctxt_t;\n\nbool irq_init_done = false;\nirq_ctxt_t irqs[IRQ_MAX_HANDLERS];\n\nstatic void _irq_enable_source(u32 irq)\n{\n\tu32 ctrl_idx = irq >> 5;\n\tu32 bit = irq % 32;\n\n\t// Set as normal IRQ.\n\tICTLR(ctrl_idx, PRI_ICTLR_COP_IEP_CLASS) &= ~BIT(bit);\n\n\t// Enable IRQ source.\n\tICTLR(ctrl_idx, PRI_ICTLR_COP_IER_SET) = BIT(bit);\n}\n\nstatic void _irq_disable_source(u32 irq)\n{\n\tu32 ctrl_idx = irq >> 5;\n\tu32 bit = irq % 32;\n\n\t// Disable IRQ source.\n\tICTLR(ctrl_idx, PRI_ICTLR_COP_IER_CLR) = BIT(bit);\n}\n\nstatic void _irq_disable_and_ack_all()\n{\n\t// Disable and ack all IRQ sources.\n\tfor (u32 ctrl_idx = 0; ctrl_idx < 6; ctrl_idx++)\n\t{\n\t\tu32 enabled_irqs = ICTLR(ctrl_idx, PRI_ICTLR_COP_IER);\n\t\tICTLR(ctrl_idx, PRI_ICTLR_COP_IER_CLR) = enabled_irqs;\n\t}\n}\n\nvoid irq_free(u32 irq)\n{\n\tfor (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++)\n\t{\n\t\tif (irqs[idx].irq == irq && irqs[idx].handler)\n\t\t{\n\t\t\tirqs[idx].irq     = 0;\n\t\t\tirqs[idx].handler = NULL;\n\t\t\tirqs[idx].data    = NULL;\n\t\t\tirqs[idx].flags   = 0;\n\n\t\t\t_irq_disable_source(irq);\n\t\t}\n\t}\n}\n\nstatic void _irq_free_all()\n{\n\tfor (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++)\n\t{\n\t\tif (irqs[idx].handler)\n\t\t{\n\t\t\t_irq_disable_source(irqs[idx].irq);\n\n\t\t\tirqs[idx].irq     = 0;\n\t\t\tirqs[idx].handler = NULL;\n\t\t\tirqs[idx].data    = NULL;\n\t\t\tirqs[idx].flags   = 0;\n\t\t}\n\t}\n}\n\nstatic irq_status_t _irq_handle_source(u32 irq)\n{\n\tint status = IRQ_NONE;\n\n\t_irq_disable_source(irq);\n\n\tu32 idx;\n\tfor (idx = 0; idx < IRQ_MAX_HANDLERS; idx++)\n\t{\n\t\tif (irqs[idx].irq == irq)\n\t\t{\n\t\t\tstatus = irqs[idx].handler(irqs[idx].irq, irqs[idx].data);\n\n\t\t\tif (status == IRQ_HANDLED)\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Do not re-enable if not handled or error.\n\tif (status != IRQ_HANDLED)\n\t\treturn status;\n\n\tif (irqs[idx].flags & IRQ_FLAG_ONE_OFF)\n\t\tirq_free(irq);\n\telse\n\t\t_irq_enable_source(irq);\n\n\treturn status;\n}\n\nvoid irq_handler()\n{\n\t// Get IRQ source.\n\tu32 irq = EXCP_VEC(EVP_COP_IRQ_STS) & 0xFF;\n\n\tif (!irq_init_done)\n\t{\n\t\t_irq_disable_source(irq);\n\n\t\treturn;\n\t}\n\n\tDPRINTF(\"IRQ: %d\\n\", irq);\n\n\tint err = _irq_handle_source(irq);\n\n\tif (err == IRQ_NONE)\n\t{\n\t\tDPRINTF(\"Unhandled IRQ got disabled: %d!\\n\", irq);\n\t}\n}\n\nstatic void _irq_init()\n{\n\t_irq_disable_and_ack_all();\n\tmemset(irqs, 0, sizeof(irq_ctxt_t) * IRQ_MAX_HANDLERS);\n\tirq_init_done = true;\n}\n\nvoid irq_end()\n{\n\tif (!irq_init_done)\n\t\treturn;\n\n\t_irq_free_all();\n\tirq_disable_cpu_irq_exceptions();\n\tirq_init_done = false;\n}\n\nvoid irq_wait_event(u32 irq)\n{\n\tirq_disable_cpu_irq_exceptions();\n\n\t_irq_enable_source(irq);\n\n\t// Halt BPMP and wait for the IRQ. No need to use WAIT_EVENT + LIC_IRQ when BPMP serves the IRQ.\n\tFLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_MODE_STOP_UNTIL_IRQ;\n\n\t_irq_disable_source(irq);\n\n\tirq_enable_cpu_irq_exceptions();\n}\n\nvoid irq_disable_wait_event()\n{\n\tirq_enable_cpu_irq_exceptions();\n}\n\nirq_status_t irq_request(u32 irq, irq_handler_t handler, void *data, irq_flags_t flags)\n{\n\tif (!irq_init_done)\n\t\t_irq_init();\n\n\tfor (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++)\n\t{\n\t\tif (irqs[idx].handler == NULL ||\n\t\t\t(irqs[idx].irq == irq && irqs[idx].flags & IRQ_FLAG_REPLACEABLE))\n\t\t{\n\t\t\tDPRINTF(\"Registered handler, IRQ: %d, Slot: %d\\n\", irq, idx);\n\t\t\tDPRINTF(\"Handler: %08p, Flags: %x\\n\", (u32)handler, flags);\n\n\t\t\tirqs[idx].irq     = irq;\n\t\t\tirqs[idx].handler = handler;\n\t\t\tirqs[idx].data    = data;\n\t\t\tirqs[idx].flags   = flags;\n\n\t\t\t_irq_enable_source(irq);\n\n\t\t\treturn IRQ_ENABLED;\n\t\t}\n\t\telse if (irqs[idx].irq == irq)\n\t\t\treturn IRQ_ALREADY_REGISTERED;\n\t}\n\n\treturn IRQ_NO_SLOTS_AVAILABLE;\n}\n\nvoid __attribute__ ((target(\"arm\"))) fiq_setup()\n{\n/*\n\tasm volatile(\"mrs r12, cpsr\\n\\t\"\n\t\t\"bic r12, r12, #0x1F\\n\\t\"\n\t\t\"orr r12, r12, #0x11\\n\\t\"\n\t\t\"msr cpsr_c, r12\\n\\t\");\n\n\tregister volatile char *text asm (\"r8\");\n\tregister volatile char *uart_tx asm (\"r9\");\n\tregister int len asm (\"r10\");\n\n\tlen = 5;\n\tuart_tx = (char *)0x70006040;\n\tmemcpy((char *)text, \"FIQ\\r\\n\", len);\n\t*uart_tx = 0;\n\n\tasm volatile(\"mrs r12, cpsr\\n\"\n\t\t\"orr r12, r12, #0x1F\\n\"\n\t\t\"msr cpsr_c, r12\");\n*/\n}\n\nvoid  __attribute__ ((target(\"arm\"), interrupt (\"FIQ\"))) fiq_handler()\n{\n/*\n\tregister volatile char *text asm (\"r8\");\n\tregister volatile char *uart_tx asm (\"r9\");\n\tregister int len asm (\"r10\");\n\n\twhile (len)\n\t{\n\t\t*uart_tx = *text++;\n\t\tlen--;\n\t}\n*/\n#ifdef BDK_WATCHDOG_FIQ_ENABLE\n\t// Set watchdog timeout status and disable WDT and its FIQ signal.\n\twatchdog_handle();\n\n#ifdef BDK_RESTART_BL_ON_WDT\n\t// Restart bootloader.\n\texcp_reset();\n#endif\n\n#endif\n}\n"
  },
  {
    "path": "bdk/soc/irq.h",
    "content": "/*\n * BPMP-Lite IRQ driver for Tegra X1\n *\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef IRQ_H\n#define IRQ_H\n\n#include <utils/types.h>\n\n#define IRQ_MAX_HANDLERS 16\n\n/* Primary interrupt controller ids */\n#define IRQ_TMR1 0\n#define IRQ_TMR2 1\n#define IRQ_RTC 2\n#define IRQ_CEC 3\n#define IRQ_SHR_SEM_INBOX_FULL 4\n#define IRQ_SHR_SEM_INBOX_EMPTY 5\n#define IRQ_SHR_SEM_OUTBOX_FULL 6\n#define IRQ_SHR_SEM_OUTBOX_EMPTY 7\n#define IRQ_NVJPEG 8\n#define IRQ_NVDEC 9\n#define IRQ_QUAD_SPI 10\n#define IRQ_DPAUX_INT1 11\n#define IRQ_SATA_RX_STAT 13\n#define IRQ_SDMMC1 14\n#define IRQ_SDMMC2 15\n#define IRQ_VGPIO_INT 16\n#define IRQ_VII2C_INT 17\n#define IRQ_SDMMC3 19\n#define IRQ_USB 20\n#define IRQ_USB2 21\n#define IRQ_SATA_CTL 23\n#define IRQ_PMC_INT 24\n#define IRQ_FC_INT 25\n#define IRQ_APB_DMA_CPU 26\n#define IRQ_ARB_SEM_GNT_COP 28\n#define IRQ_ARB_SEM_GNT_CPU 29\n#define IRQ_SDMMC4 31\n\n/* Secondary interrupt controller ids */\n#define IRQ_GPIO1 32\n#define IRQ_GPIO2 33\n#define IRQ_GPIO3 34\n#define IRQ_GPIO4 35\n#define IRQ_UARTA 36\n#define IRQ_UARTB 37\n#define IRQ_I2C 38\n#define IRQ_USB3_HOST_INT 39\n#define IRQ_USB3_HOST_SMI 40\n#define IRQ_TMR3 41\n#define IRQ_TMR4 42\n#define IRQ_USB3_HOST_PME 43\n#define IRQ_USB3_DEV_HOST 44\n#define IRQ_ACTMON 45\n#define IRQ_UARTC 46\n#define IRQ_THERMAL 48\n#define IRQ_XUSB_PADCTL 49\n#define IRQ_TSEC 50\n#define IRQ_EDP 51\n#define IRQ_I2C5 53\n#define IRQ_GPIO5 55\n#define IRQ_USB3_DEV_SMI 56\n#define IRQ_USB3_DEV_PME 57\n#define IRQ_SE 58\n#define IRQ_SPI1 59\n#define IRQ_APB_DMA_COP 60\n#define IRQ_CLDVFS 62\n#define IRQ_I2C6 63\n\n/* Tertiary interrupt controller ids */\n#define IRQ_HOST1X_SYNCPT_COP 64\n#define IRQ_HOST1X_SYNCPT_CPU 65\n#define IRQ_HOST1X_GEN_COP 66\n#define IRQ_HOST1X_GEN_CPU 67\n#define IRQ_NVENC 68\n#define IRQ_VI 69\n#define IRQ_ISPB 70\n#define IRQ_ISP 71\n#define IRQ_VIC 72\n#define IRQ_DISPLAY 73\n#define IRQ_DISPLAYB 74\n#define IRQ_SOR1 75\n#define IRQ_SOR 76\n#define IRQ_MC 77\n#define IRQ_EMC 78\n#define IRQ_TSECB 80\n#define IRQ_HDA 81\n#define IRQ_SPI2 82\n#define IRQ_SPI3 83\n#define IRQ_I2C2 84\n#define IRQ_PMU_EXT 86\n#define IRQ_GPIO6 87\n#define IRQ_GPIO7 89\n#define IRQ_UARTD 90\n#define IRQ_I2C3 92\n#define IRQ_SPI4 93\n\n/* Quaternary interrupt controller ids */\n#define IRQ_DTV 96\n#define IRQ_PCIE_INT 98\n#define IRQ_PCIE_MSI 99\n#define IRQ_AVP_CACHE 101\n#define IRQ_APE_INT1 102\n#define IRQ_APE_INT0 103\n#define IRQ_APB_DMA_CH0 104\n#define IRQ_APB_DMA_CH1 105\n#define IRQ_APB_DMA_CH2 106\n#define IRQ_APB_DMA_CH3 107\n#define IRQ_APB_DMA_CH4 108\n#define IRQ_APB_DMA_CH5 109\n#define IRQ_APB_DMA_CH6 110\n#define IRQ_APB_DMA_CH7 111\n#define IRQ_APB_DMA_CH8 112\n#define IRQ_APB_DMA_CH9 113\n#define IRQ_APB_DMA_CH10 114\n#define IRQ_APB_DMA_CH11 115\n#define IRQ_APB_DMA_CH12 116\n#define IRQ_APB_DMA_CH13 117\n#define IRQ_APB_DMA_CH14 118\n#define IRQ_APB_DMA_CH15 119\n#define IRQ_I2C4 120\n#define IRQ_TMR5 121\n#define IRQ_WDT_CPU 123\n#define IRQ_WDT_AVP 124\n#define IRQ_GPIO8 125\n#define IRQ_CAR 126\n\n/* Quinary interrupt controller ids */\n#define IRQ_APB_DMA_CH16 128\n#define IRQ_APB_DMA_CH17 129\n#define IRQ_APB_DMA_CH18 130\n#define IRQ_APB_DMA_CH19 131\n#define IRQ_APB_DMA_CH20 132\n#define IRQ_APB_DMA_CH21 133\n#define IRQ_APB_DMA_CH22 134\n#define IRQ_APB_DMA_CH23 135\n#define IRQ_APB_DMA_CH24 136\n#define IRQ_APB_DMA_CH25 137\n#define IRQ_APB_DMA_CH26 138\n#define IRQ_APB_DMA_CH27 139\n#define IRQ_APB_DMA_CH28 140\n#define IRQ_APB_DMA_CH29 141\n#define IRQ_APB_DMA_CH30 142\n#define IRQ_APB_DMA_CH31 143\n#define IRQ_CPU0_PMU_INTR 144\n#define IRQ_CPU1_PMU_INTR 145\n#define IRQ_CPU2_PMU_INTR 146\n#define IRQ_CPU3_PMU_INTR 147\n#define IRQ_SDMMC1_SYS 148\n#define IRQ_SDMMC2_SYS 149\n#define IRQ_SDMMC3_SYS 150\n#define IRQ_SDMMC4_SYS 151\n#define IRQ_TMR6 152\n#define IRQ_TMR7 153\n#define IRQ_TMR8 154\n#define IRQ_TMR9 155\n#define IRQ_TMR0 156\n#define IRQ_GPU_STALL 157\n#define IRQ_GPU_NONSTALL 158\n#define IRQ_DPAUX 159\n\n/* Senary interrupt controller ids */\n#define IRQ_MPCORE_AXIERRIRQ 160\n#define IRQ_MPCORE_INTERRIRQ 161\n#define IRQ_EVENT_GPIO_A 162\n#define IRQ_EVENT_GPIO_B 163\n#define IRQ_EVENT_GPIO_C 164\n#define IRQ_EVENT_GPIO_D_T210B01 165\n#define IRQ_FLOW_RSM_CPU 168\n#define IRQ_FLOW_RSM_COP 169\n#define IRQ_TMR_SHARED 170\n#define IRQ_MPCORE_CTIIRQ0 171\n#define IRQ_MPCORE_CTIIRQ1 172\n#define IRQ_MPCORE_CTIIRQ2 173\n#define IRQ_MPCORE_CTIIRQ3 174\n#define IRQ_MSELECT_ERROR 175\n#define IRQ_TMR10 176\n#define IRQ_TMR11 177\n#define IRQ_TMR12 178\n#define IRQ_TMR13 179\n\ntypedef int (*irq_handler_t)(u32 irq, void *data);\n\ntypedef enum _irq_status_t\n{\n\tIRQ_NONE    = 0,\n\tIRQ_HANDLED = 1,\n\tIRQ_ERROR   = 2,\n\n\tIRQ_ENABLED            = 0,\n\tIRQ_NO_SLOTS_AVAILABLE = 1,\n\tIRQ_ALREADY_REGISTERED = 2\n} irq_status_t;\n\ntypedef enum _irq_flags_t\n{\n\tIRQ_FLAG_NONE        = 0,\n\tIRQ_FLAG_ONE_OFF     = BIT(0),\n\tIRQ_FLAG_REPLACEABLE = BIT(1)\n} irq_flags_t;\n\nvoid irq_end();\nvoid irq_free(u32 irq);\nvoid irq_wait_event();\nvoid irq_disable_wait_event();\nirq_status_t irq_request(u32 irq, irq_handler_t handler, void *data, irq_flags_t flags);\n\n#endif"
  },
  {
    "path": "bdk/soc/kfuse.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <soc/kfuse.h>\n#include <soc/clock.h>\n#include <soc/t210.h>\n\nint kfuse_wait_ready()\n{\n\t// Wait for KFUSE to finish init and verification of data.\n\twhile (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE))\n\t\t;\n\n\tif (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS))\n\t\treturn 1;\n\n\treturn 0;\n}\n\nint kfuse_read(u32 *buf)\n{\n\tint res = 1;\n\n\tclock_enable_kfuse();\n\n\tif (kfuse_wait_ready())\n\t\tgoto out;\n\n\tKFUSE(KFUSE_KEYADDR) = KFUSE_KEYADDR_AUTOINC;\n\tfor (int i = 0; i < KFUSE_NUM_WORDS; i++)\n\t\tbuf[i] = KFUSE(KFUSE_KEYS);\n\n\tres = 0;\n\nout:\n\tclock_disable_kfuse();\n\treturn res;\n}\n"
  },
  {
    "path": "bdk/soc/kfuse.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _KFUSE_H_\n#define _KFUSE_H_\n\n#include <utils/types.h>\n\n#define KFUSE_STATE_CURBLOCK_MASK  0x3F\n#define KFUSE_STATE_ERRBLOCK_SHIFT 8\n#define KFUSE_STATE_ERRBLOCK_MASK  0x3F00\n#define KFUSE_STATE_DONE           BIT(16)\n#define KFUSE_STATE_CRCPASS        BIT(17)\n#define KFUSE_STATE_RESTART        BIT(24)\n#define KFUSE_STATE_STOP           BIT(25)\n#define KFUSE_STATE_SOFTRESET      BIT(31)\n\n#define KFUSE_KEYADDR_AUTOINC      BIT(16)\n\n#define KFUSE_STATE 0x80\n#define KFUSE_KEYADDR 0x88\n#define KFUSE_KEYS 0x8C\n\n#define KFUSE_NUM_WORDS 144\n\nint kfuse_wait_ready();\nint kfuse_read(u32 *buf);\n\n#endif\n"
  },
  {
    "path": "bdk/soc/pinmux.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <soc/i2c.h>\n#include <soc/pinmux.h>\n#include <soc/t210.h>\n\nvoid pinmux_config_uart(u32 idx)\n{\n\tPINMUX_AUX(PINMUX_AUX_UARTX_TX(idx))  = 0;\n\tPINMUX_AUX(PINMUX_AUX_UARTX_RX(idx))  = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;\n\tPINMUX_AUX(PINMUX_AUX_UARTX_RTS(idx)) = 0;\n\tPINMUX_AUX(PINMUX_AUX_UARTX_CTS(idx)) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;\n}\n\nvoid pinmux_config_i2c(u32 idx)\n{\n\tPINMUX_AUX(PINMUX_AUX_X_I2C_SCL(idx)) = PINMUX_INPUT_ENABLE;\n\tPINMUX_AUX(PINMUX_AUX_X_I2C_SDA(idx)) = PINMUX_INPUT_ENABLE;\n\n\t// Detach I2C4 pins from I2C3 function.\n\tif (idx == I2C_3 || idx == I2C_4)\n\t{\n\t\tPINMUX_AUX(PINMUX_AUX_X_I2C_SCL(I2C_4)) |= 1;\n\t\tPINMUX_AUX(PINMUX_AUX_X_I2C_SDA(I2C_4)) |= 1;\n\t}\n}\n\nvoid pinmux_config_i2s(u32 idx)\n{\n\tPINMUX_AUX(PINMUX_AUX_X_I2S_LRCK(idx)) = PINMUX_DRIVE_4X | PINMUX_PULL_DOWN;\n\tPINMUX_AUX(PINMUX_AUX_X_I2C_DIN(idx))  = PINMUX_DRIVE_4X | PINMUX_INPUT_ENABLE | PINMUX_TRISTATE | PINMUX_PULL_DOWN;\n\tPINMUX_AUX(PINMUX_AUX_X_I2C_DOUT(idx)) = PINMUX_DRIVE_4X | PINMUX_PULL_DOWN;\n\tPINMUX_AUX(PINMUX_AUX_X_I2C_BCLK(idx)) = PINMUX_DRIVE_4X | PINMUX_PULL_DOWN;\n}\n"
  },
  {
    "path": "bdk/soc/pinmux.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2024 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _PINMUX_H_\n#define _PINMUX_H_\n\n#include <utils/types.h>\n\n/*! APB MISC registers. */\n#define APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL 0x8D4\n#define APB_MISC_GP_SDMMC3_CLK_LPBK_CONTROL 0x8D8\n#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL   0xA98\n#define APB_MISC_GP_VGPIO_GPIO_MUX_SEL      0xB74\n\n/*! Pinmux registers. */\n#define PINMUX_AUX_SDMMC1_CLK      0x00\n#define PINMUX_AUX_SDMMC1_CMD      0x04\n#define PINMUX_AUX_SDMMC1_DAT3     0x08\n#define PINMUX_AUX_SDMMC1_DAT2     0x0C\n#define PINMUX_AUX_SDMMC1_DAT1     0x10\n#define PINMUX_AUX_SDMMC1_DAT0     0x14\n#define PINMUX_AUX_SDMMC3_CLK      0x1C\n#define PINMUX_AUX_SDMMC3_CMD      0x20\n#define PINMUX_AUX_SDMMC3_DAT0     0x24\n#define PINMUX_AUX_SDMMC3_DAT1     0x28\n#define PINMUX_AUX_SDMMC3_DAT2     0x2C\n#define PINMUX_AUX_SDMMC3_DAT3     0x30\n#define PINMUX_AUX_SATA_LED_ACTIVE 0x4C\n#define PINMUX_AUX_GPIO_PA5_T210B01 PINMUX_AUX_SATA_LED_ACTIVE\n#define PINMUX_AUX_DMIC3_CLK       0xB4\n#define PINMUX_AUX_DMIC3_DAT       0xB8\n#define PINMUX_AUX_CAM_I2C_SCL     0xD4\n#define PINMUX_AUX_CAM_I2C_SDA     0xD8\n#define PINMUX_AUX_UART2_TX        0xF4\n#define PINMUX_AUX_UART3_TX        0x104\n#define PINMUX_AUX_DAP4_DIN        0x148\n#define PINMUX_AUX_DAP4_DOUT       0x14C\n#define PINMUX_AUX_DAP4_SCLK       0x150\n#define PINMUX_AUX_CLK_32K_OUT     0x164\n#define PINMUX_AUX_AUD_MCLK        0x180\n#define PINMUX_AUX_GPIO_X1_AUD     0x18C\n#define PINMUX_AUX_GPIO_X3_AUD     0x190\n#define PINMUX_AUX_SPDIF_IN        0x1A4\n#define PINMUX_AUX_USB_VBUS_EN0    0x1A8\n#define PINMUX_AUX_USB_VBUS_EN1    0x1AC\n#define PINMUX_AUX_WIFI_EN         0x1B4\n#define PINMUX_AUX_WIFI_RST        0x1B8\n#define PINMUX_AUX_AP_WAKE_NFC     0x1CC\n#define PINMUX_AUX_NFC_EN          0x1D0\n#define PINMUX_AUX_NFC_INT         0x1D4\n#define PINMUX_AUX_CAM_RST         0x1E0\n#define PINMUX_AUX_CAM1_PWDN       0x1EC\n#define PINMUX_AUX_CAM2_PWDN       0x1F0\n#define PINMUX_AUX_CAM1_STROBE     0x1F4\n#define PINMUX_AUX_LCD_BL_PWM      0x1FC\n#define PINMUX_AUX_LCD_BL_EN       0x200\n#define PINMUX_AUX_LCD_RST         0x204\n#define PINMUX_AUX_LCD_GPIO1       0x208\n#define PINMUX_AUX_LCD_GPIO2       0x20C\n#define PINMUX_AUX_TOUCH_RST       0x214\n#define PINMUX_AUX_TOUCH_CLK       0x218\n#define PINMUX_AUX_TOUCH_INT       0x220\n#define PINMUX_AUX_MOTION_INT      0x224\n#define PINMUX_AUX_ALS_PROX_INT    0x228\n#define PINMUX_AUX_BUTTON_POWER_ON 0x230\n#define PINMUX_AUX_BUTTON_HOME     0x240\n#define PINMUX_AUX_GPIO_PE6        0x248\n#define PINMUX_AUX_GPIO_PE7        0x24C\n#define PINMUX_AUX_GPIO_PH6        0x250\n#define PINMUX_AUX_GPIO_PK3        0x260\n#define PINMUX_AUX_GPIO_PK7        0x270\n#define PINMUX_AUX_GPIO_PZ1        0x280\n#define PINMUX_AUX_GPIO_PZ4        0x28C\n/* Only in T210B01 */\n#define PINMUX_AUX_SDMMC2_DAT0     0x294\n#define PINMUX_AUX_SDMMC2_DAT1     0x298\n#define PINMUX_AUX_SDMMC2_DAT2     0x29C\n#define PINMUX_AUX_SDMMC2_DAT3     0x2A0\n#define PINMUX_AUX_SDMMC2_DAT4     0x2A4\n#define PINMUX_AUX_SDMMC2_DAT5     0x2A8\n#define PINMUX_AUX_SDMMC2_DAT6     0x2AC\n#define PINMUX_AUX_SDMMC2_DAT7     0x2B0\n#define PINMUX_AUX_SDMMC2_CLK      0x2B4\n#define PINMUX_AUX_SDMMC2_CMD      0x2BC\n\n/*! 0:UART-A, 1:UART-B, 3:UART-C, 3:UART-D */\n#define PINMUX_AUX_UARTX_TX(x)  (0xE4 + 0x10 * (x))\n#define PINMUX_AUX_UARTX_RX(x)  (0xE8 + 0x10 * (x))\n#define PINMUX_AUX_UARTX_RTS(x) (0xEC + 0x10 * (x))\n#define PINMUX_AUX_UARTX_CTS(x) (0xF0 + 0x10 * (x))\n/*! 0:GEN1, 1:GEN2, 2:GEN3, 3:CAM, 4:PWR */\n#define PINMUX_AUX_X_I2C_SCL(x) (0xBC + 8 * (x))\n#define PINMUX_AUX_X_I2C_SDA(x) (0xC0 + 8 * (x))\n/*! 0:I2S1, 1:I2S2 */\n#define PINMUX_AUX_X_I2S_LRCK(x) (0x124 + 0x10 * (x))\n#define PINMUX_AUX_X_I2C_DIN(x)  (0x128 + 0x10 * (x))\n#define PINMUX_AUX_X_I2C_DOUT(x) (0x12c + 0x10 * (x))\n#define PINMUX_AUX_X_I2C_BCLK(x) (0x130 + 0x10 * (x))\n\n#define PINMUX_FUNC_MASK    (3 << 0)\n\n#define PINMUX_PULL_MASK    (3 << 2)\n#define PINMUX_PULL_NONE    (0 << 2)\n#define PINMUX_PULL_DOWN    (1 << 2)\n#define PINMUX_PULL_UP      (2 << 2)\n\n#define PINMUX_TRISTATE     BIT(4)\n#define PINMUX_PARKED       BIT(5)\n#define PINMUX_INPUT_ENABLE BIT(6)\n#define PINMUX_LOCK         BIT(7)\n#define PINMUX_LPDR         BIT(8)\n#define PINMUX_HSM          BIT(9)\n\n#define PINMUX_IO_HV        BIT(10)\n#define PINMUX_OPEN_DRAIN   BIT(11)\n#define PINMUX_SCHMT        BIT(12)\n\n#define PINMUX_DRIVE_MASK   (3 << 13)\n#define PINMUX_DRIVE_1X     (0 << 13)\n#define PINMUX_DRIVE_2X     (1 << 13)\n#define PINMUX_DRIVE_3X     (2 << 13)\n#define PINMUX_DRIVE_4X     (3 << 13)\n\n#define PINMUX_PREEMP       BIT(15)\n\nvoid pinmux_config_uart(u32 idx);\nvoid pinmux_config_i2c(u32 idx);\nvoid pinmux_config_i2s(u32 idx);\n\n#endif\n"
  },
  {
    "path": "bdk/soc/pmc.c",
    "content": "/*\n * Copyright (c) 2020-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <soc/hw_init.h>\n#include <soc/pmc.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n\nvoid pmc_scratch_lock(pmc_sec_lock_t lock_mask)\n{\n\t// Lock Private key disable, Fuse write enable, MC carveout, Warmboot PA id and Warmboot address.\n\n\t// Happens on T210B01 LP0 always.\n\tif (lock_mask & PMC_SEC_LOCK_MISC)\n\t{\n\t\tPMC(APBDEV_PMC_SEC_DISABLE)  |= 0x700FF0;   // RW lock: 0-3.\n\t\tPMC(APBDEV_PMC_SEC_DISABLE2) |= 0xFC000000; // RW lock: 21-23.\n\t\tPMC(APBDEV_PMC_SEC_DISABLE3) |= 0x3F0FFF00; // RW lock: 28-33, 36-38.\n\t\tPMC(APBDEV_PMC_SEC_DISABLE6) |= 0xC000000;  // RW lock: 85.\n\t\t// Default: 0xFF00FF00: RW lock: 108-111, 116-119. Gets locked in LP0.\n\t\tPMC(APBDEV_PMC_SEC_DISABLE8) |= 0xFF005500; // W lock: 108-111, RW lock: 116-119.\n \t}\n\n \t// Happens on T210B01 LP0 always.\n\tif (lock_mask & PMC_SEC_LOCK_LP0_PARAMS)\n\t{\n\t\tPMC(APBDEV_PMC_SEC_DISABLE2) |= 0x3FCFFFF;  // RW lock: 8-15, 17-20. L4T expects 8-15 as write locked only.\n\t\tPMC(APBDEV_PMC_SEC_DISABLE4) |= 0x3F3FFFFF; // RW lock: 40-50, 52-54.\n\t\tPMC(APBDEV_PMC_SEC_DISABLE5)  = 0xFFFFFFFF; // RW lock: 56-71.\n\t\tPMC(APBDEV_PMC_SEC_DISABLE6) |= 0xF3FFC00F; // RW lock: 72-73, 79-84, 86-87.\n\t\tPMC(APBDEV_PMC_SEC_DISABLE7) |= 0x3FFFFF;   // RW lock: 88-98.\n\t\tPMC(APBDEV_PMC_SEC_DISABLE8) |= 0xFF;       // RW lock: 104-107.\n\t}\n\n\tif (lock_mask & PMC_SEC_LOCK_RST_VECTOR)\n\t\tPMC(APBDEV_PMC_SEC_DISABLE3) |= 0xF00000;   // RW lock: 34-35.\n\n\tif (lock_mask & PMC_SEC_LOCK_CARVEOUTS)\n\t{\n\t\tPMC(APBDEV_PMC_SEC_DISABLE2) |= 0x30000;    // RW lock: 16.\n\t\tPMC(APBDEV_PMC_SEC_DISABLE3) |= 0xC0000000; // RW lock: 39.\n\t\tPMC(APBDEV_PMC_SEC_DISABLE4) |= 0xC0C00000; // RW lock: 51, 55.\n\t\tPMC(APBDEV_PMC_SEC_DISABLE6) |= 0x3FF0;     // RW lock: 74-78.\n\t\tPMC(APBDEV_PMC_SEC_DISABLE7) |= 0xFFC00000; // RW lock: 99-103.\n\t}\n\n\t// HOS specific.\n\tif (lock_mask & PMC_SEC_LOCK_TZ_CMAC_W)\n\t\tPMC(APBDEV_PMC_SEC_DISABLE8) |= 0x550000;   // W lock: 112-115.\n\n\tif (lock_mask & PMC_SEC_LOCK_TZ_CMAC_R)\n\t\tPMC(APBDEV_PMC_SEC_DISABLE8) |= 0xAA0000;   // R lock: 112-115.\n\n\tif (lock_mask & PMC_SEC_LOCK_TZ_KEK_W)\n\t\tPMC(APBDEV_PMC_SEC_DISABLE3) |= 0x55;       // W lock: 24-27.\n\n\tif (lock_mask & PMC_SEC_LOCK_TZ_KEK_R)\n\t\tPMC(APBDEV_PMC_SEC_DISABLE3) |= 0xAA;       // R lock: 24-27.\n\t// End of HOS specific.\n\n\tif (lock_mask & PMC_SEC_LOCK_SE_SRK)\n\t\tPMC(APBDEV_PMC_SEC_DISABLE)  |= 0xFF000;    // RW lock: 4-7\n\n\tif (lock_mask & PMC_SEC_LOCK_SE2_SRK_B01)\n\t\tPMC(APBDEV_PMC_SEC_DISABLE9_B01)  |= 0x3FC; // RW lock: 120-123 (T210B01). LP0 also sets global bits (b0-1).\n\n\tif (lock_mask & PMC_SEC_LOCK_MISC_B01)\n\t\tPMC(APBDEV_PMC_SEC_DISABLE10_B01) = 0xFFFFFFFF; // RW lock: 135-150. Happens on T210B01 LP0 always.\n\n\tif (lock_mask & PMC_SEC_LOCK_CARVEOUTS_L4T)\n\t\tPMC(APBDEV_PMC_SEC_DISABLE2) |= 0x5555;     // W: 8-15 LP0 and Carveouts. Superseded by LP0 lock.\n\n\t// NVTBOOT misses APBDEV_PMC_SCRATCH_WRITE_LOCK_DISABLE_STICKY. bit0: SCRATCH_WR_DIS_ON.\n\t// They could also use the NS write disable registers instead.\n\tif (lock_mask & PMC_SEC_LOCK_LP0_PARAMS_B01)\n\t{\n\t\tPMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE0_B01) |= 0xCBCFE0;   // W lock: 5-11, 14-17, 19, 22-23.\n\t\tPMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE1_B01) |= 0x583FF;    // W lock: 24-33, 39-40, 42.\n\t\tPMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE2_B01) |= 0x1BE;      // W lock: 44-48, 50-51.\n\t\tPMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE3_B01)  = 0xFFFFFFFF; // W lock: 56-87.\n\t\tPMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE4_B01) |= 0xFFFFFFF;  // W lock: 88-115.\n\t\tPMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE5_B01) |= 0xFFFFFFF8; // W lock: 123-151.\n\t\tPMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE6_B01)  = 0xFFFFFFFF; // W lock: 152-183.\n\t\tPMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE7_B01) |= 0xFC00FFFF; // W lock: 184-199, 210-215.\n\t\tPMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE8_B01) |= 0xF;        // W lock: 216-219.\n\t}\n}\n\n/*\n * !TODO: Non CCPLEX power domains power gating/ungating.\n * Power gating: clock should be in reset if enabled and then\n * pmc_domain_pwrgate_set is run.\n * Power ungating: run pmc_domain_pwrgate_set, enable clocks and keep in\n * reset, remove clamping, remove reset, run mbist war if T210 and then clocks\n * can be disabled.\n */\n\nint pmc_domain_pwrgate_set(pmc_power_rail_t part, u32 enable)\n{\n\tu32 part_mask = BIT(part);\n\tu32 desired_state = enable << part;\n\n\t// Check if the power domain has the state we want.\n\tif ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state)\n\t\treturn 0;\n\n\tint retries = 5000;\n\twhile (PMC(APBDEV_PMC_PWRGATE_TOGGLE) & PMC_PWRGATE_TOGGLE_START)\n\t{\n\t\tusleep(1);\n\t\tif (--retries < 1)\n\t\t\treturn 1;\n\t}\n\n\t// Toggle power gating.\n\tPMC(APBDEV_PMC_PWRGATE_TOGGLE) = part | PMC_PWRGATE_TOGGLE_START;\n\n\tretries = 5000;\n\twhile ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) != desired_state)\n\t{\n\t\tusleep(1);\n\t\tif (--retries < 1)\n\t\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "bdk/soc/pmc.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018 st4rk\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _PMC_H_\n#define _PMC_H_\n\n#include <utils/types.h>\n#include <soc/pmc_t210.h>\n\ntypedef enum _pmc_sec_lock_t\n{\n\tPMC_SEC_LOCK_MISC           = BIT(0),\n\tPMC_SEC_LOCK_LP0_PARAMS     = BIT(1),\n\tPMC_SEC_LOCK_RST_VECTOR     = BIT(2),\n\tPMC_SEC_LOCK_CARVEOUTS      = BIT(3),\n\tPMC_SEC_LOCK_TZ_CMAC_W      = BIT(4),\n\tPMC_SEC_LOCK_TZ_CMAC_R      = BIT(5),\n\tPMC_SEC_LOCK_TZ_KEK_W       = BIT(6),\n\tPMC_SEC_LOCK_TZ_KEK_R       = BIT(7),\n\tPMC_SEC_LOCK_SE_SRK         = BIT(8),\n\tPMC_SEC_LOCK_SE2_SRK_B01    = BIT(9),\n\tPMC_SEC_LOCK_MISC_B01       = BIT(10),\n\tPMC_SEC_LOCK_CARVEOUTS_L4T  = BIT(11),\n\tPMC_SEC_LOCK_LP0_PARAMS_B01 = BIT(12),\n} pmc_sec_lock_t;\n\ntypedef enum _pmc_power_rail_t\n{\n\tPOWER_RAIL_CRAIL = 0,\n\tPOWER_RAIL_VE    = 2,\n\tPOWER_RAIL_PCIE  = 3,\n\tPOWER_RAIL_NVENC = 6,\n\tPOWER_RAIL_SATA  = 8,\n\tPOWER_RAIL_CE1   = 9,\n\tPOWER_RAIL_CE2   = 10,\n\tPOWER_RAIL_CE3   = 11,\n\tPOWER_RAIL_CELP  = 12,\n\tPOWER_RAIL_CE0   = 14,\n\tPOWER_RAIL_C0NC  = 15,\n\tPOWER_RAIL_C1NC  = 16,\n\tPOWER_RAIL_SOR   = 17,\n\tPOWER_RAIL_DIS   = 18,\n\tPOWER_RAIL_DISB  = 19,\n\tPOWER_RAIL_XUSBA = 20,\n\tPOWER_RAIL_XUSBB = 21,\n\tPOWER_RAIL_XUSBC = 22,\n\tPOWER_RAIL_VIC   = 23,\n\tPOWER_RAIL_IRAM  = 24,\n\tPOWER_RAIL_NVDEC = 25,\n\tPOWER_RAIL_NVJPG = 26,\n\tPOWER_RAIL_AUD   = 27,\n\tPOWER_RAIL_DFD   = 28,\n\tPOWER_RAIL_VE2   = 29\n} pmc_power_rail_t;\n\nvoid pmc_scratch_lock(pmc_sec_lock_t lock_mask);\nint  pmc_domain_pwrgate_set(pmc_power_rail_t part, u32 enable);\n\n#endif\n"
  },
  {
    "path": "bdk/soc/pmc_t210.h",
    "content": "/*\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n */\n\n#ifndef _PMC_T210_H_\n#define _PMC_T210_H_\n\n/*! PMC registers. */\n#define APBDEV_PMC_CNTRL                       0x0\n#define  PMC_CNTRL_RTC_CLK_DIS     BIT(1)\n#define  PMC_CNTRL_RTC_RST         BIT(2)\n#define  PMC_CNTRL_MAIN_RST        BIT(4)\n#define  PMC_CNTRL_LATCHWAKE_EN    BIT(5)\n#define  PMC_CNTRL_BLINK_EN        BIT(7)\n#define  PMC_CNTRL_PWRREQ_OE       BIT(9)\n#define  PMC_CNTRL_SYSCLK_OE       BIT(11)\n#define  PMC_CNTRL_PWRGATE_DIS     BIT(12)\n#define  PMC_CNTRL_SIDE_EFFECT_LP0 BIT(14)\n#define  PMC_CNTRL_CPUPWRREQ_OE    BIT(16)\n#define  PMC_CNTRL_FUSE_OVERRIDE   BIT(18)\n#define  PMC_CNTRL_SHUTDOWN_OE     BIT(22)\n\n#define APBDEV_PMC_SEC_DISABLE                 0x4\n#define APBDEV_PMC_PMC_SWRST                   0x8\n#define APBDEV_PMC_WAKE_MASK                   0xC\n#define APBDEV_PMC_WAKE_LVL                    0x10\n#define APBDEV_PMC_WAKE_STATUS                 0x14\n#define APBDEV_PMC_SW_WAKE_STATUS              0x18\n#define APBDEV_PMC_DPD_PADS_ORIDE              0x1C\n#define APBDEV_PMC_DPD_SAMPLE                  0x20\n#define APBDEV_PMC_DPD_ENABLE                  0x24\n#define APBDEV_PMC_PWRGATE_TIMER_OFF           0x28\n#define APBDEV_PMC_CLAMP_STATUS                0x2C\n\n#define APBDEV_PMC_PWRGATE_TOGGLE              0x30\n#define  PMC_PWRGATE_TOGGLE_START BIT(8)\n\n#define APBDEV_PMC_REMOVE_CLAMPING_CMD         0x34\n#define APBDEV_PMC_PWRGATE_STATUS              0x38\n#define APBDEV_PMC_PWRGOOD_TIMER               0x3C\n#define APBDEV_PMC_BLINK_TIMER                 0x40\n#define  PMC_BLINK_ON(n)  ((n & 0x7FFF))\n#define  PMC_BLINK_FORCE  BIT(15)\n#define  PMC_BLINK_OFF(n) ((u32)(n & 0xFFFF) << 16)\n\n#define APBDEV_PMC_NO_IOPOWER                  0x44\n#define  PMC_NO_IOPOWER_MEM      BIT(7)\n#define  PMC_NO_IOPOWER_SDMMC1   BIT(12)\n#define  PMC_NO_IOPOWER_SDMMC4   BIT(14)\n#define  PMC_NO_IOPOWER_MEM_COMP BIT(16)\n#define  PMC_NO_IOPOWER_AUDIO_HV BIT(18)\n#define  PMC_NO_IOPOWER_GPIO     BIT(21)\n\n#define APBDEV_PMC_PWR_DET                     0x48\n#define APBDEV_PMC_PWR_DET_LATCH               0x4C\n\n#define APBDEV_PMC_SCRATCH0                    0x50\n#define  PMC_SCRATCH0_MODE_WARMBOOT   BIT(0)\n#define  PMC_SCRATCH0_MODE_RCM        BIT(1)\n#define  PMC_SCRATCH0_MODE_PAYLOAD    BIT(29)\n#define  PMC_SCRATCH0_MODE_BOOTLOADER BIT(30)\n#define  PMC_SCRATCH0_MODE_RECOVERY   BIT(31)\n#define  PMC_SCRATCH0_MODE_CUSTOM_ALL (PMC_SCRATCH0_MODE_RECOVERY   | \\\n\t\t\t\t\t\t\t\t\t   PMC_SCRATCH0_MODE_BOOTLOADER | \\\n\t\t\t\t\t\t\t\t\t   PMC_SCRATCH0_MODE_PAYLOAD)\n\n#define APBDEV_PMC_SCRATCH1                    0x54\n#define APBDEV_PMC_SCRATCH2                    0x58\n#define APBDEV_PMC_SCRATCH3                    0x5C\n#define APBDEV_PMC_SCRATCH4                    0x60\n#define APBDEV_PMC_SCRATCH5                    0x64\n#define APBDEV_PMC_SCRATCH6                    0x68\n#define APBDEV_PMC_SCRATCH7                    0x6C\n#define APBDEV_PMC_SCRATCH8                    0x70\n#define APBDEV_PMC_SCRATCH9                    0x74\n#define APBDEV_PMC_SCRATCH10                   0x78\n#define APBDEV_PMC_SCRATCH11                   0x7C\n#define APBDEV_PMC_SCRATCH12                   0x80\n#define APBDEV_PMC_SCRATCH13                   0x84\n#define APBDEV_PMC_SCRATCH14                   0x88\n#define APBDEV_PMC_SCRATCH15                   0x8C\n#define APBDEV_PMC_SCRATCH16                   0x90\n#define APBDEV_PMC_SCRATCH17                   0x94\n#define APBDEV_PMC_SCRATCH18                   0x98\n#define APBDEV_PMC_SCRATCH19                   0x9C\n#define APBDEV_PMC_SCRATCH20                   0xA0 // ODM data/config scratch.\n#define APBDEV_PMC_SCRATCH21                   0xA4\n#define APBDEV_PMC_SCRATCH22                   0xA8\n#define APBDEV_PMC_SCRATCH23                   0xAC\n#define APBDEV_PMC_SECURE_SCRATCH0             0xB0\n#define APBDEV_PMC_SECURE_SCRATCH1             0xB4\n#define APBDEV_PMC_SECURE_SCRATCH2             0xB8\n#define APBDEV_PMC_SECURE_SCRATCH3             0xBC\n#define APBDEV_PMC_SECURE_SCRATCH4             0xC0\n#define APBDEV_PMC_SECURE_SCRATCH5             0xC4\n#define APBDEV_PMC_CPUPWRGOOD_TIMER            0xC8\n#define APBDEV_PMC_CPUPWROFF_TIMER             0xCC\n#define APBDEV_PMC_PG_MASK                     0xD0\n#define APBDEV_PMC_PG_MASK_1                   0xD4\n#define APBDEV_PMC_AUTO_WAKE_LVL               0xD8\n#define APBDEV_PMC_AUTO_WAKE_LVL_MASK          0xDC\n#define APBDEV_PMC_WAKE_DELAY                  0xE0\n\n#define APBDEV_PMC_PWR_DET_VAL                 0xE4\n#define  PMC_PWR_DET_33V_SDMMC1   BIT(12)\n#define  PMC_PWR_DET_33V_AUDIO_HV BIT(18)\n#define  PMC_PWR_DET_33V_GPIO     BIT(21)\n\n#define APBDEV_PMC_DDR_PWR                     0xE8\n#define APBDEV_PMC_USB_DEBOUNCE_DEL            0xEC\n#define APBDEV_PMC_USB_AO                      0xF0\n\n#define APBDEV_PMC_CRYPTO_OP                   0xF4\n#define  PMC_CRYPTO_OP_SE_ENABLE  0\n#define  PMC_CRYPTO_OP_SE_DISABLE 1\n\n#define APBDEV_PMC_PLLP_WB0_OVERRIDE           0xF8\n#define  PMC_PLLP_WB0_OVR_PLLM_OVR_ENABLE BIT(11)\n#define  PMC_PLLP_WB0_OVR_PLLM_ENABLE     BIT(12)\n\n#define APBDEV_PMC_SCRATCH24                   0xFC\n#define APBDEV_PMC_SCRATCH25                   0x100\n#define APBDEV_PMC_SCRATCH26                   0x104\n#define APBDEV_PMC_SCRATCH27                   0x108\n#define APBDEV_PMC_SCRATCH28                   0x10C\n#define APBDEV_PMC_SCRATCH29                   0x110\n#define APBDEV_PMC_SCRATCH30                   0x114\n#define APBDEV_PMC_SCRATCH31                   0x118\n#define APBDEV_PMC_SCRATCH32                   0x11C\n#define APBDEV_PMC_SCRATCH33                   0x120\n#define APBDEV_PMC_SCRATCH34                   0x124\n#define APBDEV_PMC_SCRATCH35                   0x128\n#define APBDEV_PMC_SCRATCH36                   0x12C\n#define APBDEV_PMC_SCRATCH37                   0x130\n#define  PMC_SCRATCH37_KERNEL_PANIC_MAGIC 0x4E415054 // \"TPAN\"\n\n#define APBDEV_PMC_SCRATCH38                   0x134\n#define APBDEV_PMC_SCRATCH39                   0x138\n#define APBDEV_PMC_SCRATCH40                   0x13C\n#define APBDEV_PMC_SCRATCH41                   0x140\n#define APBDEV_PMC_SCRATCH42                   0x144\n#define APBDEV_PMC_BONDOUT_MIRROR0             0x148\n#define APBDEV_PMC_BONDOUT_MIRROR1             0x14C\n#define APBDEV_PMC_BONDOUT_MIRROR2             0x150\n#define APBDEV_PMC_SYS_33V_EN                  0x154\n#define APBDEV_PMC_BONDOUT_MIRROR_ACCESS       0x158\n#define APBDEV_PMC_GATE                        0x15C\n#define APBDEV_PMC_WAKE2_MASK                  0x160\n#define APBDEV_PMC_WAKE2_LVL                   0x164\n#define APBDEV_PMC_WAKE2_STATUS                0x168\n#define APBDEV_PMC_SW_WAKE2_STATUS             0x16C\n#define APBDEV_PMC_AUTO_WAKE2_LVL_MASK         0x170\n#define APBDEV_PMC_PG_MASK_2                   0x174\n#define APBDEV_PMC_PG_MASK_CE1                 0x178\n#define APBDEV_PMC_PG_MASK_CE2                 0x17C\n#define APBDEV_PMC_PG_MASK_CE3                 0x180\n#define APBDEV_PMC_PWRGATE_TIMER_CE_0          0x184\n#define APBDEV_PMC_PWRGATE_TIMER_CE_1          0x188\n#define APBDEV_PMC_PWRGATE_TIMER_CE_2          0x18C\n#define APBDEV_PMC_PWRGATE_TIMER_CE_3          0x190\n#define APBDEV_PMC_PWRGATE_TIMER_CE_4          0x194\n#define APBDEV_PMC_PWRGATE_TIMER_CE_5          0x198\n#define APBDEV_PMC_PWRGATE_TIMER_CE_6          0x19C\n#define APBDEV_PMC_PCX_EDPD_CNTRL              0x1A0\n\n#define APBDEV_PMC_OSC_EDPD_OVER               0x1A4\n#define  PMC_OSC_EDPD_OVER_OSC_CTRL_OVER BIT(22)\n\n#define APBDEV_PMC_CLK_OUT_CNTRL               0x1A8\n#define  PMC_CLK_OUT_CNTRL_CLK1_FORCE_EN     BIT(2)\n#define  PMC_CLK_OUT_CNTRL_CLK2_FORCE_EN     BIT(10)\n#define  PMC_CLK_OUT_CNTRL_CLK3_FORCE_EN     BIT(18)\n#define  PMC_CLK_OUT_CNTRL_CLK1_SRC_SEL(src) (((src) & 3) << 6)\n#define  PMC_CLK_OUT_CNTRL_CLK2_SRC_SEL(src) (((src) & 3) << 14)\n#define  PMC_CLK_OUT_CNTRL_CLK3_SRC_SEL(src) (((src) & 3) << 22)\n#define   OSC_DIV1                           0\n#define   OSC_DIV2                           1\n#define   OSC_DIV4                           2\n#define   OSC_CAR                            3\n\n#define APBDEV_PMC_SATA_PWRGT                  0x1AC\n#define APBDEV_PMC_SENSOR_CTRL                 0x1B0\n\n#define APBDEV_PMC_RST_STATUS                  0x1B4\n#define  PMC_RST_STATUS_MASK     7\n#define  PMC_RST_STATUS_POR      0\n#define  PMC_RST_STATUS_WATCHDOG 1\n#define  PMC_RST_STATUS_SENSOR   2\n#define  PMC_RST_STATUS_SW_MAIN  3\n#define  PMC_RST_STATUS_LP0      4\n#define  PMC_RST_STATUS_AOTAG    5\n\n#define APBDEV_PMC_IO_DPD_REQ                  0x1B8\n#define  PMC_IO_DPD_REQ_DPD_IDLE (0 << 30u)\n#define  PMC_IO_DPD_REQ_DPD_OFF  (1 << 30u)\n#define  PMC_IO_DPD_REQ_DPD_ON   (2 << 30u)\n\n#define APBDEV_PMC_IO_DPD_STATUS               0x1BC\n#define APBDEV_PMC_IO_DPD2_REQ                 0x1C0\n#define APBDEV_PMC_IO_DPD2_STATUS              0x1C4\n#define APBDEV_PMC_SEL_DPD_TIM                 0x1C8\n#define APBDEV_PMC_VDDP_SEL                    0x1CC\n#define APBDEV_PMC_DDR_CFG                     0x1D0\n#define APBDEV_PMC_E_NO_VTTGEN                 0x1D4\n#define APBDEV_PMC_PLLM_WB0_OVERRIDE_FREQ      0x1DC\n#define APBDEV_PMC_TEST_PWRGATE                0x1E0\n#define APBDEV_PMC_PWRGATE_TIMER_MULT          0x1E4\n#define APBDEV_PMC_DSI_SEL_DPD                 0x1E8\n#define APBDEV_PMC_UTMIP_UHSIC_TRIGGERS        0x1EC\n#define APBDEV_PMC_UTMIP_UHSIC_SAVED_STATE     0x1F0\n#define APBDEV_PMC_UTMIP_TERM_PAD_CFG          0x1F8\n#define APBDEV_PMC_UTMIP_UHSIC_SLEEP_CFG       0x1FC\n#define APBDEV_PMC_UTMIP_UHSIC_SLEEPWALK_CFG   0x200\n#define APBDEV_PMC_UTMIP_SLEEPWALK_P0          0x204\n#define APBDEV_PMC_UTMIP_SLEEPWALK_P1          0x208\n#define APBDEV_PMC_UTMIP_SLEEPWALK_P2          0x20C\n#define APBDEV_PMC_UHSIC_SLEEPWALK_P0          0x210\n#define APBDEV_PMC_UTMIP_UHSIC_STATUS          0x214\n#define APBDEV_PMC_UTMIP_UHSIC_FAKE            0x218\n#define APBDEV_PMC_BONDOUT_MIRROR3             0x21C\n#define APBDEV_PMC_BONDOUT_MIRROR4             0x220\n#define APBDEV_PMC_SECURE_SCRATCH6             0x224\n#define APBDEV_PMC_SECURE_SCRATCH7             0x228\n#define APBDEV_PMC_SCRATCH43                   0x22C\n#define APBDEV_PMC_SCRATCH44                   0x230\n#define APBDEV_PMC_SCRATCH45                   0x234\n#define APBDEV_PMC_SCRATCH46                   0x238\n#define APBDEV_PMC_SCRATCH47                   0x23C\n#define APBDEV_PMC_SCRATCH48                   0x240\n#define APBDEV_PMC_SCRATCH49                   0x244\n#define APBDEV_PMC_SCRATCH50                   0x248\n#define APBDEV_PMC_SCRATCH51                   0x24C\n#define APBDEV_PMC_SCRATCH52                   0x250\n#define APBDEV_PMC_SCRATCH53                   0x254\n#define APBDEV_PMC_SCRATCH54                   0x258\n#define APBDEV_PMC_SCRATCH55                   0x25C\n#define APBDEV_PMC_SCRATCH0_ECO                0x260\n#define APBDEV_PMC_POR_DPD_CTRL                0x264\n#define APBDEV_PMC_SCRATCH2_ECO                0x268\n#define APBDEV_PMC_UTMIP_UHSIC_LINE_WAKEUP     0x26C\n#define APBDEV_PMC_UTMIP_BIAS_MASTER_CNTRL     0x270\n#define APBDEV_PMC_UTMIP_MASTER_CONFIG         0x274\n#define APBDEV_PMC_TD_PWRGATE_INTER_PART_TIMER 0x278\n#define APBDEV_PMC_UTMIP_UHSIC2_TRIGGERS       0x27C\n#define APBDEV_PMC_UTMIP_UHSIC2_SAVED_STATE    0x280\n#define APBDEV_PMC_UTMIP_UHSIC2_SLEEP_CFG      0x284\n#define APBDEV_PMC_UTMIP_UHSIC2_SLEEPWALK_CFG  0x288\n#define APBDEV_PMC_UHSIC2_SLEEPWALK_P1         0x28C\n#define APBDEV_PMC_UTMIP_UHSIC2_STATUS         0x290\n#define APBDEV_PMC_UTMIP_UHSIC2_FAKE           0x294\n#define APBDEV_PMC_UTMIP_UHSIC2_LINE_WAKEUP    0x298\n#define APBDEV_PMC_UTMIP_MASTER2_CONFIG        0x29C\n#define APBDEV_PMC_UTMIP_UHSIC_RPD_CFG         0x2A0\n#define APBDEV_PMC_PG_MASK_CE0                 0x2A4\n#define APBDEV_PMC_PG_MASK_3                   0x2A8\n#define APBDEV_PMC_PG_MASK_4                   0x2AC\n#define APBDEV_PMC_PLLM_WB0_OVERRIDE2          0x2B0\n#define APBDEV_PMC_TSC_MULT                    0x2B4\n#define APBDEV_PMC_CPU_VSENSE_OVERRIDE         0x2B8\n#define APBDEV_PMC_GLB_AMAP_CFG                0x2BC\n\n#define APBDEV_PMC_STICKY_BITS                 0x2C0\n#define  PMC_STICKY_BITS_HDA_LPBK_DIS BIT(0)\n\n#define APBDEV_PMC_SEC_DISABLE2                0x2C4\n#define APBDEV_PMC_WEAK_BIAS                   0x2C8\n#define APBDEV_PMC_REG_SHORT                   0x2CC\n#define APBDEV_PMC_PG_MASK_ANDOR               0x2D0\n#define APBDEV_PMC_GPU_RG_CNTRL                0x2D4\n#define APBDEV_PMC_SEC_DISABLE3                0x2D8\n#define APBDEV_PMC_PG_MASK_5                   0x2DC\n#define APBDEV_PMC_PG_MASK_6                   0x2E0\n#define APBDEV_PMC_SECURE_SCRATCH8             0x300\n#define APBDEV_PMC_SECURE_SCRATCH9             0x304\n#define APBDEV_PMC_SECURE_SCRATCH10            0x308\n#define APBDEV_PMC_SECURE_SCRATCH11            0x30C\n#define APBDEV_PMC_SECURE_SCRATCH12            0x310\n#define APBDEV_PMC_SECURE_SCRATCH13            0x314\n#define APBDEV_PMC_SECURE_SCRATCH14            0x318\n#define APBDEV_PMC_SECURE_SCRATCH15            0x31C\n#define APBDEV_PMC_SECURE_SCRATCH16            0x320\n#define APBDEV_PMC_SECURE_SCRATCH17            0x324\n#define APBDEV_PMC_SECURE_SCRATCH18            0x328\n#define APBDEV_PMC_SECURE_SCRATCH19            0x32C\n#define APBDEV_PMC_SECURE_SCRATCH20            0x330\n\n#define APBDEV_PMC_SECURE_SCRATCH21            0x334\n#define  PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT BIT(4)\n\n#define APBDEV_PMC_SECURE_SCRATCH22            0x338 // AArch32 reset address.\n#define APBDEV_PMC_SECURE_SCRATCH23            0x33C\n#define APBDEV_PMC_SECURE_SCRATCH24            0x340\n#define APBDEV_PMC_SECURE_SCRATCH25            0x344\n#define APBDEV_PMC_SECURE_SCRATCH26            0x348\n#define APBDEV_PMC_SECURE_SCRATCH27            0x34C\n#define APBDEV_PMC_SECURE_SCRATCH28            0x350\n#define APBDEV_PMC_SECURE_SCRATCH29            0x354\n#define APBDEV_PMC_SECURE_SCRATCH30            0x358\n#define APBDEV_PMC_SECURE_SCRATCH31            0x35C\n#define APBDEV_PMC_SECURE_SCRATCH32            0x360\n#define APBDEV_PMC_SECURE_SCRATCH33            0x364\n#define APBDEV_PMC_SECURE_SCRATCH34            0x368 // AArch64 reset address.\n#define APBDEV_PMC_SECURE_SCRATCH35            0x36C // AArch64 reset hi-address.\n#define APBDEV_PMC_SECURE_SCRATCH36            0x370\n#define APBDEV_PMC_SECURE_SCRATCH37            0x374\n#define APBDEV_PMC_SECURE_SCRATCH38            0x378\n#define APBDEV_PMC_SECURE_SCRATCH39            0x37C\n#define APBDEV_PMC_SECURE_SCRATCH40            0x380\n#define APBDEV_PMC_SECURE_SCRATCH41            0x384\n#define APBDEV_PMC_SECURE_SCRATCH42            0x388\n#define APBDEV_PMC_SECURE_SCRATCH43            0x38C\n#define APBDEV_PMC_SECURE_SCRATCH44            0x390\n#define APBDEV_PMC_SECURE_SCRATCH45            0x394\n#define APBDEV_PMC_SECURE_SCRATCH46            0x398\n#define APBDEV_PMC_SECURE_SCRATCH47            0x39C\n#define APBDEV_PMC_SECURE_SCRATCH48            0x3A0\n#define APBDEV_PMC_SECURE_SCRATCH49            0x3A4\n#define APBDEV_PMC_SECURE_SCRATCH50            0x3A8\n#define APBDEV_PMC_SECURE_SCRATCH51            0x3AC\n#define APBDEV_PMC_SECURE_SCRATCH52            0x3B0\n#define APBDEV_PMC_SECURE_SCRATCH53            0x3B4\n#define APBDEV_PMC_SECURE_SCRATCH54            0x3B8\n#define APBDEV_PMC_SECURE_SCRATCH55            0x3BC\n#define APBDEV_PMC_SECURE_SCRATCH56            0x3C0\n#define APBDEV_PMC_SECURE_SCRATCH57            0x3C4\n#define APBDEV_PMC_SECURE_SCRATCH58            0x3C8\n#define APBDEV_PMC_SECURE_SCRATCH59            0x3CC\n#define APBDEV_PMC_SECURE_SCRATCH60            0x3D0\n#define APBDEV_PMC_SECURE_SCRATCH61            0x3D4\n#define APBDEV_PMC_SECURE_SCRATCH62            0x3D8\n#define APBDEV_PMC_SECURE_SCRATCH63            0x3DC\n#define APBDEV_PMC_SECURE_SCRATCH64            0x3E0\n#define APBDEV_PMC_SECURE_SCRATCH65            0x3E4\n#define APBDEV_PMC_SECURE_SCRATCH66            0x3E8\n#define APBDEV_PMC_SECURE_SCRATCH67            0x3EC\n#define APBDEV_PMC_SECURE_SCRATCH68            0x3F0\n#define APBDEV_PMC_SECURE_SCRATCH69            0x3F4\n#define APBDEV_PMC_SECURE_SCRATCH70            0x3F8\n#define APBDEV_PMC_SECURE_SCRATCH71            0x3FC\n#define APBDEV_PMC_SECURE_SCRATCH72            0x400\n#define APBDEV_PMC_SECURE_SCRATCH73            0x404\n#define APBDEV_PMC_SECURE_SCRATCH74            0x408\n#define APBDEV_PMC_SECURE_SCRATCH75            0x40C\n#define APBDEV_PMC_SECURE_SCRATCH76            0x410\n#define APBDEV_PMC_SECURE_SCRATCH77            0x414\n#define APBDEV_PMC_SECURE_SCRATCH78            0x418\n#define APBDEV_PMC_SECURE_SCRATCH79            0x41C\n\n#define APBDEV_PMC_CNTRL2                      0x440\n#define  PMC_CNTRL2_WAKE_INT_EN      BIT(0)\n#define  PMC_CNTRL2_WAKE_DET_EN      BIT(9)\n#define  PMC_CNTRL2_SYSCLK_ORRIDE    BIT(10)\n#define  PMC_CNTRL2_HOLD_CKE_LOW_EN  BIT(12)\n#define  PMC_CNTRL2_ALLOW_PULSE_WAKE BIT(14)\n\n#define APBDEV_PMC_IO_DPD_OFF_MASK             0x444\n#define APBDEV_PMC_IO_DPD2_OFF_MASK            0x448\n#define APBDEV_PMC_EVENT_COUNTER               0x44C\n\n#define APBDEV_PMC_FUSE_CONTROL                0x450\n#define  PMC_FUSE_CONTROL_PS18_LATCH_SET BIT(8)\n#define  PMC_FUSE_CONTROL_PS18_LATCH_CLR BIT(9)\n\n#define APBDEV_PMC_SCRATCH1_ECO                0x454\n#define APBDEV_PMC_IO_DPD3_REQ                 0x45C\n#define APBDEV_PMC_IO_DPD3_STATUS              0x460\n#define APBDEV_PMC_IO_DPD4_REQ                 0x464\n#define APBDEV_PMC_IO_DPD4_STATUS              0x468\n#define APBDEV_PMC_DIRECT_THERMTRIP_CFG        0x474\n#define APBDEV_PMC_TSOSC_DELAY                 0x478\n#define APBDEV_PMC_SET_SW_CLAMP                0x47C\n#define APBDEV_PMC_DEBUG_AUTHENTICATION        0x480\n#define APBDEV_PMC_AOTAG_CFG                   0x484\n#define APBDEV_PMC_AOTAG_THRESH1_CFG           0x488\n#define APBDEV_PMC_AOTAG_THRESH2_CFG           0x48C\n#define APBDEV_PMC_AOTAG_THRESH3_CFG           0x490\n#define APBDEV_PMC_AOTAG_STATUS                0x494\n#define APBDEV_PMC_AOTAG_SECURITY              0x498\n#define APBDEV_PMC_TSENSOR_CONFIG0             0x49C\n#define APBDEV_PMC_TSENSOR_CONFIG1             0x4A0\n#define APBDEV_PMC_TSENSOR_CONFIG2             0x4A4\n#define APBDEV_PMC_TSENSOR_STATUS0             0x4A8\n#define APBDEV_PMC_TSENSOR_STATUS1             0x4AC\n#define APBDEV_PMC_TSENSOR_STATUS2             0x4B0\n#define APBDEV_PMC_TSENSOR_PDIV                0x4B4\n#define APBDEV_PMC_AOTAG_INTR_EN               0x4B8\n#define APBDEV_PMC_AOTAG_INTR_DIS              0x4BC\n#define APBDEV_PMC_UTMIP_PAD_CFG0              0x4C0\n#define APBDEV_PMC_UTMIP_PAD_CFG1              0x4C4\n#define APBDEV_PMC_UTMIP_PAD_CFG2              0x4C8\n#define APBDEV_PMC_UTMIP_PAD_CFG3              0x4CC\n#define APBDEV_PMC_UTMIP_UHSIC_SLEEP_CFG1      0x4D0\n#define APBDEV_PMC_CC4_HVC_CONTROL             0x4D4\n#define APBDEV_PMC_WAKE_DEBOUNCE_EN            0x4D8\n#define APBDEV_PMC_RAMDUMP_CTL_STATUS          0x4DC\n#define APBDEV_PMC_UTMIP_SLEEPWALK_P3          0x4E0\n#define APBDEV_PMC_DDR_CNTRL                   0x4E4\n#define APBDEV_PMC_SEC_DISABLE4                0x5B0\n#define APBDEV_PMC_SEC_DISABLE5                0x5B4\n#define APBDEV_PMC_SEC_DISABLE6                0x5B8\n#define APBDEV_PMC_SEC_DISABLE7                0x5BC\n#define APBDEV_PMC_SEC_DISABLE8                0x5C0\n#define APBDEV_PMC_SCRATCH56                   0x600\n#define APBDEV_PMC_SCRATCH57                   0x604\n#define APBDEV_PMC_SCRATCH58                   0x608\n#define APBDEV_PMC_SCRATCH59                   0x60C\n#define APBDEV_PMC_SCRATCH60                   0x610\n#define APBDEV_PMC_SCRATCH61                   0x614\n#define APBDEV_PMC_SCRATCH62                   0x618\n#define APBDEV_PMC_SCRATCH63                   0x61C\n#define APBDEV_PMC_SCRATCH64                   0x620\n#define APBDEV_PMC_SCRATCH65                   0x624\n#define APBDEV_PMC_SCRATCH66                   0x628\n#define APBDEV_PMC_SCRATCH67                   0x62C\n#define APBDEV_PMC_SCRATCH68                   0x630\n#define APBDEV_PMC_SCRATCH69                   0x634\n#define APBDEV_PMC_SCRATCH70                   0x638\n#define APBDEV_PMC_SCRATCH71                   0x63C\n#define APBDEV_PMC_SCRATCH72                   0x640\n#define APBDEV_PMC_SCRATCH73                   0x644\n#define APBDEV_PMC_SCRATCH74                   0x648\n#define APBDEV_PMC_SCRATCH75                   0x64C\n#define APBDEV_PMC_SCRATCH76                   0x650\n#define APBDEV_PMC_SCRATCH77                   0x654\n#define APBDEV_PMC_SCRATCH78                   0x658\n#define APBDEV_PMC_SCRATCH79                   0x65C\n#define APBDEV_PMC_SCRATCH80                   0x660\n#define APBDEV_PMC_SCRATCH81                   0x664\n#define APBDEV_PMC_SCRATCH82                   0x668\n#define APBDEV_PMC_SCRATCH83                   0x66C\n#define APBDEV_PMC_SCRATCH84                   0x670\n#define APBDEV_PMC_SCRATCH85                   0x674\n#define APBDEV_PMC_SCRATCH86                   0x678\n#define APBDEV_PMC_SCRATCH87                   0x67C\n#define APBDEV_PMC_SCRATCH88                   0x680\n#define APBDEV_PMC_SCRATCH89                   0x684\n#define APBDEV_PMC_SCRATCH90                   0x688\n#define APBDEV_PMC_SCRATCH91                   0x68C\n#define APBDEV_PMC_SCRATCH92                   0x690\n#define APBDEV_PMC_SCRATCH93                   0x694\n#define APBDEV_PMC_SCRATCH94                   0x698\n#define APBDEV_PMC_SCRATCH95                   0x69C\n#define APBDEV_PMC_SCRATCH96                   0x6A0\n#define APBDEV_PMC_SCRATCH97                   0x6A4\n#define APBDEV_PMC_SCRATCH98                   0x6A8\n#define APBDEV_PMC_SCRATCH99                   0x6AC\n#define APBDEV_PMC_SCRATCH100                  0x6B0\n#define APBDEV_PMC_SCRATCH101                  0x6B4\n#define APBDEV_PMC_SCRATCH102                  0x6B8\n#define APBDEV_PMC_SCRATCH103                  0x6BC\n#define APBDEV_PMC_SCRATCH104                  0x6C0\n#define APBDEV_PMC_SCRATCH105                  0x6C4\n#define APBDEV_PMC_SCRATCH106                  0x6C8\n#define APBDEV_PMC_SCRATCH107                  0x6CC\n#define APBDEV_PMC_SCRATCH108                  0x6D0\n#define APBDEV_PMC_SCRATCH109                  0x6D4\n#define APBDEV_PMC_SCRATCH110                  0x6D8\n#define APBDEV_PMC_SCRATCH111                  0x6DC\n#define APBDEV_PMC_SCRATCH112                  0x6E0\n#define APBDEV_PMC_SCRATCH113                  0x6E4\n#define APBDEV_PMC_SCRATCH114                  0x6E8\n#define APBDEV_PMC_SCRATCH115                  0x6EC\n#define APBDEV_PMC_SCRATCH116                  0x6F0\n#define APBDEV_PMC_SCRATCH117                  0x6F4\n#define APBDEV_PMC_SCRATCH118                  0x6F8\n#define APBDEV_PMC_SCRATCH119                  0x6FC\n#define APBDEV_PMC_SCRATCH120                  0x700\n#define APBDEV_PMC_SCRATCH121                  0x704\n#define APBDEV_PMC_SCRATCH122                  0x708\n#define APBDEV_PMC_SCRATCH123                  0x70C\n#define APBDEV_PMC_SCRATCH124                  0x710\n#define APBDEV_PMC_SCRATCH125                  0x714\n#define APBDEV_PMC_SCRATCH126                  0x718\n#define APBDEV_PMC_SCRATCH127                  0x71C\n#define APBDEV_PMC_SCRATCH128                  0x720\n#define APBDEV_PMC_SCRATCH129                  0x724\n#define APBDEV_PMC_SCRATCH130                  0x728\n#define APBDEV_PMC_SCRATCH131                  0x72C\n#define APBDEV_PMC_SCRATCH132                  0x730\n#define APBDEV_PMC_SCRATCH133                  0x734\n#define APBDEV_PMC_SCRATCH134                  0x738\n#define APBDEV_PMC_SCRATCH135                  0x73C\n#define APBDEV_PMC_SCRATCH136                  0x740\n#define APBDEV_PMC_SCRATCH137                  0x744\n#define APBDEV_PMC_SCRATCH138                  0x748\n#define APBDEV_PMC_SCRATCH139                  0x74C\n#define APBDEV_PMC_SCRATCH140                  0x750\n#define APBDEV_PMC_SCRATCH141                  0x754\n#define APBDEV_PMC_SCRATCH142                  0x758\n#define APBDEV_PMC_SCRATCH143                  0x75C\n#define APBDEV_PMC_SCRATCH144                  0x760\n#define APBDEV_PMC_SCRATCH145                  0x764\n#define APBDEV_PMC_SCRATCH146                  0x768\n#define APBDEV_PMC_SCRATCH147                  0x76C\n#define APBDEV_PMC_SCRATCH148                  0x770\n#define APBDEV_PMC_SCRATCH149                  0x774\n#define APBDEV_PMC_SCRATCH150                  0x778\n#define APBDEV_PMC_SCRATCH151                  0x77C\n#define APBDEV_PMC_SCRATCH152                  0x780\n#define APBDEV_PMC_SCRATCH153                  0x784\n#define APBDEV_PMC_SCRATCH154                  0x788\n#define APBDEV_PMC_SCRATCH155                  0x78C\n#define APBDEV_PMC_SCRATCH156                  0x790\n#define APBDEV_PMC_SCRATCH157                  0x794\n#define APBDEV_PMC_SCRATCH158                  0x798\n#define APBDEV_PMC_SCRATCH159                  0x79C\n#define APBDEV_PMC_SCRATCH160                  0x7A0\n#define APBDEV_PMC_SCRATCH161                  0x7A4\n#define APBDEV_PMC_SCRATCH162                  0x7A8\n#define APBDEV_PMC_SCRATCH163                  0x7AC\n#define APBDEV_PMC_SCRATCH164                  0x7B0\n#define APBDEV_PMC_SCRATCH165                  0x7B4\n#define APBDEV_PMC_SCRATCH166                  0x7B8\n#define APBDEV_PMC_SCRATCH167                  0x7BC\n#define APBDEV_PMC_SCRATCH168                  0x7C0\n#define APBDEV_PMC_SCRATCH169                  0x7C4\n#define APBDEV_PMC_SCRATCH170                  0x7C8\n#define APBDEV_PMC_SCRATCH171                  0x7CC\n#define APBDEV_PMC_SCRATCH172                  0x7D0\n#define APBDEV_PMC_SCRATCH173                  0x7D4\n#define APBDEV_PMC_SCRATCH174                  0x7D8\n#define APBDEV_PMC_SCRATCH175                  0x7DC\n#define APBDEV_PMC_SCRATCH176                  0x7E0\n#define APBDEV_PMC_SCRATCH177                  0x7E4\n#define APBDEV_PMC_SCRATCH178                  0x7E8\n#define APBDEV_PMC_SCRATCH179                  0x7EC\n#define APBDEV_PMC_SCRATCH180                  0x7F0\n#define APBDEV_PMC_SCRATCH181                  0x7F4\n#define APBDEV_PMC_SCRATCH182                  0x7F8\n#define APBDEV_PMC_SCRATCH183                  0x7FC\n#define APBDEV_PMC_SCRATCH184                  0x800\n#define APBDEV_PMC_SCRATCH185                  0x804\n#define APBDEV_PMC_SCRATCH186                  0x808\n#define APBDEV_PMC_SCRATCH187                  0x80C\n#define APBDEV_PMC_SCRATCH188                  0x810\n#define APBDEV_PMC_SCRATCH189                  0x814\n#define APBDEV_PMC_SCRATCH190                  0x818\n#define APBDEV_PMC_SCRATCH191                  0x81C\n#define APBDEV_PMC_SCRATCH192                  0x820\n#define APBDEV_PMC_SCRATCH193                  0x824\n#define APBDEV_PMC_SCRATCH194                  0x828\n#define APBDEV_PMC_SCRATCH195                  0x82C\n#define APBDEV_PMC_SCRATCH196                  0x830\n#define APBDEV_PMC_SCRATCH197                  0x834\n#define APBDEV_PMC_SCRATCH198                  0x838\n#define APBDEV_PMC_SCRATCH199                  0x83C\n\n#define APBDEV_PMC_SCRATCH200                  0x840\n#define  PMC_NX_PANIC_SAFE_MODE    0x20\n#define  PMC_NX_PANIC_BYPASS_FUSES 0x21\n\n#define APBDEV_PMC_SCRATCH201                  0x844\n#define APBDEV_PMC_SCRATCH202                  0x848\n#define APBDEV_PMC_SCRATCH203                  0x84C\n#define APBDEV_PMC_SCRATCH204                  0x850\n#define APBDEV_PMC_SCRATCH205                  0x854\n#define APBDEV_PMC_SCRATCH206                  0x858\n#define APBDEV_PMC_SCRATCH207                  0x85C\n#define APBDEV_PMC_SCRATCH208                  0x860\n#define APBDEV_PMC_SCRATCH209                  0x864\n#define APBDEV_PMC_SCRATCH210                  0x868\n#define APBDEV_PMC_SCRATCH211                  0x86C\n#define APBDEV_PMC_SCRATCH212                  0x870\n#define APBDEV_PMC_SCRATCH213                  0x874\n#define APBDEV_PMC_SCRATCH214                  0x878\n#define APBDEV_PMC_SCRATCH215                  0x87C\n#define APBDEV_PMC_SCRATCH216                  0x880\n#define APBDEV_PMC_SCRATCH217                  0x884\n#define APBDEV_PMC_SCRATCH218                  0x888\n#define APBDEV_PMC_SCRATCH219                  0x88C\n#define APBDEV_PMC_SCRATCH220                  0x890\n#define APBDEV_PMC_SCRATCH221                  0x894\n#define APBDEV_PMC_SCRATCH222                  0x898\n#define APBDEV_PMC_SCRATCH223                  0x89C\n#define APBDEV_PMC_SCRATCH224                  0x8A0\n#define APBDEV_PMC_SCRATCH225                  0x8A4\n#define APBDEV_PMC_SCRATCH226                  0x8A8\n#define APBDEV_PMC_SCRATCH227                  0x8AC\n#define APBDEV_PMC_SCRATCH228                  0x8B0\n#define APBDEV_PMC_SCRATCH229                  0x8B4\n#define APBDEV_PMC_SCRATCH230                  0x8B8\n#define APBDEV_PMC_SCRATCH231                  0x8BC\n#define APBDEV_PMC_SCRATCH232                  0x8C0\n#define APBDEV_PMC_SCRATCH233                  0x8C4\n#define APBDEV_PMC_SCRATCH234                  0x8C8\n#define APBDEV_PMC_SCRATCH235                  0x8CC\n#define APBDEV_PMC_SCRATCH236                  0x8D0\n#define APBDEV_PMC_SCRATCH237                  0x8D4\n#define APBDEV_PMC_SCRATCH238                  0x8D8\n#define APBDEV_PMC_SCRATCH239                  0x8DC\n#define APBDEV_PMC_SCRATCH240                  0x8E0\n#define APBDEV_PMC_SCRATCH241                  0x8E4\n#define APBDEV_PMC_SCRATCH242                  0x8E8\n#define APBDEV_PMC_SCRATCH243                  0x8EC\n#define APBDEV_PMC_SCRATCH244                  0x8F0\n#define APBDEV_PMC_SCRATCH245                  0x8F4\n#define APBDEV_PMC_SCRATCH246                  0x8F8\n#define APBDEV_PMC_SCRATCH247                  0x8FC\n#define APBDEV_PMC_SCRATCH248                  0x900\n#define APBDEV_PMC_SCRATCH249                  0x904\n#define APBDEV_PMC_SCRATCH250                  0x908\n#define APBDEV_PMC_SCRATCH251                  0x90C\n#define APBDEV_PMC_SCRATCH252                  0x910\n#define APBDEV_PMC_SCRATCH253                  0x914\n#define APBDEV_PMC_SCRATCH254                  0x918\n#define APBDEV_PMC_SCRATCH255                  0x91C\n#define APBDEV_PMC_SCRATCH256                  0x920\n#define APBDEV_PMC_SCRATCH257                  0x924\n#define APBDEV_PMC_SCRATCH258                  0x928\n#define APBDEV_PMC_SCRATCH259                  0x92C\n#define APBDEV_PMC_SCRATCH260                  0x930\n#define APBDEV_PMC_SCRATCH261                  0x934\n#define APBDEV_PMC_SCRATCH262                  0x938\n#define APBDEV_PMC_SCRATCH263                  0x93C\n#define APBDEV_PMC_SCRATCH264                  0x940\n#define APBDEV_PMC_SCRATCH265                  0x944\n#define APBDEV_PMC_SCRATCH266                  0x948\n#define APBDEV_PMC_SCRATCH267                  0x94C\n#define APBDEV_PMC_SCRATCH268                  0x950\n#define APBDEV_PMC_SCRATCH269                  0x954\n#define APBDEV_PMC_SCRATCH270                  0x958\n#define APBDEV_PMC_SCRATCH271                  0x95C\n#define APBDEV_PMC_SCRATCH272                  0x960\n#define APBDEV_PMC_SCRATCH273                  0x964\n#define APBDEV_PMC_SCRATCH274                  0x968\n#define APBDEV_PMC_SCRATCH275                  0x96C\n#define APBDEV_PMC_SCRATCH276                  0x970\n#define APBDEV_PMC_SCRATCH277                  0x974\n#define APBDEV_PMC_SCRATCH278                  0x978\n#define APBDEV_PMC_SCRATCH279                  0x97C\n#define APBDEV_PMC_SCRATCH280                  0x980\n#define APBDEV_PMC_SCRATCH281                  0x984\n#define APBDEV_PMC_SCRATCH282                  0x988\n#define APBDEV_PMC_SCRATCH283                  0x98C\n#define APBDEV_PMC_SCRATCH284                  0x990\n#define APBDEV_PMC_SCRATCH285                  0x994\n#define APBDEV_PMC_SCRATCH286                  0x998\n#define APBDEV_PMC_SCRATCH287                  0x99C\n#define APBDEV_PMC_SCRATCH288                  0x9A0\n#define APBDEV_PMC_SCRATCH289                  0x9A4\n#define APBDEV_PMC_SCRATCH290                  0x9A8\n#define APBDEV_PMC_SCRATCH291                  0x9AC\n#define APBDEV_PMC_SCRATCH292                  0x9B0\n#define APBDEV_PMC_SCRATCH293                  0x9B4\n#define APBDEV_PMC_SCRATCH294                  0x9B8\n#define APBDEV_PMC_SCRATCH295                  0x9BC\n#define APBDEV_PMC_SCRATCH296                  0x9C0\n#define APBDEV_PMC_SCRATCH297                  0x9C4\n#define APBDEV_PMC_SCRATCH298                  0x9C8\n#define APBDEV_PMC_SCRATCH299                  0x9CC\n#define APBDEV_PMC_SECURE_SCRATCH80            0xA98\n#define APBDEV_PMC_SECURE_SCRATCH81            0xA9C\n#define APBDEV_PMC_SECURE_SCRATCH82            0xAA0\n#define APBDEV_PMC_SECURE_SCRATCH83            0xAA4\n#define APBDEV_PMC_SECURE_SCRATCH84            0xAA8\n#define APBDEV_PMC_SECURE_SCRATCH85            0xAAC\n#define APBDEV_PMC_SECURE_SCRATCH86            0xAB0\n#define APBDEV_PMC_SECURE_SCRATCH87            0xAB4\n#define APBDEV_PMC_SECURE_SCRATCH88            0xAB8\n#define APBDEV_PMC_SECURE_SCRATCH89            0xABC\n#define APBDEV_PMC_SECURE_SCRATCH90            0xAC0\n#define APBDEV_PMC_SECURE_SCRATCH91            0xAC4\n#define APBDEV_PMC_SECURE_SCRATCH92            0xAC8\n#define APBDEV_PMC_SECURE_SCRATCH93            0xACC\n#define APBDEV_PMC_SECURE_SCRATCH94            0xAD0\n#define APBDEV_PMC_SECURE_SCRATCH95            0xAD4\n#define APBDEV_PMC_SECURE_SCRATCH96            0xAD8\n#define APBDEV_PMC_SECURE_SCRATCH97            0xADC\n#define APBDEV_PMC_SECURE_SCRATCH98            0xAE0\n#define APBDEV_PMC_SECURE_SCRATCH99            0xAE4\n#define APBDEV_PMC_SECURE_SCRATCH100           0xAE8\n#define APBDEV_PMC_SECURE_SCRATCH101           0xAEC\n#define APBDEV_PMC_SECURE_SCRATCH102           0xAF0\n#define APBDEV_PMC_SECURE_SCRATCH103           0xAF4\n#define APBDEV_PMC_SECURE_SCRATCH104           0xAF8\n#define APBDEV_PMC_SECURE_SCRATCH105           0xAFC\n#define APBDEV_PMC_SECURE_SCRATCH106           0xB00\n#define APBDEV_PMC_SECURE_SCRATCH107           0xB04\n#define APBDEV_PMC_SECURE_SCRATCH108           0xB08\n#define APBDEV_PMC_SECURE_SCRATCH109           0xB0C\n#define APBDEV_PMC_SECURE_SCRATCH110           0xB10\n#define APBDEV_PMC_SECURE_SCRATCH111           0xB14\n#define APBDEV_PMC_SECURE_SCRATCH112           0xB18\n#define APBDEV_PMC_SECURE_SCRATCH113           0xB1C\n#define APBDEV_PMC_SECURE_SCRATCH114           0xB20\n#define APBDEV_PMC_SECURE_SCRATCH115           0xB24\n#define APBDEV_PMC_SECURE_SCRATCH116           0xB28\n#define APBDEV_PMC_SECURE_SCRATCH117           0xB2C\n#define APBDEV_PMC_SECURE_SCRATCH118           0xB30\n#define APBDEV_PMC_SECURE_SCRATCH119           0xB34\n\n/* T210B01 only registers */\n#define APBDEV_PMC_SEC_DISABLE9_B01            0x5C4\n#define APBDEV_PMC_SEC_DISABLE10_B01           0x5C8\n#define APBDEV_PMC_SCRATCH_WRITE_DISABLE0_B01  0xA48\n#define APBDEV_PMC_SCRATCH_WRITE_DISABLE1_B01  0xA4C\n#define APBDEV_PMC_SCRATCH_WRITE_DISABLE2_B01  0xA50\n#define APBDEV_PMC_SCRATCH_WRITE_DISABLE3_B01  0xA54\n#define APBDEV_PMC_SCRATCH_WRITE_DISABLE4_B01  0xA58\n#define APBDEV_PMC_SCRATCH_WRITE_DISABLE5_B01  0xA5C\n#define APBDEV_PMC_SCRATCH_WRITE_DISABLE6_B01  0xA60\n#define APBDEV_PMC_SCRATCH_WRITE_DISABLE7_B01  0xA64\n#define APBDEV_PMC_SCRATCH_WRITE_DISABLE8_B01  0xA68\n#define APBDEV_PMC_SCRATCH_WRITE_DISABLE9_B01  0xA6C\n#define APBDEV_PMC_SCRATCH_WRITE_DISABLE10_B01 0xA70\n#define APBDEV_PMC_SCRATCH_WRITE_LOCK_DISABLE_STICKY_B01 0xA74\n#define APBDEV_PMC_SECURE_SCRATCH120_B01       0xB38\n#define APBDEV_PMC_SECURE_SCRATCH121_B01       0xB3C\n#define APBDEV_PMC_SECURE_SCRATCH122_B01       0xB40\n#define APBDEV_PMC_SECURE_SCRATCH123_B01       0xB44\n\n#define APBDEV_PMC_LED_BREATHING_CTRL_B01      0xB48\n#define  PMC_LED_BREATHING_CTRL_ENABLE      BIT(0)\n#define  PMC_LED_BREATHING_CTRL_COUNTER1_EN BIT(1)\n\n#define APBDEV_PMC_LED_BREATHING_SLOPE_STEPS_B01  0xB4C\n#define APBDEV_PMC_LED_BREATHING_ON_COUNTER_B01   0xB50\n#define APBDEV_PMC_LED_BREATHING_OFF_COUNTER1_B01 0xB54\n#define APBDEV_PMC_LED_BREATHING_OFF_COUNTER0_B01 0xB58\n#define  PMC_LED_BREATHING_COUNTER_HZ 32768\n\n#define APBDEV_PMC_LED_BREATHING_STATUS_B01    0xB5C\n#define  PMC_LED_BREATHING_FSM_STATUS_MASK          0x7\n#define  PMC_LED_BREATHING_FSM_STS_IDLE             0\n#define  PMC_LED_BREATHING_FSM_STS_UP_RAMP          1\n#define  PMC_LED_BREATHING_FSM_STS_PLATEAU          2\n#define  PMC_LED_BREATHING_FSM_STS_DOWN_RAMP        3\n#define  PMC_LED_BREATHING_FSM_STS_SHORT_LOW_PERIOD 4\n#define  PMC_LED_BREATHING_FSM_STS_LONG_LOW_PERIOD  5\n\n#define APBDEV_PMC_SECURE_SCRATCH124_B01       0xB68\n#define APBDEV_PMC_SECURE_SCRATCH125_B01       0xB6C\n#define APBDEV_PMC_SECURE_SCRATCH126_B01       0xB70\n#define APBDEV_PMC_SECURE_SCRATCH127_B01       0xB74\n#define APBDEV_PMC_SECURE_SCRATCH128_B01       0xB78\n#define APBDEV_PMC_SECURE_SCRATCH129_B01       0xB7C\n#define APBDEV_PMC_SECURE_SCRATCH130_B01       0xB80\n#define APBDEV_PMC_SECURE_SCRATCH131_B01       0xB84\n#define APBDEV_PMC_SECURE_SCRATCH132_B01       0xB88\n#define APBDEV_PMC_SECURE_SCRATCH133_B01       0xB8C\n#define APBDEV_PMC_SECURE_SCRATCH134_B01       0xB90\n#define APBDEV_PMC_SECURE_SCRATCH135_B01       0xB94\n#define APBDEV_PMC_SECURE_SCRATCH136_B01       0xB98\n#define APBDEV_PMC_SECURE_SCRATCH137_B01       0xB9C\n#define APBDEV_PMC_SECURE_SCRATCH138_B01       0xBA0\n#define APBDEV_PMC_SECURE_SCRATCH139_B01       0xBA4\n#define APBDEV_PMC_SEC_DISABLE_NS_B01          0xBB0\n#define APBDEV_PMC_SEC_DISABLE2_NS_B01         0xBB4\n#define APBDEV_PMC_SEC_DISABLE3_NS_B01         0xBB8\n#define APBDEV_PMC_SEC_DISABLE4_NS_B01         0xBBC\n#define APBDEV_PMC_SEC_DISABLE5_NS_B01         0xBC0\n#define APBDEV_PMC_SEC_DISABLE6_NS_B01         0xBC4\n#define APBDEV_PMC_SEC_DISABLE7_NS_B01         0xBC8\n#define APBDEV_PMC_SEC_DISABLE8_NS_B01         0xBCC\n#define APBDEV_PMC_SEC_DISABLE9_NS_B01         0xBD0\n#define APBDEV_PMC_SEC_DISABLE10_NS_B01        0xBD4\n\n#define APBDEV_PMC_TZRAM_PWR_CNTRL_B01         0xBE8\n#define  PMC_TZRAM_PWR_CNTRL_SD BIT(0)\n\n#define APBDEV_PMC_TZRAM_SEC_DISABLE_B01       0xBEC\n#define APBDEV_PMC_TZRAM_NON_SEC_DISABLE_B01   0xBF0\n#define  PMC_TZRAM_DISABLE_REG_WRITE BIT(0)\n#define  PMC_TZRAM_DISABLE_REG_READ  BIT(1)\n\ntypedef struct _pmc_regs_t210_t  {\n/* 0x000 */\tu32 pmc_cntrl;\n/* 0x004 */\tu32 pmc_sec_disable;\n/* 0x008 */\tu32 pmc_pmc_swrst;\n/* 0x00c */\tu32 pmc_wake_mask;\n/* 0x010 */\tu32 pmc_wake_lvl;\n/* 0x014 */\tu32 pmc_wake_status;\n/* 0x018 */\tu32 pmc_sw_wake_status;\n/* 0x01c */\tu32 pmc_dpd_pads_oride;\n/* 0x020 */\tu32 pmc_dpd_sample;\n/* 0x024 */\tu32 pmc_dpd_enable;\n/* 0x028 */\tu32 pmc_pwrgate_timer_off;\n/* 0x02c */\tu32 pmc_clamp_status;\n/* 0x030 */\tu32 pmc_pwrgate_toggle;\n/* 0x034 */\tu32 pmc_remove_clamping_cmd;\n/* 0x038 */\tu32 pmc_pwrgate_status;\n/* 0x03c */\tu32 pmc_pwrgood_timer;\n/* 0x040 */\tu32 pmc_blink_timer;\n/* 0x044 */\tu32 pmc_no_iopower;\n/* 0x048 */\tu32 pmc_pwr_det;\n/* 0x04c */\tu32 pmc_pwr_det_latch;\n/* 0x050 */\tu32 pmc_scratch0;\n/* 0x054 */\tu32 pmc_scratch1;\n/* 0x058 */\tu32 pmc_scratch2;\n/* 0x05c */\tu32 pmc_scratch3;\n/* 0x060 */\tu32 pmc_scratch4;\n/* 0x064 */\tu32 pmc_scratch5;\n/* 0x068 */\tu32 pmc_scratch6;\n/* 0x06c */\tu32 pmc_scratch7;\n/* 0x070 */\tu32 pmc_scratch8;\n/* 0x074 */\tu32 pmc_scratch9;\n/* 0x078 */\tu32 pmc_scratch10;\n/* 0x07c */\tu32 pmc_scratch11;\n/* 0x080 */\tu32 pmc_scratch12;\n/* 0x084 */\tu32 pmc_scratch13;\n/* 0x088 */\tu32 pmc_scratch14;\n/* 0x08c */\tu32 pmc_scratch15;\n/* 0x090 */\tu32 pmc_scratch16;\n/* 0x094 */\tu32 pmc_scratch17;\n/* 0x098 */\tu32 pmc_scratch18;\n/* 0x09c */\tu32 pmc_scratch19;\n/* 0x0a0 */\tu32 pmc_scratch20; // ODM data/config scratch.\n/* 0x0a4 */\tu32 pmc_scratch21;\n/* 0x0a8 */\tu32 pmc_scratch22;\n/* 0x0ac */\tu32 pmc_scratch23;\n/* 0x0b0 */\tu32 pmc_secure_scratch0;\n/* 0x0b4 */\tu32 pmc_secure_scratch1;\n/* 0x0b8 */\tu32 pmc_secure_scratch2;\n/* 0x0bc */\tu32 pmc_secure_scratch3;\n/* 0x0c0 */\tu32 pmc_secure_scratch4;\n/* 0x0c4 */\tu32 pmc_secure_scratch5;\n/* 0x0c8 */\tu32 pmc_cpupwrgood_timer;\n/* 0x0cc */\tu32 pmc_cpupwroff_timer;\n/* 0x0d0 */\tu32 pmc_pg_mask;\n/* 0x0d4 */\tu32 pmc_pg_mask_1;\n/* 0x0d8 */\tu32 pmc_auto_wake_lvl;\n/* 0x0dc */\tu32 pmc_auto_wake_lvl_mask;\n/* 0x0e0 */\tu32 pmc_wake_delay;\n/* 0x0e4 */\tu32 pmc_pwr_det_val;\n/* 0x0e8 */\tu32 pmc_ddr_pwr;\n/* 0x0ec */\tu32 pmc_usb_debounce_del;\n/* 0x0f0 */\tu32 pmc_usb_ao;\n/* 0x0f4 */\tu32 pmc_crypto_op;\n/* 0x0f8 */\tu32 pmc_pllp_wb0_override;\n/* 0x0fc */\tu32 pmc_scratch24;\n/* 0x100 */\tu32 pmc_scratch25;\n/* 0x104 */\tu32 pmc_scratch26;\n/* 0x108 */\tu32 pmc_scratch27;\n/* 0x10c */\tu32 pmc_scratch28;\n/* 0x110 */\tu32 pmc_scratch29;\n/* 0x114 */\tu32 pmc_scratch30;\n/* 0x118 */\tu32 pmc_scratch31;\n/* 0x11c */\tu32 pmc_scratch32;\n/* 0x120 */\tu32 pmc_scratch33;\n/* 0x124 */\tu32 pmc_scratch34;\n/* 0x128 */\tu32 pmc_scratch35;\n/* 0x12c */\tu32 pmc_scratch36;\n/* 0x130 */\tu32 pmc_scratch37;\n/* 0x134 */\tu32 pmc_scratch38;\n/* 0x138 */\tu32 pmc_scratch39;\n/* 0x13c */\tu32 pmc_scratch40;\n/* 0x140 */\tu32 pmc_scratch41;\n/* 0x144 */\tu32 pmc_scratch42;\n/* 0x148 */\tu32 pmc_bondout_mirror0;\n/* 0x14c */\tu32 pmc_bondout_mirror1;\n/* 0x150 */\tu32 pmc_bondout_mirror2;\n/* 0x154 */\tu32 pmc_sys_33v_en;\n/* 0x158 */\tu32 pmc_bondout_mirror_access;\n/* 0x15c */\tu32 pmc_gate;\n/* 0x160 */\tu32 pmc_wake2_mask;\n/* 0x164 */\tu32 pmc_wake2_lvl;\n/* 0x168 */\tu32 pmc_wake2_status;\n/* 0x16c */\tu32 pmc_sw_wake2_status;\n/* 0x170 */\tu32 pmc_auto_wake2_lvl_mask;\n/* 0x174 */\tu32 pmc_pg_mask_2;\n/* 0x178 */\tu32 pmc_pg_mask_ce1;\n/* 0x17c */\tu32 pmc_pg_mask_ce2;\n/* 0x180 */\tu32 pmc_pg_mask_ce3;\n/* 0x184 */\tu32 pmc_pwrgate_timer_ce_0;\n/* 0x188 */\tu32 pmc_pwrgate_timer_ce_1;\n/* 0x18c */\tu32 pmc_pwrgate_timer_ce_2;\n/* 0x190 */\tu32 pmc_pwrgate_timer_ce_3;\n/* 0x194 */\tu32 pmc_pwrgate_timer_ce_4;\n/* 0x198 */\tu32 pmc_pwrgate_timer_ce_5;\n/* 0x19c */\tu32 pmc_pwrgate_timer_ce_6;\n/* 0x1a0 */\tu32 pmc_pcx_edpd_cntrl;\n/* 0x1a4 */\tu32 pmc_osc_edpd_over;\n/* 0x1a8 */\tu32 pmc_clk_out_cntrl;\n/* 0x1ac */\tu32 pmc_sata_pwrgt;\n/* 0x1b0 */\tu32 pmc_sensor_ctrl;\n/* 0x1b4 */\tu32 pmc_rst_status;\n/* 0x1b8 */\tu32 pmc_io_dpd_req;\n/* 0x1bc */\tu32 pmc_io_dpd_status;\n/* 0x1c0 */\tu32 pmc_io_dpd2_req;\n/* 0x1c4 */\tu32 pmc_io_dpd2_status;\n/* 0x1c8 */\tu32 pmc_sel_dpd_tim;\n/* 0x1cc */\tu32 pmc_vddp_sel;\n/* 0x1d0 */\tu32 pmc_ddr_cfg;\n/* 0x1d4 */\tu32 pmc_e_no_vttgen;\n/* 0x1d8 */\tu32 rsvd_1d8;\n/* 0x1dc */\tu32 pmc_pllm_wb0_override_freq;\n/* 0x1e0 */\tu32 pmc_test_pwrgate;\n/* 0x1e4 */\tu32 pmc_pwrgate_timer_mult;\n/* 0x1e8 */\tu32 pmc_dsi_sel_dpd;\n/* 0x1ec */\tu32 pmc_utmip_uhsic_triggers;\n/* 0x1f0 */\tu32 pmc_utmip_uhsic_saved_state;\n/* 0x1f4 */\tu32 rsvd_1f4;\n/* 0x1f8 */\tu32 pmc_utmip_term_pad_cfg;\n/* 0x1fc */\tu32 pmc_utmip_uhsic_sleep_cfg;\n/* 0x200 */\tu32 pmc_utmip_uhsic_sleepwalk_cfg;\n/* 0x204 */\tu32 pmc_utmip_sleepwalk_p0;\n/* 0x208 */\tu32 pmc_utmip_sleepwalk_p1;\n/* 0x20c */\tu32 pmc_utmip_sleepwalk_p2;\n/* 0x210 */\tu32 pmc_uhsic_sleepwalk_p0;\n/* 0x214 */\tu32 pmc_utmip_uhsic_status;\n/* 0x218 */\tu32 pmc_utmip_uhsic_fake;\n/* 0x21c */\tu32 pmc_bondout_mirror3;\n/* 0x220 */\tu32 pmc_bondout_mirror4;\n/* 0x224 */\tu32 pmc_secure_scratch6;\n/* 0x228 */\tu32 pmc_secure_scratch7;\n/* 0x22c */\tu32 pmc_scratch43;\n/* 0x230 */\tu32 pmc_scratch44;\n/* 0x234 */\tu32 pmc_scratch45;\n/* 0x238 */\tu32 pmc_scratch46;\n/* 0x23c */\tu32 pmc_scratch47;\n/* 0x240 */\tu32 pmc_scratch48;\n/* 0x244 */\tu32 pmc_scratch49;\n/* 0x248 */\tu32 pmc_scratch50;\n/* 0x24c */\tu32 pmc_scratch51;\n/* 0x250 */\tu32 pmc_scratch52;\n/* 0x254 */\tu32 pmc_scratch53;\n/* 0x258 */\tu32 pmc_scratch54;\n/* 0x25c */\tu32 pmc_scratch55;\n/* 0x260 */\tu32 pmc_scratch0_eco;\n/* 0x264 */\tu32 pmc_por_dpd_ctrl;\n/* 0x268 */\tu32 pmc_scratch2_eco;\n/* 0x26c */\tu32 pmc_utmip_uhsic_line_wakeup;\n/* 0x270 */\tu32 pmc_utmip_bias_master_cntrl;\n/* 0x274 */\tu32 pmc_utmip_master_config;\n/* 0x278 */\tu32 pmc_td_pwrgate_inter_part_timer;\n/* 0x27c */\tu32 pmc_utmip_uhsic2_triggers;\n/* 0x280 */\tu32 pmc_utmip_uhsic2_saved_state;\n/* 0x284 */\tu32 pmc_utmip_uhsic2_sleep_cfg;\n/* 0x288 */\tu32 pmc_utmip_uhsic2_sleepwalk_cfg;\n/* 0x28c */\tu32 pmc_uhsic2_sleepwalk_p1;\n/* 0x290 */\tu32 pmc_utmip_uhsic2_status;\n/* 0x294 */\tu32 pmc_utmip_uhsic2_fake;\n/* 0x298 */\tu32 pmc_utmip_uhsic2_line_wakeup;\n/* 0x29c */\tu32 pmc_utmip_master2_config;\n/* 0x2a0 */\tu32 pmc_utmip_uhsic_rpd_cfg;\n/* 0x2a4 */\tu32 pmc_pg_mask_ce0;\n/* 0x2a8 */\tu32 pmc_pg_mask_3;\n/* 0x2ac */\tu32 pmc_pg_mask_4;\n/* 0x2b0 */\tu32 pmc_pllm_wb0_override2;\n/* 0x2b4 */\tu32 pmc_tsc_mult;\n/* 0x2b8 */\tu32 pmc_cpu_vsense_override;\n/* 0x2bc */\tu32 pmc_glb_amap_cfg;\n/* 0x2c0 */\tu32 pmc_sticky_bits;\n/* 0x2c4 */\tu32 pmc_sec_disable2;\n/* 0x2c8 */\tu32 pmc_weak_bias;\n/* 0x2cc */\tu32 pmc_reg_short;\n/* 0x2d0 */\tu32 pmc_pg_mask_andor;\n/* 0x2d4 */\tu32 pmc_gpu_rg_cntrl;\n/* 0x2d8 */\tu32 pmc_sec_disable3;\n/* 0x2dc */\tu32 pmc_pg_mask_5;\n/* 0x2e0 */\tu32 pmc_pg_mask_6;\n/* 0x2e4 */\tu32 rsvd_2e4[7];\n/* 0x300 */\tu32 pmc_secure_scratch8;\n/* 0x304 */\tu32 pmc_secure_scratch9;\n/* 0x308 */\tu32 pmc_secure_scratch10;\n/* 0x30c */\tu32 pmc_secure_scratch11;\n/* 0x310 */\tu32 pmc_secure_scratch12;\n/* 0x314 */\tu32 pmc_secure_scratch13;\n/* 0x318 */\tu32 pmc_secure_scratch14;\n/* 0x31c */\tu32 pmc_secure_scratch15;\n/* 0x320 */\tu32 pmc_secure_scratch16;\n/* 0x324 */\tu32 pmc_secure_scratch17;\n/* 0x328 */\tu32 pmc_secure_scratch18;\n/* 0x32c */\tu32 pmc_secure_scratch19;\n/* 0x330 */\tu32 pmc_secure_scratch20;\n/* 0x334 */\tu32 pmc_secure_scratch21;\n/* 0x338 */\tu32 pmc_secure_scratch22; // AArch32 reset address.\n/* 0x33c */\tu32 pmc_secure_scratch23;\n/* 0x340 */\tu32 pmc_secure_scratch24;\n/* 0x344 */\tu32 pmc_secure_scratch25;\n/* 0x348 */\tu32 pmc_secure_scratch26;\n/* 0x34c */\tu32 pmc_secure_scratch27;\n/* 0x350 */\tu32 pmc_secure_scratch28;\n/* 0x354 */\tu32 pmc_secure_scratch29;\n/* 0x358 */\tu32 pmc_secure_scratch30;\n/* 0x35c */\tu32 pmc_secure_scratch31;\n/* 0x360 */\tu32 pmc_secure_scratch32;\n/* 0x364 */\tu32 pmc_secure_scratch33;\n/* 0x368 */\tu32 pmc_secure_scratch34; // AArch64 reset address.\n/* 0x36c */\tu32 pmc_secure_scratch35; // AArch64 reset hi-address.\n/* 0x370 */\tu32 pmc_secure_scratch36;\n/* 0x374 */\tu32 pmc_secure_scratch37;\n/* 0x378 */\tu32 pmc_secure_scratch38;\n/* 0x37c */\tu32 pmc_secure_scratch39;\n/* 0x380 */\tu32 pmc_secure_scratch40;\n/* 0x384 */\tu32 pmc_secure_scratch41;\n/* 0x388 */\tu32 pmc_secure_scratch42;\n/* 0x38c */\tu32 pmc_secure_scratch43;\n/* 0x390 */\tu32 pmc_secure_scratch44;\n/* 0x394 */\tu32 pmc_secure_scratch45;\n/* 0x398 */\tu32 pmc_secure_scratch46;\n/* 0x39c */\tu32 pmc_secure_scratch47;\n/* 0x3a0 */\tu32 pmc_secure_scratch48;\n/* 0x3a4 */\tu32 pmc_secure_scratch49;\n/* 0x3a8 */\tu32 pmc_secure_scratch50;\n/* 0x3ac */\tu32 pmc_secure_scratch51;\n/* 0x3b0 */\tu32 pmc_secure_scratch52;\n/* 0x3b4 */\tu32 pmc_secure_scratch53;\n/* 0x3b8 */\tu32 pmc_secure_scratch54;\n/* 0x3bc */\tu32 pmc_secure_scratch55;\n/* 0x3c0 */\tu32 pmc_secure_scratch56;\n/* 0x3c4 */\tu32 pmc_secure_scratch57;\n/* 0x3c8 */\tu32 pmc_secure_scratch58;\n/* 0x3cc */\tu32 pmc_secure_scratch59;\n/* 0x3d0 */\tu32 pmc_secure_scratch60;\n/* 0x3d4 */\tu32 pmc_secure_scratch61;\n/* 0x3d8 */\tu32 pmc_secure_scratch62;\n/* 0x3dc */\tu32 pmc_secure_scratch63;\n/* 0x3e0 */\tu32 pmc_secure_scratch64;\n/* 0x3e4 */\tu32 pmc_secure_scratch65;\n/* 0x3e8 */\tu32 pmc_secure_scratch66;\n/* 0x3ec */\tu32 pmc_secure_scratch67;\n/* 0x3f0 */\tu32 pmc_secure_scratch68;\n/* 0x3f4 */\tu32 pmc_secure_scratch69;\n/* 0x3f8 */\tu32 pmc_secure_scratch70;\n/* 0x3fc */\tu32 pmc_secure_scratch71;\n/* 0x400 */\tu32 pmc_secure_scratch72;\n/* 0x404 */\tu32 pmc_secure_scratch73;\n/* 0x408 */\tu32 pmc_secure_scratch74;\n/* 0x40c */\tu32 pmc_secure_scratch75;\n/* 0x410 */\tu32 pmc_secure_scratch76;\n/* 0x414 */\tu32 pmc_secure_scratch77;\n/* 0x418 */\tu32 pmc_secure_scratch78;\n/* 0x41c */\tu32 pmc_secure_scratch79;\n/* 0x420 */\tu32 rsvd_420[8];\n/* 0x440 */\tu32 pmc_cntrl2;\n/* 0x444 */\tu32 pmc_io_dpd_off_mask;\n/* 0x448 */\tu32 pmc_io_dpd2_off_mask;\n/* 0x44c */\tu32 pmc_event_counter;\n/* 0x450 */\tu32 pmc_fuse_control;\n/* 0x454 */\tu32 pmc_scratch1_eco;\n/* 0x458 */\tu32 rsvd_458;\n/* 0x45c */\tu32 pmc_io_dpd3_req;\n/* 0x460 */\tu32 pmc_io_dpd3_status;\n/* 0x464 */\tu32 pmc_io_dpd4_req;\n/* 0x468 */\tu32 pmc_io_dpd4_status;\n/* 0x46c */\tu32 rsvd_46c[2];\n/* 0x474 */\tu32 pmc_direct_thermtrip_cfg;\n/* 0x478 */\tu32 pmc_tsosc_delay;\n/* 0x47c */\tu32 pmc_set_sw_clamp;\n/* 0x480 */\tu32 pmc_debug_authentication;\n/* 0x484 */\tu32 pmc_aotag_cfg;\n/* 0x488 */\tu32 pmc_aotag_thresh1_cfg;\n/* 0x48c */\tu32 pmc_aotag_thresh2_cfg;\n/* 0x490 */\tu32 pmc_aotag_thresh3_cfg;\n/* 0x494 */\tu32 pmc_aotag_status;\n/* 0x498 */\tu32 pmc_aotag_security;\n/* 0x49c */\tu32 pmc_tsensor_config0;\n/* 0x4a0 */\tu32 pmc_tsensor_config1;\n/* 0x4a4 */\tu32 pmc_tsensor_config2;\n/* 0x4a8 */\tu32 pmc_tsensor_status0;\n/* 0x4ac */\tu32 pmc_tsensor_status1;\n/* 0x4b0 */\tu32 pmc_tsensor_status2;\n/* 0x4b4 */\tu32 pmc_tsensor_pdiv;\n/* 0x4b8 */\tu32 pmc_aotag_intr_en;\n/* 0x4bc */\tu32 pmc_aotag_intr_dis;\n/* 0x4c0 */\tu32 pmc_utmip_pad_cfg0;\n/* 0x4c4 */\tu32 pmc_utmip_pad_cfg1;\n/* 0x4c8 */\tu32 pmc_utmip_pad_cfg2;\n/* 0x4cc */\tu32 pmc_utmip_pad_cfg3;\n/* 0x4d0 */\tu32 pmc_utmip_uhsic_sleep_cfg1;\n/* 0x4d4 */\tu32 pmc_cc4_hvc_control;\n/* 0x4d8 */\tu32 pmc_wake_debounce_en;\n/* 0x4dc */\tu32 pmc_ramdump_ctl_status;\n/* 0x4e0 */\tu32 pmc_utmip_sleepwalk_p3;\n/* 0x4e4 */\tu32 pmc_ddr_cntrl;\n/* 0x4e8 */\tu32 rsvd_4e8[50];\n/* 0x5b0 */\tu32 pmc_sec_disable4;\n/* 0x5b4 */\tu32 pmc_sec_disable5;\n/* 0x5b8 */\tu32 pmc_sec_disable6;\n/* 0x5bc */\tu32 pmc_sec_disable7;\n/* 0x5c0 */\tu32 pmc_sec_disable8;\n/* 0x5c4 */\tu32 pmc_sec_disable9_b01;\n/* 0x5c8 */\tu32 pmc_sec_disable10_b01;\n/* 0x5cc */\tu32 rsvd_5cc[13];\n/* 0x600 */\tu32 pmc_scratch56;\n/* 0x604 */\tu32 pmc_scratch57;\n/* 0x608 */\tu32 pmc_scratch58;\n/* 0x60c */\tu32 pmc_scratch59;\n/* 0x610 */\tu32 pmc_scratch60;\n/* 0x614 */\tu32 pmc_scratch61;\n/* 0x618 */\tu32 pmc_scratch62;\n/* 0x61c */\tu32 pmc_scratch63;\n/* 0x620 */\tu32 pmc_scratch64;\n/* 0x624 */\tu32 pmc_scratch65;\n/* 0x628 */\tu32 pmc_scratch66;\n/* 0x62c */\tu32 pmc_scratch67;\n/* 0x630 */\tu32 pmc_scratch68;\n/* 0x634 */\tu32 pmc_scratch69;\n/* 0x638 */\tu32 pmc_scratch70;\n/* 0x63c */\tu32 pmc_scratch71;\n/* 0x640 */\tu32 pmc_scratch72;\n/* 0x644 */\tu32 pmc_scratch73;\n/* 0x648 */\tu32 pmc_scratch74;\n/* 0x64c */\tu32 pmc_scratch75;\n/* 0x650 */\tu32 pmc_scratch76;\n/* 0x654 */\tu32 pmc_scratch77;\n/* 0x658 */\tu32 pmc_scratch78;\n/* 0x65c */\tu32 pmc_scratch79;\n/* 0x660 */\tu32 pmc_scratch80;\n/* 0x664 */\tu32 pmc_scratch81;\n/* 0x668 */\tu32 pmc_scratch82;\n/* 0x66c */\tu32 pmc_scratch83;\n/* 0x670 */\tu32 pmc_scratch84;\n/* 0x674 */\tu32 pmc_scratch85;\n/* 0x678 */\tu32 pmc_scratch86;\n/* 0x67c */\tu32 pmc_scratch87;\n/* 0x680 */\tu32 pmc_scratch88;\n/* 0x684 */\tu32 pmc_scratch89;\n/* 0x688 */\tu32 pmc_scratch90;\n/* 0x68c */\tu32 pmc_scratch91;\n/* 0x690 */\tu32 pmc_scratch92;\n/* 0x694 */\tu32 pmc_scratch93;\n/* 0x698 */\tu32 pmc_scratch94;\n/* 0x69c */\tu32 pmc_scratch95;\n/* 0x6a0 */\tu32 pmc_scratch96;\n/* 0x6a4 */\tu32 pmc_scratch97;\n/* 0x6a8 */\tu32 pmc_scratch98;\n/* 0x6ac */\tu32 pmc_scratch99;\n/* 0x6b0 */\tu32 pmc_scratch100;\n/* 0x6b4 */\tu32 pmc_scratch101;\n/* 0x6b8 */\tu32 pmc_scratch102;\n/* 0x6bc */\tu32 pmc_scratch103;\n/* 0x6c0 */\tu32 pmc_scratch104;\n/* 0x6c4 */\tu32 pmc_scratch105;\n/* 0x6c8 */\tu32 pmc_scratch106;\n/* 0x6cc */\tu32 pmc_scratch107;\n/* 0x6d0 */\tu32 pmc_scratch108;\n/* 0x6d4 */\tu32 pmc_scratch109;\n/* 0x6d8 */\tu32 pmc_scratch110;\n/* 0x6dc */\tu32 pmc_scratch111;\n/* 0x6e0 */\tu32 pmc_scratch112;\n/* 0x6e4 */\tu32 pmc_scratch113;\n/* 0x6e8 */\tu32 pmc_scratch114;\n/* 0x6ec */\tu32 pmc_scratch115;\n/* 0x6f0 */\tu32 pmc_scratch116;\n/* 0x6f4 */\tu32 pmc_scratch117;\n/* 0x6f8 */\tu32 pmc_scratch118;\n/* 0x6fc */\tu32 pmc_scratch119;\n/* 0x700 */\tu32 pmc_scratch120;\n/* 0x704 */\tu32 pmc_scratch121;\n/* 0x708 */\tu32 pmc_scratch122;\n/* 0x70c */\tu32 pmc_scratch123;\n/* 0x710 */\tu32 pmc_scratch124;\n/* 0x714 */\tu32 pmc_scratch125;\n/* 0x718 */\tu32 pmc_scratch126;\n/* 0x71c */\tu32 pmc_scratch127;\n/* 0x720 */\tu32 pmc_scratch128;\n/* 0x724 */\tu32 pmc_scratch129;\n/* 0x728 */\tu32 pmc_scratch130;\n/* 0x72c */\tu32 pmc_scratch131;\n/* 0x730 */\tu32 pmc_scratch132;\n/* 0x734 */\tu32 pmc_scratch133;\n/* 0x738 */\tu32 pmc_scratch134;\n/* 0x73c */\tu32 pmc_scratch135;\n/* 0x740 */\tu32 pmc_scratch136;\n/* 0x744 */\tu32 pmc_scratch137;\n/* 0x748 */\tu32 pmc_scratch138;\n/* 0x74c */\tu32 pmc_scratch139;\n/* 0x750 */\tu32 pmc_scratch140;\n/* 0x754 */\tu32 pmc_scratch141;\n/* 0x758 */\tu32 pmc_scratch142;\n/* 0x75c */\tu32 pmc_scratch143;\n/* 0x760 */\tu32 pmc_scratch144;\n/* 0x764 */\tu32 pmc_scratch145;\n/* 0x768 */\tu32 pmc_scratch146;\n/* 0x76c */\tu32 pmc_scratch147;\n/* 0x770 */\tu32 pmc_scratch148;\n/* 0x774 */\tu32 pmc_scratch149;\n/* 0x778 */\tu32 pmc_scratch150;\n/* 0x77c */\tu32 pmc_scratch151;\n/* 0x780 */\tu32 pmc_scratch152;\n/* 0x784 */\tu32 pmc_scratch153;\n/* 0x788 */\tu32 pmc_scratch154;\n/* 0x78c */\tu32 pmc_scratch155;\n/* 0x790 */\tu32 pmc_scratch156;\n/* 0x794 */\tu32 pmc_scratch157;\n/* 0x798 */\tu32 pmc_scratch158;\n/* 0x79c */\tu32 pmc_scratch159;\n/* 0x7a0 */\tu32 pmc_scratch160;\n/* 0x7a4 */\tu32 pmc_scratch161;\n/* 0x7a8 */\tu32 pmc_scratch162;\n/* 0x7ac */\tu32 pmc_scratch163;\n/* 0x7b0 */\tu32 pmc_scratch164;\n/* 0x7b4 */\tu32 pmc_scratch165;\n/* 0x7b8 */\tu32 pmc_scratch166;\n/* 0x7bc */\tu32 pmc_scratch167;\n/* 0x7c0 */\tu32 pmc_scratch168;\n/* 0x7c4 */\tu32 pmc_scratch169;\n/* 0x7c8 */\tu32 pmc_scratch170;\n/* 0x7cc */\tu32 pmc_scratch171;\n/* 0x7d0 */\tu32 pmc_scratch172;\n/* 0x7d4 */\tu32 pmc_scratch173;\n/* 0x7d8 */\tu32 pmc_scratch174;\n/* 0x7dc */\tu32 pmc_scratch175;\n/* 0x7e0 */\tu32 pmc_scratch176;\n/* 0x7e4 */\tu32 pmc_scratch177;\n/* 0x7e8 */\tu32 pmc_scratch178;\n/* 0x7ec */\tu32 pmc_scratch179;\n/* 0x7f0 */\tu32 pmc_scratch180;\n/* 0x7f4 */\tu32 pmc_scratch181;\n/* 0x7f8 */\tu32 pmc_scratch182;\n/* 0x7fc */\tu32 pmc_scratch183;\n/* 0x800 */\tu32 pmc_scratch184;\n/* 0x804 */\tu32 pmc_scratch185;\n/* 0x808 */\tu32 pmc_scratch186;\n/* 0x80c */\tu32 pmc_scratch187;\n/* 0x810 */\tu32 pmc_scratch188;\n/* 0x814 */\tu32 pmc_scratch189;\n/* 0x818 */\tu32 pmc_scratch190;\n/* 0x81c */\tu32 pmc_scratch191;\n/* 0x820 */\tu32 pmc_scratch192;\n/* 0x824 */\tu32 pmc_scratch193;\n/* 0x828 */\tu32 pmc_scratch194;\n/* 0x82c */\tu32 pmc_scratch195;\n/* 0x830 */\tu32 pmc_scratch196;\n/* 0x834 */\tu32 pmc_scratch197;\n/* 0x838 */\tu32 pmc_scratch198;\n/* 0x83c */\tu32 pmc_scratch199;\n/* 0x840 */\tu32 pmc_scratch200;\n/* 0x844 */\tu32 pmc_scratch201;\n/* 0x848 */\tu32 pmc_scratch202;\n/* 0x84c */\tu32 pmc_scratch203;\n/* 0x850 */\tu32 pmc_scratch204;\n/* 0x854 */\tu32 pmc_scratch205;\n/* 0x858 */\tu32 pmc_scratch206;\n/* 0x85c */\tu32 pmc_scratch207;\n/* 0x860 */\tu32 pmc_scratch208;\n/* 0x864 */\tu32 pmc_scratch209;\n/* 0x868 */\tu32 pmc_scratch210;\n/* 0x86c */\tu32 pmc_scratch211;\n/* 0x870 */\tu32 pmc_scratch212;\n/* 0x874 */\tu32 pmc_scratch213;\n/* 0x878 */\tu32 pmc_scratch214;\n/* 0x87c */\tu32 pmc_scratch215;\n/* 0x880 */\tu32 pmc_scratch216;\n/* 0x884 */\tu32 pmc_scratch217;\n/* 0x888 */\tu32 pmc_scratch218;\n/* 0x88c */\tu32 pmc_scratch219;\n/* 0x890 */\tu32 pmc_scratch220;\n/* 0x894 */\tu32 pmc_scratch221;\n/* 0x898 */\tu32 pmc_scratch222;\n/* 0x89c */\tu32 pmc_scratch223;\n/* 0x8a0 */\tu32 pmc_scratch224;\n/* 0x8a4 */\tu32 pmc_scratch225;\n/* 0x8a8 */\tu32 pmc_scratch226;\n/* 0x8ac */\tu32 pmc_scratch227;\n/* 0x8b0 */\tu32 pmc_scratch228;\n/* 0x8b4 */\tu32 pmc_scratch229;\n/* 0x8b8 */\tu32 pmc_scratch230;\n/* 0x8bc */\tu32 pmc_scratch231;\n/* 0x8c0 */\tu32 pmc_scratch232;\n/* 0x8c4 */\tu32 pmc_scratch233;\n/* 0x8c8 */\tu32 pmc_scratch234;\n/* 0x8cc */\tu32 pmc_scratch235;\n/* 0x8d0 */\tu32 pmc_scratch236;\n/* 0x8d4 */\tu32 pmc_scratch237;\n/* 0x8d8 */\tu32 pmc_scratch238;\n/* 0x8dc */\tu32 pmc_scratch239;\n/* 0x8e0 */\tu32 pmc_scratch240;\n/* 0x8e4 */\tu32 pmc_scratch241;\n/* 0x8e8 */\tu32 pmc_scratch242;\n/* 0x8ec */\tu32 pmc_scratch243;\n/* 0x8f0 */\tu32 pmc_scratch244;\n/* 0x8f4 */\tu32 pmc_scratch245;\n/* 0x8f8 */\tu32 pmc_scratch246;\n/* 0x8fc */\tu32 pmc_scratch247;\n/* 0x900 */\tu32 pmc_scratch248;\n/* 0x904 */\tu32 pmc_scratch249;\n/* 0x908 */\tu32 pmc_scratch250;\n/* 0x90c */\tu32 pmc_scratch251;\n/* 0x910 */\tu32 pmc_scratch252;\n/* 0x914 */\tu32 pmc_scratch253;\n/* 0x918 */\tu32 pmc_scratch254;\n/* 0x91c */\tu32 pmc_scratch255;\n/* 0x920 */\tu32 pmc_scratch256;\n/* 0x924 */\tu32 pmc_scratch257;\n/* 0x928 */\tu32 pmc_scratch258;\n/* 0x92c */\tu32 pmc_scratch259;\n/* 0x930 */\tu32 pmc_scratch260;\n/* 0x934 */\tu32 pmc_scratch261;\n/* 0x938 */\tu32 pmc_scratch262;\n/* 0x93c */\tu32 pmc_scratch263;\n/* 0x940 */\tu32 pmc_scratch264;\n/* 0x944 */\tu32 pmc_scratch265;\n/* 0x948 */\tu32 pmc_scratch266;\n/* 0x94c */\tu32 pmc_scratch267;\n/* 0x950 */\tu32 pmc_scratch268;\n/* 0x954 */\tu32 pmc_scratch269;\n/* 0x958 */\tu32 pmc_scratch270;\n/* 0x95c */\tu32 pmc_scratch271;\n/* 0x960 */\tu32 pmc_scratch272;\n/* 0x964 */\tu32 pmc_scratch273;\n/* 0x968 */\tu32 pmc_scratch274;\n/* 0x96c */\tu32 pmc_scratch275;\n/* 0x970 */\tu32 pmc_scratch276;\n/* 0x974 */\tu32 pmc_scratch277;\n/* 0x978 */\tu32 pmc_scratch278;\n/* 0x97c */\tu32 pmc_scratch279;\n/* 0x980 */\tu32 pmc_scratch280;\n/* 0x984 */\tu32 pmc_scratch281;\n/* 0x988 */\tu32 pmc_scratch282;\n/* 0x98c */\tu32 pmc_scratch283;\n/* 0x990 */\tu32 pmc_scratch284;\n/* 0x994 */\tu32 pmc_scratch285;\n/* 0x998 */\tu32 pmc_scratch286;\n/* 0x99c */\tu32 pmc_scratch287;\n/* 0x9a0 */\tu32 pmc_scratch288;\n/* 0x9a4 */\tu32 pmc_scratch289;\n/* 0x9a8 */\tu32 pmc_scratch290;\n/* 0x9ac */\tu32 pmc_scratch291;\n/* 0x9b0 */\tu32 pmc_scratch292;\n/* 0x9b4 */\tu32 pmc_scratch293;\n/* 0x9b8 */\tu32 pmc_scratch294;\n/* 0x9bc */\tu32 pmc_scratch295;\n/* 0x9c0 */\tu32 pmc_scratch296;\n/* 0x9c4 */\tu32 pmc_scratch297;\n/* 0x9c8 */\tu32 pmc_scratch298;\n/* 0x9cc */\tu32 pmc_scratch299;\n/* 0x9d0 */\tu32 rsvd_9d0[30];\n/* 0xa48 */\tu32 pmc_scratch_write_disable0_b01;\n/* 0xa4c */\tu32 pmc_scratch_write_disable1_b01;\n/* 0xa50 */\tu32 pmc_scratch_write_disable2_b01;\n/* 0xa54 */\tu32 pmc_scratch_write_disable3_b01;\n/* 0xa58 */\tu32 pmc_scratch_write_disable4_b01;\n/* 0xa5c */\tu32 pmc_scratch_write_disable5_b01;\n/* 0xa60 */\tu32 pmc_scratch_write_disable6_b01;\n/* 0xa64 */\tu32 pmc_scratch_write_disable7_b01;\n/* 0xa68 */\tu32 pmc_scratch_write_disable8_b01;\n/* 0xa6c */\tu32 pmc_scratch_write_disable9_b01;\n/* 0xa70 */\tu32 pmc_scratch_write_disable10_b01;\n/* 0xa74 */\tu32 pmc_scratch_write_lock_disable_sticky_b01;\n/* 0xa78 */\tu32 rsvd_a78[8];\n/* 0xa98 */\tu32 pmc_secure_scratch80;\n/* 0xa9c */\tu32 pmc_secure_scratch81;\n/* 0xaa0 */\tu32 pmc_secure_scratch82;\n/* 0xaa4 */\tu32 pmc_secure_scratch83;\n/* 0xaa8 */\tu32 pmc_secure_scratch84;\n/* 0xaac */\tu32 pmc_secure_scratch85;\n/* 0xab0 */\tu32 pmc_secure_scratch86;\n/* 0xab4 */\tu32 pmc_secure_scratch87;\n/* 0xab8 */\tu32 pmc_secure_scratch88;\n/* 0xabc */\tu32 pmc_secure_scratch89;\n/* 0xac0 */\tu32 pmc_secure_scratch90;\n/* 0xac4 */\tu32 pmc_secure_scratch91;\n/* 0xac8 */\tu32 pmc_secure_scratch92;\n/* 0xacc */\tu32 pmc_secure_scratch93;\n/* 0xad0 */\tu32 pmc_secure_scratch94;\n/* 0xad4 */\tu32 pmc_secure_scratch95;\n/* 0xad8 */\tu32 pmc_secure_scratch96;\n/* 0xadc */\tu32 pmc_secure_scratch97;\n/* 0xae0 */\tu32 pmc_secure_scratch98;\n/* 0xae4 */\tu32 pmc_secure_scratch99;\n/* 0xae8 */\tu32 pmc_secure_scratch100;\n/* 0xaec */\tu32 pmc_secure_scratch101;\n/* 0xaf0 */\tu32 pmc_secure_scratch102;\n/* 0xaf4 */\tu32 pmc_secure_scratch103;\n/* 0xaf8 */\tu32 pmc_secure_scratch104;\n/* 0xafc */\tu32 pmc_secure_scratch105;\n/* 0xb00 */\tu32 pmc_secure_scratch106;\n/* 0xb04 */\tu32 pmc_secure_scratch107;\n/* 0xb08 */\tu32 pmc_secure_scratch108;\n/* 0xb0c */\tu32 pmc_secure_scratch109;\n/* 0xb10 */\tu32 pmc_secure_scratch110;\n/* 0xb14 */\tu32 pmc_secure_scratch111;\n/* 0xb18 */\tu32 pmc_secure_scratch112;\n/* 0xb1c */\tu32 pmc_secure_scratch113;\n/* 0xb20 */\tu32 pmc_secure_scratch114;\n/* 0xb24 */\tu32 pmc_secure_scratch115;\n/* 0xb28 */\tu32 pmc_secure_scratch116;\n/* 0xb2c */\tu32 pmc_secure_scratch117;\n/* 0xb30 */\tu32 pmc_secure_scratch118;\n/* 0xb34 */\tu32 pmc_secure_scratch119;\n/* 0xb38 */\tu32 pmc_secure_scratch120_b01;\n/* 0xb3c */\tu32 pmc_secure_scratch121_b01;\n/* 0xb40 */\tu32 pmc_secure_scratch122_b01;\n/* 0xb44 */\tu32 pmc_secure_scratch123_b01;\n/* 0xb48 */\tu32 pmc_led_breathing_ctrl_b01;\n/* 0xb4c */\tu32 pmc_led_breathing_counter0_b01; // Slope Steps.\n/* 0xb50 */\tu32 pmc_led_breathing_counter1_b01; // ON counter.\n/* 0xb54 */\tu32 pmc_led_breathing_counter2_b01; // OFF counter1.\n/* 0xb58 */\tu32 pmc_led_breathing_counter3_b01; // OFF counter0.\n/* 0xb5c */\tu32 pmc_led_breathing_status_b01;\n/* 0xb60 */\tu32 rsvd_b60[2];\n/* 0xb68 */\tu32 pmc_secure_scratch124_b01;\n/* 0xb6c */\tu32 pmc_secure_scratch125_b01;\n/* 0xb70 */\tu32 pmc_secure_scratch126_b01;\n/* 0xb74 */\tu32 pmc_secure_scratch127_b01;\n/* 0xb78 */\tu32 pmc_secure_scratch128_b01;\n/* 0xb7c */\tu32 pmc_secure_scratch129_b01;\n/* 0xb80 */\tu32 pmc_secure_scratch130_b01;\n/* 0xb84 */\tu32 pmc_secure_scratch131_b01;\n/* 0xb88 */\tu32 pmc_secure_scratch132_b01;\n/* 0xb8c */\tu32 pmc_secure_scratch133_b01;\n/* 0xb90 */\tu32 pmc_secure_scratch134_b01;\n/* 0xb94 */\tu32 pmc_secure_scratch135_b01;\n/* 0xb98 */\tu32 pmc_secure_scratch136_b01;\n/* 0xb9c */\tu32 pmc_secure_scratch137_b01;\n/* 0xba0 */\tu32 pmc_secure_scratch138_b01;\n/* 0xba4 */\tu32 pmc_secure_scratch139_b01;\n/* 0xba8 */\tu32 rsvd_ba8[2];\n/* 0xbb0 */\tu32 pmc_sec_disable_ns_b01;\n/* 0xbb4 */\tu32 pmc_sec_disable2_ns_b01;\n/* 0xbb8 */\tu32 pmc_sec_disable3_ns_b01;\n/* 0xbbc */\tu32 pmc_sec_disable4_ns_b01;\n/* 0xbc0 */\tu32 pmc_sec_disable5_ns_b01;\n/* 0xbc4 */\tu32 pmc_sec_disable6_ns_b01;\n/* 0xbc8 */\tu32 pmc_sec_disable7_ns_b01;\n/* 0xbcc */\tu32 pmc_sec_disable8_ns_b01;\n/* 0xbd0 */\tu32 pmc_sec_disable9_ns_b01;\n/* 0xbd4 */\tu32 pmc_sec_disable10_ns_b01;\n/* 0xbd8 */\tu32 rsvd_bd8[4];\n/* 0xbe8 */\tu32 pmc_tzram_pwr_cntrl_b01;\n/* 0xbec */\tu32 pmc_tzram_sec_disable_b01;\n/* 0xbf0 */\tu32 pmc_tzram_non_sec_disable_b01;\n} pmc_regs_t210_t;\n\n\n#endif\t/* _PMC_T210_H_ */\n"
  },
  {
    "path": "bdk/soc/t210.h",
    "content": "/*\n* Copyright (c) 2018 naehrwert\n* Copyright (c) 2018-2023 CTCaer\n*\n* This program is free software; you can redistribute it and/or modify it\n* under the terms and conditions of the GNU General Public License,\n* version 2, as published by the Free Software Foundation.\n*\n* This program is distributed in the hope it will be useful, but WITHOUT\n* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n* more details.\n*\n* You should have received a copy of the GNU General Public License\n* along with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n#ifndef _T210_H_\n#define _T210_H_\n\n#include <utils/types.h>\n\n#define IROM_BASE          0x100000\n#define IRAM_BASE        0x40000000\n#define HOST1X_BASE      0x50000000\n#define BPMP_CACHE_BASE  0x50040000\n#define MSELECT_BASE     0x50060000\n#define DPAUX1_BASE      0x54040000\n#define TSEC2_BASE       0x54100000\n#define DISPLAY_A_BASE   0x54200000\n#define DISPLAY_B_BASE   0x54240000\n#define DSI_BASE         0x54300000\n#define VIC_BASE         0x54340000\n#define NVJPG_BASE       0x54380000\n#define NVDEC_BASE       0x54480000\n#define NVENC_BASE       0x544C0000\n#define TSEC_BASE        0x54500000\n#define SOR1_BASE        0x54580000\n#define GPU_BASE         0x57000000\n#define GPU_USER_BASE    0x58000000\n#define PG_BASE          0x60000000\n#define RES_SEMAPH_BASE  0x60001000\n#define ARB_SEMAPH_BASE  0x60002000\n#define ARB_PRI_BASE     0x60003000\n#define ICTLR_BASE       0x60004000\n#define TMR_BASE         0x60005000\n#define CLOCK_BASE       0x60006000\n#define FLOW_CTLR_BASE   0x60007000\n#define AHBDMA_BASE      0x60008000\n#define SYSREG_BASE      0x6000C000\n#define SB_BASE          (SYSREG_BASE + 0x200)\n#define ACTMON_BASE      0x6000C800\n#define GPIO_BASE        0x6000D000\n#define EXCP_VEC_BASE    0x6000F000\n#define IPATCH_BASE      0x6001DC00\n#define APBDMA_BASE      0x60020000\n#define VGPIO_BASE       0x60024000\n#define APB_MISC_BASE    0x70000000\n#define PINMUX_AUX_BASE  0x70003000\n#define UART_BASE        0x70006000\n#define PWM_BASE         0x7000A000\n#define I2C_BASE         0x7000C000\n#define RTC_BASE         0x7000E000\n#define PMC_BASE         0x7000E400\n#define FUSE_BASE        0x7000F800\n#define KFUSE_BASE       0x7000FC00\n#define SE_BASE          0x70012000\n#define TSENSOR_BASE     0x70014000\n#define ATOMICS_BASE     0x70016000\n#define MC_BASE          0x70019000\n#define EMC_BASE         0x7001B000\n#define MC0_BASE         0x7001C000\n#define MC1_BASE         0x7001D000\n#define EMC0_BASE        0x7001E000\n#define EMC1_BASE        0x7001F000\n#define XUSB_HOST_BASE   0x70090000\n#define XUSB_PADCTL_BASE 0x7009F000\n#define XUSB_DEV_BASE    0x700D0000\n#define SDMMC_BASE       0x700B0000\n#define SOC_THERM_BASE   0x700E2000\n#define MIPI_CAL_BASE    0x700E3000\n#define SYSCTR0_BASE     0x700F0000\n#define SYSCTR1_BASE     0x70100000\n#define CL_DVFS_BASE     0x70110000\n#define APE_BASE         0x702C0000\n#define AHUB_BASE        0x702D0000\n#define ADMAIF_BASE      0x702D0000\n#define AXBAR_BASE       0x702D0800\n#define I2S_BASE         0x702D1000\n#define ADMA_BASE        0x702E2000\n#define AMC_BASE         0x702EF000\n#define SE2_BASE         0x70412000\n#define SE_PKA1_BASE     0x70420000\n#define TZRAM_BASE       0x7C010000\n#define  TZRAM_SIZE         0x10000\n#define  TZRAM_T210B01_SIZE 0x3C000\n#define USB_BASE         0x7D000000\n#define USB_OTG_BASE     USB_BASE\n#define USB1_BASE        0x7D004000\n#define EMEM_BASE        0x80000000\n\n#define MMIO_REG32(base, off) *(vu32 *)((base) + (off))\n\n#define HOST1X(off)          MMIO_REG32(HOST1X_BASE, off)\n#define BPMP_CACHE_CTRL(off) MMIO_REG32(BPMP_CACHE_BASE, off)\n#define MSELECT(off)         MMIO_REG32(MSELECT_BASE, off)\n#define DPAUX1(off)          MMIO_REG32(DPAUX1_BASE, off)\n#define TSEC2(off)           MMIO_REG32(TSEC2_BASE, off)\n#define DISPLAY_A(off)       MMIO_REG32(DISPLAY_A_BASE, (off) << 2u)\n#define DISPLAY_B(off)       MMIO_REG32(DISPLAY_B_BASE, (off) << 2u)\n#define DSI(off)             MMIO_REG32(DSI_BASE, (off) << 2u)\n#define VIC(off)             MMIO_REG32(VIC_BASE, off)\n#define NVJPG(off)           MMIO_REG32(NVJPG_BASE, off)\n#define NVDEC(off)           MMIO_REG32(NVDEC_BASE, off)\n#define NVENC(off)           MMIO_REG32(NVENC_BASE, off)\n#define TSEC(off)            MMIO_REG32(TSEC_BASE, off)\n#define SOR1(off)            MMIO_REG32(SOR1_BASE, off)\n#define GPU(off)             MMIO_REG32(GPU_BASE, off)\n#define GPU_USER(off)        MMIO_REG32(GPU_USER_BASE, off)\n#define PG(off)              MMIO_REG32(PG_BASE, off)\n#define ARB_PRI(off)         MMIO_REG32(ARB_PRI_BASE, off)\n#define ICTLR(cidx, off)     MMIO_REG32(ICTLR_BASE + (0x100 * (cidx)), off)\n#define TMR(off)             MMIO_REG32(TMR_BASE, off)\n#define CLOCK(off)           MMIO_REG32(CLOCK_BASE, off)\n#define FLOW_CTLR(off)       MMIO_REG32(FLOW_CTLR_BASE, off)\n#define AHBDMA(off)          MMIO_REG32(AHBDMA_BASE, off)\n#define SYSREG(off)          MMIO_REG32(SYSREG_BASE, off)\n#define AHB_GIZMO(off)       MMIO_REG32(SYSREG_BASE, off)\n#define SB(off)              MMIO_REG32(SB_BASE, off)\n#define ACTMON(off)          MMIO_REG32(ACTMON_BASE, off)\n#define GPIO(off)            MMIO_REG32(GPIO_BASE, off)\n#define EXCP_VEC(off)        MMIO_REG32(EXCP_VEC_BASE, off)\n#define APBDMA(off)          MMIO_REG32(APBDMA_BASE, off)\n#define VGPIO(off)           MMIO_REG32(VGPIO_BASE, off)\n#define APB_MISC(off)        MMIO_REG32(APB_MISC_BASE, off)\n#define PINMUX_AUX(off)      MMIO_REG32(PINMUX_AUX_BASE, off)\n#define PWM(off)             MMIO_REG32(PWM_BASE, off)\n#define RTC(off)             MMIO_REG32(RTC_BASE, off)\n#define PMC(off)             MMIO_REG32(PMC_BASE, off)\n#define SYSCTR0(off)         MMIO_REG32(SYSCTR0_BASE, off)\n#define SYSCTR1(off)         MMIO_REG32(SYSCTR1_BASE, off)\n#define FUSE(off)            MMIO_REG32(FUSE_BASE, off)\n#define KFUSE(off)           MMIO_REG32(KFUSE_BASE, off)\n#define SE(off)              MMIO_REG32(SE_BASE, off)\n#define MC(off)              MMIO_REG32(MC_BASE, off)\n#define EMC(off)             MMIO_REG32(EMC_BASE, off)\n#define MC_CH0(off)          MMIO_REG32(MC0_BASE, off)\n#define MC_CH1(off)          MMIO_REG32(MC1_BASE, off)\n#define EMC_CH0(off)         MMIO_REG32(EMC0_BASE, off)\n#define EMC_CH1(off)         MMIO_REG32(EMC1_BASE, off)\n#define XUSB_HOST(off)       MMIO_REG32(XUSB_HOST_BASE, off)\n#define XUSB_PADCTL(off)     MMIO_REG32(XUSB_PADCTL_BASE, off)\n#define XUSB_DEV(off)        MMIO_REG32(XUSB_DEV_BASE, off)\n#define XUSB_DEV_XHCI(off)   MMIO_REG32(XUSB_DEV_BASE, off)\n#define XUSB_DEV_PCI(off)    MMIO_REG32(XUSB_DEV_BASE + 0x8000, off)\n#define XUSB_DEV_DEV(off)    MMIO_REG32(XUSB_DEV_BASE + 0x9000, off)\n#define MIPI_CAL(off)        MMIO_REG32(MIPI_CAL_BASE, (off) << 2u)\n#define CL_DVFS(off)         MMIO_REG32(CL_DVFS_BASE, off)\n#define I2S(off)             MMIO_REG32(I2S_BASE, off)\n#define ADMA(off)            MMIO_REG32(ADMA_BASE, off)\n#define AMC(off)             MMIO_REG32(AMC_BASE, off)\n#define SE2(off)             MMIO_REG32(SE2_BASE, off)\n#define SE_PKA1(off)         MMIO_REG32(SE_PKA1_BASE, off)\n#define USB(off)             MMIO_REG32(USB_BASE, off)\n#define USB1(off)            MMIO_REG32(USB1_BASE, off)\n#define TEST_REG(off)        MMIO_REG32(0x0, off)\n\n/* HOST1X v3 registers. */\n#define HOST1X_CH0_SYNC_BASE        0x2100\n#define HOST1X_CH0_SYNC_SYNCPT_BASE (HOST1X_CH0_SYNC_BASE + 0xF80)\n#define HOST1X_CH0_SYNC_SYNCPT_9    (HOST1X_CH0_SYNC_SYNCPT_BASE + 0x24)\n#define HOST1X_CH0_SYNC_SYNCPT_160  (HOST1X_CH0_SYNC_SYNCPT_BASE + 0x280)\n\n/*! EVP registers. */\n#define EVP_CPU_RESET_VECTOR          0x100\n#define EVP_COP_RESET_VECTOR          0x200\n#define EVP_COP_UNDEF_VECTOR          0x204\n#define EVP_COP_SWI_VECTOR            0x208\n#define EVP_COP_PREFETCH_ABORT_VECTOR 0x20C\n#define EVP_COP_DATA_ABORT_VECTOR     0x210\n#define EVP_COP_RSVD_VECTOR           0x214\n#define EVP_COP_IRQ_VECTOR            0x218\n#define EVP_COP_FIQ_VECTOR            0x21C\n#define EVP_COP_IRQ_STS               0x220\n\n/*! Primary Interrupt Controller registers. */\n#define PRI_ICTLR_ISR           0x10\n#define PRI_ICTLR_FIR           0x14\n#define PRI_ICTLR_FIR_SET       0x18\n#define PRI_ICTLR_FIR_CLR       0x1C\n#define PRI_ICTLR_CPU_IER       0x20\n#define PRI_ICTLR_CPU_IER_SET   0x24\n#define PRI_ICTLR_CPU_IER_CLR   0x28\n#define PRI_ICTLR_CPU_IEP_CLASS 0x2C\n#define PRI_ICTLR_COP_IER       0x30\n#define PRI_ICTLR_COP_IER_SET   0x34\n#define PRI_ICTLR_COP_IER_CLR   0x38\n#define PRI_ICTLR_COP_IEP_CLASS 0x3C\n\n/* Arbiter registers */\n#define ARB_PRIO_CPU_PRIORITY 0x0\n#define ARB_PRIO_COP_PRIORITY 0x4\n#define ARB_PRIO_VCP_PRIORITY 0x8\n#define ARB_PRIO_DMA_PRIORITY 0xC\n#define ARB_PRIO_UCQ_PRIORITY 0x10\n\n/*! AHB Gizmo registers. */\n#define AHB_ARBITRATION_PRIORITY_CTRL        0x8\n#define  PRIORITY_CTRL_WEIGHT(x)              (((x) & 7) << 29)\n#define  PRIORITY_SELECT_USB                  BIT(6)  // USB-OTG.\n#define  PRIORITY_SELECT_USB2                 BIT(18) // USB-HSIC.\n#define  PRIORITY_SELECT_USB3                 BIT(17) // XUSB.\n#define AHB_GIZMO_AHB_MEM                    0x10\n#define  AHB_MEM_ENB_FAST_REARBITRATE         BIT(2)\n#define  AHB_MEM_DONT_SPLIT_AHB_WR            BIT(7)\n#define  AHB_MEM_IMMEDIATE                    BIT(18)\n#define AHB_GIZMO_APB_DMA                    0x14\n#define AHB_GIZMO_USB                        0x20\n#define AHB_GIZMO_SDMMC4                     0x48\n#define AHB_GIZMO_USB2                       0x7C\n#define AHB_GIZMO_USB3                       0x80 // Doesn't exist on T21x??\n#define  AHB_GIZMO_IMMEDIATE                  BIT(18)\n#define AHB_ARBITRATION_XBAR_CTRL            0xE0\n#define AHB_AHB_MEM_PREFETCH_CFG3            0xE4\n#define AHB_AHB_MEM_PREFETCH_CFG4            0xE8\n#define AHB_AHB_MEM_PREFETCH_CFG1            0xF0\n#define AHB_AHB_MEM_PREFETCH_CFG2            0xF4\n#define  MST_ID(x)                            (((x) & 0x1F) << 26)\n#define  MEM_PREFETCH_AHBDMA_MST_ID           MST_ID(5)\n#define  MEM_PREFETCH_USB_MST_ID              MST_ID(6)  // USB-OTG.  Doesn't exist on T210B01.\n#define  MEM_PREFETCH_USB2_MST_ID             MST_ID(18) // USB-HSIC. Doesn't exist on T210B01.\n#define  MEM_PREFETCH_USB3_MST_ID             MST_ID(17) // XUSB.     Doesn't exist on T210B01.\n#define  MEM_PREFETCH_ADDR_BNDRY(x)           (((x) & 0xF) << 21)\n#define  MEM_PREFETCH_ENABLE                  BIT(31)\n#define AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID 0xFC\n#define  MEM_WRQUE_SE_MST_ID                  BIT(14)\n#define AHB_AHB_SPARE_REG                    0x110\n\n/*! Misc registers. */\n#define APB_MISC_PP_STRAPPING_OPT_A           0x8\n#define APB_MISC_PP_PINMUX_GLOBAL             0x40\n#define APB_MISC_GP_HIDREV                    0x804\n#define  GP_HIDREV_MAJOR_T210                  0x1\n#define  GP_HIDREV_MAJOR_T210B01               0x2\n#define APB_MISC_GP_ASDBGREG                  0x810\n#define APB_MISC_GP_TRANSACTOR_SCRATCH        0x864\n#define APB_MISC_GP_AVP_TRANSACTOR_SCRATCH    0x880\n#define APB_MISC_GP_CPU0_TRANSACTOR_SCRATCH   0x884\n#define APB_MISC_GP_CPU1_TRANSACTOR_SCRATCH   0x888\n#define APB_MISC_GP_CPU2_TRANSACTOR_SCRATCH   0x88C\n#define APB_MISC_GP_CPU3_TRANSACTOR_SCRATCH   0x890\n#define APB_MISC_GP_AUD_MCLK_CFGPADCTRL       0x8F4\n#define APB_MISC_GP_LCD_BL_PWM_CFGPADCTRL     0xA34\n#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL     0xA98\n#define APB_MISC_GP_EMMC2_PAD_CFGPADCTRL      0xA9C\n#define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL      0xAB4\n#define APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL 0xABC\n#define APB_MISC_GP_DSI_PAD_CONTROL           0xAC0\n#define APB_MISC_GP_WIFI_EN_CFGPADCTRL        0xB64\n#define APB_MISC_GP_WIFI_RST_CFGPADCTRL       0xB68\n\n/*! Secure boot registers. */\n#define SB_CSR                       0x0\n#define  SB_CSR_NS_RST_VEC_WR_DIS     BIT(1)\n#define  SB_CSR_PIROM_DISABLE         BIT(4)\n#define SB_AA64_RESET_LOW            0x30\n#define  SB_AA64_RST_AARCH64_MODE_EN  BIT(0)\n#define SB_AA64_RESET_HIGH           0x34\n\n/*! SOR registers. */\n#define SOR_DP_HDCP_BKSV_LSB   0x1E8\n#define SOR_TMDS_HDCP_BKSV_LSB 0x21C\n#define SOR_TMDS_HDCP_CN_MSB   0x208\n#define SOR_TMDS_HDCP_CN_LSB   0x20C\n\n/*! RTC registers. */\n#define APBDEV_RTC_SECONDS        0x8\n#define APBDEV_RTC_SHADOW_SECONDS 0xC\n#define APBDEV_RTC_MILLI_SECONDS  0x10\n\n/*! SYSCTR0 registers. */\n#define SYSCTR0_CNTCR         0x00\n#define SYSCTR0_CNTFID0       0x20\n#define SYSCTR0_COUNTERS_BASE 0xFD0\n#define  SYSCTR0_COUNTERS      12\n#define SYSCTR0_COUNTERID0    0xFE0\n#define SYSCTR0_COUNTERID1    0xFE4\n#define SYSCTR0_COUNTERID2    0xFE8\n#define SYSCTR0_COUNTERID3    0xFEC\n#define SYSCTR0_COUNTERID4    0xFD0\n#define SYSCTR0_COUNTERID5    0xFD4\n#define SYSCTR0_COUNTERID6    0xFD8\n#define SYSCTR0_COUNTERID7    0xFDC\n#define SYSCTR0_COUNTERID8    0xFF0\n#define SYSCTR0_COUNTERID9    0xFF4\n#define SYSCTR0_COUNTERID10   0xFF8\n#define SYSCTR0_COUNTERID11   0xFFC\n\n/*! IPATCH registers. */\n#define IPATCH_CAM_VALID   0x0\n#define IPATCH_CAM_BASE    0x4\n#define IPATCH_CAM(i)      (IPATCH_CAM_BASE + (i) * 4)\n#define IPATCH_CAM_ENTRIES 12\n\n/*! I2S registers. */\n#define I2S_CG    0x88\n#define I2S_CTRL  0xA0\n#define I2S1_CG   I2S_CG\n#define I2S1_CTRL I2S_CTRL\n#define I2S2_CG   0x188\n#define I2S2_CTRL 0x1A0\n#define I2S3_CG   0x288\n#define I2S3_CTRL 0x2A0\n#define I2S4_CG   0x388\n#define I2S4_CTRL 0x3A0\n#define I2S5_CG   0x488\n#define I2S5_CTRL 0x4A0\n#define  I2S_CG_SLCG_DISABLE 0\n#define  I2S_CG_SLCG_ENABLE  BIT(0)\n#define  I2S_CTRL_MASTER_EN  BIT(10)\n\n/*! PWM registers. */\n#define PWM_CONTROLLER_PWM_CSR_0 0x00\n#define PWM_CONTROLLER_PWM_CSR_1 0x10\n#define  PWM_CSR_EN BIT(31)\n\n/*! Special registers. */\n#define EMC_SCRATCH0 0x324\n#define  EMC_HEKA_UPD BIT(30)\n\n/*! Flow controller registers. */\n#define FLOW_CTLR_HALT_COP_EVENTS          0x4\n#define FLOW_CTLR_HALT_CPU0_EVENTS         0x0\n#define FLOW_CTLR_HALT_CPU1_EVENTS         0x14\n#define FLOW_CTLR_HALT_CPU2_EVENTS         0x1C\n#define FLOW_CTLR_HALT_CPU3_EVENTS         0x24\n#define  HALT_GIC_IRQ                       BIT(9)\n#define  HALT_LIC_IRQ                       BIT(11)\n#define  HALT_SEC                           BIT(23)\n#define  HALT_MSEC                          BIT(24)\n#define  HALT_USEC                          BIT(25)\n#define  HALT_JTAG                          BIT(28)\n#define  HALT_MODE_NONE                     (0 << 29u)\n#define  HALT_MODE_RUN_AND_INT              (1 << 29u)\n#define  HALT_MODE_WAITEVENT                (2 << 29u)\n#define  HALT_MODE_WAITEVENT_AND_INT        (3 << 29u)\n#define  HALT_MODE_STOP_UNTIL_IRQ           (4 << 29u)\n#define  HALT_MODE_STOP_UNTIL_IRQ_AND_INT   (5 << 29u)\n#define  HALT_MODE_STOP_UNTIL_EVENT_AND_IRQ (6 << 29u)\n#define  HALT_MAX_CNT                       0xFF\n#define FLOW_CTLR_COP_CSR                  0xC\n#define FLOW_CTLR_CPU0_CSR                 0x8\n#define FLOW_CTLR_CPU1_CSR                 0x18\n#define FLOW_CTLR_CPU2_CSR                 0x20\n#define FLOW_CTLR_CPU3_CSR                 0x28\n#define  CSR_ENABLE                         BIT(0)\n#define  CSR_WAIT_WFI_NONE                  (0 << 8u)\n#define  CSR_WAIT_WFI_CPU0                  (BIT(0) << 8u)\n#define  CSR_ENABLE_EXT_CPU_ONLY            (0 << 12u)\n#define  CSR_ENABLE_EXT_CPU_NCPU            (1 << 12u)\n#define  CSR_ENABLE_EXT_CPU_RAIL            (2 << 12u)\n#define  CSR_EVENT_FLAG                     BIT(14)\n#define  CSR_INTR_FLAG                      BIT(15)\n#define  CSR_HALT                           BIT(22)\n#define FLOW_CTLR_CPU_PWR_CSR              0x38\n#define  CPU_PWR_RAIL_STS_MASK              (3 << 1u)\n#define  CPU_PWR_RAIL_OFF                   0\n#define FLOW_CTLR_RAM_REPAIR               0x40\n#define  RAM_REPAIR_REQ                     BIT(0)\n#define  RAM_REPAIR_STS                     BIT(1)\n#define FLOW_CTLR_BPMP_CLUSTER_CONTROL     0x98\n#define  CLUSTER_CTRL_ACTIVE_SLOW           BIT(0)\n\n/* MSelect registers */\n#define MSELECT_CONFIG 0x00\n#define  MSELECT_CFG_ERR_RESP_EN_PCIE  BIT(24)\n#define  MSELECT_CFG_ERR_RESP_EN_GPU   BIT(25)\n#define  MSELECT_CFG_WRAP_TO_INCR_BPMP BIT(27)\n#define  MSELECT_CFG_WRAP_TO_INCR_PCIE BIT(28)\n#define  MSELECT_CFG_WRAP_TO_INCR_GPU  BIT(29)\n\n/* NVDEC registers */\n#define NVDEC_SA_KEYSLOT_FALCON    0x2100\n#define NVDEC_SA_KEYSLOT_TZ        0x2104\n#define NVDEC_SA_KEYSLOT_OTF       0x210C\n#define NVDEC_SA_KEYSLOT_GLOBAL_RW 0x2118\n#define NVDEC_VPR_ALL_OTF_GOTO_VPR 0x211C\n\n/* PG registers */\n#define PG_UP_TAG 0x0 // Changes depending on what does the reg read request.\n#define  TAG_PID_CCPLEX 0x55555555\n#define  TAG_PID_BPMP   0xAAAAAAAA\n#define  TAG_PID_COP2   0x99999999\n#define  TAG_PID_OTHER  0xCCCCCCCC\n\n#endif\n"
  },
  {
    "path": "bdk/soc/timer.c",
    "content": "/*\n * Timer/Watchdog driver for Tegra X1\n *\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <soc/bpmp.h>\n#include <soc/irq.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n#include <utils/types.h>\n\n#define EXCP_TYPE_ADDR 0x4003FF18\n#define  EXCP_TYPE_WDT 0x544457 // \"WDT\".\n\n#define USE_RTC_TIMER\n\nu32 get_tmr_s()\n{\n\t(void)RTC(APBDEV_RTC_MILLI_SECONDS);\n\treturn (u32)RTC(APBDEV_RTC_SECONDS);\n}\n\nu32 get_tmr_ms()\n{\n\t// The registers must be read with the following order:\n\t// RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC)\n\treturn (u32)(RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000));\n}\n\nu32 get_tmr_us()\n{\n\treturn (u32)TMR(TIMERUS_CNTR_1US);\n}\n\nvoid msleep(u32 ms)\n{\n#ifdef USE_RTC_TIMER\n\tu32 start = (u32)RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000);\n\t// Casting to u32 is important!\n\twhile (((u32)(RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)) - start) <= ms)\n\t\t;\n#else\n\tbpmp_msleep(ms);\n#endif\n}\n\nvoid usleep(u32 us)\n{\n#ifdef USE_RTC_TIMER\n\tu32 start = (u32)TMR(TIMERUS_CNTR_1US);\n\n\t// Check if timer is at upper limits and use BPMP sleep so it doesn't wake up immediately.\n\tif ((start + us) < start)\n\t\tbpmp_usleep(us);\n\telse\n\t\twhile ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= us) // Casting to u32 is important!\n\t\t\t;\n#else\n\tbpmp_usleep(us);\n#endif\n}\n\n// Instruction wait loop. Each loop is 3 cycles (SUBS+BGT). Usage: isleep(ILOOP(instr)). Base 408MHz: 7.35ns.\nvoid __attribute__((target(\"arm\"))) isleep(u32 is)\n{\n\tasm volatile( \"0:\" \"SUBS %[is_cnt], #1;\" \"BGT 0b;\" : [is_cnt] \"+r\" (is));\n}\n\nvoid timer_usleep(u32 us)\n{\n\tTMR(TIMER_TMR8_TMR_PTV) = TIMER_EN | us;\n\n\tirq_wait_event(IRQ_TMR8);\n\n\tTMR(TIMER_TMR8_TMR_PCR) = TIMER_INTR_CLR;\n}\n\nvoid watchdog_start(u32 us, u32 mode)\n{\n\t// WDT4 is for BPMP.\n\tTMR(TIMER_WDT4_UNLOCK_PATTERN) = TIMER_MAGIC_PTRN;\n\tTMR(TIMER_TMR9_TMR_PTV) = TIMER_EN | TIMER_PER_EN | us;\n\tTMR(TIMER_WDT4_CONFIG)  = TIMER_SRC(9) | TIMER_PER(1) | mode;\n\tTMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT;\n}\n\nvoid watchdog_end()\n{\n\t// WDT4 is for BPMP.\n\tTMR(TIMER_TMR9_TMR_PTV) = 0;\n\tTMR(TIMER_WDT4_UNLOCK_PATTERN) = TIMER_MAGIC_PTRN;\n\tTMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT; // Re-arm to clear any interrupts.\n\tTMR(TIMER_WDT4_COMMAND) = TIMER_CNT_DISABLE;\n\tTMR(TIMER_TMR9_TMR_PCR) = TIMER_INTR_CLR;\n}\n\nvoid watchdog_handle()\n{\n\t// Disable watchdog and clear its interrupts.\n\twatchdog_end();\n\n\t// Set watchdog magic.\n\t*(u32 *)EXCP_TYPE_ADDR = EXCP_TYPE_WDT;\n}\n\nbool watchdog_fired()\n{\n\t// Return if watchdog got fired. User handles clearing.\n\treturn (*(u32 *)EXCP_TYPE_ADDR == EXCP_TYPE_WDT);\n}\n"
  },
  {
    "path": "bdk/soc/timer.h",
    "content": "/*\n * Timer/Watchdog driver for Tegra X1\n *\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _TIMER_H_\n#define _TIMER_H_\n\n#include <utils/types.h>\n\n// TMR registers.\n#define TIMERUS_CNTR_1US   (0x10 + 0x0)\n#define TIMERUS_USEC_CFG   (0x10 + 0x4)\n#define TIMER_TMR8_TMR_PTV 0x78\n#define TIMER_TMR9_TMR_PTV 0x80\n#define  TIMER_PER_EN       BIT(30)\n#define  TIMER_EN           BIT(31)\n#define TIMER_TMR8_TMR_PCR 0x7C\n#define TIMER_TMR9_TMR_PCR 0x8C\n#define  TIMER_INTR_CLR     BIT(30)\n\n// WDT registers.\n#define TIMER_WDT4_CONFIG         (0x100 + 0x80)\n#define  TIMER_SRC(TMR)    ((TMR) & 0xF)\n#define  TIMER_PER(PER)    (((PER) & 0xFF) << 4)\n#define  TIMER_IRQENABL_EN BIT(12)\n#define  TIMER_FIQENABL_EN BIT(13)\n#define  TIMER_SYSRESET_EN BIT(14)\n#define  TIMER_PMCRESET_EN BIT(15)\n#define TIMER_WDT4_COMMAND        (0x108 + 0x80)\n#define  TIMER_START_CNT   BIT(0)\n#define  TIMER_CNT_DISABLE BIT(1)\n#define TIMER_WDT4_UNLOCK_PATTERN (0x10C + 0x80)\n#define  TIMER_MAGIC_PTRN  0xC45A\n\nu32  get_tmr_us();\nu32  get_tmr_ms();\nu32  get_tmr_s();\nvoid usleep(u32 us);\nvoid msleep(u32 ms);\n#define ILOOP(is) ((is) / 3)\nvoid isleep(u32 is);\n\nvoid timer_usleep(u32 us);\n\nvoid watchdog_start(u32 us, u32 mode);\nvoid watchdog_end();\nvoid watchdog_handle();\nbool watchdog_fired();\n\n#endif\n"
  },
  {
    "path": "bdk/soc/uart.c",
    "content": "/*\n* Copyright (c) 2018 naehrwert\n* Copyright (c) 2019-2022 CTCaer\n*\n* This program is free software; you can redistribute it and/or modify it\n* under the terms and conditions of the GNU General Public License,\n* version 2, as published by the Free Software Foundation.\n*\n* This program is distributed in the hope it will be useful, but WITHOUT\n* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n* more details.\n*\n* You should have received a copy of the GNU General Public License\n* along with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n#include <soc/uart.h>\n#include <soc/clock.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n\n/* UART A, B, C, D and E. */\nstatic const u16 _uart_base_offsets[5] = { 0, 0x40, 0x200, 0x300, 0x400 };\n\nvoid uart_init(u32 idx, u32 baud, u32 mode)\n{\n\tuart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]);\n\n\t// Make sure no data is being sent.\n\tif (!(mode & (UART_MCR_CTS_EN | UART_MCR_DTR)))\n\t\tuart_wait_xfer(idx, UART_TX_IDLE);\n\n\t// Set clock.\n\tbool clk_type = clock_uart_use_src_div(idx, baud);\n\n\t// 2 STOP bits for rates > 1M. (Reduced efficiency but less errors on high baudrates).\n\tu32 uart_lcr_stop = baud > 1000000 ? UART_LCR_STOP : 0;\n\n\t// Misc settings.\n\tu32 div = clk_type ? ((8 * baud + 408000000) / (16 * baud)) : 1; // DIV_ROUND_CLOSEST.\n\tuart->UART_IER_DLAB = 0; // Disable interrupts.\n\tuart->UART_LCR      = UART_LCR_DLAB | UART_LCR_WORD_LENGTH_8; // Enable DLAB & set 8n1 mode.\n\tuart->UART_THR_DLAB = (u8)div;        // Divisor latch LSB.\n\tuart->UART_IER_DLAB = (u8)(div >> 8); // Divisor latch MSB.\n\n\t// Disable DLAB and set STOP bits setting if applicable.\n\tuart->UART_LCR = uart_lcr_stop | UART_LCR_WORD_LENGTH_8;\n\t(void)uart->UART_SPR;\n\n\t// Enable fifo.\n\tuart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO;\n\t(void)uart->UART_SPR;\n\tusleep(20);\n\n\t// Disable hardware flow control.\n\tuart->UART_MCR = 0;\n\tusleep(96);\n\n\t// Clear tx/rx fifos.\n\tuart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | UART_IIR_FCR_TX_CLR | UART_IIR_FCR_RX_CLR;\n\n\t// Set hardware flow control.\n\tuart->UART_MCR = mode;\n\n\t// Wait 3 symbols for baudrate change.\n\tusleep(3 * ((baud + 999999) / baud));\n\tuart_wait_xfer(idx, UART_TX_IDLE | UART_RX_RDYR);\n}\n\nvoid uart_wait_xfer(u32 idx, u32 which)\n{\n\tuart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]);\n\tif (UART_TX_IDLE & which)\n\t{\n\t\twhile (!(uart->UART_LSR & UART_LSR_TMTY))\n\t\t\t;\n\t}\n\tif (UART_RX_RDYR & which)\n\t{\n\t\twhile (uart->UART_LSR & UART_LSR_RDR)\n\t\t\t(void)uart->UART_THR_DLAB;\n\t}\n}\n\nvoid uart_send(u32 idx, const u8 *buf, u32 len)\n{\n\tuart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]);\n\n\tfor (u32 i = 0; i != len; i++)\n\t{\n\t\twhile (!(uart->UART_LSR & UART_LSR_THRE))\n\t\t\t;\n\t\tuart->UART_THR_DLAB = buf[i];\n\t}\n}\n\nu32 uart_recv(u32 idx, u8 *buf, u32 len)\n{\n\tuart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]);\n\tbool manual_mode = uart->UART_MCR & UART_MCR_RTS;\n\tu32 timeout = get_tmr_us() + 250;\n\tu32 i;\n\n\tif (manual_mode)\n\t\tuart->UART_MCR &= ~UART_MCR_RTS;\n\n\tfor (i = 0; ; i++)\n\t{\n\t\tif (len && len <= i)\n\t\t\tbreak;\n\n\t\twhile (!(uart->UART_LSR & UART_LSR_RDR))\n\t\t\tif (timeout < get_tmr_us())\n\t\t\t\tgoto out;\n\n\t\tbuf[i] = uart->UART_THR_DLAB;\n\t\ttimeout = get_tmr_us() + 250;\n\t}\n\nout:\n\tif (manual_mode)\n\t\tuart->UART_MCR |= UART_MCR_RTS;\n\n\treturn i;\n}\n\nvoid uart_invert(u32 idx, bool enable, u32 invert_mask)\n{\n\tuart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]);\n\n\tif (enable)\n\t\tuart->UART_IRDA_CSR |= invert_mask;\n\telse\n\t\tuart->UART_IRDA_CSR &= ~invert_mask;\n\t(void)uart->UART_SPR;\n}\n\nvoid uart_set_mode(u32 idx, u32 mode)\n{\n\tuart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]);\n\n\tuart->UART_MCR = mode;\n\t(void)uart->UART_SPR;\n}\n\nu32 uart_get_IIR(u32 idx)\n{\n\tuart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]);\n\n\tu32 iir = uart->UART_IIR_FCR & UART_IIR_INT_MASK;\n\n\tif (iir & UART_IIR_NO_INT)\n\t\treturn 0;\n\telse\n\t\treturn ((iir >> 1) + 1); // Return encoded interrupt.\n}\n\nvoid uart_set_IIR(u32 idx)\n{\n\tuart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]);\n\n\tuart->UART_IER_DLAB &= ~UART_IER_DLAB_IE_EORD;\n\t(void)uart->UART_SPR;\n\tuart->UART_IER_DLAB |= UART_IER_DLAB_IE_EORD;\n\t(void)uart->UART_SPR;\n}\n\nvoid uart_empty_fifo(u32 idx, u32 which)\n{\n\tuart_t *uart = (uart_t *)(UART_BASE + (u32)_uart_base_offsets[idx]);\n\n\tuart->UART_MCR = 0;\n\t(void)uart->UART_SPR;\n\tusleep(96);\n\n\tuart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | which;\n\t(void)uart->UART_SPR;\n\tusleep(18);\n\tu32 tries = 0;\n\n\tif (UART_IIR_FCR_TX_CLR & which)\n\t{\n\t\twhile (tries < 10 && !(uart->UART_LSR & UART_LSR_TMTY))\n\t\t{\n\t\t\ttries++;\n\t\t\tusleep(100);\n\t\t}\n\t\ttries = 0;\n\t}\n\n\tif (UART_IIR_FCR_RX_CLR & which)\n\t{\n\t\twhile (tries < 10 && (uart->UART_LSR & UART_LSR_RDR))\n\t\t{\n\t\t\ttries++;\n\t\t\tusleep(100);\n\t\t}\n\t}\n}\n\n#ifdef DEBUG_UART_PORT\n#include <stdarg.h>\n#include <string.h>\n\n#include <utils/sprintf.h>\n\nvoid uart_printf(const char *fmt, ...)\n{\n\tva_list ap;\n\n\t//! NOTE: Anything more and it will hang. Heap usage is out of the question.\n\tchar text[256];\n\n\tva_start(ap, fmt);\n\ts_vprintf(text, fmt, ap);\n\tva_end(ap);\n\n\tuart_send(DEBUG_UART_PORT, (u8 *)text, strlen(text));\n}\n#endif\n"
  },
  {
    "path": "bdk/soc/uart.h",
    "content": "/*\n* Copyright (c) 2018 naehrwert\n* Copyright (c) 2019-2020 CTCaer\n*\n* This program is free software; you can redistribute it and/or modify it\n* under the terms and conditions of the GNU General Public License,\n* version 2, as published by the Free Software Foundation.\n*\n* This program is distributed in the hope it will be useful, but WITHOUT\n* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n* more details.\n*\n* You should have received a copy of the GNU General Public License\n* along with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n#ifndef _UART_H_\n#define _UART_H_\n\n#include <utils/types.h>\n\n#define UART_A 0\n#define UART_B 1\n#define UART_C 2\n#define UART_D 3\n#define UART_E 4\n\n#define BAUD_115200 115200\n\n#define UART_TX_IDLE BIT(0)\n#define UART_RX_RDYR BIT(1)\n\n#define UART_TX_FIFO_FULL  BIT(8)\n#define UART_RX_FIFO_EMPTY BIT(9)\n\n#define UART_INVERT_RXD BIT(0)\n#define UART_INVERT_TXD BIT(1)\n#define UART_INVERT_CTS BIT(2)\n#define UART_INVERT_RTS BIT(3)\n\n#define UART_IER_DLAB_IE_EORD BIT(5)\n\n#define UART_LCR_WORD_LENGTH_8 0x3\n#define UART_LCR_STOP BIT(2)\n#define UART_LCR_DLAB BIT(7)\n\n#define UART_LSR_RDR   BIT(0)\n#define UART_LSR_THRE  BIT(5)\n#define UART_LSR_TMTY  BIT(6)\n#define UART_LSR_FIFOE BIT(7)\n\n#define UART_IIR_FCR_EN_FIFO BIT(0)\n#define UART_IIR_FCR_RX_CLR  BIT(1)\n#define UART_IIR_FCR_TX_CLR  BIT(2)\n\n#define UART_IIR_NO_INT   BIT(0)\n#define UART_IIR_INT_MASK 0xF\n/* Custom returned interrupt results. Actual interrupts are -1 */\n#define UART_IIR_NOI   0 // No interrupt.\n#define UART_IIR_MSI   1 // Modem status interrupt.\n#define UART_IIR_THRI  2 // Transmitter holding register empty.\n#define UART_IIR_RDI   3 // Receiver data interrupt.\n#define UART_IIR_ERROR 4 // Overrun Error, Parity Error, Framing Error, Break.\n#define UART_IIR_REDI  5 // Receiver end of data interrupt.\n#define UART_IIR_RDTI  7 // Receiver data timeout interrupt.\n\n#define UART_MCR_DTR    BIT(0)\n#define UART_MCR_RTS    BIT(1)\n#define UART_MCR_CTS_EN BIT(5)\n#define UART_MCR_RTS_EN BIT(6)\n\n#define UART_FIFO_SIZE  36\n\ntypedef struct _uart_t\n{\n\t/* 0x00 */ vu32 UART_THR_DLAB;\n\t/* 0x04 */ vu32 UART_IER_DLAB;\n\t/* 0x08 */ vu32 UART_IIR_FCR;\n\t/* 0x0C */ vu32 UART_LCR;\n\t/* 0x10 */ vu32 UART_MCR;\n\t/* 0x14 */ vu32 UART_LSR;\n\t/* 0x18 */ vu32 UART_MSR;\n\t/* 0x1C */ vu32 UART_SPR;\n\t/* 0x20 */ vu32 UART_IRDA_CSR;\n\t/* 0x24 */ vu32 UART_RX_FIFO_CFG;\n\t/* 0x28 */ vu32 UART_MIE;\n\t/* 0x2C */ vu32 UART_VENDOR_STATUS;\n\t/* 0x30 */ u8 _pad_30[0xC];\n\t/* 0x3C */ vu32 UART_ASR;\n} uart_t;\n\n//! TODO: Commented out modes are not supported yet.\ntypedef enum _uart_mode_t\n{\n\tUART_AO_TX_AO_RX = 0,\n\t//UART_MN_TX_AO_RX = UART_MCR_RTS | UART_MCR_DTR,\n\tUART_AO_TX_MN_RX = UART_MCR_RTS, // Up to 36 bytes read.\n\t//UART_MN_TX_AO_RX = UART_MCR_DTR,\n\t//UART_HW_TX_HW_RX = UART_MCR_RTS_EN | UART_MCR_CTS_EN,\n\tUART_AO_TX_HW_RX = UART_MCR_RTS_EN,\n\t//UART_HW_TX_AO_RX = UART_MCR_CTS_EN,\n} uart_mode_t;\n\nvoid uart_init(u32 idx, u32 baud, u32 mode);\nvoid uart_wait_xfer(u32 idx, u32 which);\nvoid uart_send(u32 idx, const u8 *buf, u32 len);\nu32  uart_recv(u32 idx, u8 *buf, u32 len);\nvoid uart_invert(u32 idx, bool enable, u32 invert_mask);\nvoid uart_set_mode(u32 idx, u32 mode);\nu32  uart_get_IIR(u32 idx);\nvoid uart_set_IIR(u32 idx);\nvoid uart_empty_fifo(u32 idx, u32 which);\n#ifdef DEBUG_UART_PORT\nvoid uart_printf(const char *fmt, ...);\n#endif\n\n#endif\n"
  },
  {
    "path": "bdk/storage/emmc.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2019-2024 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include \"emmc.h\"\n#include <mem/heap.h>\n#include <soc/fuse.h>\n#include <storage/mbr_gpt.h>\n#include <utils/list.h>\n\nstatic u16 emmc_errors[3] = { 0 }; // Init and Read/Write errors.\nstatic u32 emmc_mode = EMMC_MMC_HS400;\n\nsdmmc_t emmc_sdmmc;\nsdmmc_storage_t emmc_storage;\nFATFS emmc_fs;\n\n#ifdef BDK_EMUMMC_ENABLE\nint emummc_storage_read(u32 sector, u32 num_sectors, void *buf);\nint emummc_storage_write(u32 sector, u32 num_sectors, void *buf);\n#endif\n\nvoid emmc_error_count_increment(u8 type)\n{\n\tswitch (type)\n\t{\n\tcase EMMC_ERROR_INIT_FAIL:\n\t\temmc_errors[0]++;\n\t\tbreak;\n\tcase EMMC_ERROR_RW_FAIL:\n\t\temmc_errors[1]++;\n\t\tbreak;\n\tcase EMMC_ERROR_RW_RETRY:\n\t\temmc_errors[2]++;\n\t\tbreak;\n\t}\n}\n\nu16 *emmc_get_error_count()\n{\n\treturn emmc_errors;\n}\n\nu32 emmc_get_mode()\n{\n\treturn emmc_mode;\n}\n\nvoid emmc_end() { sdmmc_storage_end(&emmc_storage); }\n\nint emmc_init_retry(bool power_cycle)\n{\n\tu32 bus_width = SDMMC_BUS_WIDTH_8;\n\tu32 type = SDHCI_TIMING_MMC_HS400;\n\n\t// Power cycle SD eMMC.\n\tif (power_cycle)\n\t{\n\t\temmc_mode--;\n\t\temmc_end();\n\t}\n\n\t// Get init parameters.\n\tswitch (emmc_mode)\n\t{\n\tcase EMMC_INIT_FAIL: // Reset to max.\n\t\treturn 1;\n\tcase EMMC_1BIT_HS52:\n\t\tbus_width = SDMMC_BUS_WIDTH_1;\n\t\ttype = SDHCI_TIMING_MMC_HS52;\n\t\tbreak;\n\tcase EMMC_8BIT_HS52:\n\t\ttype = SDHCI_TIMING_MMC_HS52;\n\t\tbreak;\n\tcase EMMC_MMC_HS200:\n\t\ttype = SDHCI_TIMING_MMC_HS200;\n\t\tbreak;\n\tcase EMMC_MMC_HS400:\n\t\ttype = SDHCI_TIMING_MMC_HS400;\n\t\tbreak;\n\tdefault:\n\t\temmc_mode = EMMC_MMC_HS400;\n\t}\n\n\treturn sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, bus_width, type);\n}\n\nint emmc_initialize(bool power_cycle)\n{\n\t// Reset mode in case of previous failure.\n\tif (emmc_mode == EMMC_INIT_FAIL)\n\t\temmc_mode = EMMC_MMC_HS400;\n\n\tif (power_cycle)\n\t\temmc_end();\n\n\tint res = emmc_init_retry(false);\n\n\twhile (true)\n\t{\n\t\tif (!res)\n\t\t\treturn 0;\n\t\telse\n\t\t{\n\t\t\temmc_errors[EMMC_ERROR_INIT_FAIL]++;\n\n\t\t\tif (emmc_mode == EMMC_INIT_FAIL)\n\t\t\t\tbreak;\n\t\t\telse\n\t\t\t\tres = emmc_init_retry(true);\n\t\t}\n\t}\n\n\temmc_end();\n\n\treturn 1;\n}\n\nint emmc_set_partition(u32 partition) { return sdmmc_storage_set_mmc_partition(&emmc_storage, partition); }\n\nvoid emmc_gpt_parse(link_t *gpt)\n{\n\tgpt_t *gpt_buf = (gpt_t *)zalloc(GPT_NUM_BLOCKS * EMMC_BLOCKSIZE);\n\n#ifdef BDK_EMUMMC_ENABLE\n\temummc_storage_read(GPT_FIRST_LBA, GPT_NUM_BLOCKS, gpt_buf);\n#else\n\tsdmmc_storage_read(&emmc_storage, GPT_FIRST_LBA, GPT_NUM_BLOCKS, gpt_buf);\n#endif\n\n\t// Check if no GPT or more than max allowed entries.\n\tif (memcmp(&gpt_buf->header.signature, \"EFI PART\", 8) || gpt_buf->header.num_part_ents > 128)\n\t\tgoto out;\n\n\tfor (u32 i = 0; i < gpt_buf->header.num_part_ents; i++)\n\t{\n\t\temmc_part_t *part = (emmc_part_t *)zalloc(sizeof(emmc_part_t));\n\n\t\tif (gpt_buf->entries[i].lba_start < gpt_buf->header.first_use_lba)\n\t\t\tcontinue;\n\n\t\tpart->index     = i;\n\t\tpart->lba_start = gpt_buf->entries[i].lba_start;\n\t\tpart->lba_end   = gpt_buf->entries[i].lba_end;\n\t\tpart->attrs     = gpt_buf->entries[i].attrs;\n\n\t\t// ASCII conversion. Copy only the LSByte of the UTF-16LE name.\n\t\tfor (u32 j = 0; j < 36; j++)\n\t\t\tpart->name[j] = gpt_buf->entries[i].name[j];\n\t\tpart->name[35] = 0;\n\n\t\tlist_append(gpt, &part->link);\n\t}\n\nout:\n\tfree(gpt_buf);\n}\n\nvoid emmc_gpt_free(link_t *gpt)\n{\n\tLIST_FOREACH_SAFE(iter, gpt)\n\t\tfree(CONTAINER_OF(iter, emmc_part_t, link));\n}\n\nemmc_part_t *emmc_part_find(link_t *gpt, const char *name)\n{\n\tLIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link)\n\t\tif (!strcmp(part->name, name))\n\t\t\treturn part;\n\n\treturn NULL;\n}\n\nint emmc_part_read(emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf)\n{\n\t// The last LBA is inclusive.\n\tif (part->lba_start + sector_off > part->lba_end)\n\t\treturn 1;\n\n#ifdef BDK_EMUMMC_ENABLE\n\treturn emummc_storage_read(part->lba_start + sector_off, num_sectors, buf);\n#else\n\treturn sdmmc_storage_read(&emmc_storage, part->lba_start + sector_off, num_sectors, buf);\n#endif\n}\n\nint emmc_part_write(emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf)\n{\n\t// The last LBA is inclusive.\n\tif (part->lba_start + sector_off > part->lba_end)\n\t\treturn 1;\n\n#ifdef BDK_EMUMMC_ENABLE\n\treturn emummc_storage_write(part->lba_start + sector_off, num_sectors, buf);\n#else\n\treturn sdmmc_storage_write(&emmc_storage, part->lba_start + sector_off, num_sectors, buf);\n#endif\n}\n\nvoid nx_emmc_get_autorcm_masks(u8 *mod0, u8 *mod1)\n{\n\tif (fuse_read_hw_state() == FUSE_NX_HW_STATE_PROD)\n\t{\n\t\t*mod0 = 0xF7;\n\t\t*mod1 = 0x86;\n\t}\n\telse\n\t{\n\t\t*mod0 = 0x37;\n\t\t*mod1 = 0x84;\n\t}\n}\n"
  },
  {
    "path": "bdk/storage/emmc.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2019-2022 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _EMMC_H_\n#define _EMMC_H_\n\n#include <storage/sdmmc.h>\n#include <utils/types.h>\n#include <utils/list.h>\n\n#include <libs/fatfs/ff.h>\n\n#define GPT_FIRST_LBA  1\n#define GPT_NUM_BLOCKS 33\n#define EMMC_BLOCKSIZE SDMMC_DAT_BLOCKSIZE\n\nenum\n{\n\tEMMC_INIT_FAIL = 0,\n\tEMMC_1BIT_HS52 = 1,\n\tEMMC_8BIT_HS52 = 2,\n\tEMMC_MMC_HS200 = 3,\n\tEMMC_MMC_HS400 = 4,\n};\n\nenum\n{\n\tEMMC_ERROR_INIT_FAIL = 0,\n\tEMMC_ERROR_RW_FAIL   = 1,\n\tEMMC_ERROR_RW_RETRY  = 2\n};\n\ntypedef struct _emmc_part_t\n{\n\tu32 index;\n\tu32 lba_start;\n\tu32 lba_end;\n\tu64 attrs;\n\tchar name[37];\n\tlink_t link;\n} emmc_part_t;\n\nextern sdmmc_t emmc_sdmmc;\nextern sdmmc_storage_t emmc_storage;\nextern FATFS emmc_fs;\n\nvoid emmc_error_count_increment(u8 type);\nu16 *emmc_get_error_count();\nu32  emmc_get_mode();\nint  emmc_init_retry(bool power_cycle);\nint  emmc_initialize(bool power_cycle);\nint  emmc_set_partition(u32 partition);\nvoid emmc_end();\n\nvoid emmc_gpt_parse(link_t *gpt);\nvoid emmc_gpt_free(link_t *gpt);\nemmc_part_t *emmc_part_find(link_t *gpt, const char *name);\nint  emmc_part_read(emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf);\nint  emmc_part_write(emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf);\n\nvoid nx_emmc_get_autorcm_masks(u8 *mod0, u8 *mod1);\n\n#endif\n"
  },
  {
    "path": "bdk/storage/mbr_gpt.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef MBR_GPT_H\n#define MBR_GPT_H\n\n#include <utils/types.h>\n\ntypedef struct _mbr_chs_t\n{\n\tu8 head;\n\tu8 sector;\n\tu8 cylinder;\n} __attribute__((packed)) mbr_chs_t;\n\ntypedef struct _mbr_part_t\n{\n\tu8  status;\n\tmbr_chs_t start_sct_chs;\n\tu8  type;\n\tmbr_chs_t end_sct_chs;\n\tu32 start_sct;\n\tu32 size_sct;\n} __attribute__((packed)) mbr_part_t;\n\ntypedef struct _mbr_t\n{\n/* 0x000 */\tu8  bootstrap[440];\n/* 0x1B8 */\tu32 signature;\n/* 0x1BC */\tu16 copy_protected;\n/* 0x1BE */\tmbr_part_t partitions[4];\n/* 0x1FE */\tu16 boot_signature;\n} __attribute__((packed)) mbr_t;\n\ntypedef struct _gpt_entry_t\n{\n/* 0x00 */\tu8  type_guid[0x10];\n/* 0x10 */\tu8  part_guid[0x10];\n/* 0x20 */\tu64 lba_start;\n/* 0x28 */\tu64 lba_end;\n/* 0x30 */\tu64 attrs;\n/* 0x38 */\tu16 name[36];\n} gpt_entry_t;\n\ntypedef struct _gpt_header_t\n{\n/* 0x00 */\tu64 signature; // \"EFI PART\"\n/* 0x08 */\tu32 revision;\n/* 0x0C */\tu32 size;\n/* 0x10 */\tu32 crc32;\n/* 0x14 */\tu32 res1;\n/* 0x18 */\tu64 my_lba;\n/* 0x20 */\tu64 alt_lba;\n/* 0x28 */\tu64 first_use_lba;\n/* 0x30 */\tu64 last_use_lba;\n/* 0x38 */\tu8  disk_guid[0x10];\n/* 0x48 */\tu64 part_ent_lba;\n/* 0x50 */\tu32 num_part_ents;\n/* 0x54 */\tu32 part_ent_size;\n/* 0x58 */\tu32 part_ents_crc32;\n/* 0x5C */\tu8  res2[420]; // Used as first 3 partition entries backup for HOS.\n} gpt_header_t;\n\ntypedef struct _gpt_t\n{\n\tgpt_header_t header;\n\tgpt_entry_t  entries[128];\n} gpt_t;\n\n#endif\n"
  },
  {
    "path": "bdk/storage/mmc_def.h",
    "content": "/*\n * Header for MultiMediaCard (MMC)\n *\n * Copyright 2002 Hewlett-Packard Company\n * Copyright 2018-2021 CTCaer\n *\n * Use consistent with the GNU GPL is permitted,\n * provided that this copyright notice is\n * preserved in its entirety in all copies and derived works.\n *\n * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,\n * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS\n * FITNESS FOR ANY PARTICULAR PURPOSE.\n *\n * Many thanks to Alessandro Rubini and Jonathan Corbet!\n *\n * Based strongly on code by:\n *\n * Author: Yong-iL Joh <tolkien@mizi.com>\n *\n * Author:  Andrew Christian\n *          15 May 2002\n */\n\n#ifndef MMC_H\n#define MMC_H\n\n/* Standard MMC commands (4.1)           type  argument     response */\n/* class 1 */\n#define MMC_GO_IDLE_STATE         0   /* bc                          */\n#define MMC_SEND_OP_COND          1   /* bcr  [31:0] OCR         R3  */\n#define MMC_ALL_SEND_CID          2   /* bcr                     R2  */\n#define MMC_SET_RELATIVE_ADDR     3   /* ac   [31:16] RCA        R1  */\n#define MMC_SET_DSR               4   /* bc   [31:16] RCA            */\n#define MMC_SLEEP_AWAKE           5   /* ac   [31:16] RCA 15:flg R1b */\n#define MMC_SWITCH                6   /* ac   [31:0] See below   R1b */\n#define MMC_SELECT_CARD           7   /* ac   [31:16] RCA        R1  */\n#define MMC_SEND_EXT_CSD          8   /* adtc                    R1  */\n#define MMC_SEND_CSD              9   /* ac   [31:16] RCA        R2  */\n#define MMC_SEND_CID             10   /* ac   [31:16] RCA        R2  */\n#define MMC_READ_DAT_UNTIL_STOP  11   /* adtc [31:0] dadr        R1  */\n#define MMC_STOP_TRANSMISSION    12   /* ac                      R1b */\n#define MMC_SEND_STATUS          13   /* ac   [31:16] RCA        R1  */\n#define MMC_BUS_TEST_R           14   /* adtc                    R1  */\n#define MMC_GO_INACTIVE_STATE    15   /* ac   [31:16] RCA            */\n#define MMC_BUS_TEST_W           19   /* adtc                    R1  */\n#define MMC_SPI_READ_OCR         58   /* spi                  spi_R3 */\n#define MMC_SPI_CRC_ON_OFF       59   /* spi  [0:0] flag      spi_R1 */\n\n/* class 2 */\n#define MMC_SET_BLOCKLEN         16   /* ac   [31:0] block len   R1  */\n#define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1  */\n#define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1  */\n#define MMC_SEND_TUNING_BLOCK    19   /* adtc                    R1  */\n#define MMC_SEND_TUNING_BLOCK_HS200 21\t/* adtc R1  */\n\n/* class 3 */\n#define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */\n\n/* class 4 */\n#define MMC_SET_BLOCK_COUNT      23   /* adtc [31:0] data addr   R1  */\n#define MMC_WRITE_BLOCK          24   /* adtc [31:0] data addr   R1  */\n#define MMC_WRITE_MULTIPLE_BLOCK 25   /* adtc                    R1  */\n#define MMC_PROGRAM_CID          26   /* adtc                    R1  */\n#define MMC_PROGRAM_CSD          27   /* adtc                    R1  */\n\n/* class 6 */\n#define MMC_SET_WRITE_PROT       28   /* ac   [31:0] data addr   R1b */\n#define MMC_CLR_WRITE_PROT       29   /* ac   [31:0] data addr   R1b */\n#define MMC_SEND_WRITE_PROT      30   /* adtc [31:0] wpdata addr R1  */\n\n/* class 5 */\n#define MMC_ERASE_GROUP_START    35   /* ac   [31:0] data addr   R1  */\n#define MMC_ERASE_GROUP_END      36   /* ac   [31:0] data addr   R1  */\n#define MMC_ERASE                38   /* ac                      R1b */\n\n/* class 9 */\n#define MMC_FAST_IO              39   /* ac   <Complex>          R4  */\n#define MMC_GO_IRQ_STATE         40   /* bcr                     R5  */\n\n/* class 7 */\n#define MMC_LOCK_UNLOCK          42   /* adtc                    R1b */\n\n/* class 8 */\n#define MMC_APP_CMD              55   /* ac   [31:16] RCA        R1  */\n#define MMC_GEN_CMD              56   /* adtc [0] RD/WR          R1  */\n\n#define MMC_VENDOR_60_CMD        60   /* Vendor Defined              */\n#define MMC_VENDOR_61_CMD        61   /* Vendor Defined              */\n#define MMC_VENDOR_62_CMD        62   /* Vendor Defined              */\n#define MMC_VENDOR_63_CMD        63   /* Vendor Defined              */\n\n/* class 11 */\n#define MMC_QUE_TASK_PARAMS      44   /* ac   [20:16] task id    R1  */\n#define MMC_QUE_TASK_ADDR        45   /* ac   [31:0] data addr   R1  */\n#define MMC_EXECUTE_READ_TASK    46   /* adtc [20:16] task id    R1  */\n#define MMC_EXECUTE_WRITE_TASK   47   /* adtc [20:16] task id    R1  */\n#define MMC_CMDQ_TASK_MGMT       48   /* ac   [20:16] task id    R1b */\n\n/*\n * MMC_SWITCH argument format:\n *\n *\t[31:26] Always 0\n *\t[25:24] Access Mode\n *\t[23:16] Location of target Byte in EXT_CSD\n *\t[15:08] Value Byte\n *\t[07:03] Always 0\n *\t[02:00] Command Set\n */\n\n/*\n * MMC status in R1, for native mode (SPI bits are different)\n * Type\n * e : error bit\n * s : status bit\n * r : detected and set for the actual command response\n * x : detected and set during command execution. the host must poll\n *     the card by sending status command in order to read these bits.\n * Clear condition\n * a : according to the card state\n * b : always related to the previous command. Reception of a valid\n *     command will clear it (with a delay of one command)\n * c : clear by read\n*/\n\n#define R1_OUT_OF_RANGE\t\t(1 << 31)\t/* er, c */\n#define R1_ADDRESS_ERROR\t(1 << 30)\t/* erx, c */\n#define R1_BLOCK_LEN_ERROR\t(1 << 29)\t/* er, c */\n#define R1_ERASE_SEQ_ERROR      (1 << 28)\t/* er, c */\n#define R1_ERASE_PARAM\t\t(1 << 27)\t/* ex, c */\n#define R1_WP_VIOLATION\t\t(1 << 26)\t/* erx, c */\n#define R1_CARD_IS_LOCKED\t(1 << 25)\t/* sx, a */\n#define R1_LOCK_UNLOCK_FAILED\t(1 << 24)\t/* erx, c */\n#define R1_COM_CRC_ERROR\t(1 << 23)\t/* er, b */\n#define R1_ILLEGAL_COMMAND\t(1 << 22)\t/* er, b */\n#define R1_CARD_ECC_FAILED\t(1 << 21)\t/* ex, c */\n#define R1_CC_ERROR\t\t(1 << 20)\t/* erx, c */\n#define R1_ERROR\t\t(1 << 19)\t/* erx, c */\n#define R1_UNDERRUN\t\t(1 << 18)\t/* ex, c */\n#define R1_OVERRUN\t\t(1 << 17)\t/* ex, c */\n#define R1_CID_CSD_OVERWRITE\t(1 << 16)\t/* erx, c, CID/CSD overwrite */\n#define R1_WP_ERASE_SKIP\t(1 << 15)\t/* sx, c */\n#define R1_CARD_ECC_DISABLED\t(1 << 14)\t/* sx, a */\n#define R1_ERASE_RESET\t\t(1 << 13)\t/* sr, c */\n#define R1_STATUS(x)            ((x) & 0xFFFFE000)\n#define R1_CURRENT_STATE(x)\t(((x) & 0x00001E00) >> 9)\t/* sx, b (4 bits) */\n#define R1_READY_FOR_DATA\t(1 << 8)\t/* sx, a */\n#define R1_SWITCH_ERROR\t\t(1 << 7)\t/* sx, c */\n#define R1_EXCEPTION_EVENT\t(1 << 6)\t/* sr, a */\n#define R1_APP_CMD\t\t(1 << 5)\t/* sr, c */\n#define R1_SKIP_STATE_CHECK\t(1 << 4)\t/* Custom state to skip expected state check */\n#define R1_AKE_SEQ_ERROR\t(1 << 3)\n\n/* R1_CURRENT_STATE 12:9 */\n#define R1_STATE(x)     ((x) << 9)\n#define R1_STATE_IDLE\t0\n#define R1_STATE_READY\t1\n#define R1_STATE_IDENT\t2\n#define R1_STATE_STBY\t3\n#define R1_STATE_TRAN\t4\n#define R1_STATE_DATA\t5\n#define R1_STATE_RCV\t6\n#define R1_STATE_PRG\t7\n#define R1_STATE_DIS\t8\n\n/*\n * MMC/SD in SPI mode reports R1 status always, and R2 for SEND_STATUS\n * R1 is the low order byte; R2 is the next highest byte, when present.\n */\n#define R1_SPI_IDLE\t\t(1 << 0)\n#define R1_SPI_ERASE_RESET\t(1 << 1)\n#define R1_SPI_ILLEGAL_COMMAND\t(1 << 2)\n#define R1_SPI_COM_CRC\t\t(1 << 3)\n#define R1_SPI_ERASE_SEQ\t(1 << 4)\n#define R1_SPI_ADDRESS\t\t(1 << 5)\n#define R1_SPI_PARAMETER\t(1 << 6)\n/* R1 bit 7 is always zero */\n#define R2_SPI_CARD_LOCKED\t(1 << 8)\n#define R2_SPI_WP_ERASE_SKIP\t(1 << 9)\t/* or lock/unlock fail */\n#define R2_SPI_LOCK_UNLOCK_FAIL\tR2_SPI_WP_ERASE_SKIP\n#define R2_SPI_ERROR\t\t(1 << 10)\n#define R2_SPI_CC_ERROR\t\t(1 << 11)\n#define R2_SPI_CARD_ECC_ERROR\t(1 << 12)\n#define R2_SPI_WP_VIOLATION\t(1 << 13)\n#define R2_SPI_ERASE_PARAM\t(1 << 14)\n#define R2_SPI_OUT_OF_RANGE\t(1 << 15)\t/* or CSD overwrite */\n#define R2_SPI_CSD_OVERWRITE\tR2_SPI_OUT_OF_RANGE\n\n/*\n * OCR bits are mostly in host.h\n */\n#define MMC_CARD_VDD_18\t\t(1 << 7)\t/* Card VDD voltage 1.8 */\n#define MMC_CARD_VDD_27_34\t(0x7F << 15)\t/* Card VDD voltage 2.7 ~ 3.4 */\n#define MMC_CARD_CCS\t\t(1 << 30)\t/* Card Capacity status bit */\n#define MMC_CARD_BUSY\t\t(1 << 31)\t/* Card Power up status bit */\n\n/*\n * Card Command Classes (CCC)\n */\n#define CCC_BASIC\t\t(1<<0)\t/* (0) Basic protocol functions */\n/* (CMD0,1,2,3,4,7,9,10,12,13,15) */\n/* (and for SPI, CMD58,59) */\n#define CCC_STREAM_READ\t\t(1<<1)\t/* (1) Stream read commands */\n/* (CMD11) */\n#define CCC_BLOCK_READ\t\t(1<<2)\t/* (2) Block read commands */\n/* (CMD16,17,18) */\n#define CCC_STREAM_WRITE\t(1<<3)\t/* (3) Stream write commands */\n/* (CMD20) */\n#define CCC_BLOCK_WRITE\t\t(1<<4)\t/* (4) Block write commands */\n/* (CMD16,24,25,26,27) */\n#define CCC_ERASE\t\t(1<<5)\t/* (5) Ability to erase blocks */\n/* (CMD32,33,34,35,36,37,38,39) */\n#define CCC_WRITE_PROT\t\t(1<<6)\t/* (6) Able to write protect blocks */\n/* (CMD28,29,30) */\n#define CCC_LOCK_CARD\t\t(1<<7)\t/* (7) Able to lock down card */\n/* (CMD16,CMD42) */\n#define CCC_APP_SPEC\t\t(1<<8)\t/* (8) Application specific */\n/* (CMD55,56,57,ACMD*) */\n#define CCC_IO_MODE\t\t(1<<9)\t/* (9) I/O mode */\n/* (CMD5,39,40,52,53) */\n#define CCC_SWITCH\t\t(1<<10)\t/* (10) High speed switch */\n/* (CMD6,34,35,36,37,50) */\n/* (11) Reserved */\n/* (CMD?) */\n\n/*\n * CSD field definitions\n */\n\n#define CSD_STRUCT_VER_1_0  0           /* Valid for system specification 1.0 - 1.2 */\n#define CSD_STRUCT_VER_1_1  1           /* Valid for system specification 1.4 - 2.2 */\n#define CSD_STRUCT_VER_1_2  2           /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */\n#define CSD_STRUCT_EXT_CSD  3           /* Version is coded in CSD_STRUCTURE in EXT_CSD */\n\n#define CSD_SPEC_VER_0      0           /* Implements system specification 1.0 - 1.2 */\n#define CSD_SPEC_VER_1      1           /* Implements system specification 1.4 */\n#define CSD_SPEC_VER_2      2           /* Implements system specification 2.0 - 2.2 */\n#define CSD_SPEC_VER_3      3           /* Implements system specification 3.1 - 3.2 - 3.31 */\n#define CSD_SPEC_VER_4      4           /* Implements system specification 4.0 - 4.1 */\n\n/*\n * EXT_CSD fields\n */\n\n#define EXT_CSD_CMDQ_MODE_EN\t\t15\t/* R/W */\n#define EXT_CSD_FLUSH_CACHE\t\t32      /* W */\n#define EXT_CSD_CACHE_CTRL\t\t33      /* R/W */\n#define EXT_CSD_POWER_OFF_NOTIFICATION\t34\t/* R/W */\n#define EXT_CSD_PACKED_FAILURE_INDEX\t35\t/* RO */\n#define EXT_CSD_PACKED_CMD_STATUS\t36\t/* RO */\n#define EXT_CSD_EXP_EVENTS_STATUS\t54\t/* RO, 2 bytes */\n#define EXT_CSD_EXP_EVENTS_CTRL\t\t56\t/* R/W, 2 bytes */\n#define EXT_CSD_DATA_SECTOR_SIZE\t61\t/* R */\n#define EXT_CSD_GP_SIZE_MULT\t\t143\t/* R/W */\n#define EXT_CSD_PARTITION_SETTING_COMPLETED 155\t/* R/W */\n#define EXT_CSD_PARTITION_ATTRIBUTE\t156\t/* R/W */\n#define EXT_CSD_MAX_ENH_SIZE_MULT\t157\t/* RO, 3 bytes */\n#define EXT_CSD_PARTITION_SUPPORT\t160\t/* RO */\n#define EXT_CSD_HPI_MGMT\t\t161\t/* R/W */\n#define EXT_CSD_RST_N_FUNCTION\t\t162\t/* R/W */\n#define EXT_CSD_BKOPS_EN\t\t163\t/* R/W */\n#define EXT_CSD_BKOPS_START\t\t164\t/* W */\n#define EXT_CSD_SANITIZE_START\t\t165     /* W */\n#define EXT_CSD_WR_REL_PARAM\t\t166\t/* RO */\n#define EXT_CSD_RPMB_MULT\t\t168\t/* RO */\n#define EXT_CSD_FW_CONFIG\t\t169\t/* R/W */\n#define EXT_CSD_BOOT_WP\t\t\t173\t/* R/W */\n#define EXT_CSD_ERASE_GROUP_DEF\t\t175\t/* R/W */\n#define EXT_CSD_PART_CONFIG\t\t179\t/* R/W */\n#define EXT_CSD_ERASED_MEM_CONT\t\t181\t/* RO */\n#define EXT_CSD_BUS_WIDTH\t\t183\t/* R/W */\n#define EXT_CSD_STROBE_SUPPORT\t\t184\t/* RO */\n#define EXT_CSD_HS_TIMING\t\t185\t/* R/W */\n#define EXT_CSD_POWER_CLASS\t\t187\t/* R/W */\n#define EXT_CSD_REV\t\t\t192\t/* RO */\n#define EXT_CSD_STRUCTURE\t\t194\t/* RO */\n#define EXT_CSD_CARD_TYPE\t\t196\t/* RO */\n#define EXT_CSD_DRIVER_STRENGTH\t\t197\t/* RO */\n#define EXT_CSD_OUT_OF_INTERRUPT_TIME\t198\t/* RO */\n#define EXT_CSD_PART_SWITCH_TIME        199     /* RO */\n#define EXT_CSD_PWR_CL_52_195\t\t200\t/* RO */\n#define EXT_CSD_PWR_CL_26_195\t\t201\t/* RO */\n#define EXT_CSD_PWR_CL_52_360\t\t202\t/* RO */\n#define EXT_CSD_PWR_CL_26_360\t\t203\t/* RO */\n#define EXT_CSD_SEC_CNT\t\t\t212\t/* RO, 4 bytes */\n#define EXT_CSD_S_A_TIMEOUT\t\t217\t/* RO */\n#define EXT_CSD_REL_WR_SEC_C\t\t222\t/* RO */\n#define EXT_CSD_HC_WP_GRP_SIZE\t\t221\t/* RO */\n#define EXT_CSD_ERASE_TIMEOUT_MULT\t223\t/* RO */\n#define EXT_CSD_HC_ERASE_GRP_SIZE\t224\t/* RO */\n#define EXT_CSD_BOOT_MULT\t\t226\t/* RO */\n#define EXT_CSD_SEC_TRIM_MULT\t\t229\t/* RO */\n#define EXT_CSD_SEC_ERASE_MULT\t\t230\t/* RO */\n#define EXT_CSD_SEC_FEATURE_SUPPORT\t231\t/* RO */\n#define EXT_CSD_TRIM_MULT\t\t232\t/* RO */\n#define EXT_CSD_PWR_CL_200_195\t\t236\t/* RO */\n#define EXT_CSD_PWR_CL_200_360\t\t237\t/* RO */\n#define EXT_CSD_PWR_CL_DDR_52_195\t238\t/* RO */\n#define EXT_CSD_PWR_CL_DDR_52_360\t239\t/* RO */\n#define EXT_CSD_BKOPS_STATUS\t\t246\t/* RO */\n#define EXT_CSD_POWER_OFF_LONG_TIME\t247\t/* RO */\n#define EXT_CSD_GENERIC_CMD6_TIME\t248\t/* RO */\n#define EXT_CSD_CACHE_SIZE\t\t249\t/* RO, 4 bytes */\n#define EXT_CSD_PWR_CL_DDR_200_360\t253\t/* RO */\n#define EXT_CSD_FIRMWARE_VERSION\t254\t/* RO, 8 bytes */\n#define EXT_CSD_DEVICE_VERSION\t\t262\t/* RO, 2 bytes */\n#define EXT_CSD_PRE_EOL_INFO\t\t267\t/* RO */\n#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A\t268\t/* RO */\n#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B\t269\t/* RO */\n#define EXT_CSD_CMDQ_DEPTH\t\t307\t/* RO */\n#define EXT_CSD_CMDQ_SUPPORT\t\t308\t/* RO */\n#define EXT_CSD_SUPPORTED_MODE\t\t493\t/* RO */\n#define EXT_CSD_TAG_UNIT_SIZE\t\t498\t/* RO */\n#define EXT_CSD_DATA_TAG_SUPPORT\t499\t/* RO */\n#define EXT_CSD_MAX_PACKED_WRITES\t500\t/* RO */\n#define EXT_CSD_MAX_PACKED_READS\t501\t/* RO */\n#define EXT_CSD_BKOPS_SUPPORT\t\t502\t/* RO */\n#define EXT_CSD_HPI_FEATURES\t\t503\t/* RO */\n\n/*\n * EXT_CSD field definitions\n */\n\n#define EXT_CSD_WR_REL_PARAM_EN\t\t(1<<2)\n\n#define EXT_CSD_BOOT_WP_B_PWR_WP_DIS\t(0x40)\n#define EXT_CSD_BOOT_WP_B_PERM_WP_DIS\t(0x10)\n#define EXT_CSD_BOOT_WP_B_PERM_WP_EN\t(0x04)\n#define EXT_CSD_BOOT_WP_B_PWR_WP_EN\t(0x01)\n\n#define EXT_CSD_PART_CONFIG_ACC_MASK\t(0x7)\n#define EXT_CSD_PART_CONFIG_ACC_BOOT0\t(0x1)\n#define EXT_CSD_PART_CONFIG_ACC_RPMB\t(0x3)\n#define EXT_CSD_PART_CONFIG_ACC_GP0\t(0x4)\n\n#define EXT_CSD_PART_SETTING_COMPLETED\t(0x1)\n#define EXT_CSD_PART_SUPPORT_PART_EN\t(0x1)\n\n#define EXT_CSD_CMD_SET_NORMAL\t\t(1<<0)\n#define EXT_CSD_CMD_SET_SECURE\t\t(1<<1)\n#define EXT_CSD_CMD_SET_CPSECURE\t(1<<2)\n\n#define EXT_CSD_CARD_TYPE_HS_26\t(1<<0)\t/* Card can run at 26MHz */\n#define EXT_CSD_CARD_TYPE_HS_52\t(1<<1)\t/* Card can run at 52MHz */\n#define EXT_CSD_CARD_TYPE_HS\t(EXT_CSD_CARD_TYPE_HS_26 | \\\n\t\t\t\t EXT_CSD_CARD_TYPE_HS_52)\n#define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */\n/* DDR mode @1.8V or 3V I/O */\n#define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */\n/* DDR mode @1.2V I/O */\n#define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \\\n\t\t\t\t\t| EXT_CSD_CARD_TYPE_DDR_1_2V)\n#define EXT_CSD_CARD_TYPE_HS200_1_8V\t(1<<4)\t/* Card can run at 200MHz */\n#define EXT_CSD_CARD_TYPE_HS200_1_2V\t(1<<5)\t/* Card can run at 200MHz */\n/* SDR mode @1.2V I/O */\n#define EXT_CSD_CARD_TYPE_HS200\t\t(EXT_CSD_CARD_TYPE_HS200_1_8V | \\\n\t\t\t\t\t EXT_CSD_CARD_TYPE_HS200_1_2V)\n#define EXT_CSD_CARD_TYPE_HS400_1_8V\t(1<<6)\t/* Card can run at 200MHz DDR, 1.8V */\n#define EXT_CSD_CARD_TYPE_HS400_1_2V\t(1<<7)\t/* Card can run at 200MHz DDR, 1.2V */\n#define EXT_CSD_CARD_TYPE_HS400\t\t(EXT_CSD_CARD_TYPE_HS400_1_8V | \\\n\t\t\t\t\t EXT_CSD_CARD_TYPE_HS400_1_2V)\n#define EXT_CSD_CARD_TYPE_HS400ES\t(1<<8)\t/* Card can run at HS400ES */\n\n#define EXT_CSD_BUS_WIDTH_1\t0\t/* Card is in 1 bit mode */\n#define EXT_CSD_BUS_WIDTH_4\t1\t/* Card is in 4 bit mode */\n#define EXT_CSD_BUS_WIDTH_8\t2\t/* Card is in 8 bit mode */\n#define EXT_CSD_DDR_BUS_WIDTH_4\t5\t/* Card is in 4 bit DDR mode */\n#define EXT_CSD_DDR_BUS_WIDTH_8\t6\t/* Card is in 8 bit DDR mode */\n#define EXT_CSD_BUS_WIDTH_STROBE (1<<7)\t/* Enhanced strobe mode */\n\n#define EXT_CSD_TIMING_BC\t0\t/* Backwards compatility */\n#define EXT_CSD_TIMING_HS\t1\t/* High speed */\n#define EXT_CSD_TIMING_HS200\t2\t/* HS200 */\n#define EXT_CSD_TIMING_HS400\t3\t/* HS400 */\n#define EXT_CSD_DRV_STR_SHIFT\t4\t/* Driver Strength shift */\n\n#define EXT_CSD_SEC_ER_EN\t(1<<0)\n#define EXT_CSD_SEC_BD_BLK_EN\t(1<<2)\n#define EXT_CSD_SEC_GB_CL_EN\t(1<<4)\n#define EXT_CSD_SEC_SANITIZE\t(1<<6)  /* v4.5 only */\n\n#define EXT_CSD_RST_N_EN_MASK\t0x3\n#define EXT_CSD_RST_N_ENABLED\t1\t/* RST_n is enabled on card */\n\n#define EXT_CSD_NO_POWER_NOTIFICATION\t0\n#define EXT_CSD_POWER_ON\t\t1\n#define EXT_CSD_POWER_OFF_SHORT\t\t2\n#define EXT_CSD_POWER_OFF_LONG\t\t3\n\n#define EXT_CSD_PWR_CL_8BIT_MASK\t0xF0\t/* 8 bit PWR CLS */\n#define EXT_CSD_PWR_CL_4BIT_MASK\t0x0F\t/* 8 bit PWR CLS */\n#define EXT_CSD_PWR_CL_8BIT_SHIFT\t4\n#define EXT_CSD_PWR_CL_4BIT_SHIFT\t0\n\n#define EXT_CSD_PACKED_EVENT_EN\t(1<<3)\n\n/*\n * EXCEPTION_EVENT_STATUS field\n */\n#define EXT_CSD_URGENT_BKOPS\t\t(1<<0)\n#define EXT_CSD_DYNCAP_NEEDED\t\t(1<<1)\n#define EXT_CSD_SYSPOOL_EXHAUSTED\t(1<<2)\n#define EXT_CSD_PACKED_FAILURE\t\t(1<<3)\n\n#define EXT_CSD_PACKED_GENERIC_ERROR\t(1<<0)\n#define EXT_CSD_PACKED_INDEXED_ERROR\t(1<<1)\n\n/*\n * BKOPS status level\n */\n#define EXT_CSD_BKOPS_OK\t\t0x0\n#define EXT_CSD_BKOPS_NON_CRITICAL\t0x1\n#define EXT_CSD_BKOPS_PERF_IMPACTED\t0x2\n#define EXT_CSD_BKOPS_CRITICAL\t\t0x3\n\n/*\n * BKOPS modes\n */\n#define EXT_CSD_BKOPS_MANUAL\t0x01 /* STICKY! */\n#define EXT_CSD_BKOPS_AUTO\t\t0x02\n\n/*\n * Command Queue\n */\n#define EXT_CSD_CMDQ_MODE_ENABLED\t(1<<0)\n#define EXT_CSD_CMDQ_DEPTH_MASK\t\t0x1F\n#define EXT_CSD_CMDQ_SUPPORTED\t\t(1<<0)\n\n/*\n * MMC_SWITCH access modes\n */\n#define MMC_SWITCH_MODE_CMD_SET\t\t0x00\t/* Change the command set */\n#define MMC_SWITCH_MODE_SET_BITS\t0x01\t/* Set bits which are 1 in value */\n#define MMC_SWITCH_MODE_CLEAR_BITS\t0x02\t/* Clear bits which are 1 in value */\n#define MMC_SWITCH_MODE_WRITE_BYTE\t0x03\t/* Set target to value */\n\n/*\n * Erase/trim/discard\n */\n#define MMC_ERASE_ARG\t\t\t0x00000000\n#define MMC_SECURE_ERASE_ARG\t\t0x80000000\n#define MMC_TRIM_ARG\t\t\t0x00000001\n#define MMC_DISCARD_ARG\t\t\t0x00000003\n#define MMC_SECURE_TRIM1_ARG\t\t0x80000001\n#define MMC_SECURE_TRIM2_ARG\t\t0x80008000\n#define MMC_SECURE_ARGS\t\t\t0x80000000\n#define MMC_TRIM_ARGS\t\t\t0x00008001\n\n/*\n * Vendor definitions and structs\n */\n#define MMC_SANDISK_HEALTH_REPORT 0x96C9D71C\n\n#endif /* MMC_H */\n"
  },
  {
    "path": "bdk/storage/nx_emmc_bis.c",
    "content": "/*\n * eMMC BIS driver for Nintendo Switch\n *\n * Copyright (c) 2019-2020 shchmue\n * Copyright (c) 2019-2022 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <memory_map.h>\n\n#include <mem/heap.h>\n#include <sec/se.h>\n#include <storage/emmc.h>\n#include <storage/sd.h>\n#include <storage/sdmmc.h>\n#include <utils/types.h>\n\n#define BIS_CLUSTER_SECTORS   32\n#define BIS_CLUSTER_SIZE      16384\n#define BIS_CACHE_MAX_ENTRIES 16384\n#define BIS_CACHE_LOOKUP_TBL_EMPTY_ENTRY -1\n\ntypedef struct _cluster_cache_t\n{\n\tu32  cluster_idx;            // Index of the cluster in the partition.\n\tbool dirty;                  // Has been modified without write-back flag.\n\tu8   data[BIS_CLUSTER_SIZE]; // The cached cluster itself. Aligned to 8 bytes for DMA engine.\n} cluster_cache_t;\n\ntypedef struct _bis_cache_t\n{\n\tbool full;\n\tbool enabled;\n\tu32  dirty_cnt;\n\tu32  top_idx;\n\tu8   dma_buff[BIS_CLUSTER_SIZE]; // Aligned to 8 bytes for DMA engine.\n\tcluster_cache_t clusters[];\n} bis_cache_t;\n\nstatic u8  ks_crypt = 0;\nstatic u8  ks_tweak = 0;\nstatic u32 emu_offset = 0;\nstatic emmc_part_t *system_part = NULL;\nstatic u32 *cache_lookup_tbl = (u32 *)NX_BIS_LOOKUP_ADDR;\nstatic bis_cache_t *bis_cache = (bis_cache_t *)NX_BIS_CACHE_ADDR;\n\nstatic int nx_emmc_bis_write_block(u32 sector, u32 count, void *buff, bool flush)\n{\n\tif (!system_part)\n\t\treturn 3; // Not ready.\n\n\tint res;\n\tu8   tweak[SE_KEY_128_SIZE] __attribute__((aligned(4)));\n\tu32  cluster = sector / BIS_CLUSTER_SECTORS;\n\tu32  aligned_sector = cluster * BIS_CLUSTER_SECTORS;\n\tu32  sector_in_cluster = sector % BIS_CLUSTER_SECTORS;\n\tu32  lookup_idx = cache_lookup_tbl[cluster];\n\tbool is_cached = lookup_idx != (u32)BIS_CACHE_LOOKUP_TBL_EMPTY_ENTRY;\n\n\t// Write to cached cluster.\n\tif (is_cached)\n\t{\n\t\tif (buff)\n\t\t\tmemcpy(bis_cache->clusters[lookup_idx].data + sector_in_cluster * EMMC_BLOCKSIZE, buff, count * EMMC_BLOCKSIZE);\n\t\telse\n\t\t\tbuff = bis_cache->clusters[lookup_idx].data;\n\t\tif (!bis_cache->clusters[lookup_idx].dirty)\n\t\t\tbis_cache->dirty_cnt++;\n\t\tbis_cache->clusters[lookup_idx].dirty = true;\n\n\t\tif (!flush)\n\t\t\treturn 0; // Success.\n\n\t\t// Reset args to trigger a full cluster flush to emmc.\n\t\tsector_in_cluster = 0;\n\t\tsector = aligned_sector;\n\t\tcount = BIS_CLUSTER_SECTORS;\n\t}\n\n\t// Encrypt cluster.\n\tif (se_aes_crypt_xts_sec_nx(ks_tweak, ks_crypt, ENCRYPT, cluster, tweak, true, sector_in_cluster, bis_cache->dma_buff, buff, count * EMMC_BLOCKSIZE))\n\t\treturn 1; // Encryption error.\n\n\t// If not reading from cache, do a regular read and decrypt.\n\tif (!emu_offset)\n\t\tres = emmc_part_write(system_part, sector, count, bis_cache->dma_buff);\n\telse\n\t\tres = sdmmc_storage_write(&sd_storage, emu_offset + system_part->lba_start + sector, count, bis_cache->dma_buff);\n\tif (res)\n\t\treturn 1; // R/W error.\n\n\t// Mark cache entry not dirty if write succeeds.\n\tif (is_cached)\n\t{\n\t\tbis_cache->clusters[lookup_idx].dirty = false;\n\t\tbis_cache->dirty_cnt--;\n\t}\n\n\treturn 0; // Success.\n}\n\nstatic void _nx_emmc_bis_cluster_cache_init(bool enable_cache)\n{\n\tu32 cache_lookup_tbl_size = (system_part->lba_end - system_part->lba_start + 1) / BIS_CLUSTER_SECTORS * sizeof(*cache_lookup_tbl);\n\n\t// Clear cache header.\n\tmemset(bis_cache, 0, sizeof(bis_cache_t));\n\n\t// Clear cluster lookup table.\n\tmemset(cache_lookup_tbl, BIS_CACHE_LOOKUP_TBL_EMPTY_ENTRY, cache_lookup_tbl_size);\n\n\t// Enable cache.\n\tbis_cache->enabled = enable_cache;\n}\n\nstatic void _nx_emmc_bis_flush_cache()\n{\n\tif (!bis_cache->enabled || !bis_cache->dirty_cnt)\n\t\treturn;\n\n\tfor (u32 i = 0; i < bis_cache->top_idx && bis_cache->dirty_cnt; i++)\n\t{\n\t\tif (bis_cache->clusters[i].dirty) {\n\t\t\tnx_emmc_bis_write_block(bis_cache->clusters[i].cluster_idx * BIS_CLUSTER_SECTORS, BIS_CLUSTER_SECTORS, NULL, true);\n\t\t\tbis_cache->dirty_cnt--;\n\t\t}\n\t}\n\n\t_nx_emmc_bis_cluster_cache_init(true);\n}\n\nstatic int nx_emmc_bis_read_block_normal(u32 sector, u32 count, void *buff)\n{\n\tstatic u32 prev_cluster = -1;\n\tstatic u32 prev_sector = 0;\n\tstatic u8  tweak[SE_KEY_128_SIZE] __attribute__((aligned(4)));\n\n\tint  res;\n\tbool regen_tweak = true;\n\tu32  tweak_exp = 0;\n\tu32  cluster = sector / BIS_CLUSTER_SECTORS;\n\tu32  sector_in_cluster = sector % BIS_CLUSTER_SECTORS;\n\n\t// If not reading from cache, do a regular read and decrypt.\n\tif (!emu_offset)\n\t\tres = emmc_part_read(system_part, sector, count, bis_cache->dma_buff);\n\telse\n\t\tres = sdmmc_storage_read(&sd_storage, emu_offset + system_part->lba_start + sector, count, bis_cache->dma_buff);\n\tif (res)\n\t\treturn 1; // R/W error.\n\n\tif (prev_cluster != cluster) // Sector in different cluster than last read.\n\t{\n\t\tprev_cluster = cluster;\n\t\ttweak_exp = sector_in_cluster;\n\t}\n\telse if (sector > prev_sector) // Sector in same cluster and past last sector.\n\t{\n\t\t// Calculates the new tweak using the saved one, reducing expensive _gf256_mul_x_le calls.\n\t\ttweak_exp = sector - prev_sector - 1;\n\t\tregen_tweak = false;\n\t}\n\telse // Sector in same cluster and before or same as last sector.\n\t\ttweak_exp = sector_in_cluster;\n\n\t// Maximum one cluster (1 XTS crypto block 16KB).\n\tif (se_aes_crypt_xts_sec_nx(ks_tweak, ks_crypt, DECRYPT, prev_cluster, tweak, regen_tweak, tweak_exp, buff, bis_cache->dma_buff, count * EMMC_BLOCKSIZE))\n\t\treturn 1; // R/W error.\n\n\tprev_sector = sector + count - 1;\n\n\treturn 0; // Success.\n}\n\nstatic int nx_emmc_bis_read_block_cached(u32 sector, u32 count, void *buff)\n{\n\tint res;\n\tu8  cache_tweak[SE_KEY_128_SIZE] __attribute__((aligned(4)));\n\tu32 cluster = sector / BIS_CLUSTER_SECTORS;\n\tu32 cluster_sector = cluster * BIS_CLUSTER_SECTORS;\n\tu32 sector_in_cluster = sector % BIS_CLUSTER_SECTORS;\n\tu32 lookup_idx = cache_lookup_tbl[cluster];\n\n\t// Read from cached cluster.\n\tif (lookup_idx != (u32)BIS_CACHE_LOOKUP_TBL_EMPTY_ENTRY)\n\t{\n\t\tmemcpy(buff, bis_cache->clusters[lookup_idx].data + sector_in_cluster * EMMC_BLOCKSIZE, count * EMMC_BLOCKSIZE);\n\n\t\treturn 0; // Success.\n\t}\n\n\t// Flush cache if full.\n\tif (bis_cache->top_idx >= BIS_CACHE_MAX_ENTRIES)\n\t\t_nx_emmc_bis_flush_cache();\n\n\t// Set new cached cluster parameters.\n\tbis_cache->clusters[bis_cache->top_idx].cluster_idx = cluster;\n\tbis_cache->clusters[bis_cache->top_idx].dirty = false;\n\tcache_lookup_tbl[cluster] = bis_cache->top_idx;\n\n\t// Read the whole cluster the sector resides in.\n\tif (!emu_offset)\n\t\tres = emmc_part_read(system_part, cluster_sector, BIS_CLUSTER_SECTORS, bis_cache->dma_buff);\n\telse\n\t\tres = sdmmc_storage_read(&sd_storage, emu_offset + system_part->lba_start + cluster_sector, BIS_CLUSTER_SECTORS, bis_cache->dma_buff);\n\tif (res)\n\t\treturn 1; // R/W error.\n\n\t// Decrypt cluster.\n\tif (se_aes_crypt_xts_sec_nx(ks_tweak, ks_crypt, DECRYPT, cluster, cache_tweak, true, 0, bis_cache->dma_buff, bis_cache->dma_buff, BIS_CLUSTER_SIZE))\n\t\treturn 1; // Decryption error.\n\n\t// Copy to cluster cache.\n\tmemcpy(bis_cache->clusters[bis_cache->top_idx].data, bis_cache->dma_buff, BIS_CLUSTER_SIZE);\n\tmemcpy(buff, bis_cache->dma_buff + sector_in_cluster * EMMC_BLOCKSIZE, count * EMMC_BLOCKSIZE);\n\n\t// Increment cache count.\n\tbis_cache->top_idx++;\n\n\treturn 0; // Success.\n}\n\nstatic int nx_emmc_bis_read_block(u32 sector, u32 count, void *buff)\n{\n\tif (!system_part)\n\t\treturn 3; // Not ready.\n\n\tif (bis_cache->enabled)\n\t\treturn nx_emmc_bis_read_block_cached(sector, count, buff);\n\telse\n\t\treturn nx_emmc_bis_read_block_normal(sector, count, buff);\n}\n\nint nx_emmc_bis_read(u32 sector, u32 count, void *buff)\n{\n\tu8 *buf = (u8 *)buff;\n\tu32 curr_sct = sector;\n\n\twhile (count)\n\t{\n\t\t// Get sector index in cluster and use it as boundary check.\n\t\tu32 cnt_max = (curr_sct % BIS_CLUSTER_SECTORS);\n\t\tcnt_max = BIS_CLUSTER_SECTORS - cnt_max;\n\n\t\tu32 sct_cnt = MIN(count, cnt_max); // Only allow cluster sized access.\n\n\t\tif (nx_emmc_bis_read_block(curr_sct, sct_cnt, buf))\n\t\t\treturn 1;\n\n\t\tcount    -= sct_cnt;\n\t\tcurr_sct += sct_cnt;\n\t\tbuf      += sct_cnt * EMMC_BLOCKSIZE;\n\t}\n\n\treturn 0;\n}\n\nint nx_emmc_bis_write(u32 sector, u32 count, void *buff)\n{\n\tu8 *buf = (u8 *)buff;\n\tu32 curr_sct = sector;\n\n\twhile (count)\n\t{\n\t\t// Get sector index in cluster and use it as boundary check.\n\t\tu32 cnt_max = (curr_sct % BIS_CLUSTER_SECTORS);\n\t\tcnt_max = BIS_CLUSTER_SECTORS - cnt_max;\n\n\t\tu32 sct_cnt = MIN(count, cnt_max); // Only allow cluster sized access.\n\n\t\tif (nx_emmc_bis_write_block(curr_sct, sct_cnt, buf, false))\n\t\t\treturn 1;\n\n\t\tcount    -= sct_cnt;\n\t\tcurr_sct += sct_cnt;\n\t\tbuf      += sct_cnt * EMMC_BLOCKSIZE;\n\t}\n\n\treturn 0;\n}\n\nvoid nx_emmc_bis_init(emmc_part_t *part, bool enable_cache, u32 emummc_offset)\n{\n\tsystem_part = part;\n\temu_offset = emummc_offset;\n\n\t_nx_emmc_bis_cluster_cache_init(enable_cache);\n\n\tif (!strcmp(part->name, \"PRODINFO\") || !strcmp(part->name, \"PRODINFOF\"))\n\t{\n\t\tks_crypt = 0;\n\t\tks_tweak = 1;\n\t}\n\telse if (!strcmp(part->name, \"SAFE\"))\n\t{\n\t\tks_crypt = 2;\n\t\tks_tweak = 3;\n\t}\n\telse if (!strcmp(part->name, \"SYSTEM\") || !strcmp(part->name, \"USER\"))\n\t{\n\t\tks_crypt = 4;\n\t\tks_tweak = 5;\n\t}\n\telse\n\t\tsystem_part = NULL;\n}\n\nvoid nx_emmc_bis_end()\n{\n\t_nx_emmc_bis_flush_cache();\n\tsystem_part = NULL;\n}\n"
  },
  {
    "path": "bdk/storage/nx_emmc_bis.h",
    "content": "/*\n * Copyright (c) 2019 shchmue\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef NX_EMMC_BIS_H\n#define NX_EMMC_BIS_H\n\n#include <storage/emmc.h>\n#include <storage/sdmmc.h>\n\n#define NAND_PATROL_SECTOR   0xC20\n\ntypedef struct _nx_emmc_cal0_spk_t\n{\n\tu16 unk0;\n\tu16 unk1;\n\tu16 eq_bw_lop;\n\tu16 eq_gn_lop;\n\tu16 eq_fc_bp1;\n\tu16 eq_bw_bp1;\n\tu16 eq_gn_bp1;\n\tu16 eq_fc_bp2;\n\tu16 eq_bw_bp2;\n\tu16 eq_gn_bp2;\n\tu16 eq_fc_bp3;\n\tu16 eq_bw_bp3;\n\tu16 eq_gn_bp3;\n\tu16 eq_fc_bp4;\n\tu16 eq_bw_bp4;\n\tu16 eq_gn_bp4;\n\tu16 eq_fc_hip1;\n\tu16 eq_gn_hip1;\n\tu16 eq_fc_hip2;\n\tu16 eq_bw_hip2;\n\tu16 eq_gn_hip2;\n\tu16 eq_pre_vol;\n\tu16 eq_pst_vol;\n\tu16 eq_ctrl2;\n\tu16 eq_ctrl1;\n\tu16 drc_agc_2;\n\tu16 drc_agc_3;\n\tu16 drc_agc_1;\n\tu16 spk_vol;\n\tu16 hp_vol;\n\tu16 dac1_min_vol_spk;\n\tu16 dac1_max_vol_spk;\n\tu16 dac1_min_vol_hp;\n\tu16 dac1_max_vol_hp;\n\tu16 in1_in2;\n\tu16 adc_vol_min;\n\tu16 adc_vol_max;\n\tu8  unk4[16];\n} __attribute__((packed)) nx_emmc_cal0_spk_t;\n\ntypedef struct _nx_emmc_cal0_t\n{\n\t// Header.\n\tu32  magic; // 'CAL0'.\n\tu32  version;\n\tu32  body_size;\n\tu16  model;\n\tu16  update_cnt;\n\tu8   pad_crc16_hdr[0x10];\n\n\t// SHA256 for body.\n\tu8   body_sha256[0x20];\n\n\t// Body.\n\tchar cfg_id1[0x1E];\n\tu8   crc16_pad1[2];\n\tu8   rsvd0[0x20];\n\tu32  wlan_cc_num;\n\tu32  wlan_cc_last;\n\tchar wlan_cc[128][3];\n\tu8   crc16_pad2[8];\n\tu8   wlan_mac[6];\n\tu8   crc16_pad3[2];\n\tu8   rsvd1[8];\n\tu8   bd_mac[6];\n\tu8   crc16_pad4[2];\n\tu8   rsvd2[8];\n\tu16  acc_offset[3];\n\tu8   crc16_pad5[2];\n\tu16  acc_scale[3];\n\tu8   crc16_pad6[2];\n\tu16  gyro_offset[3];\n\tu8   crc16_pad7[2];\n\tu16  gyro_scale[3];\n\tu8   crc16_pad8[2];\n\tchar serial_number[0x18];\n\tu8   crc16_pad9[8];\n\n\tu8   ecc_p256_device_key[0x30];\n\tu8   crc16_pad10[0x10];\n\tu8   ecc_p256_device_cert[0x180];\n\tu8   crc16_pad11[0x10];\n\tu8   ecc_p233_device_key[0x30];\n\tu8   crc16_pad12[0x10];\n\tu8   ecc_p33_device_cert[0x180];\n\tu8   crc16_pad13[0x10];\n\tu8   ecc_p256_ticket_key[0x30];\n\tu8   crc16_pad14[0x10];\n\tu8   ecc_p256_ticket_cert[0x180];\n\tu8   crc16_pad15[0x10];\n\tu8   ecc_p233_ticket_key[0x30];\n\tu8   crc16_pad16[0x10];\n\tu8   ecc_p33_ticket_cert[0x180];\n\tu8   crc16_pad17[0x10];\n\tu8   ssl_key[0x110];\n\tu8   crc16_pad18[0x10];\n\tu32  ssl_cert_size;\n\tu8   crc16_pad19[0xC];\n\tu8   ssl_cert[0x800];\n\tu8   ssl_sha256[0x20];\n\tu8   random_number[0x1000];\n\tu8   random_number_sha256[0x20];\n\tu8   gc_key[0x110];\n\tu8   crc16_pad20[0x10];\n\tu8   gc_cert[0x400];\n\tu8   gc_cert_sha256[0x20];\n\tu8   rsa2048_eticket_key[0x220];\n\tu8   crc16_pad21[0x10];\n\tu8   rsa2048_eticket_cert[0x240];\n\tu8   crc16_pad22[0x10];\n\n\tchar battery_lot[0x1E];\n\tu8   crc16_pad23[2];\n\tnx_emmc_cal0_spk_t spk_cal;\n\tu8   spk_cal_rsvd[0x800 - sizeof(nx_emmc_cal0_spk_t)];\n\tu8   crc16_pad24[0x10];\n\tu32  region_code;\n\tu8   crc16_pad25[0xC];\n\n\tu8   amiibo_key[0x50];\n\tu8   crc16_pad26[0x10];\n\tu8   amiibo_ecqv_cert[0x14];\n\tu8   crc16_pad27[0xC];\n\tu8   amiibo_ecqdsa_cert[0x70];\n\tu8   crc16_pad28[0x10];\n\tu8   amiibo_ecqv_bls_key[0x40];\n\tu8   crc16_pad29[0x10];\n\tu8   amiibo_ecqv_bls_cert[0x20];\n\tu8   crc16_pad30[0x10];\n\tu8   amiibo_ecqv_bls_root_cert[0x90];\n\tu8   crc16_pad31[0x10];\n\n\tu32  product_model; // 1: Nx, 2: Copper, 4: Hoag.\n\tu8   crc16_pad32[0xC];\n\tu8   home_menu_scheme_main_color[6];\n\tu8   crc16_pad33[0xA];\n\tu32  lcd_bl_brightness_mapping[3]; // Floats. Normally 100%, 0% and 2%.\n\tu8   crc16_pad34[0x4];\n\n\tu8   ext_ecc_b233_device_key[0x50];\n\tu8   crc16_pad35[0x10];\n\tu8   ext_ecc_p256_eticket_key[0x50];\n\tu8   crc16_pad36[0x10];\n\tu8   ext_ecc_b233_eticket_key[0x50];\n\tu8   crc16_pad37[0x10];\n\tu8   ext_ecc_rsa2048_eticket_key[0x240];\n\tu8   crc16_pad38[0x10];\n\tu8   ext_ssl_key[0x130];\n\tu8   crc16_pad39[0x10];\n\tu8   ext_gc_key[0x130];\n\tu8   crc16_pad40[0x10];\n\n\tu32  lcd_vendor;\n\tu8   crc16_pad41[0xC];\n\n\t// 5.0.0 and up.\n\tu8   ext_rsa2048_device_key[0x240];\n\tu8   crc16_pad42[0x10];\n\tu8   rsa2048_device_cert[0x240];\n\tu8   crc16_pad43[0x10];\n\n\tu8   usbc_pwr_src_circuit_ver;\n\tu8   crc16_pad44[0xF];\n\n\t// 9.0.0 and up.\n\tu32  home_menu_scheme_sub_color;\n\tu8   crc16_pad45[0xC];\n\tu32  home_menu_scheme_bezel_color;\n\tu8   crc16_pad46[0xC];\n\tu32  home_menu_scheme_main_color1;\n\tu8   crc16_pad47[0xC];\n\tu32  home_menu_scheme_main_color2;\n\tu8   crc16_pad48[0xC];\n\tu32  home_menu_scheme_main_color3;\n\tu8   crc16_pad49[0xC];\n\n\tu8   analog_stick_type_l;\n\tu8   crc16_pad50[0xF];\n\tu8   analog_stick_param_l[0x12];\n\tu8   crc16_pad51[0xE];\n\tu8   analog_stick_cal_l[0x9];\n\tu8   crc16_pad52[0x7];\n\tu8   analog_stick_type_r;\n\tu8   crc16_pad53[0xF];\n\tu8   analog_stick_param_r[0x12];\n\tu8   crc16_pad54[0xE];\n\tu8   analog_stick_cal_r[0x9];\n\tu8   crc16_pad55[0x7];\n\tu8   console_6axis_sensor_type;\n\tu8   crc16_pad56[0xF];\n\tu8   console_6axis_sensor_hor_off[0x6];\n\tu8   crc16_pad57[0xA];\n\n\t// 6.0.0 and up.\n\tu8   battery_ver;\n\tu8   crc16_pad58[0xF];\n\n\t// 10.0.0 and up.\n\tu8   touch_ic_vendor_id;\n\tu8   crc16_pad59[0xF];\n\n\t// 9.0.0 and up.\n\tu32  color_model;\n\tu8   crc16_pad60[0xC];\n\n\t// 10.0.0 and up.\n\tu8   console_6axis_sensor_mount_type;\n\tu8   crc16_pad61[0xF];\n} __attribute__((packed)) nx_emmc_cal0_t;\n\nint  nx_emmc_bis_read(u32 sector, u32 count, void *buff);\nint  nx_emmc_bis_write(u32 sector, u32 count, void *buff);\nvoid nx_emmc_bis_init(emmc_part_t *part, bool enable_cache, u32 emummc_offset);\nvoid nx_emmc_bis_end();\n\n#endif\n"
  },
  {
    "path": "bdk/storage/ramdisk.c",
    "content": "/*\n * Ramdisk driver for Tegra X1\n *\n * Copyright (c) 2019-2021 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include \"ramdisk.h\"\n#include <libs/fatfs/diskio.h>\n#include <libs/fatfs/ff.h>\n#include <mem/heap.h>\n#include <utils/types.h>\n\n#include <memory_map.h>\n\nstatic u32 disk_size = 0;\n\nint ram_disk_init(void *ram_fs, u32 ramdisk_size)\n{\n\tint res = 0;\n\tdisk_size = ramdisk_size;\n\tFATFS *ram_fatfs = (FATFS *)ram_fs;\n\n\t// If ramdisk is not raw, format it.\n\tif (ram_fs)\n\t{\n\t\tu8 *buf = malloc(0x400000);\n\n\t\t// Set ramdisk size.\n\t\tramdisk_size >>= 9;\n\t\tdisk_set_info(DRIVE_RAM, SET_SECTOR_COUNT, &ramdisk_size);\n\n\t\t// Unmount ramdisk.\n\t\tf_unmount(\"ram:\");\n\n\t\t// Format as exFAT w/ 32KB cluster with no MBR.\n\t\tres = f_mkfs(\"ram:\", FM_EXFAT | FM_SFD, RAMDISK_CLUSTER_SZ, buf, 0x400000);\n\n\t\t// Mount ramdisk.\n\t\tif (!res)\n\t\t\tres = f_mount(ram_fatfs, \"ram:\", 1);\n\n\t\tfree(buf);\n\t}\n\n\treturn res;\n}\n\nint ram_disk_read(u32 sector, u32 sector_count, void *buf)\n{\n\tu32 sector_off = RAM_DISK_ADDR + (sector << 9);\n\tu32 bytes_count = sector_count << 9;\n\n\tif ((sector_off - RAM_DISK_ADDR) > disk_size)\n\t\treturn 1;\n\n\tmemcpy(buf, (void *)sector_off, bytes_count);\n\n\treturn 0;\n}\n\nint ram_disk_write(u32 sector, u32 sector_count, const void *buf)\n{\n\tu32 sector_off = RAM_DISK_ADDR + (sector << 9);\n\tu32 bytes_count = sector_count << 9;\n\n\tif ((sector_off - RAM_DISK_ADDR) > disk_size)\n\t\treturn 1;\n\n\tmemcpy((void *)sector_off, buf, bytes_count);\n\n\treturn 0;\n}\n"
  },
  {
    "path": "bdk/storage/ramdisk.h",
    "content": "/*\n * Ramdisk driver for Tegra X1\n *\n * Copyright (c) 2019-2021 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef RAM_DISK_H\n#define RAM_DISK_H\n\n#include <utils/types.h>\n\n#define RAMDISK_CLUSTER_SZ 32768\n\nint ram_disk_init(void *ram_fs, u32 ramdisk_size);\nint ram_disk_read(u32 sector, u32 sector_count, void *buf);\nint ram_disk_write(u32 sector, u32 sector_count, const void *buf);\n\n#endif"
  },
  {
    "path": "bdk/storage/sd.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2023 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <storage/sd.h>\n#include <storage/sdmmc.h>\n#include <storage/sdmmc_driver.h>\n#include <gfx_utils.h>\n#include <libs/fatfs/ff.h>\n#include <mem/heap.h>\n\n#ifndef BDK_SDMMC_UHS_DDR200_SUPPORT\n#define SD_DEFAULT_SPEED SD_UHS_SDR104\n#else\n#define SD_DEFAULT_SPEED SD_UHS_DDR208\n#endif\n\nstatic bool sd_mounted = false;\nstatic bool sd_init_done = false;\nstatic bool insertion_event = false;\nstatic u16  sd_errors[3] = { 0 }; // Init and Read/Write errors.\nstatic u32  sd_mode = SD_DEFAULT_SPEED;\n\n\nsdmmc_t sd_sdmmc;\nsdmmc_storage_t sd_storage;\nFATFS sd_fs;\n\nvoid sd_error_count_increment(u8 type)\n{\n\tswitch (type)\n\t{\n\tcase SD_ERROR_INIT_FAIL:\n\t\tsd_errors[0]++;\n\t\tbreak;\n\tcase SD_ERROR_RW_FAIL:\n\t\tsd_errors[1]++;\n\t\tbreak;\n\tcase SD_ERROR_RW_RETRY:\n\t\tsd_errors[2]++;\n\t\tbreak;\n\t}\n}\n\nu16 *sd_get_error_count()\n{\n\treturn sd_errors;\n}\n\nbool sd_get_card_removed()\n{\n\tif (insertion_event && !sdmmc_get_sd_inserted())\n\t\treturn true;\n\n\treturn false;\n}\n\nbool sd_get_card_initialized()\n{\n\treturn sd_init_done;\n}\n\nbool sd_get_card_mounted()\n{\n\treturn sd_mounted;\n}\n\nu32 sd_get_mode()\n{\n\treturn sd_mode;\n}\n\nint sd_init_retry(bool power_cycle)\n{\n\tu32 bus_width = SDMMC_BUS_WIDTH_4;\n#ifndef BDK_SDMMC_UHS_DDR200_SUPPORT\n\tu32 type = SDHCI_TIMING_UHS_SDR104;\n#else\n\tu32 type = SDHCI_TIMING_UHS_DDR200;\n#endif\n\n\t// Power cycle SD card.\n\tif (power_cycle)\n\t{\n\t\tsd_mode--;\n\t\tsdmmc_storage_end(&sd_storage);\n\t}\n\n\t// Get init parameters.\n\tswitch (sd_mode)\n\t{\n\tcase SD_INIT_FAIL: // Reset to max.\n\t\treturn 1;\n\n\tcase SD_1BIT_HS25:\n\t\tbus_width = SDMMC_BUS_WIDTH_1;\n\t\ttype = SDHCI_TIMING_SD_HS25;\n\t\tbreak;\n\n\tcase SD_4BIT_HS25:\n\t\ttype = SDHCI_TIMING_SD_HS25;\n\t\tbreak;\n\n\tcase SD_UHS_SDR82:\n\t\ttype = SDHCI_TIMING_UHS_SDR82;\n\t\tbreak;\n\n\tcase SD_UHS_SDR104:\n\t\ttype = SDHCI_TIMING_UHS_SDR104;\n\t\tbreak;\n\n#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT\n\tcase SD_UHS_DDR208:\n\t\ttype = SDHCI_TIMING_UHS_DDR200;\n\t\tbreak;\n#endif\n\n\tdefault:\n\t\tsd_mode = SD_DEFAULT_SPEED;\n\t\tbreak;\n\t}\n\n\tint res = sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, bus_width, type);\n\tif (!res)\n\t{\n\t\tsd_init_done    = true;\n\t\tinsertion_event = true;\n\t}\n\telse\n\t\tsd_init_done = false;\n\n\treturn res;\n}\n\nint sd_initialize(bool power_cycle)\n{\n\tif (power_cycle)\n\t\tsdmmc_storage_end(&sd_storage);\n\n\tint res = sd_init_retry(false);\n\n\twhile (true)\n\t{\n\t\tif (!res)\n\t\t\treturn 0;\n\t\telse if (!sdmmc_get_sd_inserted()) // SD Card is not inserted.\n\t\t{\n\t\t\tsd_mode = SD_DEFAULT_SPEED;\n\t\t\tbreak;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsd_errors[SD_ERROR_INIT_FAIL]++;\n\n\t\t\tif (sd_mode == SD_INIT_FAIL)\n\t\t\t\tbreak;\n\t\t\telse\n\t\t\t\tres = sd_init_retry(true);\n\t\t}\n\t}\n\n\tsdmmc_storage_end(&sd_storage);\n\n\treturn 1;\n}\n\nint sd_mount()\n{\n\tif (sd_init_done && sd_mounted)\n\t\treturn 0;\n\n\tint res = 0;\n\n\tif (!sd_init_done)\n\t\tres = sd_initialize(false);\n\n\tif (res)\n\t{\n\t\tgfx_con.mute = false;\n\t\tEPRINTF(\"Failed to init SD card.\");\n\t\tif (!sdmmc_get_sd_inserted())\n\t\t\tEPRINTF(\"Make sure that it is inserted.\");\n\t\telse\n\t\t\tEPRINTF(\"SD Card Reader is not properly seated!\");\n\t}\n\telse\n\t{\n\t\tif (!sd_mounted)\n\t\t\tres = f_mount(&sd_fs, \"0:\", 1); // Volume 0 is SD.\n\t\tif (res == FR_OK)\n\t\t{\n\t\t\tsd_mounted = true;\n\t\t\treturn 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tgfx_con.mute = false;\n\t\t\tEPRINTFARGS(\"Failed to mount SD card (FatFS Error %d).\\nMake sure that a FAT partition exists..\", res);\n\t\t}\n\t}\n\n\treturn 1;\n}\n\nstatic void _sd_deinit(bool deinit)\n{\n\tif (deinit)\n\t{\n\t\tinsertion_event = false;\n\t\tif (sd_mode == SD_INIT_FAIL)\n\t\t\tsd_mode = SD_DEFAULT_SPEED;\n\t}\n\n\tif (sd_init_done)\n\t{\n\t\tif (sd_mounted)\n\t\t\tf_unmount(\"0:\"); // Volume 0 is SD.\n\n\t\tif (deinit)\n\t\t{\n\t\t\tsdmmc_storage_end(&sd_storage);\n\t\t\tsd_init_done = false;\n\t\t}\n\t}\n\tsd_mounted = false;\n}\n\nvoid sd_unmount() { _sd_deinit(false); }\nvoid sd_end()     { _sd_deinit(true); }\n\nbool sd_is_gpt()\n{\n\treturn sd_fs.part_type;\n}\n\nvoid *sd_file_read(const char *path, u32 *fsize)\n{\n\tFIL fp;\n\tif (!sd_get_card_mounted())\n\t\treturn NULL;\n\n\tif (f_open(&fp, path, FA_READ) != FR_OK)\n\t\treturn NULL;\n\n\tu32 size = f_size(&fp);\n\tif (fsize)\n\t\t*fsize = size;\n\n\tvoid *buf = malloc(size);\n\n\tif (f_read(&fp, buf, size, NULL) != FR_OK)\n\t{\n\t\tfree(buf);\n\t\tf_close(&fp);\n\n\t\treturn NULL;\n\t}\n\n\tf_close(&fp);\n\n\treturn buf;\n}\n\nint sd_save_to_file(const void *buf, u32 size, const char *filename)\n{\n\tFIL fp;\n\tu32 res = 0;\n\tif (!sd_get_card_mounted())\n\t\treturn FR_DISK_ERR;\n\n\tres = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE);\n\tif (res)\n\t{\n\t\tEPRINTFARGS(\"Error (%d) creating file\\n%s.\\n\", res, filename);\n\t\treturn res;\n\t}\n\n\tf_write(&fp, buf, size, NULL);\n\tf_close(&fp);\n\n\treturn 0;\n}\n"
  },
  {
    "path": "bdk/storage/sd.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2023 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef SD_H\n#define SD_H\n\n#include <storage/sdmmc.h>\n#include <storage/sdmmc_driver.h>\n#include <libs/fatfs/ff.h>\n\n#define SD_BLOCKSIZE SDMMC_DAT_BLOCKSIZE\n\nenum\n{\n\tSD_INIT_FAIL  = 0,\n\tSD_1BIT_HS25  = 1,\n\tSD_4BIT_HS25  = 2,\n\tSD_UHS_SDR82  = 3,\n\tSD_UHS_SDR104 = 4,\n#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT\n    SD_UHS_DDR208 = 5\n#endif\n\n};\n\nenum\n{\n\tSD_ERROR_INIT_FAIL = 0,\n\tSD_ERROR_RW_FAIL   = 1,\n\tSD_ERROR_RW_RETRY  = 2\n};\n\nextern sdmmc_t sd_sdmmc;\nextern sdmmc_storage_t sd_storage;\nextern FATFS sd_fs;\n\nvoid sd_error_count_increment(u8 type);\nu16 *sd_get_error_count();\nbool sd_get_card_removed();\nbool sd_get_card_initialized();\nbool sd_get_card_mounted();\nu32  sd_get_mode();\nint  sd_init_retry(bool power_cycle);\nint  sd_initialize(bool power_cycle);\nint  sd_mount();\nvoid sd_unmount();\nvoid sd_end();\nbool sd_is_gpt();\nvoid *sd_file_read(const char *path, u32 *fsize);\nint  sd_save_to_file(const void *buf, u32 size, const char *filename);\n\n#endif"
  },
  {
    "path": "bdk/storage/sd_def.h",
    "content": "/*\n *  Copyright (c) 2005-2007 Pierre Ossman, All Rights Reserved.\n *  Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or (at\n * your option) any later version.\n */\n\n#ifndef SD_DEF_H\n#define SD_DEF_H\n\n/* SD commands                           type  argument     response */\n/* class 0 */\n/* This is basically the same command as for MMC with some quirks. */\n#define SD_SEND_RELATIVE_ADDR     3 /* bcr                     R6  */\n#define SD_SEND_IF_COND           8 /* bcr  [11:0] See below   R7  */\n#define SD_SWITCH_VOLTAGE        11 /* ac                      R1  */\n/* Class 2 */\n#define SD_ADDR_EXT              22 /* ac   [5:0]              R1  */\n/* class 10 */\n#define SD_SWITCH                 6 /* adtc [31:0] See below   R1  */\n/* class 5 */\n#define SD_ERASE_WR_BLK_START    32 /* ac   [31:0] data addr   R1  */\n#define SD_ERASE_WR_BLK_END      33 /* ac   [31:0] data addr   R1  */\n /* class 11 */\n#define SD_READ_EXTR_SINGLE      48 /* adtc [31:0]             R1  */\n#define SD_WRITE_EXTR_SINGLE     49 /* adtc [31:0]             R1  */\n\n/* Application commands */\n#define SD_APP_SET_BUS_WIDTH             6 /* ac   [1:0] bus width    R1  */\n#define SD_APP_SD_STATUS                13 /* adtc                    R1  */\n#define SD_APP_SEND_NUM_WR_BLKS         22 /* adtc                    R1  */\n#define SD_APP_OP_COND                  41 /* bcr  [31:0] OCR         R3  */\n#define SD_APP_SET_CLR_CARD_DETECT      42 /* adtc                    R1  */\n#define SD_APP_SEND_SCR                 51 /* adtc                    R1  */\n\n/* Application secure commands */\n#define SD_APP_SECURE_READ_MULTI_BLOCK  18 /* adtc                      R1  */\n#define SD_APP_SECURE_WRITE_MULTI_BLOCK 25 /* adtc                      R1  */\n#define SD_APP_SECURE_WRITE_MKB         26 /* adtc                      R1  */\n#define SD_APP_SECURE_ERASE             38 /* adtc                      R1b */\n#define SD_APP_GET_MKB                  43 /* adtc   [31:0] See below   R1  */\n#define SD_APP_GET_MID                  44 /* adtc                      R1  */\n#define SD_APP_SET_CER_RN1              45 /* adtc                      R1  */\n#define SD_APP_GET_CER_RN2              46 /* adtc                      R1  */\n#define SD_APP_SET_CER_RES2             47 /* adtc                      R1  */\n#define SD_APP_GET_CER_RES1             48 /* adtc                      R1  */\n#define SD_APP_CHANGE_SECURE_AREA       49 /* adtc                      R1b */\n\n/* OCR bit definitions */\n#define SD_OCR_VDD_18       (1U << 7)     /* VDD voltage 1.8 */\n#define SD_VHS_27_36        (1U << 8)     /* VDD voltage 2.7 ~ 3.6 */\n#define SD_OCR_VDD_32_33    (1U << 20)    /* VDD voltage 3.2 ~ 3.3 */\n#define SD_OCR_S18R         (1U << 24)    /* 1.8V switching request */\n#define SD_ROCR_S18A        SD_OCR_S18R   /* 1.8V switching accepted by card */\n#define SD_OCR_XPC          (1U << 28)    /* SDXC power control */\n#define SD_OCR_CCS          (1U << 30)    /* Card Capacity Status */\n#define SD_OCR_BUSY         (1U << 31)    /* Card Power up Status */\n\n/*\n * SD_SWITCH argument format:\n *\n *      [31] Check (0) or switch (1)\n *      [30:24] Reserved (0)\n *      [23:20] Function group 6\n *      [19:16] Function group 5\n *      [15:12] Function group 4\n *      [11:8] Function group 3\n *      [7:4] Function group 2\n *      [3:0] Function group 1\n */\n\n/*\n * SD_SEND_IF_COND argument format:\n *\n *\t[31:12] Reserved (0)\n *\t[11:8] Host Voltage Supply Flags\n *\t[7:0] Check Pattern (0xAA)\n */\n\n/*\n * SD_APP_GET_MKB argument format:\n *\n *\t[31:24] Number of blocks to read (512 block size)\n *\t[23:16] MKB ID\n *\t[15:0] Block offset\n */\n\n/*\n * SCR field definitions\n */\n#define SCR_SPEC_VER_0\t\t0\t/* Implements system specification 1.0 - 1.01 */\n#define SCR_SPEC_VER_1\t\t1\t/* Implements system specification 1.10 */\n#define SCR_SPEC_VER_2\t\t2\t/* Implements system specification 2.00-3.0X */\n#define SD_SCR_BUS_WIDTH_1\t(1U << 0)\n#define SD_SCR_BUS_WIDTH_4\t(1U << 2)\n\n/*\n * SD bus widths\n */\n#define SD_BUS_WIDTH_1\t\t0\n#define SD_BUS_WIDTH_4\t\t2\n\n/*\n * SD bus speeds\n */\n#define UHS_SDR12_BUS_SPEED\t0\n#define HIGH_SPEED_BUS_SPEED\t1\n#define UHS_SDR25_BUS_SPEED\t1\n#define UHS_SDR50_BUS_SPEED\t2\n#define UHS_SDR104_BUS_SPEED\t3\n#define UHS_DDR50_BUS_SPEED\t4\n#define HS400_BUS_SPEED \t5\n\n#define SD_MODE_HIGH_SPEED\t(1U << HIGH_SPEED_BUS_SPEED)\n#define SD_MODE_UHS_SDR12\t(1U << UHS_SDR12_BUS_SPEED)\n#define SD_MODE_UHS_SDR25\t(1U << UHS_SDR25_BUS_SPEED)\n#define SD_MODE_UHS_SDR50\t(1U << UHS_SDR50_BUS_SPEED)\n#define SD_MODE_UHS_SDR104\t(1U << UHS_SDR104_BUS_SPEED)\n#define SD_MODE_UHS_DDR50\t(1U << UHS_DDR50_BUS_SPEED)\n\n\n#define SD_SET_DRIVER_TYPE_B\t0\n#define SD_SET_DRIVER_TYPE_A\t1\n#define SD_SET_DRIVER_TYPE_C\t2\n#define SD_SET_DRIVER_TYPE_D\t3\n\n#define SD_DRIVER_TYPE_B\t(1U << SD_SET_DRIVER_TYPE_B)\n#define SD_DRIVER_TYPE_A\t(1U << SD_SET_DRIVER_TYPE_A)\n#define SD_DRIVER_TYPE_C\t(1U << SD_SET_DRIVER_TYPE_C)\n#define SD_DRIVER_TYPE_D\t(1U << SD_SET_DRIVER_TYPE_D)\n\n#define SD_SET_POWER_LIMIT_0_72\t0\n#define SD_SET_POWER_LIMIT_1_44\t1\n#define SD_SET_POWER_LIMIT_2_16\t2\n#define SD_SET_POWER_LIMIT_2_88\t3\n\n#define SD_MAX_POWER_0_72\t(1U << SD_SET_POWER_LIMIT_0_72)\n#define SD_MAX_POWER_1_44\t(1U << SD_SET_POWER_LIMIT_1_44)\n#define SD_MAX_POWER_2_16\t(1U << SD_SET_POWER_LIMIT_2_16)\n#define SD_MAX_POWER_2_88\t(1U << SD_SET_POWER_LIMIT_2_88)\n\n#define SD_SET_CMD_SYSTEM_DEF\t0\n#define SD_SET_CMD_SYSTEM_MEC\t1\n#define SD_SET_CMD_SYSTEM_OTP\t3\n#define SD_SET_CMD_SYSTEM_OSD\t3\n#define SD_SET_CMD_SYSTEM_VND\t14\n#define UHS_DDR200_BUS_SPEED\tSD_SET_CMD_SYSTEM_VND\n\n#define SD_CMD_SYSTEM_DEF\t(1U << SD_SET_CMD_SYSTEM_DEF)\n#define SD_CMD_SYSTEM_MEC\t(1U << SD_SET_CMD_SYSTEM_MEC)\n#define SD_CMD_SYSTEM_OTP\t(1U << SD_SET_CMD_SYSTEM_OTP)\n#define SD_CMD_SYSTEM_OSD\t(1U << SD_SET_CMD_SYSTEM_OSD)\n#define SD_CMD_SYSTEM_VND\t(1U << SD_SET_CMD_SYSTEM_VND)\n#define SD_MODE_UHS_DDR200\tSD_CMD_SYSTEM_VND\n\n/*\n * SD_SWITCH mode\n */\n#define SD_SWITCH_CHECK\t\t0\n#define SD_SWITCH_SET\t\t1\n\n/*\n * SD_SWITCH function groups\n */\n#define SD_SWITCH_GRP_ACCESS\t0\n#define SD_SWITCH_GRP_CMDSYS\t1\n#define SD_SWITCH_GRP_DRVSTR\t2\n#define SD_SWITCH_GRP_PWRLIM\t3\n\n/*\n * SD_SWITCH access modes\n */\n#define SD_SWITCH_ACCESS_DEF\t0\n#define SD_SWITCH_ACCESS_HS\t1\n\n#endif /* SD_DEF_H */\n"
  },
  {
    "path": "bdk/storage/sdmmc.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <mem/heap.h>\n#include <mem/mc.h>\n#include <soc/timer.h>\n#include <storage/emmc.h>\n#include <storage/sdmmc.h>\n#include <storage/mmc_def.h>\n#include <storage/sd.h>\n#include <storage/sd_def.h>\n#include <memory_map.h>\n#include <gfx_utils.h>\n\n//#define DPRINTF(...) gfx_printf(__VA_ARGS__)\n#define DPRINTF(...)\n\n//#define SDMMC_DEBUG_PRINT_SD_REGS\n#ifdef SDMMC_DEBUG_PRINT_SD_REGS\n#define DREGPRINTF(...) gfx_printf(__VA_ARGS__)\n#else\n#define DREGPRINTF(...)\n#endif\n\n#ifdef BDK_SDMMC_EXTRA_PRINT\n#define ERROR_EXTRA_PRINTING\n#endif\n\nu32 sd_power_cycle_time_start;\n\nstatic inline u32 unstuff_bits(const u32 *resp, u32 start, u32 size)\n{\n\tstart %= 128;\n\n\tconst u32 mask = (size < 32 ? 1 << size : 0) - 1;\n\tconst u32 off  = 3 - ((start) / 32);\n\tconst u32 shft = (start) & 31;\n\n\tu32 res = resp[off] >> shft;\n\tif (size + shft > 32)\n\t\tres |= resp[off - 1] << ((32 - shft) % 32);\n\treturn res & mask;\n}\n\n/*\n * Common functions for SD and MMC.\n */\n\nstatic int _sdmmc_storage_check_card_status(u32 res)\n{\n\t//Error mask:\n\t//!WARN: R1_SWITCH_ERROR is reserved on SD. The card isn't supposed to use it.\n\tif (res &\n\t\t(R1_OUT_OF_RANGE       | R1_ADDRESS_ERROR | R1_BLOCK_LEN_ERROR |\n\t\t R1_ERASE_SEQ_ERROR    | R1_ERASE_PARAM   | R1_WP_VIOLATION    |\n\t\t R1_LOCK_UNLOCK_FAILED | R1_COM_CRC_ERROR | R1_ILLEGAL_COMMAND |\n\t\t R1_CARD_ECC_FAILED    | R1_CC_ERROR      | R1_ERROR           |\n\t\t R1_CID_CSD_OVERWRITE  | R1_WP_ERASE_SKIP | R1_ERASE_RESET     |\n\t\t R1_SWITCH_ERROR))\n\t\treturn 1;\n\n\t// No errors.\n\treturn 0;\n}\n\nstatic int _sdmmc_storage_execute_cmd_type1_ex(sdmmc_storage_t *storage, u32 *resp, u32 cmd, u32 arg, u32 check_busy, u32 expected_state, u32 mask)\n{\n\tsdmmc_cmd_t cmdbuf;\n\tsdmmc_init_cmd(&cmdbuf, cmd, arg, SDMMC_RSP_TYPE_1, check_busy);\n\tif (sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL))\n\t\treturn 1;\n\n\tsdmmc_get_cached_rsp(storage->sdmmc, resp, SDMMC_RSP_TYPE_1);\n\tif (mask)\n\t\t*resp &= ~mask;\n\n\tif (!_sdmmc_storage_check_card_status(*resp))\n\t\tif (expected_state == R1_SKIP_STATE_CHECK || R1_CURRENT_STATE(*resp) == expected_state)\n\t\t\treturn 0;\n\n\treturn 1;\n}\n\nstatic int _sdmmc_storage_execute_cmd_type1(sdmmc_storage_t *storage, u32 cmd, u32 arg, u32 check_busy, u32 expected_state)\n{\n\tu32 tmp;\n\treturn _sdmmc_storage_execute_cmd_type1_ex(storage, &tmp, cmd, arg, check_busy, expected_state, 0);\n}\n\nstatic int _sdmmc_storage_go_idle_state(sdmmc_storage_t *storage)\n{\n\tsdmmc_cmd_t cmdbuf;\n\tsdmmc_init_cmd(&cmdbuf, MMC_GO_IDLE_STATE, 0, SDMMC_RSP_TYPE_0, 0);\n\n\treturn sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL);\n}\n\nstatic int _sdmmc_storage_get_cid(sdmmc_storage_t *storage)\n{\n\tsdmmc_cmd_t cmdbuf;\n\tsdmmc_init_cmd(&cmdbuf, MMC_ALL_SEND_CID, 0, SDMMC_RSP_TYPE_2, 0);\n\tif (sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL))\n\t\treturn 1;\n\n\tsdmmc_get_cached_rsp(storage->sdmmc, (u32 *)storage->raw_cid, SDMMC_RSP_TYPE_2);\n\n\treturn 0;\n}\n\nstatic int _sdmmc_storage_select_card(sdmmc_storage_t *storage)\n{\n\treturn _sdmmc_storage_execute_cmd_type1(storage, MMC_SELECT_CARD, storage->rca << 16, 1, R1_SKIP_STATE_CHECK);\n}\n\nstatic int _sdmmc_storage_get_csd(sdmmc_storage_t *storage)\n{\n\tsdmmc_cmd_t cmdbuf;\n\tsdmmc_init_cmd(&cmdbuf, MMC_SEND_CSD, storage->rca << 16, SDMMC_RSP_TYPE_2, 0);\n\tif (sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL))\n\t\treturn 1;\n\n\tsdmmc_get_cached_rsp(storage->sdmmc, (u32 *)storage->raw_csd, SDMMC_RSP_TYPE_2);\n\n\treturn 0;\n}\n\nstatic int _sdmmc_storage_set_blocklen(sdmmc_storage_t *storage, u32 blocklen)\n{\n\treturn _sdmmc_storage_execute_cmd_type1(storage, MMC_SET_BLOCKLEN, blocklen, 0, R1_STATE_TRAN);\n}\n\nstatic int _sdmmc_storage_get_status(sdmmc_storage_t *storage, u32 *resp, u32 mask)\n{\n\treturn _sdmmc_storage_execute_cmd_type1_ex(storage, resp, MMC_SEND_STATUS, storage->rca << 16, 0, R1_STATE_TRAN, mask);\n}\n\nstatic int _sdmmc_storage_check_status(sdmmc_storage_t *storage)\n{\n\tu32 tmp;\n\treturn _sdmmc_storage_get_status(storage, &tmp, 0);\n}\n\nint sdmmc_storage_execute_vendor_cmd(sdmmc_storage_t *storage, u32 arg)\n{\n\tsdmmc_cmd_t cmdbuf;\n\tsdmmc_init_cmd(&cmdbuf, MMC_VENDOR_62_CMD, arg, SDMMC_RSP_TYPE_1, 1);\n\tif (sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0))\n\t\treturn 1;\n\n\tu32 resp;\n\tsdmmc_get_cached_rsp(storage->sdmmc, &resp, SDMMC_RSP_TYPE_1);\n\n\tresp = -1;\n\tu32 timeout = get_tmr_ms() + 1500;\n\twhile (true)\n\t{\n\t\t_sdmmc_storage_get_status(storage, &resp, 0);\n\n\t\tif (resp == (R1_READY_FOR_DATA | R1_STATE(R1_STATE_TRAN)))\n\t\t\tbreak;\n\n\t\tif (get_tmr_ms() > timeout)\n\t\t\tbreak;\n\t\tmsleep(10);\n\t}\n\n\treturn _sdmmc_storage_check_card_status(resp);\n}\n\nint sdmmc_storage_vendor_sandisk_report(sdmmc_storage_t *storage, void *buf)\n{\n\t// Request health report.\n\tif (sdmmc_storage_execute_vendor_cmd(storage, MMC_SANDISK_HEALTH_REPORT))\n\t\treturn 2;\n\n\tu32 tmp = 0;\n\tsdmmc_cmd_t cmdbuf;\n\tsdmmc_req_t reqbuf;\n\n\tsdmmc_init_cmd(&cmdbuf, MMC_VENDOR_63_CMD, 0, SDMMC_RSP_TYPE_1, 0); // similar to CMD17 with arg 0x0.\n\n\treqbuf.buf              = buf;\n\treqbuf.num_sectors      = 1;\n\treqbuf.blksize          = SDMMC_DAT_BLOCKSIZE;\n\treqbuf.is_write         = 0;\n\treqbuf.is_multi_block   = 0;\n\treqbuf.is_auto_stop_trn = 0;\n\n\tu32 blkcnt_out;\n\tif (sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, &blkcnt_out))\n\t{\n\t\tsdmmc_stop_transmission(storage->sdmmc, &tmp);\n\t\t_sdmmc_storage_get_status(storage, &tmp, 0);\n\n\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n\nstatic int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out, u32 sector, u32 num_sectors, void *buf, u32 is_write)\n{\n\tu32 tmp = 0;\n\tsdmmc_cmd_t cmdbuf;\n\tsdmmc_req_t reqbuf;\n\n\t// If SDSC convert block address to byte address.\n\tif (!storage->has_sector_access)\n\t\tsector <<= 9;\n\n\tsdmmc_init_cmd(&cmdbuf, is_write ? MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK, sector, SDMMC_RSP_TYPE_1, 0);\n\n\treqbuf.buf              = buf;\n\treqbuf.num_sectors      = num_sectors;\n\treqbuf.blksize          = SDMMC_DAT_BLOCKSIZE;\n\treqbuf.is_write         = is_write;\n\treqbuf.is_multi_block   = 1;\n\treqbuf.is_auto_stop_trn = 1;\n\n\tif (sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, blkcnt_out))\n\t{\n\t\tsdmmc_stop_transmission(storage->sdmmc, &tmp);\n\t\t_sdmmc_storage_get_status(storage, &tmp, 0);\n\n\t\treturn 1;\n\t}\n\n\tsdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);\n\tif (_sdmmc_storage_check_card_status(tmp))\n\t\treturn 1;\n\n\treturn 0;\n}\n\nint sdmmc_storage_end(sdmmc_storage_t *storage)\n{\n\tDPRINTF(\"[SDMMC%d] end\\n\", storage->sdmmc->id);\n\n\tif (_sdmmc_storage_go_idle_state(storage))\n\t\treturn 1;\n\n\tsdmmc_end(storage->sdmmc);\n\n\tstorage->initialized = 0;\n\n\treturn 0;\n}\n\nstatic int _sdmmc_storage_handle_io_error(sdmmc_storage_t *storage, bool first_reinit)\n{\n\tint res = 1;\n\n\tif (storage->sdmmc->id == SDMMC_1 || storage->sdmmc->id == SDMMC_4)\n\t{\n\t\tif (storage->sdmmc->id == SDMMC_1)\n\t\t{\n\t\t\tsd_error_count_increment(SD_ERROR_RW_FAIL);\n\n\t\t\tif (first_reinit)\n\t\t\t\tres = sd_initialize(true);\n\t\t\telse\n\t\t\t{\n\t\t\t\tres = sd_init_retry(true);\n\t\t\t\tif (res)\n\t\t\t\t\tsd_error_count_increment(SD_ERROR_INIT_FAIL);\n\t\t\t}\n\t\t}\n\t\telse if (storage->sdmmc->id == SDMMC_4)\n\t\t{\n\t\t\temmc_error_count_increment(EMMC_ERROR_RW_FAIL);\n\n\t\t\tif (first_reinit)\n\t\t\t\tres = emmc_initialize(true);\n\t\t\telse\n\t\t\t{\n\t\t\t\tres = emmc_init_retry(true);\n\t\t\t\tif (res)\n\t\t\t\t\temmc_error_count_increment(EMMC_ERROR_INIT_FAIL);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn res;\n}\n\nstatic int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf, u32 is_write)\n{\n\tu8 *bbuf = (u8 *)buf;\n\tu32 sct_off = sector;\n\tu32 sct_total = num_sectors;\n\tbool first_reinit = true;\n\n\t// Exit if not initialized.\n\tif (!storage->initialized)\n\t\treturn 1;\n\n\t// Check if out of bounds.\n\tif (((u64)sector + num_sectors) > storage->sec_cnt)\n\t{\n#ifdef ERROR_EXTRA_PRINTING\n\t\tEPRINTFARGS(\"SDMMC%d: Out of bounds!\", storage->sdmmc->id + 1);\n#endif\n\t\treturn 1;\n\t}\n\n\twhile (sct_total)\n\t{\n\t\tu32 blkcnt = 0;\n\t\t// Retry 5 times if failed.\n\t\tu32 retries = 5;\n\t\tdo\n\t\t{\nreinit_try:\n\t\t\tif (!_sdmmc_storage_readwrite_ex(storage, &blkcnt, sct_off, MIN(sct_total, SDMMC_AMAX_BLOCKNUM), bbuf, is_write))\n\t\t\t\tgoto out;\n\t\t\telse\n\t\t\t\tretries--;\n\n\t\t\tsd_error_count_increment(SD_ERROR_RW_RETRY);\n\n\t\t\tmsleep(50);\n\t\t} while (retries);\n\n\t\t// Disk IO failure! Reinit SD/EMMC to a lower speed.\n\t\tif (!_sdmmc_storage_handle_io_error(storage, first_reinit))\n\t\t{\n\t\t\t// Reset values for a retry.\n\t\t\tblkcnt = 0;\n\t\t\tretries = 3;\n\t\t\tfirst_reinit = false;\n\n\t\t\tbbuf = (u8 *)buf;\n\t\t\tsct_off = sector;\n\t\t\tsct_total = num_sectors;\n\n\t\t\tgoto reinit_try;\n\t\t}\n\n\t\t// Failed.\n\t\treturn 1;\n\nout:\n\t\tsct_off += blkcnt;\n\t\tsct_total -= blkcnt;\n\t\tbbuf += SDMMC_DAT_BLOCKSIZE * blkcnt;\n\t}\n\n\treturn 0;\n}\n\nint sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)\n{\n\t// Ensure that SDMMC has access to buffer and it's SDMMC DMA aligned.\n\tif (mc_client_has_access(buf) && !((u32)buf % SDMMC_ADMA_ADDR_ALIGN))\n\t\treturn _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 0);\n\n\tif (num_sectors > (SDMMC_ALT_DMA_BUF_SZ / SDMMC_DAT_BLOCKSIZE))\n\t\treturn 1;\n\n\tu8 *tmp_buf = (u8 *)SDMMC_ALT_DMA_BUFFER;\n\tif (_sdmmc_storage_readwrite(storage, sector, num_sectors, tmp_buf, 0))\n\t\treturn 1;\n\n\tmemcpy(buf, tmp_buf, SDMMC_DAT_BLOCKSIZE * num_sectors);\n\n\treturn 0;\n}\n\nint sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)\n{\n\t// Ensure that SDMMC has access to buffer and it's SDMMC DMA aligned.\n\tif (mc_client_has_access(buf) && !((u32)buf % SDMMC_ADMA_ADDR_ALIGN))\n\t\treturn _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 1);\n\n\tif (num_sectors > (SDMMC_ALT_DMA_BUF_SZ / SDMMC_DAT_BLOCKSIZE))\n\t\treturn 1;\n\n\tu8 *tmp_buf = (u8 *)SDMMC_ALT_DMA_BUFFER;\n\tmemcpy(tmp_buf, buf, SDMMC_DAT_BLOCKSIZE * num_sectors);\n\n\treturn _sdmmc_storage_readwrite(storage, sector, num_sectors, tmp_buf, 1);\n}\n\n/*\n* MMC specific functions.\n*/\n\nstatic int _mmc_storage_get_op_cond_inner(sdmmc_storage_t *storage, u32 *pout, u32 power)\n{\n\tsdmmc_cmd_t cmdbuf;\n\n\tu32 arg = 0;\n\tswitch (power)\n\t{\n\tcase SDMMC_POWER_1_8:\n\t\targ = MMC_CARD_CCS | MMC_CARD_VDD_18;\n\t\tbreak;\n\n\tcase SDMMC_POWER_3_3:\n\t\targ = MMC_CARD_CCS | MMC_CARD_VDD_27_34;\n\t\tbreak;\n\n\tdefault:\n\t\treturn 1;\n\t}\n\n\tsdmmc_init_cmd(&cmdbuf, MMC_SEND_OP_COND, arg, SDMMC_RSP_TYPE_3, 0);\n\tif (sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL))\n\t\treturn 1;\n\n\treturn sdmmc_get_cached_rsp(storage->sdmmc, pout, SDMMC_RSP_TYPE_3);\n}\n\nstatic int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power)\n{\n\tu32 timeout = get_tmr_ms() + 1500;\n\n\twhile (true)\n\t{\n\t\tu32 cond = 0;\n\t\tif (_mmc_storage_get_op_cond_inner(storage, &cond, power))\n\t\t\tbreak;\n\n\t\t// Check if power up is done.\n\t\tif (cond & MMC_CARD_BUSY)\n\t\t{\n\t\t\t// Check if card is high capacity.\n\t\t\tif (cond & MMC_CARD_CCS)\n\t\t\t\tstorage->has_sector_access = 1;\n\n\t\t\treturn 0;\n\t\t}\n\t\tif (get_tmr_ms() > timeout)\n\t\t\tbreak;\n\n\t\tusleep(1000);\n\t}\n\n\treturn 1;\n}\n\nstatic int _mmc_storage_set_relative_addr(sdmmc_storage_t *storage)\n{\n\treturn _sdmmc_storage_execute_cmd_type1(storage, MMC_SET_RELATIVE_ADDR, storage->rca << 16, 0, R1_SKIP_STATE_CHECK);\n}\n\nstatic void _mmc_storage_parse_cid(sdmmc_storage_t *storage)\n{\n\tu32 *raw_cid = (u32 *)&(storage->raw_cid);\n\n\tswitch (storage->csd.mmca_vsn)\n\t{\n\tcase 0: /* MMC v1.0 - v1.2 */\n\tcase 1: /* MMC v1.4 */\n\t\tstorage->cid.prod_name[6] = unstuff_bits(raw_cid, 48, 8);\n\t\tstorage->cid.manfid       = unstuff_bits(raw_cid, 104, 24);\n\t\tstorage->cid.hwrev        = unstuff_bits(raw_cid, 44, 4);\n\t\tstorage->cid.fwrev        = unstuff_bits(raw_cid, 40, 4);\n\t\tstorage->cid.serial       = unstuff_bits(raw_cid, 16, 24);\n\t\tbreak;\n\n\tcase 2: /* MMC v2.0 - v2.2 */\n\tcase 3: /* MMC v3.1 - v3.3 */\n\tcase 4: /* MMC v4 */\n\t\tstorage->cid.manfid = unstuff_bits(raw_cid, 120, 8);\n\t\tstorage->cid.oemid  = unstuff_bits(raw_cid, 104, 8);\n\t\tstorage->cid.prv    = unstuff_bits(raw_cid, 48, 8);\n\t\tstorage->cid.serial = unstuff_bits(raw_cid, 16, 32);\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\tstorage->cid.prod_name[0] = unstuff_bits(raw_cid, 96, 8);\n\tstorage->cid.prod_name[1] = unstuff_bits(raw_cid, 88, 8);\n\tstorage->cid.prod_name[2] = unstuff_bits(raw_cid, 80, 8);\n\tstorage->cid.prod_name[3] = unstuff_bits(raw_cid, 72, 8);\n\tstorage->cid.prod_name[4] = unstuff_bits(raw_cid, 64, 8);\n\tstorage->cid.prod_name[5] = unstuff_bits(raw_cid, 56, 8);\n\n\tstorage->cid.month = unstuff_bits(raw_cid, 12, 4);\n\tstorage->cid.year  = unstuff_bits(raw_cid, 8, 4) + 1997;\n\tif (storage->ext_csd.rev >= 5)\n\t{\n\t\tif (storage->cid.year < 2010)\n\t\t\tstorage->cid.year += 16;\n\t}\n}\n\nstatic void _mmc_storage_parse_csd(sdmmc_storage_t *storage)\n{\n\tu32 *raw_csd = (u32 *)storage->raw_csd;\n\n\tstorage->csd.mmca_vsn     = unstuff_bits(raw_csd, 122, 4);\n\tstorage->csd.structure    = unstuff_bits(raw_csd, 126, 2);\n\tstorage->csd.cmdclass     = unstuff_bits(raw_csd, 84, 12);\n\tstorage->csd.read_blkbits = unstuff_bits(raw_csd, 80, 4);\n\tstorage->csd.capacity     = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2);\n\tstorage->sec_cnt          = storage->csd.capacity;\n}\n\nstatic void _mmc_storage_parse_ext_csd(sdmmc_storage_t *storage)\n{\n\tu8 *ext_csd = storage->raw_ext_csd;\n\n\tstorage->ext_csd.rev          = ext_csd[EXT_CSD_REV];\n\tstorage->ext_csd.ext_struct   = ext_csd[EXT_CSD_STRUCTURE];\n\tstorage->ext_csd.card_type    = ext_csd[EXT_CSD_CARD_TYPE];\n\tstorage->ext_csd.dev_version  = *(u16 *)&ext_csd[EXT_CSD_DEVICE_VERSION];\n\tstorage->ext_csd.boot_mult    = ext_csd[EXT_CSD_BOOT_MULT];\n\tstorage->ext_csd.rpmb_mult    = ext_csd[EXT_CSD_RPMB_MULT];\n\tstorage->ext_csd.bkops        = ext_csd[EXT_CSD_BKOPS_SUPPORT];\n\tstorage->ext_csd.bkops_en     = ext_csd[EXT_CSD_BKOPS_EN];\n\n\tstorage->ext_csd.pre_eol_info   = ext_csd[EXT_CSD_PRE_EOL_INFO];\n\tstorage->ext_csd.dev_life_est_a = ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A];\n\tstorage->ext_csd.dev_life_est_b = ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B];\n\n\tstorage->ext_csd.cache_size   =  ext_csd[EXT_CSD_CACHE_SIZE]            |\n\t\t\t\t\t\t\t\t\t(ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8)  |\n\t\t\t\t\t\t\t\t\t(ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16) |\n\t\t\t\t\t\t\t\t\t(ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24);\n\n\tstorage->ext_csd.max_enh_mult = (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]             |\n\t\t\t\t\t\t\t\t\t(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT + 1] << 8)   |\n\t\t\t\t\t\t\t\t\t(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT + 2] << 16)) *\n\t\t\t\t\t\t\t\t\t ext_csd[EXT_CSD_HC_WP_GRP_SIZE] * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];\n\n\tstorage->sec_cnt = *(u32 *)&ext_csd[EXT_CSD_SEC_CNT];\n}\n\nint mmc_storage_get_ext_csd(sdmmc_storage_t *storage)\n{\n\tsdmmc_cmd_t cmdbuf;\n\tsdmmc_init_cmd(&cmdbuf, MMC_SEND_EXT_CSD, 0, SDMMC_RSP_TYPE_1, 0);\n\n\tsdmmc_req_t reqbuf;\n\treqbuf.buf = storage->raw_ext_csd;\n\treqbuf.blksize = SDMMC_DAT_BLOCKSIZE;\n\treqbuf.num_sectors = 1;\n\treqbuf.is_write = 0;\n\treqbuf.is_multi_block = 0;\n\treqbuf.is_auto_stop_trn = 0;\n\n\tif (sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, NULL))\n\t\treturn 1;\n\n\tu32 tmp = 0;\n\tsdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);\n\t_mmc_storage_parse_ext_csd(storage);\n\n\treturn _sdmmc_storage_check_card_status(tmp);\n}\n\nint sd_storage_get_ext_reg(sdmmc_storage_t *storage, u8 fno, u8 page, u16 address, u32 len, void *buf)\n{\n\tif (!(storage->scr.cmds & BIT(2)))\n\t\treturn 1;\n\n\tsdmmc_cmd_t cmdbuf;\n\n\tu32 arg = fno << 27 | page << 18 | address << 9 | (len - 1);\n\n\tsdmmc_init_cmd(&cmdbuf, SD_READ_EXTR_SINGLE, arg, SDMMC_RSP_TYPE_1, 0);\n\n\tsdmmc_req_t reqbuf;\n\treqbuf.buf = buf;\n\treqbuf.blksize = SDMMC_DAT_BLOCKSIZE;\n\treqbuf.num_sectors = 1;\n\treqbuf.is_write = 0;\n\treqbuf.is_multi_block = 0;\n\treqbuf.is_auto_stop_trn = 0;\n\n\tif (sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, NULL))\n\t\treturn 1;\n\n\tu32 tmp = 0;\n\tsdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);\n\n\treturn _sdmmc_storage_check_card_status(tmp);\n}\n\nstatic int _mmc_storage_switch(sdmmc_storage_t *storage, u32 arg)\n{\n\treturn _sdmmc_storage_execute_cmd_type1(storage, MMC_SWITCH, arg, 1, R1_SKIP_STATE_CHECK);\n}\n\nstatic int _mmc_storage_switch_buswidth(sdmmc_storage_t *storage, u32 bus_width)\n{\n\tif (bus_width == SDMMC_BUS_WIDTH_1)\n\t\treturn 0;\n\n\tu32 arg = 0;\n\tswitch (bus_width)\n\t{\n\tcase SDMMC_BUS_WIDTH_4:\n\t\targ = SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4);\n\t\tbreak;\n\n\tcase SDMMC_BUS_WIDTH_8:\n\t\targ = SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_8);\n\t\tbreak;\n\t}\n\n\tif (!_mmc_storage_switch(storage, arg))\n\t\tif (!_sdmmc_storage_check_status(storage))\n\t\t{\n\t\t\tsdmmc_set_bus_width(storage->sdmmc, bus_width);\n\n\t\t\treturn 0;\n\t\t}\n\n\treturn 1;\n}\n\nstatic int _mmc_storage_enable_HS(sdmmc_storage_t *storage, bool check_sts_before_clk_setup)\n{\n\tif (_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS)))\n\t\treturn 1;\n\n\tif (check_sts_before_clk_setup && _sdmmc_storage_check_status(storage))\n\t\treturn 1;\n\n\tif (sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS52))\n\t\treturn 1;\n\n\tDPRINTF(\"[MMC] switched to HS52\\n\");\n\tstorage->csd.busspeed = 52;\n\n\tif (check_sts_before_clk_setup || !_sdmmc_storage_check_status(storage))\n\t\treturn 0;\n\n\treturn 1;\n}\n\nstatic int _mmc_storage_enable_HS200(sdmmc_storage_t *storage)\n{\n\tif (_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200)))\n\t\treturn 1;\n\n\tif (sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS200))\n\t\treturn 1;\n\n\tif (sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_HS200, MMC_SEND_TUNING_BLOCK_HS200))\n\t\treturn 1;\n\n\tDPRINTF(\"[MMC] switched to HS200\\n\");\n\tstorage->csd.busspeed = 200;\n\n\treturn _sdmmc_storage_check_status(storage);\n}\n\nstatic int _mmc_storage_enable_HS400(sdmmc_storage_t *storage)\n{\n\tif (_mmc_storage_enable_HS200(storage))\n\t\treturn 1;\n\n\tsdmmc_save_tap_value(storage->sdmmc);\n\n\tif (_mmc_storage_enable_HS(storage, false))\n\t\treturn 1;\n\n\tif (_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH, EXT_CSD_DDR_BUS_WIDTH_8)))\n\t\treturn 1;\n\n\tif (_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400)))\n\t\treturn 1;\n\n\tif (sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS400))\n\t\treturn 1;\n\n\tDPRINTF(\"[MMC] switched to HS400\\n\");\n\tstorage->csd.busspeed = 400;\n\n\treturn _sdmmc_storage_check_status(storage);\n}\n\nstatic int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type, u32 type)\n{\n\tif (sdmmc_get_io_power(storage->sdmmc) != SDMMC_POWER_1_8)\n\t\tgoto hs52_mode;\n\n\t// HS400 needs 8-bit bus width mode.\n\tif (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 &&\n\t\tcard_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == SDHCI_TIMING_MMC_HS400)\n\t\treturn _mmc_storage_enable_HS400(storage);\n\n\t// Try HS200 if HS400 and 4-bit width bus or just HS200.\n\tif ((sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 ||\n\t\t sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_4) &&\n\t\tcard_type & EXT_CSD_CARD_TYPE_HS200_1_8V &&\n\t\t(type == SDHCI_TIMING_MMC_HS400 || type == SDHCI_TIMING_MMC_HS200))\n\t\treturn _mmc_storage_enable_HS200(storage);\n\nhs52_mode:\n\tif (card_type & EXT_CSD_CARD_TYPE_HS_52)\n\t\treturn _mmc_storage_enable_HS(storage, true);\n\n\treturn 0;\n}\n\n/*\nstatic int _mmc_storage_enable_auto_bkops(sdmmc_storage_t *storage)\n{\n\tif (_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_SET_BITS, EXT_CSD_BKOPS_EN, EXT_CSD_BKOPS_AUTO)))\n\t\treturn 1;\n\n\treturn _sdmmc_storage_check_status(storage);\n}\n*/\n\nint sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type)\n{\n\tmemset(storage, 0, sizeof(sdmmc_storage_t));\n\tstorage->sdmmc = sdmmc;\n\tstorage->rca = 2; // Set default device address. This could be a config item.\n\n\tDPRINTF(\"[MMC]-[init: bus: %d, type: %d]\\n\", bus_width, type);\n\n\tif (sdmmc_init(sdmmc, SDMMC_4, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_MMC_ID))\n\t\treturn 1;\n\tDPRINTF(\"[MMC] after init\\n\");\n\n\t// Wait 1ms + 74 cycles.\n\tusleep(1000 + (74 * 1000 + sdmmc->card_clock - 1) / sdmmc->card_clock);\n\n\tif (_sdmmc_storage_go_idle_state(storage))\n\t\treturn 1;\n\tDPRINTF(\"[MMC] went to idle state\\n\");\n\n\tif (_mmc_storage_get_op_cond(storage, SDMMC_POWER_1_8))\n\t\treturn 1;\n\tDPRINTF(\"[MMC] got op cond\\n\");\n\n\tif (_sdmmc_storage_get_cid(storage))\n\t\treturn 1;\n\tDPRINTF(\"[MMC] got cid\\n\");\n\n\tif (_mmc_storage_set_relative_addr(storage))\n\t\treturn 1;\n\tDPRINTF(\"[MMC] set relative addr\\n\");\n\n\tif (_sdmmc_storage_get_csd(storage))\n\t\treturn 1;\n\tDPRINTF(\"[MMC] got csd\\n\");\n\t_mmc_storage_parse_csd(storage);\n\n\tif (sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_LS26))\n\t\treturn 1;\n\tDPRINTF(\"[MMC] after setup clock\\n\");\n\n\tif (_sdmmc_storage_select_card(storage))\n\t\treturn 1;\n\tDPRINTF(\"[MMC] card selected\\n\");\n\n\tif (_sdmmc_storage_set_blocklen(storage, EMMC_BLOCKSIZE))\n\t\treturn 1;\n\tDPRINTF(\"[MMC] set blocklen to EMMC_BLOCKSIZE\\n\");\n\n\t// Check system specification version, only version 4.0 and later support below features.\n\tif (storage->csd.mmca_vsn < CSD_SPEC_VER_4)\n\t\tgoto done;\n\n\tif (_mmc_storage_switch_buswidth(storage, bus_width))\n\t\treturn 1;\n\tDPRINTF(\"[MMC] switched buswidth\\n\");\n\n\tif (mmc_storage_get_ext_csd(storage))\n\t\treturn 1;\n\tDPRINTF(\"[MMC] got ext_csd\\n\");\n\n\t_mmc_storage_parse_cid(storage); // This needs to be after csd and ext_csd.\n\n/*\n\tif (storage->cid.manfid == 0x11 && storage->ext_csd.bkops && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_AUTO))\n\t{\n\t\t_mmc_storage_enable_auto_bkops(storage);\n\t\tDPRINTF(\"[MMC] BKOPS enabled\\n\");\n\t}\n*/\n\n\tif (_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type))\n\t\treturn 1;\n\tDPRINTF(\"[MMC] successfully switched to HS mode\\n\");\n\n\tsdmmc_card_clock_powersave(storage->sdmmc, SDMMC_POWER_SAVE_ENABLE);\n\ndone:\n\tstorage->initialized = 1;\n\n\treturn 0;\n}\n\nint sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition)\n{\n\tif (_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_PART_CONFIG, partition)))\n\t\treturn 1;\n\n\tif (_sdmmc_storage_check_status(storage))\n\t\treturn 1;\n\n\tstorage->partition = partition;\n\n\treturn 0;\n}\n\n/*\n * SD specific functions.\n */\n\nstatic int _sd_storage_execute_app_cmd(sdmmc_storage_t *storage, u32 expected_state, u32 mask, sdmmc_cmd_t *cmdbuf, sdmmc_req_t *req, u32 *blkcnt_out)\n{\n\tu32 tmp;\n\tif (_sdmmc_storage_execute_cmd_type1_ex(storage, &tmp, MMC_APP_CMD, storage->rca << 16, 0, expected_state, mask))\n\t\treturn 1;\n\n\treturn sdmmc_execute_cmd(storage->sdmmc, cmdbuf, req, blkcnt_out);\n}\n\nstatic int _sd_storage_execute_app_cmd_type1(sdmmc_storage_t *storage, u32 *resp, u32 cmd, u32 arg, u32 check_busy, u32 expected_state)\n{\n\tif (_sdmmc_storage_execute_cmd_type1(storage, MMC_APP_CMD, storage->rca << 16, 0, R1_STATE_TRAN))\n\t\treturn 1;\n\n\treturn _sdmmc_storage_execute_cmd_type1_ex(storage, resp, cmd, arg, check_busy, expected_state, 0);\n}\n\n#ifdef SDMMC_DEBUG_PRINT_SD_REGS\nvoid _sd_storage_debug_print_cid(const u32 *raw_cid)\n{\n\tgfx_printf(\"Card Identification\\n\");\n\n\tgfx_printf(\"MID:                   %02X\\n\", unstuff_bits(raw_cid, 120, 8));\n\tgfx_printf(\"OID                    %04X\\n\", unstuff_bits(raw_cid, 104, 16));\n\tgfx_printf(\"PNM:                   %02X %02X %02X %02X %02X\\n\",\n\t\tunstuff_bits(raw_cid, 96, 8), unstuff_bits(raw_cid, 88, 8),\n\t\tunstuff_bits(raw_cid, 80, 8), unstuff_bits(raw_cid, 72, 8),\n\t\tunstuff_bits(raw_cid, 64, 8));\n\tgfx_printf(\"PRV:                   %02X\\n\", unstuff_bits(raw_cid, 56, 8));\n\tgfx_printf(\"PSN:                   %08X\\n\", unstuff_bits(raw_cid, 24, 32));\n\tgfx_printf(\"MDT:                   %03X\\n\", unstuff_bits(raw_cid, 8, 12));\n\tgfx_printf(\"--RSVD--               %X\\n\",   unstuff_bits(raw_cid, 20, 4));\n}\n\nvoid _sd_storage_debug_print_csd(const u32 *raw_csd)\n{\n\tgfx_printf(\"\\n\");\n\n\tgfx_printf(\"\\nCSD_STRUCTURE:         %X\\n\", unstuff_bits(raw_csd, 126, 2));\n\tgfx_printf(\"TAAC:                  %02X\\n\", unstuff_bits(raw_csd, 112, 8));\n\tgfx_printf(\"NSAC:                  %02X\\n\", unstuff_bits(raw_csd, 104, 8));\n\tgfx_printf(\"TRAN_SPEED:            %02X\\n\", unstuff_bits(raw_csd, 96, 8));\n\tgfx_printf(\"CCC:                   %03X\\n\", unstuff_bits(raw_csd, 84, 12));\n\tgfx_printf(\"READ_BL_LEN:           %X\\n\",   unstuff_bits(raw_csd, 80, 4));\n\tgfx_printf(\"READ_BL_PARTIAL:       %X\\n\",   unstuff_bits(raw_csd, 79, 1));\n\tgfx_printf(\"WRITE_BLK_MISALIGN:    %X\\n\",   unstuff_bits(raw_csd, 78, 1));\n\tgfx_printf(\"READ_BLK_MISALIGN:     %X\\n\",   unstuff_bits(raw_csd, 77, 1));\n\tgfx_printf(\"DSR_IMP:               %X\\n\",   unstuff_bits(raw_csd, 76, 1));\n\tgfx_printf(\"C_SIZE:                %06X\\n\", unstuff_bits(raw_csd, 48, 28)); // CSD 3 (SDUC).\n\n\tgfx_printf(\"ERASE_BLK_LEN:         %X\\n\",   unstuff_bits(raw_csd, 46, 1));\n\tgfx_printf(\"SECTOR_SIZE:           %02X\\n\", unstuff_bits(raw_csd, 39, 6));\n\tgfx_printf(\"WP_GRP_SIZE:           %02X\\n\", unstuff_bits(raw_csd, 32, 6));\n\tgfx_printf(\"WP_GRP_ENABLE:         %X\\n\",   unstuff_bits(raw_csd, 31, 1));\n\n\tgfx_printf(\"R2W_FACTOR:            %X\\n\",   unstuff_bits(raw_csd, 26, 3));\n\tgfx_printf(\"WRITE_BL_LEN:          %X\\n\",   unstuff_bits(raw_csd, 22, 4));\n\tgfx_printf(\"WRITE_BL_PARTIAL:      %X\\n\",   unstuff_bits(raw_csd, 21, 1));\n\n\tgfx_printf(\"FILE_FORMAT_GRP:       %X\\n\",   unstuff_bits(raw_csd, 15, 1));\n\tgfx_printf(\"COPY:                  %X\\n\",   unstuff_bits(raw_csd, 14, 1));\n\tgfx_printf(\"PERM_WRITE_PROTECT:    %X\\n\",   unstuff_bits(raw_csd, 13, 1));\n\tgfx_printf(\"TMP_WRITE_PROTECT:     %X\\n\",   unstuff_bits(raw_csd, 12, 1));\n\tgfx_printf(\"FILE_FORMAT:           %X\\n\",   unstuff_bits(raw_csd, 10, 2));\n\n\tgfx_printf(\"--RSVD--               %02X %X %X %02X %X\\n\",\n\t\tunstuff_bits(raw_csd, 120, 6),\n\t\tunstuff_bits(raw_csd, 47, 1),  unstuff_bits(raw_csd, 29, 2),\n\t\tunstuff_bits(raw_csd, 16, 5),  unstuff_bits(raw_csd, 8, 2));\n}\n\nvoid _sd_storage_debug_print_scr(const u32 *raw_scr)\n{\n\tu32 resp[4];\n\tmemcpy(&resp[2], raw_scr, 8);\n\n\tgfx_printf(\"\\n\");\n\n\tgfx_printf(\"SCR_STRUCTURE:         %X\\n\",   unstuff_bits(resp, 60, 4));\n\tgfx_printf(\"SD_SPEC:               %X\\n\",   unstuff_bits(resp, 56, 4));\n\tgfx_printf(\"DATA_STAT_AFTER_ERASE: %X\\n\",   unstuff_bits(resp, 55, 1));\n\tgfx_printf(\"SD_SECURITY:           %X\\n\",   unstuff_bits(resp, 52, 3));\n\tgfx_printf(\"SD_BUS widths:         %X\\n\",   unstuff_bits(resp, 48, 4));\n\tgfx_printf(\"SD_SPEC3:              %X\\n\",   unstuff_bits(resp, 47, 1));\n\tgfx_printf(\"EX_SECURITY:           %X\\n\",   unstuff_bits(resp, 43, 4));\n\tgfx_printf(\"SD_SPEC4:              %X\\n\",   unstuff_bits(resp, 42, 1));\n\tgfx_printf(\"SD_SPECX:              %X\\n\",   unstuff_bits(resp, 38, 4));\n\tgfx_printf(\"CMD_SUPPORT:           %X\\n\",   unstuff_bits(resp, 32, 4));\n\tgfx_printf(\"VENDOR:                %08X\\n\", unstuff_bits(resp, 0, 32));\n\tgfx_printf(\"--RSVD--               %X\\n\",   unstuff_bits(resp, 36, 2));\n}\n\nvoid _sd_storage_debug_print_ssr(const u8 *raw_ssr)\n{\n\tu32 raw_ssr0[4]; // 511:384.\n\tu32 raw_ssr1[4]; // 383:256.\n\tu32 raw_ssr2[4]; // 255:128.\n\tu32 raw_ssr3[4]; // 127:0.\n\tmemcpy(raw_ssr0, &raw_ssr[0],  16);\n\tmemcpy(raw_ssr1, &raw_ssr[16], 16);\n\tmemcpy(raw_ssr2, &raw_ssr[32], 16);\n\tmemcpy(raw_ssr3, &raw_ssr[48], 16);\n\n\tgfx_printf(\"\\nSD Status:\\n\");\n\n\tgfx_printf(\"DAT_BUS_WIDTH:         %X\\n\",   unstuff_bits(raw_ssr0, 510, 2));\n\tgfx_printf(\"SECURED_MODE:          %X\\n\",   unstuff_bits(raw_ssr0, 509, 1));\n\tgfx_printf(\"SECURITY_FUNCTIONS:    %02X\\n\", unstuff_bits(raw_ssr0, 502, 6));\n\tgfx_printf(\"SD_CARD_TYPE:          %04X\\n\", unstuff_bits(raw_ssr0, 480, 16));\n\tgfx_printf(\"SZ_OF_PROTECTED_AREA:  %08X\\n\", unstuff_bits(raw_ssr0, 448, 32));\n\tgfx_printf(\"SPEED_CLASS:           %02X\\n\", unstuff_bits(raw_ssr0, 440, 8));\n\tgfx_printf(\"PERFORMANCE_MOVE:      %02X\\n\", unstuff_bits(raw_ssr0, 432, 8));\n\tgfx_printf(\"AU_SIZE:               %X\\n\",   unstuff_bits(raw_ssr0, 428, 4));\n\tgfx_printf(\"ERAZE_SIZE:            %04X\\n\", unstuff_bits(raw_ssr0, 408, 16));\n\tgfx_printf(\"ERASE_TIMEOUT:         %02X\\n\", unstuff_bits(raw_ssr0, 402, 6));\n\tgfx_printf(\"ERASE_OFFSET:          %X\\n\",   unstuff_bits(raw_ssr0, 400, 2));\n\tgfx_printf(\"UHS_SPEED_GRADE:       %X\\n\",   unstuff_bits(raw_ssr0, 396, 4));\n\tgfx_printf(\"UHS_AU_SIZE:           %X\\n\",   unstuff_bits(raw_ssr0, 392, 4));\n\tgfx_printf(\"VIDEO_SPEED_CLASS:     %02X\\n\", unstuff_bits(raw_ssr0, 384, 8));\n\n\tgfx_printf(\"VSC_AU_SIZE:           %03X\\n\", unstuff_bits(raw_ssr1, 368, 10));\n\tgfx_printf(\"SUS_ADDR:              %06X\\n\", unstuff_bits(raw_ssr1, 346, 22));\n\tgfx_printf(\"APP_PERF_CLASS:        %X\\n\",   unstuff_bits(raw_ssr1, 336, 4));\n\tgfx_printf(\"PERFORMANCE_ENHANCE:   %02X\\n\", unstuff_bits(raw_ssr1, 328, 8));\n\tgfx_printf(\"DISCARD_SUPPORT:       %X\\n\",   unstuff_bits(raw_ssr1, 313, 1));\n\tgfx_printf(\"FULE_SUPPORT:          %X\\n\",   unstuff_bits(raw_ssr1, 312, 1));\n\n\tgfx_printf(\"--RSVD--               %02X %X %02X %02X %04X\\n\",\n\t\tunstuff_bits(raw_ssr0, 496, 6),   unstuff_bits(raw_ssr0, 424, 4),\n\t\tunstuff_bits(raw_ssr1, 378, 6),   unstuff_bits(raw_ssr1, 340, 6),\n\t\tunstuff_bits(raw_ssr1, 314, 14));\n\n\tgfx_printf(\"VENDOR_1: %06X   %08X\\n\",\n\t\tunstuff_bits(raw_ssr1, 288, 24),  unstuff_bits(raw_ssr1, 256, 32));\n\n\tgfx_printf(\"VENDOR_2: %08X %08X %08X %08X\\n\",\n\t\tunstuff_bits(raw_ssr2, 224, 32),  unstuff_bits(raw_ssr2, 192, 32),\n\t\tunstuff_bits(raw_ssr2, 160, 32),  unstuff_bits(raw_ssr2, 128, 32));\n\tgfx_printf(\"VENDOR_3: %08X %08X %08X %08X\\n\",\n\t\tunstuff_bits(raw_ssr3, 96 - 0, 32),     unstuff_bits(raw_ssr3, 64, 32),\n\t\tunstuff_bits(raw_ssr3, 32 - 0, 32),     unstuff_bits(raw_ssr3, 0, 32));\n}\n#endif\n\nstatic int _sd_storage_send_if_cond(sdmmc_storage_t *storage, bool *is_sdsc)\n{\n\tsdmmc_cmd_t cmdbuf;\n\tu16 vhd_pattern = SD_VHS_27_36 | 0xAA;\n\tsdmmc_init_cmd(&cmdbuf, SD_SEND_IF_COND, vhd_pattern, SDMMC_RSP_TYPE_7, 0);\n\tif (sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL))\n\t{\n\t\t// The SD Card is version 1.X (SDSC) if there is no response.\n\t\tif (storage->sdmmc->error_sts == SDHCI_ERR_INT_CMD_TIMEOUT)\n\t\t{\n\t\t\t*is_sdsc = 1;\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn 1;\n\t}\n\n\t// For Card version >= 2.0, parse results.\n\tu32 resp = 0;\n\tsdmmc_get_cached_rsp(storage->sdmmc, &resp, SDMMC_RSP_TYPE_7);\n\n\t// Check if VHD was accepted and pattern was properly returned.\n\tif ((resp & 0xFFF) == vhd_pattern)\n\t\treturn 0;\n\n\treturn 1;\n}\n\nstatic int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, bool is_sdsc, int bus_uhs_support)\n{\n\tsdmmc_cmd_t cmdbuf;\n\t// Support for Current > 150mA.\n\tu32 arg = !is_sdsc ? SD_OCR_XPC : 0;\n\t// Support for handling block-addressed SDHC cards.\n\targ\t|= !is_sdsc ? SD_OCR_CCS : 0;\n\t// Support for 1.8V signaling.\n\targ |= (bus_uhs_support && !is_sdsc) ? SD_OCR_S18R : 0;\n\t// Support for 3.3V power supply (VDD1).\n\targ |= SD_OCR_VDD_32_33;\n\n\tsdmmc_init_cmd(&cmdbuf, SD_APP_OP_COND, arg, SDMMC_RSP_TYPE_3, 0);\n\n\tif (_sd_storage_execute_app_cmd(storage, R1_SKIP_STATE_CHECK, is_sdsc ? R1_ILLEGAL_COMMAND : 0, &cmdbuf, NULL, NULL))\n\t\treturn 1;\n\n\treturn sdmmc_get_cached_rsp(storage->sdmmc, cond, SDMMC_RSP_TYPE_3);\n}\n\nstatic int _sd_storage_get_op_cond(sdmmc_storage_t *storage, bool is_sdsc, int bus_uhs_support)\n{\n\tu32 timeout = get_tmr_ms() + 1500;\n\n\twhile (true)\n\t{\n\t\tu32 cond = 0;\n\t\tif (_sd_storage_get_op_cond_once(storage, &cond, is_sdsc, bus_uhs_support))\n\t\t\tbreak;\n\n\t\t// Check if power up is done.\n\t\tif (cond & SD_OCR_BUSY)\n\t\t{\n\t\t\tDPRINTF(\"[SD] op cond: %08X, lv: %d\\n\", cond, bus_uhs_support);\n\n\t\t\t// Check if card is high capacity.\n\t\t\tif (cond & SD_OCR_CCS)\n\t\t\t\tstorage->has_sector_access = 1;\n\n\t\t\t// Check if card supports 1.8V signaling.\n\t\t\tif (cond & SD_ROCR_S18A && bus_uhs_support && !storage->is_low_voltage)\n\t\t\t{\n\t\t\t\t// Switch to 1.8V signaling.\n\t\t\t\tif (!_sdmmc_storage_execute_cmd_type1(storage, SD_SWITCH_VOLTAGE, 0, 0, R1_STATE_READY))\n\t\t\t\t{\n\t\t\t\t\tif (sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_UHS_SDR12))\n\t\t\t\t\t\treturn 1;\n\n\t\t\t\t\tif (sdmmc_enable_low_voltage(storage->sdmmc))\n\t\t\t\t\t\treturn 1;\n\n\t\t\t\t\tstorage->is_low_voltage = 1;\n\n\t\t\t\t\tDPRINTF(\"-> switched to low voltage\\n\");\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tDPRINTF(\"[SD] no low voltage support\\n\");\n\t\t\t}\n\n\t\t\treturn 0;\n\t\t}\n\t\tif (get_tmr_ms() > timeout)\n\t\t\tbreak;\n\t\tmsleep(10); // Needs to be at least 10ms for some SD Cards\n\t}\n\n\treturn 1;\n}\n\nstatic int _sd_storage_get_rca(sdmmc_storage_t *storage)\n{\n\tsdmmc_cmd_t cmdbuf;\n\tsdmmc_init_cmd(&cmdbuf, SD_SEND_RELATIVE_ADDR, 0, SDMMC_RSP_TYPE_6, 0);\n\n\tu32 timeout = get_tmr_ms() + 1500;\n\n\twhile (true)\n\t{\n\t\tif (sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL))\n\t\t\tbreak;\n\n\t\tu32 resp = 0;\n\t\tif (sdmmc_get_cached_rsp(storage->sdmmc, &resp, SDMMC_RSP_TYPE_6))\n\t\t\tbreak;\n\n\t\tif (resp >> 16)\n\t\t{\n\t\t\tstorage->rca = resp >> 16;\n\t\t\treturn 0;\n\t\t}\n\n\t\tif (get_tmr_ms() > timeout)\n\t\t\tbreak;\n\t\tusleep(1000);\n\t}\n\n\treturn 1;\n}\n\nstatic void _sd_storage_parse_scr(sdmmc_storage_t *storage)\n{\n\t// unstuff_bits can parse only 4 u32\n\tu32 resp[4];\n\n\tmemcpy(&resp[2], storage->raw_scr, 8);\n\n#ifdef SDMMC_DEBUG_PRINT_SD_REGS\n\t_sd_storage_debug_print_scr((u32 *)storage->raw_scr);\n#endif\n\n\tstorage->scr.sda_vsn = unstuff_bits(resp, 56, 4);\n\tstorage->scr.bus_widths = unstuff_bits(resp, 48, 4);\n\n\t// If v2.0 is supported, check if Physical Layer Spec v3.0 is supported.\n\tif (storage->scr.sda_vsn == SCR_SPEC_VER_2)\n\t\tstorage->scr.sda_spec3 = unstuff_bits(resp, 47, 1);\n\tif (storage->scr.sda_spec3)\n\t{\n\t\tu8 sda_spec4 = unstuff_bits(resp, 42, 1);\n\t\tif (sda_spec4)\n\t\t\tstorage->scr.cmds = unstuff_bits(resp, 32, 4);\n\t\telse\n\t\t\tstorage->scr.cmds = unstuff_bits(resp, 32, 2);\n\t}\n}\n\nint sd_storage_get_scr(sdmmc_storage_t *storage)\n{\n\tu8 buf[8] __attribute__ ((aligned(SDMMC_ADMA_ADDR_ALIGN)));\n\n\tsdmmc_cmd_t cmdbuf;\n\tsdmmc_init_cmd(&cmdbuf, SD_APP_SEND_SCR, 0, SDMMC_RSP_TYPE_1, 0);\n\n\tsdmmc_req_t reqbuf;\n\treqbuf.buf              = buf;\n\treqbuf.blksize          = 8;\n\treqbuf.num_sectors      = 1;\n\treqbuf.is_write         = 0;\n\treqbuf.is_multi_block   = 0;\n\treqbuf.is_auto_stop_trn = 0;\n\n\tif (_sd_storage_execute_app_cmd(storage, R1_STATE_TRAN, 0, &cmdbuf, &reqbuf, NULL))\n\t\treturn 1;\n\n\tu32 tmp = 0;\n\tsdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);\n\t//Prepare buffer for unstuff_bits\n\tfor (u32 i = 0; i < 8; i += 4)\n\t{\n\t\tstorage->raw_scr[i + 3] = buf[i];\n\t\tstorage->raw_scr[i + 2] = buf[i + 1];\n\t\tstorage->raw_scr[i + 1] = buf[i + 2];\n\t\tstorage->raw_scr[i]     = buf[i + 3];\n\t}\n\t_sd_storage_parse_scr(storage);\n\n\treturn _sdmmc_storage_check_card_status(tmp);\n}\n\nstatic int _sd_storage_switch_get(sdmmc_storage_t *storage, void *buf)\n{\n\tsdmmc_cmd_t cmdbuf;\n\tsdmmc_init_cmd(&cmdbuf, SD_SWITCH, 0xFFFFFF, SDMMC_RSP_TYPE_1, 0);\n\n\tsdmmc_req_t reqbuf;\n\treqbuf.buf              = buf;\n\treqbuf.blksize          = SDMMC_CMD_BLOCKSIZE;\n\treqbuf.num_sectors      = 1;\n\treqbuf.is_write         = 0;\n\treqbuf.is_multi_block   = 0;\n\treqbuf.is_auto_stop_trn = 0;\n\n\tif (sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, NULL))\n\t\treturn 1;\n\n\tu32 tmp = 0;\n\tsdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);\n\treturn _sdmmc_storage_check_card_status(tmp);\n}\n\nstatic int _sd_storage_switch(sdmmc_storage_t *storage, void *buf, int mode, int group, u32 arg)\n{\n\tsdmmc_cmd_t cmdbuf;\n\tu32 switchcmd = mode << 31 | 0x00FFFFFF;\n\tswitchcmd &= ~(0xF << (group * 4));\n\tswitchcmd |= arg << (group * 4);\n\tsdmmc_init_cmd(&cmdbuf, SD_SWITCH, switchcmd, SDMMC_RSP_TYPE_1, 0);\n\n\tsdmmc_req_t reqbuf;\n\treqbuf.buf              = buf;\n\treqbuf.blksize          = SDMMC_CMD_BLOCKSIZE;\n\treqbuf.num_sectors      = 1;\n\treqbuf.is_write         = 0;\n\treqbuf.is_multi_block   = 0;\n\treqbuf.is_auto_stop_trn = 0;\n\n\tif (sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, NULL))\n\t\treturn 1;\n\n\tu32 tmp = 0;\n\tsdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);\n\treturn _sdmmc_storage_check_card_status(tmp);\n}\n\nstatic void _sd_storage_set_power_limit(sdmmc_storage_t *storage, u16 power_limit, u8 *buf)\n{\n\tu32 pwr = SD_SET_POWER_LIMIT_0_72;\n\n\t// If UHS-I only, anything above 1.44W defaults to 1.44W.\n\t/*\n\tif (power_limit & SD_MAX_POWER_2_88)\n\t\tpwr = SD_SET_POWER_LIMIT_2_88;\n\telse if (power_limit & SD_MAX_POWER_2_16)\n\t\tpwr = SD_SET_POWER_LIMIT_2_16;\n\t*/\n\tif (power_limit & SD_MAX_POWER_1_44)\n\t\tpwr = SD_SET_POWER_LIMIT_1_44;\n\n\t_sd_storage_switch(storage, buf, SD_SWITCH_SET, SD_SWITCH_GRP_PWRLIM, pwr);\n\n\tswitch ((buf[15] >> 4) & 0x0F)\n\t{\n\t/*\n\tcase SD_SET_POWER_LIMIT_2_88:\n\t\tDPRINTF(\"[SD] power limit raised to 2880 mW\\n\");\n\t\tbreak;\n\n\tcase SD_SET_POWER_LIMIT_2_16:\n\t\tDPRINTF(\"[SD] power limit raised to 2160 mW\\n\");\n\t\tbreak;\n\t*/\n\tcase SD_SET_POWER_LIMIT_1_44:\n\t\tDPRINTF(\"[SD] power limit raised to 1440 mW\\n\");\n\t\tbreak;\n\n\tdefault:\n\tcase SD_SET_POWER_LIMIT_0_72:\n\t\tDPRINTF(\"[SD] power limit defaulted to 720 mW\\n\");\n\t\tbreak;\n\t}\n}\n\n__attribute__ ((unused)) static int _sd_storage_set_driver_type(sdmmc_storage_t *storage, u32 driver, u8 *buf)\n{\n\tif (_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, SD_SWITCH_GRP_DRVSTR, driver))\n\t\treturn 1;\n\n\tu32 driver_out = buf[15] & 0xF;\n\tif (driver_out != driver)\n\t\treturn 1;\n\tDPRINTF(\"[SD] supports Driver Strength %d\\n\", driver);\n\n\tif (_sd_storage_switch(storage, buf, SD_SWITCH_SET, SD_SWITCH_GRP_DRVSTR, driver))\n\t\treturn 1;\n\n\tif (driver_out != (buf[15] & 0xF))\n\t\treturn 1;\n\tDPRINTF(\"[SD] card accepted Driver Strength %d\\n\", driver);\n\n\tsdmmc_setup_drv_type(storage->sdmmc, driver);\n\n\treturn 0;\n}\n\n/*\n * SD Card DDR200 (DDR208) support\n *\n * DLL Tuning (a) or Tuning Window (b) procedure:\n * 1. Check that Vendor Specific Command System is supported.\n *    Used as Enable DDR200 Bus.\n * 2. Enable DDR200 bus mode via setting 14 to Group 2 via CMD6.\n *    Access Mode group is left to default 0 (SDR12).\n * 3. Setup clock to 200 or 208 MHz.\n * 4a. Set host to DDR200/HS400 bus mode that enables DLL syncing.\n *     Actual implementation supported by all DDR200 cards.\n * --\n * 4b. Set host to DDR50 bus mode that supports such high clocks.\n *     Execute Manual Tuning.\n *     Limited to non-Sandisk cards.\n *\n * On Tegra SoCs, that can be done with DDR50 host mode.\n * That's because HS400 4-bit or HS400 generally, is not supported on SD SDMMC.\n * And also, tuning can't be done automatically on any DDR mode.\n * So it needs to be done manually and selected tap will be applied from the\n * biggest sampling window.\n * That allows DDR200 support on every DDR200 SD card, other than the original\n * maker of DDR200, Sandisk.\n *\n * On the original implementation of DDR200 from Sandisk, a DLL mechanism,\n * like the one in eMMC HS400 is mandatory.\n * So the card can start data signals whenever it wants, and the host should\n * synchronize to the first DAT signal edge change.\n * Every single other vendor that implemented that, always starts data transfers\n * aligned to clock. That basically makes DDR200 in such SD cards a SDR104 but\n * sampled on both edges. So effectively, it's an in-spec signal with DDR50,\n * only that is clocked at 200MHz, instead of 50MHz.\n * So the extra needed thing is using a tuning window, which is absent from the\n * original implementation, since DDL syncing does not use that.\n *\n * On DLL tuning method expected cards, the tuning window is tiny.\n * So check against a minimum of 8 taps window, to disallow DDR200.\n */\n#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT\nstatic int _sd_storage_enable_DDR200(sdmmc_storage_t *storage, u8 *buf)\n{\n\tu32 cmd_system = UHS_DDR200_BUS_SPEED;\n\tif (_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, SD_SWITCH_GRP_CMDSYS, cmd_system))\n\t\treturn 1;\n\n\tu32 system_out = (buf[16] >> 4) & 0xF;\n\tif (system_out != cmd_system)\n\t\treturn 1;\n\tDPRINTF(\"[SD] supports DDR200 mode\\n\");\n\n\tu16 total_pwr_consumption = ((u16)buf[0] << 8) | buf[1];\n\tDPRINTF(\"[SD] max power: %d mW\\n\", total_pwr_consumption * 3600 / 1000);\n\tstorage->max_power = total_pwr_consumption;\n\n\t// Check if total is low than max and switch.\n\tif (total_pwr_consumption <= 800)\n\t{\n\t\tif (_sd_storage_switch(storage, buf, SD_SWITCH_SET, SD_SWITCH_GRP_CMDSYS, cmd_system))\n\t\t\treturn 1;\n\n\t\tif (system_out != ((buf[16] >> 4) & 0xF))\n\t\t\treturn 1;\n\t\tDPRINTF(\"[SD] card accepted DDR200\\n\");\n\n\t\tif (sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_UHS_DDR200))\n\t\t\treturn 1;\n\t\tDPRINTF(\"[SD] after setup clock DDR200\\n\");\n\n\t\tif (sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_UHS_DDR200, MMC_SEND_TUNING_BLOCK))\n\t\t\treturn 1;\n\t\tDPRINTF(\"[SD] after tuning DDR200\\n\");\n\n\t\treturn _sdmmc_storage_check_status(storage);\n\t}\n\n\tDPRINTF(\"[SD] card max power over limit\\n\");\n\treturn 1;\n}\n#endif\n\nstatic int _sd_storage_set_card_bus_speed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf)\n{\n\tif (_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, SD_SWITCH_GRP_ACCESS, hs_type))\n\t\treturn 1;\n\n\tu32 type_out = buf[16] & 0xF;\n\tif (type_out != hs_type)\n\t\treturn 1;\n\tDPRINTF(\"[SD] supports selected (U)HS mode %d\\n\", buf[16] & 0xF);\n\n\tu16 total_pwr_consumption = ((u16)buf[0] << 8) | buf[1];\n\tDPRINTF(\"[SD] max power: %d mW\\n\", total_pwr_consumption * 3600 / 1000);\n\tstorage->max_power = total_pwr_consumption;\n\n\t// Check if total is low than max and switch.\n\tif (total_pwr_consumption <= 800)\n\t{\n\t\tif (_sd_storage_switch(storage, buf, SD_SWITCH_SET, SD_SWITCH_GRP_ACCESS, hs_type))\n\t\t\treturn 1;\n\n\t\tif (type_out != (buf[16] & 0xF))\n\t\t\treturn 1;\n\n\t\treturn 0;\n\t}\n\n\tDPRINTF(\"[SD] card max power over limit\\n\");\n\treturn 1;\n}\n\nint sd_storage_get_fmodes(sdmmc_storage_t *storage, u8 *buf, sd_func_modes_t *fmodes)\n{\n\tif (!buf)\n\t\tbuf = (u8 *)SDMMC_ALT_DMA_BUFFER;\n\n\tif (_sd_storage_switch_get(storage, buf))\n\t\treturn 1;\n\n\tfmodes->access_mode     = buf[13] | (buf[12] << 8);\n\tfmodes->cmd_system      = buf[11] | (buf[10] << 8);\n\tfmodes->driver_strength = buf[9]  | (buf[8]  << 8);\n\tfmodes->power_limit     = buf[7]  | (buf[6]  << 8);\n\n\treturn 0;\n}\n\nstatic int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type)\n{\n\tsd_func_modes_t fmodes;\n\tu8 *buf = storage->raw_ext_csd;\n\n\tif (sdmmc_get_bus_width(storage->sdmmc) != SDMMC_BUS_WIDTH_4)\n\t\treturn 1;\n\n\tif (sd_storage_get_fmodes(storage, buf, &fmodes))\n\t\treturn 1;\n\n#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT\n\tDPRINTF(\"[SD] access: %02X, power: %02X, cmd: %02X\\n\", fmodes.access_mode, fmodes.power_limit, fmodes.cmd_system);\n#else\n\tDPRINTF(\"[SD] access: %02X, power: %02X\\n\", fmodes.access_mode, fmodes.power_limit);\n#endif\n\n\tu32 hs_type = 0;\n\tswitch (type)\n\t{\n#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT\n\tcase SDHCI_TIMING_UHS_DDR200:\n\t\t// Fall through if DDR200 is not supported.\n\t\tif (fmodes.cmd_system & SD_MODE_UHS_DDR200)\n\t\t{\n\t\t\tDPRINTF(\"[SD] setting bus speed to DDR200\\n\");\n\t\t\tstorage->csd.busspeed = 200;\n\t\t\t_sd_storage_set_power_limit(storage, fmodes.power_limit, buf);\n\t\t\treturn _sd_storage_enable_DDR200(storage, buf);\n\t\t}\n#endif\n\n\tcase SDHCI_TIMING_UHS_SDR104:\n\tcase SDHCI_TIMING_UHS_SDR82:\n\t\t// Fall through if not supported.\n\t\tif (fmodes.access_mode & SD_MODE_UHS_SDR104)\n\t\t{\n\t\t\ttype    = SDHCI_TIMING_UHS_SDR104;\n\t\t\ths_type = UHS_SDR104_BUS_SPEED;\n\t\t\tDPRINTF(\"[SD] setting bus speed to SDR104\\n\");\n\t\t\tswitch (type)\n\t\t\t{\n\t\t\tcase SDHCI_TIMING_UHS_SDR104:\n\t\t\t\tstorage->csd.busspeed = 104;\n\t\t\t\tbreak;\n\t\t\tcase SDHCI_TIMING_UHS_SDR82:\n\t\t\t\tstorage->csd.busspeed = 82;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\tcase SDHCI_TIMING_UHS_SDR50:\n\t\tif (fmodes.access_mode & SD_MODE_UHS_SDR50)\n\t\t{\n\t\t\ttype    = SDHCI_TIMING_UHS_SDR50;\n\t\t\ths_type = UHS_SDR50_BUS_SPEED;\n\t\t\tDPRINTF(\"[SD] setting bus speed to SDR50\\n\");\n\t\t\tstorage->csd.busspeed = 50;\n\t\t\tbreak;\n\t\t}\n/*\n\tcase SDHCI_TIMING_UHS_DDR50:\n\t\tif (fmodes.access_mode & SD_MODE_UHS_DDR50)\n\t\t{\n\t\t\ttype    = SDHCI_TIMING_UHS_DDR50;\n\t\t\ths_type = UHS_DDR50_BUS_SPEED;\n\t\t\tDPRINTF(\"[SD] setting bus speed to DDR50\\n\");\n\t\t\tstorage->csd.busspeed = 50;\n\t\t\tbreak;\n\t\t}\n*/\n\tcase SDHCI_TIMING_UHS_SDR25:\n\t\tif (fmodes.access_mode & SD_MODE_UHS_SDR25)\n\t\t{\n\t\t\ttype = SDHCI_TIMING_UHS_SDR25;\n\t\t\ths_type = UHS_SDR25_BUS_SPEED;\n\t\t\tDPRINTF(\"[SD] setting bus speed to SDR25\\n\");\n\t\t\tstorage->csd.busspeed = 25;\n\t\t\tbreak;\n\t\t}\n\n\tdefault:\n\t\tDPRINTF(\"[SD] bus speed defaulted to SDR12\\n\");\n\t\tstorage->csd.busspeed = 12;\n\t\treturn 0; // Already set.\n\t}\n\n\t// Try to raise the power limit to let the card perform better.\n\tif (hs_type != UHS_SDR25_BUS_SPEED) // Not applicable for SDR12/SDR25.\n\t\t_sd_storage_set_power_limit(storage, fmodes.power_limit, buf);\n\n\t// Setup and set selected card and bus speed.\n\tif (_sd_storage_set_card_bus_speed(storage, hs_type, buf))\n\t\treturn 1;\n\tDPRINTF(\"[SD] card accepted UHS\\n\");\n\n\tif (sdmmc_setup_clock(storage->sdmmc, type))\n\t\treturn 1;\n\tDPRINTF(\"[SD] after setup clock\\n\");\n\n\tif (sdmmc_tuning_execute(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK))\n\t\treturn 1;\n\tDPRINTF(\"[SD] after tuning\\n\");\n\n\treturn _sdmmc_storage_check_status(storage);\n}\n\nstatic int _sd_storage_enable_hs_high_volt(sdmmc_storage_t *storage)\n{\n\tsd_func_modes_t fmodes;\n\tu8 *buf = storage->raw_ext_csd;\n\n\tif (sd_storage_get_fmodes(storage, buf, &fmodes))\n\t\treturn 1;\n\n\tDPRINTF(\"[SD] access: %02X, power: %02X\\n\", fmodes.access_mode, fmodes.power_limit);\n\n\t// No support, return success.\n\tif (!(fmodes.access_mode & SD_MODE_HIGH_SPEED))\n\t\treturn 0;\n\n\tif (_sd_storage_set_card_bus_speed(storage, HIGH_SPEED_BUS_SPEED, buf))\n\t\treturn 1;\n\n\tif (_sdmmc_storage_check_status(storage))\n\t\treturn 1;\n\n\treturn sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_HS25);\n}\n\nu32 sd_storage_get_ssr_au(sdmmc_storage_t *storage)\n{\n\tu32 au_size = storage->ssr.uhs_au_size;\n\n\tif (!au_size)\n\t\tau_size = storage->ssr.au_size;\n\n\tif (au_size <= 10)\n\t{\n\t\tu32 shift = au_size;\n\t\tau_size = shift ? 8 : 0;\n\t\tau_size <<= shift;\n\t}\n\telse\n\t{\n\t\tswitch (au_size)\n\t\t{\n\t\tcase 11:\n\t\t\tau_size = 12288;\n\t\t\tbreak;\n\t\tcase 12:\n\t\t\tau_size = 16384;\n\t\t\tbreak;\n\t\tcase 13:\n\t\t\tau_size = 24576;\n\t\t\tbreak;\n\t\tcase 14:\n\t\t\tau_size = 32768;\n\t\t\tbreak;\n\t\tcase 15:\n\t\t\tau_size = 65536;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn au_size;\n}\n\nstatic void _sd_storage_parse_ssr(sdmmc_storage_t *storage)\n{\n\t// unstuff_bits supports only 4 u32 so break into 2 x u32x4 groups.\n\tu32 raw_ssr1[4]; // 511:384.\n\tu32 raw_ssr2[4]; // 383:256.\n\n\tmemcpy(raw_ssr1, &storage->raw_ssr[0],  16);\n\tmemcpy(raw_ssr2, &storage->raw_ssr[16], 16);\n\n#ifdef SDMMC_DEBUG_PRINT_SD_REGS\n\t_sd_storage_debug_print_ssr(storage->raw_ssr);\n#endif\n\n\tstorage->ssr.bus_width = (unstuff_bits(raw_ssr1, 510, 2) & SD_BUS_WIDTH_4) ? 4 : 1;\n\tstorage->ssr.protected_size = unstuff_bits(raw_ssr1, 448, 32);\n\n\tu32 speed_class = unstuff_bits(raw_ssr1, 440, 8);\n\tswitch(speed_class)\n\t{\n\tcase 0:\n\tcase 1:\n\tcase 2:\n\tcase 3:\n\t\tstorage->ssr.speed_class = speed_class << 1;\n\t\tbreak;\n\n\tcase 4:\n\t\tstorage->ssr.speed_class = 10;\n\t\tbreak;\n\n\tdefault:\n\t\tstorage->ssr.speed_class = speed_class;\n\t\tbreak;\n\t}\n\tstorage->ssr.uhs_grade   = unstuff_bits(raw_ssr1, 396, 4);\n\tstorage->ssr.video_class = unstuff_bits(raw_ssr1, 384, 8);\n\tstorage->ssr.app_class   = unstuff_bits(raw_ssr2, 336, 4);\n\n\tstorage->ssr.au_size     = unstuff_bits(raw_ssr1, 428, 4);\n\tstorage->ssr.uhs_au_size = unstuff_bits(raw_ssr1, 392, 4);\n\n\tstorage->ssr.perf_enhance = unstuff_bits(raw_ssr2, 328, 8);\n}\n\nint sd_storage_parse_perf_enhance(sdmmc_storage_t *storage, u8 fno, u8 page, u16 offset, u8 *buf)\n{\n\t// Check status reg for support.\n\tstorage->ser.cache = (storage->ssr.perf_enhance >> 2) & BIT(0);\n\tstorage->ser.cmdq  = (storage->ssr.perf_enhance >> 3) & 0x1F;\n\n\tif (sd_storage_get_ext_reg(storage, fno, page, offset, 512, buf))\n\t{\n\t\tstorage->ser.cache_ext = 0;\n\t\tstorage->ser.cmdq_ext  = 0;\n\n\t\treturn 1;\n\t}\n\n\tstorage->ser.cache_ext = buf[4] & BIT(0);\n\tstorage->ser.cmdq_ext  = buf[6] & 0x1F;\n\n\treturn 0;\n}\n\nstatic void _sd_storage_parse_ext_reg(sdmmc_storage_t *storage, u8 *buf, u16 *addr_next)\n{\n\tu16 addr = *addr_next;\n\n\t// Address to the next extension.\n\t*addr_next = (buf[addr + 41] << 8) | buf[addr + 40];\n\n\tu16 sfc = (buf[addr + 1] << 8) | buf[addr];\n\n\tu32 reg_sets = buf[addr + 42];\n\n#ifdef SDMMC_DEBUG_PRINT_SD_REGS\n\tfor (u32 i = 0; i < reg_sets; i++)\n\t{\n\t\tu32 reg_set_addr;\n\t\tmemcpy(&reg_set_addr, &buf[addr + 44 + 4 * i], 4);\n\t\tu16 off = reg_set_addr & 0x1FF;\n\t\tu8 page = reg_set_addr >> 9 & 0xFF;\n\t\tu8 fno  = reg_set_addr >> 18 & 0xFF;\n\t\tgfx_printf(\"Addr: %04X sfc:%02X - fno:%02X, page:%02X, off:%04X\\n\", addr, sfc, fno, page, off);\n\t}\n#endif\n\n\t// Parse Performance Enhance.\n\tif (sfc == 2 && reg_sets == 1)\n\t{\n\t\tu32 reg_set0_addr;\n\t\tmemcpy(&reg_set0_addr, &buf[addr + 44], 4);\n\t\tu16 off = reg_set0_addr & 0x1FF;\n\t\tu8 page = reg_set0_addr >> 9 & 0xFF;\n\t\tu8 fno  = reg_set0_addr >> 18 & 0xFF;\n\n\t\tif (sd_storage_parse_perf_enhance(storage, fno, page, off, buf))\n\t\t\tstorage->ser.valid = 1;\n\t}\n}\n\nvoid sd_storage_get_ext_regs(sdmmc_storage_t *storage, u8 *buf)\n{\n\tDREGPRINTF(\"SD Extension Registers:\\n\\n\");\n\n\tif (!(storage->scr.cmds & BIT(2)))\n\t{\n\t\tDREGPRINTF(\"Not Supported!\\n\");\n\t\treturn;\n\t}\n\n\tif (sd_storage_get_ext_reg(storage, 0, 0, 0, 512, buf))\n\t{\n\t\tDREGPRINTF(\"Failed to get general info!\\n\");\n\t\treturn;\n\t}\n\n\tu16 size = (buf[3] << 8) | buf[2];\n\tu16 addr_next = 16;\n\tu32 num_ext = buf[4];\n\tfor (u32 i = 0; i < num_ext && addr_next < size; i++)\n\t\t_sd_storage_parse_ext_reg(storage, buf, &addr_next);\n}\n\nint sd_storage_get_ssr(sdmmc_storage_t *storage)\n{\n\tsdmmc_cmd_t cmdbuf;\n\tu8 *buf = storage->raw_ext_csd;\n\n\tsdmmc_init_cmd(&cmdbuf, SD_APP_SD_STATUS, 0, SDMMC_RSP_TYPE_1, 0);\n\n\tsdmmc_req_t reqbuf;\n\treqbuf.buf              = buf;\n\treqbuf.blksize          = SDMMC_CMD_BLOCKSIZE;\n\treqbuf.num_sectors      = 1;\n\treqbuf.is_write         = 0;\n\treqbuf.is_multi_block   = 0;\n\treqbuf.is_auto_stop_trn = 0;\n\n\tif (!(storage->csd.cmdclass & CCC_APP_SPEC))\n\t{\n\t\tDPRINTF(\"[SD] ssr: Not supported\\n\");\n\t\treturn 1;\n\t}\n\n\tif (_sd_storage_execute_app_cmd(storage, R1_STATE_TRAN, 0, &cmdbuf, &reqbuf, NULL))\n\t\treturn 1;\n\n\tu32 tmp = 0;\n\tsdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);\n\n\t// Convert buffer to LE.\n\tfor (u32 i = 0; i < SDMMC_CMD_BLOCKSIZE; i += 4)\n\t{\n\t\tstorage->raw_ssr[i + 3] = buf[i];\n\t\tstorage->raw_ssr[i + 2] = buf[i + 1];\n\t\tstorage->raw_ssr[i + 1] = buf[i + 2];\n\t\tstorage->raw_ssr[i]     = buf[i + 3];\n\t}\n\n\t_sd_storage_parse_ssr(storage);\n\n\treturn _sdmmc_storage_check_card_status(tmp);\n}\n\nstatic void _sd_storage_parse_cid(sdmmc_storage_t *storage)\n{\n\tu32 *raw_cid = (u32 *)&(storage->raw_cid);\n\n#ifdef SDMMC_DEBUG_PRINT_SD_REGS\n\t_sd_storage_debug_print_cid(raw_cid);\n#endif\n\n\tstorage->cid.manfid       = unstuff_bits(raw_cid, 120, 8);\n\tstorage->cid.oemid        = unstuff_bits(raw_cid, 104, 16);\n\tstorage->cid.prod_name[0] = unstuff_bits(raw_cid, 96,  8);\n\tstorage->cid.prod_name[1] = unstuff_bits(raw_cid, 88,  8);\n\tstorage->cid.prod_name[2] = unstuff_bits(raw_cid, 80,  8);\n\tstorage->cid.prod_name[3] = unstuff_bits(raw_cid, 72,  8);\n\tstorage->cid.prod_name[4] = unstuff_bits(raw_cid, 64,  8);\n\tstorage->cid.hwrev        = unstuff_bits(raw_cid, 60,  4);\n\tstorage->cid.fwrev        = unstuff_bits(raw_cid, 56,  4);\n\tstorage->cid.serial       = unstuff_bits(raw_cid, 24,  32);\n\tstorage->cid.year         = unstuff_bits(raw_cid, 12,  8) + 2000;\n\tstorage->cid.month        = unstuff_bits(raw_cid, 8,   4);\n}\n\nstatic void _sd_storage_parse_csd(sdmmc_storage_t *storage)\n{\n\tu32 *raw_csd = (u32 *)&(storage->raw_csd);\n\n#ifdef SDMMC_DEBUG_PRINT_SD_REGS\n\t_sd_storage_debug_print_csd(raw_csd);\n#endif\n\n\tstorage->csd.structure     = unstuff_bits(raw_csd, 126, 2);\n\tstorage->csd.cmdclass      = unstuff_bits(raw_csd, 84, 12);\n\tstorage->csd.read_blkbits  = unstuff_bits(raw_csd, 80, 4);\n\tstorage->csd.write_protect = unstuff_bits(raw_csd, 12, 2);\n\tswitch(storage->csd.structure)\n\t{\n\tcase 0:\n\t\tstorage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2);\n\t\tstorage->csd.capacity <<= unstuff_bits(raw_csd, 80, 4) - 9; // Convert native block size to LBA SDMMC_DAT_BLOCKSIZE.\n\t\tbreak;\n\n\tcase 1:\n\t\tstorage->csd.c_size       = (1 + unstuff_bits(raw_csd, 48, 22));\n\t\tstorage->csd.capacity     = storage->csd.c_size << 10;\n\t\tstorage->csd.read_blkbits = 9;\n\t\tbreak;\n\n\tdefault:\n\t\tDPRINTF(\"[SD] unknown CSD structure %d\\n\", storage->csd.structure);\n\t\tbreak;\n\t}\n\n\tstorage->sec_cnt = storage->csd.capacity;\n}\n\nstatic bool _sdmmc_storage_get_bus_uhs_support(u32 bus_width, u32 type)\n{\n\tswitch (type)\n\t{\n\tcase SDHCI_TIMING_UHS_SDR12:\n\tcase SDHCI_TIMING_UHS_SDR25:\n\tcase SDHCI_TIMING_UHS_SDR50:\n\tcase SDHCI_TIMING_UHS_SDR104:\n\tcase SDHCI_TIMING_UHS_SDR82:\n\tcase SDHCI_TIMING_UHS_DDR50:\n\tcase SDHCI_TIMING_UHS_DDR200:\n\t\tif (bus_width == SDMMC_BUS_WIDTH_4)\n\t\t\treturn true;\n\tdefault:\n\t\treturn false;\n\t}\n}\n\nvoid sdmmc_storage_init_wait_sd()\n{\n\t// T210/T210B01 WAR: Wait exactly 239ms for IO and Controller power to discharge.\n\tu32 sd_poweroff_time = (u32)get_tmr_ms() - sd_power_cycle_time_start;\n\tif (sd_poweroff_time < 239)\n\t\tmsleep(239 - sd_poweroff_time);\n}\n\nint sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type)\n{\n\tu32  tmp = 0;\n\tbool is_sdsc = 0;\n\tbool bus_uhs_support = _sdmmc_storage_get_bus_uhs_support(bus_width, type);\n\n\tDPRINTF(\"[SD]-[init: bus: %d, type: %d]\\n\", bus_width, type);\n\n\t// Some cards (SanDisk U1), do not like a fast power cycle. Wait min 100ms.\n\tsdmmc_storage_init_wait_sd();\n\n\tmemset(storage, 0, sizeof(sdmmc_storage_t));\n\tstorage->sdmmc = sdmmc;\n\n\tif (sdmmc_init(sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID))\n\t\treturn 1;\n\tDPRINTF(\"[SD] after init\\n\");\n\n\t// Wait 1ms + 74 cycles.\n\tusleep(1000 + (74 * 1000 + sdmmc->card_clock - 1) / sdmmc->card_clock);\n\n\tif (_sdmmc_storage_go_idle_state(storage))\n\t\treturn 1;\n\tDPRINTF(\"[SD] went to idle state\\n\");\n\n\tif (_sd_storage_send_if_cond(storage, &is_sdsc))\n\t\treturn 1;\n\tDPRINTF(\"[SD] after send if cond\\n\");\n\n\tif (_sd_storage_get_op_cond(storage, is_sdsc, bus_uhs_support))\n\t\treturn 1;\n\tDPRINTF(\"[SD] got op cond\\n\");\n\n\tif (_sdmmc_storage_get_cid(storage))\n\t\treturn 1;\n\tDPRINTF(\"[SD] got cid\\n\");\n\t_sd_storage_parse_cid(storage);\n\n\tif (_sd_storage_get_rca(storage))\n\t\treturn 1;\n\tDPRINTF(\"[SD] got rca (= %04X)\\n\", storage->rca);\n\n\tif (_sdmmc_storage_get_csd(storage))\n\t\treturn 1;\n\tDPRINTF(\"[SD] got csd\\n\");\n\t_sd_storage_parse_csd(storage);\n\n\tif (!storage->is_low_voltage)\n\t{\n\t\tif (sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_DS12))\n\t\t\treturn 1;\n\t\tDPRINTF(\"[SD] after setup default clock\\n\");\n\t}\n\n\tif (_sdmmc_storage_select_card(storage))\n\t\treturn 1;\n\tDPRINTF(\"[SD] card selected\\n\");\n\n\tif (_sdmmc_storage_set_blocklen(storage, SD_BLOCKSIZE))\n\t\treturn 1;\n\tDPRINTF(\"[SD] set blocklen to SD_BLOCKSIZE\\n\");\n\n\t// Disconnect Card Detect resistor from DAT3.\n\tif (_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_CLR_CARD_DETECT, 0, 0, R1_STATE_TRAN))\n\t\treturn 1;\n\tDPRINTF(\"[SD] cleared card detect\\n\");\n\n\tif (sd_storage_get_scr(storage))\n\t\treturn 1;\n\tDPRINTF(\"[SD] got scr\\n\");\n\n\t// If card supports a wider bus and if it's not SD Version 1.0 switch bus width.\n\tif (bus_width == SDMMC_BUS_WIDTH_4 && (storage->scr.bus_widths & BIT(SD_BUS_WIDTH_4)) && storage->scr.sda_vsn)\n\t{\n\t\tif (_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_BUS_WIDTH, SD_BUS_WIDTH_4, 0, R1_STATE_TRAN))\n\t\t\treturn 1;\n\n\t\tsdmmc_set_bus_width(storage->sdmmc, SDMMC_BUS_WIDTH_4);\n\t\tDPRINTF(\"[SD] switched to wide bus width\\n\");\n\t}\n\telse\n\t{\n\t\tbus_width = SDMMC_BUS_WIDTH_1;\n\t\tDPRINTF(\"[SD] SD does not support wide bus width\\n\");\n\t}\n\n\tif (storage->is_low_voltage)\n\t{\n\t\tif (_sd_storage_enable_uhs_low_volt(storage, type))\n\t\t\treturn 1;\n\t\tDPRINTF(\"[SD] enabled UHS\\n\");\n\t}\n\telse if (type != SDHCI_TIMING_SD_DS12 && storage->scr.sda_vsn) // Not default speed and not SD Version 1.0.\n\t{\n\t\tif (_sd_storage_enable_hs_high_volt(storage))\n\t\t\treturn 1;\n\n\t\tDPRINTF(\"[SD] enabled HS\\n\");\n\t\tswitch (bus_width)\n\t\t{\n\t\tcase SDMMC_BUS_WIDTH_4:\n\t\t\tstorage->csd.busspeed = 25;\n\t\t\tbreak;\n\n\t\tcase SDMMC_BUS_WIDTH_1:\n\t\t\tstorage->csd.busspeed = 6;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Parse additional card info from sd status.\n\tif (!sd_storage_get_ssr(storage))\n\t{\n\t\tDPRINTF(\"[SD] got sd status\\n\");\n\t}\n\n\tsdmmc_card_clock_powersave(sdmmc, SDMMC_POWER_SAVE_ENABLE);\n\n\tstorage->initialized = 1;\n\n\treturn 0;\n}\n\n/*\n * Gamecard specific functions.\n */\n\nint _gc_storage_custom_cmd(sdmmc_storage_t *storage, void *buf)\n{\n\tu32 resp;\n\tsdmmc_cmd_t cmdbuf;\n\tsdmmc_init_cmd(&cmdbuf, MMC_VENDOR_60_CMD, 0, SDMMC_RSP_TYPE_1, 1);\n\n\tsdmmc_req_t reqbuf;\n\treqbuf.buf              = buf;\n\treqbuf.blksize          = SDMMC_CMD_BLOCKSIZE;\n\treqbuf.num_sectors      = 1;\n\treqbuf.is_write         = 1;\n\treqbuf.is_multi_block   = 0;\n\treqbuf.is_auto_stop_trn = 0;\n\n\tif (sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, NULL))\n\t{\n\t\tsdmmc_stop_transmission(storage->sdmmc, &resp);\n\t\treturn 1;\n\t}\n\n\tif (sdmmc_get_cached_rsp(storage->sdmmc, &resp, SDMMC_RSP_TYPE_1))\n\t\treturn 1;\n\tif (_sdmmc_storage_check_card_status(resp))\n\t\treturn 1;\n\treturn _sdmmc_storage_check_status(storage);\n}\n\nint sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)\n{\n\tmemset(storage, 0, sizeof(sdmmc_storage_t));\n\tstorage->sdmmc = sdmmc;\n\n\tif (sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS100))\n\t\treturn 1;\n\tDPRINTF(\"[GC] after init\\n\");\n\n\t// Wait 1ms + 10 clock cycles.\n\tusleep(1000 + (10 * 1000 + sdmmc->card_clock - 1) / sdmmc->card_clock);\n\n\tif (sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_HS100, MMC_SEND_TUNING_BLOCK_HS200))\n\t\treturn 1;\n\tDPRINTF(\"[GC] after tuning\\n\");\n\n\tsdmmc_card_clock_powersave(sdmmc, SDMMC_POWER_SAVE_ENABLE);\n\n\tstorage->initialized = 1;\n\n\treturn 0;\n}\n"
  },
  {
    "path": "bdk/storage/sdmmc.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _SDMMC_H_\n#define _SDMMC_H_\n\n#include <utils/types.h>\n#include <storage/sd_def.h>\n#include <storage/sdmmc_driver.h>\n\n#define SDMMC_CMD_BLOCKSIZE 64\n#define SDMMC_DAT_BLOCKSIZE 512\n#define SDMMC_HMAX_BLOCKNUM 0xFFFF // HW max.\n#define SDMMC_AMAX_BLOCKNUM 0xF000 // Aligned max.\n\nextern u32 sd_power_cycle_time_start;\n\ntypedef enum _sdmmc_type\n{\n\tMMC_SD   = 0,\n\tMMC_EMMC = 1,\n\n\tEMMC_GPP   = 0,\n\tEMMC_BOOT0 = 1,\n\tEMMC_BOOT1 = 2,\n\tEMMC_RPMB  = 3\n} sdmmc_type;\n\ntypedef struct _mmc_sandisk_advanced_report_t\n{\n\tu32 power_inits;\n\n\tu32 max_erase_cycles_sys;\n\tu32 max_erase_cycles_slc;\n\tu32 max_erase_cycles_mlc;\n\n\tu32 min_erase_cycles_sys;\n\tu32 min_erase_cycles_slc;\n\tu32 min_erase_cycles_mlc;\n\n\tu32 max_erase_cycles_euda;\n\tu32 min_erase_cycles_euda;\n\tu32 avg_erase_cycles_euda;\n\tu32 read_reclaim_cnt_euda;\n\tu32 bad_blocks_euda;\n\n\tu32 pre_eol_euda;\n\tu32 pre_eol_sys;\n\tu32 pre_eol_mlc;\n\n\tu32 uncorrectable_ecc;\n\n\tu32 temperature_now;\n\tu32 temperature_min;\n\tu32 temperature_max;\n\n\tu32 health_pct_euda;\n\tu32 health_pct_sys;\n\tu32 health_pct_mlc;\n\n\tu32 unk0;\n\tu32 unk1;\n\tu32 unk2;\n\n\tu32 reserved[78];\n} mmc_sandisk_advanced_report_t;\n\ntypedef struct _mmc_sandisk_report_t\n{\n\tu32 avg_erase_cycles_sys;\n\tu32 avg_erase_cycles_slc;\n\tu32 avg_erase_cycles_mlc;\n\n\tu32 read_reclaim_cnt_sys;\n\tu32 read_reclaim_cnt_slc;\n\tu32 read_reclaim_cnt_mlc;\n\n\tu32 bad_blocks_factory;\n\tu32 bad_blocks_sys;\n\tu32 bad_blocks_slc;\n\tu32 bad_blocks_mlc;\n\n\tu32 fw_updates_cnt;\n\n\tu8  fw_update_date[12];\n\tu8  fw_update_time[8];\n\n\tu32 total_writes_100mb;\n\tu32 vdrops;\n\tu32 vdroops;\n\n\tu32 vdrops_failed_data_rec;\n\tu32 vdrops_data_rec_ops;\n\n\tu32 total_writes_slc_100mb;\n\tu32 total_writes_mlc_100mb;\n\n\tu32 mlc_bigfile_mode_limit_exceeded;\n\tu32 avg_erase_cycles_hybrid;\n\n\tmmc_sandisk_advanced_report_t advanced;\n} mmc_sandisk_report_t;\n\ntypedef struct _mmc_cid\n{\n\tu32 manfid;\n\tu8  prod_name[8];\n\tu32 serial;\n\tu16 oemid;\n\tu16\tyear;\n\tu8  prv;\n\tu8  hwrev;\n\tu8  fwrev;\n\tu8  month;\n} mmc_cid_t;\n\ntypedef struct _mmc_csd\n{\n\tu8  structure;\n\tu8  mmca_vsn;\n\tu16 cmdclass;\n\tu32 c_size;\n\tu32 r2w_factor;\n\tu32 read_blkbits;\n\tu32 capacity;\n\tu8  write_protect;\n\tu16 busspeed;\n} mmc_csd_t;\n\ntypedef struct _mmc_ext_csd\n{\n\tu8  bkops;        /* background support bit */\n\tu8  bkops_en;     /* manual bkops enable bit */\n\tu8  rev;\n\tu8  ext_struct;   /* 194 */\n\tu8  card_type;    /* 196 */\n\tu8  pre_eol_info;\n\tu8  dev_life_est_a;\n\tu8  dev_life_est_b;\n\tu8  boot_mult;\n\tu8  rpmb_mult;\n\tu16 dev_version;\n\tu32 cache_size;\n\tu32 max_enh_mult;\n} mmc_ext_csd_t;\n\ntypedef struct _sd_scr\n{\n\tu8 sda_vsn;\n\tu8 sda_spec3;\n\tu8 bus_widths;\n\tu8 cmds;\n} sd_scr_t;\n\ntypedef struct _sd_ssr\n{\n\tu8  bus_width;\n\tu8  speed_class;\n\tu8  uhs_grade;\n\tu8  video_class;\n\tu8  app_class;\n\tu8  au_size;\n\tu8  uhs_au_size;\n\tu8  perf_enhance;\n\tu32 protected_size;\n} sd_ssr_t;\n\ntypedef struct _sd_ext_reg_t\n{\n\tu8  cmdq;\n\tu8  cmdq_ext;\n\tu8  cache;\n\tu8  cache_ext;\n\tint valid;\n} sd_ext_reg_t;\n\n/*! SDMMC storage context. */\ntypedef struct _sdmmc_storage_t\n{\n\tsdmmc_t *sdmmc;\n\n\tint initialized;\n\tint is_low_voltage;\n\tint has_sector_access;\n\tu32 rca;\n\tu32 sec_cnt;\n\tu32 partition;\n\tu32 max_power;\n\tu8  raw_cid[0x10]                    __attribute__((aligned(SDMMC_ADMA_ADDR_ALIGN)));\n\tu8  raw_csd[0x10]                    __attribute__((aligned(SDMMC_ADMA_ADDR_ALIGN)));\n\tu8  raw_scr[8]                       __attribute__((aligned(SDMMC_ADMA_ADDR_ALIGN)));\n\tu8  raw_ssr[SDMMC_CMD_BLOCKSIZE]     __attribute__((aligned(SDMMC_ADMA_ADDR_ALIGN)));\n\tu8  raw_ext_csd[SDMMC_DAT_BLOCKSIZE] __attribute__((aligned(SDMMC_ADMA_ADDR_ALIGN)));\n\tmmc_cid_t     cid;\n\tmmc_csd_t     csd;\n\tmmc_ext_csd_t ext_csd;\n\tsd_scr_t      scr;\n\tsd_ssr_t      ssr;\n\tsd_ext_reg_t  ser;\n} sdmmc_storage_t;\n\ntypedef struct _sd_func_modes_t\n{\n\tu16 access_mode;\n\tu16 cmd_system;\n\tu16 driver_strength;\n\tu16 power_limit;\n} sd_func_modes_t;\n\nint  sdmmc_storage_end(sdmmc_storage_t *storage);\nint  sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);\nint  sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);\nint  sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type);\nint  sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition);\nvoid sdmmc_storage_init_wait_sd();\nint  sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type);\nint  sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);\n\nint  sdmmc_storage_execute_vendor_cmd(sdmmc_storage_t *storage, u32 arg);\nint  sdmmc_storage_vendor_sandisk_report(sdmmc_storage_t *storage, void *buf);\n\nint  mmc_storage_get_ext_csd(sdmmc_storage_t *storage);\n\nint  sd_storage_get_ext_reg(sdmmc_storage_t *storage, u8 fno, u8 page, u16 offset, u32 len, void *buf);\nint  sd_storage_get_fmodes(sdmmc_storage_t *storage, u8 *buf, sd_func_modes_t *functions);\nint  sd_storage_get_scr(sdmmc_storage_t *storage);\nint  sd_storage_get_ssr(sdmmc_storage_t *storage);\nu32  sd_storage_get_ssr_au(sdmmc_storage_t *storage);\n\nvoid sd_storage_get_ext_regs(sdmmc_storage_t *storage, u8 *buf);\nint  sd_storage_parse_perf_enhance(sdmmc_storage_t *storage, u8 fno, u8 page, u16 offset, u8 *buf);\n\n#endif\n"
  },
  {
    "path": "bdk/storage/sdmmc_driver.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <storage/mmc_def.h>\n#include <storage/sdmmc.h>\n#include <gfx_utils.h>\n#include <power/max7762x.h>\n#include <soc/bpmp.h>\n#include <soc/clock.h>\n#include <soc/gpio.h>\n#include <soc/hw_init.h>\n#include <soc/pinmux.h>\n#include <soc/pmc.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n\n//#define DPRINTF(...) gfx_printf(__VA_ARGS__)\n//#define ERROR_EXTRA_PRINTING\n#define DPRINTF(...)\n\n#ifdef BDK_SDMMC_EXTRA_PRINT\n#define ERROR_EXTRA_PRINTING\n#endif\n\n/*! SCMMC controller base addresses. */\nstatic const u16 _sdmmc_base_offsets[4] = { 0x0, 0x200, 0x400, 0x600 };\n\nint sdmmc_get_io_power(sdmmc_t *sdmmc)\n{\n\tu32 p = sdmmc->regs->pwrcon;\n\tif (!(p & SDHCI_POWER_ON))\n\t\treturn SDMMC_POWER_OFF;\n\tif (p & SDHCI_POWER_180)\n\t\treturn SDMMC_POWER_1_8;\n\tif (p & SDHCI_POWER_330)\n\t\treturn SDMMC_POWER_3_3;\n\treturn -1;\n}\n\nstatic int _sdmmc_set_io_power(sdmmc_t *sdmmc, u32 power)\n{\n\tswitch (power)\n\t{\n\tcase SDMMC_POWER_OFF:\n\t\tsdmmc->regs->pwrcon &= ~SDHCI_POWER_ON;\n\t\tbreak;\n\n\tcase SDMMC_POWER_1_8:\n\t\tsdmmc->regs->pwrcon = SDHCI_POWER_180;\n\t\tbreak;\n\n\tcase SDMMC_POWER_3_3:\n\t\tsdmmc->regs->pwrcon = SDHCI_POWER_330;\n\t\tbreak;\n\n\tdefault:\n\t\treturn 1;\n\t}\n\n\tif (power != SDMMC_POWER_OFF)\n\t\tsdmmc->regs->pwrcon |= SDHCI_POWER_ON;\n\n\treturn 0;\n}\n\nu32 sdmmc_get_bus_width(sdmmc_t *sdmmc)\n{\n\tu32 h = sdmmc->regs->hostctl;\n\tif (h & SDHCI_CTRL_8BITBUS) // eMMC only (or UHS-II).\n\t\treturn SDMMC_BUS_WIDTH_8;\n\tif (h & SDHCI_CTRL_4BITBUS) // SD only.\n\t\treturn SDMMC_BUS_WIDTH_4;\n\treturn SDMMC_BUS_WIDTH_1;\n}\n\nvoid sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width)\n{\n\tu32 host_control = sdmmc->regs->hostctl & ~(SDHCI_CTRL_4BITBUS | SDHCI_CTRL_8BITBUS);\n\n\tif (bus_width == SDMMC_BUS_WIDTH_1)\n\t\tsdmmc->regs->hostctl = host_control;\n\telse if (bus_width == SDMMC_BUS_WIDTH_4)\n\t\tsdmmc->regs->hostctl = host_control | SDHCI_CTRL_4BITBUS; // SD only.\n\telse if (bus_width == SDMMC_BUS_WIDTH_8)\n\t\tsdmmc->regs->hostctl = host_control | SDHCI_CTRL_8BITBUS; // eMMC only (or UHS-II).\n}\n\nvoid sdmmc_save_tap_value(sdmmc_t *sdmmc)\n{\n\tsdmmc->venclkctl_tap = (sdmmc->regs->venclkctl & 0xFF0000) >> 16;\n\tsdmmc->venclkctl_set = 1;\n}\n\nstatic int _sdmmc_config_tap_val(sdmmc_t *sdmmc, u32 type)\n{\n\tstatic const u32 dqs_trim_val = 40; // 24 if HS533/HS667.\n\tstatic const u8  tap_values_t210[4] = { 4, 0, 3, 0 };\n\n\tu32 tap_val = 0;\n\n\tif (type == SDHCI_TIMING_MMC_HS400)\n\t\tsdmmc->regs->vencapover = (sdmmc->regs->vencapover & ~0x3F00) | (dqs_trim_val << 8);\n\n\tsdmmc->regs->ventunctl0 &= ~SDHCI_TEGRA_TUNING_TAP_HW_UPDATED;\n\n\tif (type == SDHCI_TIMING_MMC_HS400)\n\t{\n\t\t// Tap is saved during HS200 switch.\n\t\tif (!sdmmc->venclkctl_set)\n\t\t\treturn 1;\n\n\t\ttap_val = sdmmc->venclkctl_tap;\n\t}\n\telse\n\t\ttap_val = sdmmc->t210b01 ? 11 : tap_values_t210[sdmmc->id];\n\n\tsdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & ~0xFF0000) | (tap_val << 16);\n\n\treturn 0;\n}\n\nstatic void _sdmmc_commit_changes(sdmmc_t *sdmmc)\n{\n\t(void)sdmmc->regs->clkcon;\n}\n\nstatic void _sdmmc_pad_config_fallback(sdmmc_t *sdmmc, u32 power)\n{\n\t_sdmmc_commit_changes(sdmmc);\n\tswitch (sdmmc->id)\n\t{\n\tcase SDMMC_1: // 50 Ohm 2X Driver.\n\t\tif (power == SDMMC_POWER_OFF)\n\t\t\tbreak;\n\t\tu32 sdmmc1_pad_cfg = APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) & 0xF8080FFF;\n\t\tif (sdmmc->t210b01)\n\t\t\tsdmmc1_pad_cfg |= (0x808 << 12); // Up:  8, Dn:  8. For 50 ohm.\n\t\telse if (power == SDMMC_POWER_1_8)\n\t\t\tsdmmc1_pad_cfg |= (0xB0F << 12); // Up: 11, Dn: 15. For 50 ohm.\n\t\telse if (power == SDMMC_POWER_3_3)\n\t\t\tsdmmc1_pad_cfg |= (0xC0C << 12); // Up: 12, Dn: 12. For 50 ohm.\n\t\tAPB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = sdmmc1_pad_cfg;\n\t\t(void)APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL); // Commit write.\n\t\tbreak;\n\n\tcase SDMMC_2:\n\t\tif (sdmmc->t210b01)\n\t\t\tAPB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) & 0xF8080FFF) | 0xA0A000;\n\t\telse\n\t\t\tAPB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) & 0xFFFFC003) | 0x1040; // PU:16, PD:16.\n\t\t(void)APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL);\n\t\tbreak;\n\n\tcase SDMMC_4: // 50 Ohm 2X Driver. PU:16, PD:16, B01: PU:10, PD:10.\n\t\tAPB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) & 0xFFFFC003) |\n\t\t\t\t\t\t\t\t\t\t\t\t\t (sdmmc->t210b01 ? 0xA28 : 0x1040);\n\t\t(void)APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL); // Commit write.\n\t\tbreak;\n\t}\n}\n\nstatic void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power)\n{\n\tbool should_enable_sd_clock = false;\n\tif (sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)\n\t{\n\t\tshould_enable_sd_clock = true;\n\t\tsdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;\n\t}\n\n\t// Enable E_INPUT (SD) or Disable E_PWRD (eMMC) power.\n\tif (!(sdmmc->regs->sdmemcmppadctl & SDHCI_TEGRA_PADCTRL_E_INPUT_PWRD))\n\t{\n\t\tsdmmc->regs->sdmemcmppadctl |= SDHCI_TEGRA_PADCTRL_E_INPUT_PWRD;\n\t\t_sdmmc_commit_changes(sdmmc);\n\t\tusleep(1);\n\t}\n\n\t// Enable auto calibration and start auto configuration.\n\tsdmmc->regs->autocalcfg |= SDHCI_TEGRA_AUTOCAL_ENABLE | SDHCI_TEGRA_AUTOCAL_START;\n\t_sdmmc_commit_changes(sdmmc);\n\tusleep(2);\n\n\tu32 timeout = get_tmr_ms() + 10;\n\twhile (sdmmc->regs->autocalsts & SDHCI_TEGRA_AUTOCAL_ACTIVE)\n\t{\n\t\tif (get_tmr_ms() > timeout)\n\t\t{\n\t\t\ttimeout = 0; // Set timeout to 0 if we timed out.\n\t\t\tbreak;\n\t\t}\n\t}\n\n#ifdef ERROR_EXTRA_PRINTING\n\t// Check if Comp pad is open or short to ground.\n\t// SDMMC1: CZ pads - T210/T210B01: 7-bit/5-bit. SDMMC2/4: LV_CZ pads - 5-bit.\n\t// Use 0x1F mask for all.\n\tu8 autocal_pu_status = sdmmc->regs->autocalsts & 0x1F;\n\tif (!autocal_pu_status)\n\t\tEPRINTFARGS(\"SDMMC%d: Comp Pad open!\", sdmmc->id + 1); // Or resistance is extreme.\n\telse if (autocal_pu_status == 0x1F)\n\t\tEPRINTFARGS(\"SDMMC%d: Comp Pad short to gnd!\", sdmmc->id + 1);\n#endif\n\n\t// In case auto calibration fails, we load suggested standard values.\n\tif (!timeout)\n\t{\n\t\tsdmmc->regs->autocalcfg &= ~SDHCI_TEGRA_AUTOCAL_ENABLE;\n\t\t_sdmmc_pad_config_fallback(sdmmc, power);\n#ifdef ERROR_EXTRA_PRINTING\n\t\tEPRINTFARGS(\"SDMMC%d: Comp Pad cal timeout!\", sdmmc->id + 1);\n#endif\n\t}\n\n\t// Disable E_INPUT (SD) or enable E_PWRD (eMMC) to conserve power.\n\tsdmmc->regs->sdmemcmppadctl &= ~SDHCI_TEGRA_PADCTRL_E_INPUT_PWRD;\n\n\tif (should_enable_sd_clock)\n\t\tsdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;\n}\n\nstatic int _sdmmc_dll_cal_execute(sdmmc_t *sdmmc)\n{\n\tint res = 0, should_disable_sd_clock = 0;\n\n\tif (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN))\n\t{\n\t\tshould_disable_sd_clock = 1;\n\t\tsdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;\n\t}\n\n\t // Add -4 TX_DLY_CODE_OFFSET if HS533/HS667.\n\t // if (sdmmc->id == SDMMC_4 && sdmmc->card_clock > 208000)\n\t //\tsdmmc->regs->vendllctl0 = sdmmc->regs->vendllctl0 &= 0xFFFFC07F | (0x7C << 7);\n\n\tsdmmc->regs->vendllcalcfg |= SDHCI_TEGRA_DLLCAL_CALIBRATE;\n\t_sdmmc_commit_changes(sdmmc);\n\n\tu32 timeout = get_tmr_ms() + 5;\n\twhile (sdmmc->regs->vendllcalcfg & SDHCI_TEGRA_DLLCAL_CALIBRATE)\n\t{\n\t\tif (get_tmr_ms() > timeout)\n\t\t{\n\t\t\tres = 1;\n\t\t\tgoto out;\n\t\t}\n\t}\n\n\ttimeout = get_tmr_ms() + 10;\n\twhile (sdmmc->regs->vendllcalcfgsts & SDHCI_TEGRA_DLLCAL_ACTIVE)\n\t{\n\t\tif (get_tmr_ms() > timeout)\n\t\t{\n\t\t\tres = 1;\n\t\t\tgoto out;\n\t\t}\n\t}\n\nout:\n\tif (should_disable_sd_clock)\n\t\tsdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;\n\n\treturn res;\n}\n\nstatic void _sdmmc_reset_cmd_data(sdmmc_t *sdmmc)\n{\n\tsdmmc->regs->swrst |= SDHCI_RESET_CMD | SDHCI_RESET_DATA;\n\t_sdmmc_commit_changes(sdmmc);\n\tu32 timeout = get_tmr_ms() + 2000;\n\twhile ((sdmmc->regs->swrst & (SDHCI_RESET_CMD | SDHCI_RESET_DATA)) && get_tmr_ms() < timeout)\n\t\t;\n}\n\nstatic void _sdmmc_reset_all(sdmmc_t *sdmmc)\n{\n\tsdmmc->regs->swrst |= SDHCI_RESET_ALL;\n\t_sdmmc_commit_changes(sdmmc);\n\tu32 timeout = get_tmr_ms() + 2000;//100ms\n\twhile ((sdmmc->regs->swrst & SDHCI_RESET_ALL) && get_tmr_ms() < timeout)\n\t\t;\n}\n\nvoid sdmmc_setup_drv_type(sdmmc_t *sdmmc, u32 type)\n{\n\tsdmmc->regs->hostctl2  = (sdmmc->regs->hostctl2 & (~SDHCI_CTRL_DRV_TYPE_MASK)) | SDHCI_CTRL_DRV_TYPE(type);\n\n\t_sdmmc_commit_changes(sdmmc);\n}\n\nint sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)\n{\n\t// Disable the SD clock if it was enabled, and reenable it later.\n\tbool should_enable_sd_clock = false;\n\tif (sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)\n\t{\n\t\tshould_enable_sd_clock = true;\n\t\tsdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;\n\t}\n\n\t_sdmmc_config_tap_val(sdmmc, type);\n\n\t_sdmmc_reset_cmd_data(sdmmc);\n\n\tswitch (type)\n\t{\n\tcase SDHCI_TIMING_MMC_ID:\n\tcase SDHCI_TIMING_MMC_LS26:\n\tcase SDHCI_TIMING_SD_ID:\n\tcase SDHCI_TIMING_SD_DS12:\n\t\tsdmmc->regs->hostctl  &= ~SDHCI_CTRL_HISPD;\n\t\tsdmmc->regs->hostctl2 &= ~SDHCI_CTRL_VDD_180;\n\t\tbreak;\n\n\tcase SDHCI_TIMING_MMC_HS52:\n\tcase SDHCI_TIMING_SD_HS25:\n\t\tsdmmc->regs->hostctl  |= SDHCI_CTRL_HISPD;\n\t\tsdmmc->regs->hostctl2 &= ~SDHCI_CTRL_VDD_180;\n\t\tbreak;\n\n\tcase SDHCI_TIMING_MMC_HS200:\n\tcase SDHCI_TIMING_UHS_SDR50: // T210 Errata: the host must be set to SDR104 to WAR a CRC issue.\n\tcase SDHCI_TIMING_UHS_SDR104:\n\tcase SDHCI_TIMING_UHS_SDR82:\n\tcase SDHCI_TIMING_MMC_HS100:\n\t\tsdmmc->regs->hostctl2  = (sdmmc->regs->hostctl2 & (~SDHCI_CTRL_UHS_MASK)) | UHS_SDR104_BUS_SPEED;\n\t\tsdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;\n\t\tbreak;\n\n\tcase SDHCI_TIMING_MMC_HS400:\n\t\t// Non standard.\n\t\tsdmmc->regs->hostctl2  = (sdmmc->regs->hostctl2 & (~SDHCI_CTRL_UHS_MASK)) | HS400_BUS_SPEED;\n\t\tsdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;\n\t\tbreak;\n\n\tcase SDHCI_TIMING_UHS_SDR25:\n\t\tsdmmc->regs->hostctl2  = (sdmmc->regs->hostctl2 & (~SDHCI_CTRL_UHS_MASK)) | UHS_SDR25_BUS_SPEED;\n\t\tsdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;\n\t\tbreak;\n\n\tcase SDHCI_TIMING_UHS_SDR12:\n\t\tsdmmc->regs->hostctl2  = (sdmmc->regs->hostctl2 & (~SDHCI_CTRL_UHS_MASK)) | UHS_SDR12_BUS_SPEED;\n\t\tsdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;\n\t\tbreak;\n\n\tcase SDHCI_TIMING_UHS_DDR50:\n#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT\n\tcase SDHCI_TIMING_UHS_DDR200:\n#endif\n\t\tsdmmc->regs->hostctl2  = (sdmmc->regs->hostctl2 & (~SDHCI_CTRL_UHS_MASK)) | UHS_DDR50_BUS_SPEED;\n\t\tsdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;\n\t\tbreak;\n\t}\n\n\t_sdmmc_commit_changes(sdmmc);\n\n\tu32 clock;\n\tu16 divisor;\n\tclock_sdmmc_get_card_clock_div(&clock, &divisor, type);\n\tclock_sdmmc_config_clock_source(&clock, sdmmc->id, clock);\n\tsdmmc->card_clock = (clock + divisor - 1) / divisor;\n\n\t// (divisor != 1) && (divisor & 1) -> error\n\n\tu16 div_lo = divisor >> 1;\n\tu16 div_hi = div_lo  >> 8;\n\n\tsdmmc->regs->clkcon = (sdmmc->regs->clkcon & ~(SDHCI_DIV_MASK | SDHCI_DIV_HI_MASK)) |\n\t\t\t\t\t\t  (div_lo << SDHCI_DIV_LO_SHIFT) | (div_hi << SDHCI_DIV_HI_SHIFT);\n\n\t// Enable the SD clock again.\n\tif (should_enable_sd_clock)\n\t\tsdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;\n\n\tif (type == SDHCI_TIMING_MMC_HS400)\n\t\treturn _sdmmc_dll_cal_execute(sdmmc);\n\n\treturn 0;\n}\n\nstatic void _sdmmc_card_clock_enable(sdmmc_t *sdmmc)\n{\n\t// Recalibrate periodically if needed.\n\tif (sdmmc->periodic_calibration && !sdmmc->powersave_enabled)\n\t\t_sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc));\n\n\tif (!sdmmc->powersave_enabled)\n\t{\n\t\tif (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN))\n\t\t\tsdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;\n\t}\n\tsdmmc->card_clock_enabled = 1;\n}\n\nstatic void _sdmmc_card_clock_disable(sdmmc_t *sdmmc)\n{\n\tsdmmc->card_clock_enabled = 0;\n\tsdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;\n}\n\nvoid sdmmc_card_clock_powersave(sdmmc_t *sdmmc, int powersave_enable)\n{\n\t// Recalibrate periodically if needed.\n\tif (sdmmc->periodic_calibration && !powersave_enable && sdmmc->card_clock_enabled)\n\t\t_sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc));\n\n\tsdmmc->powersave_enabled = powersave_enable;\n\tif (powersave_enable)\n\t{\n\t\tif (sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)\n\t\t\tsdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;\n\t\treturn;\n\t}\n\n\tif (sdmmc->card_clock_enabled)\n\t\tif (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN))\n\t\t\tsdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;\n}\n\nstatic int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 type)\n{\n\tswitch (type)\n\t{\n\tcase SDMMC_RSP_TYPE_1:\n\tcase SDMMC_RSP_TYPE_3:\n\tcase SDMMC_RSP_TYPE_6:\n\tcase SDMMC_RSP_TYPE_7:\n\t\trsp[0] = sdmmc->regs->rspreg[0];\n\t\tbreak;\n\n\tcase SDMMC_RSP_TYPE_2:\n\t\t// CRC is stripped, so shifting is needed.\n\t\tfor (u32 i = 0; i < 4; i++)\n\t\t{\n\t\t\tu32 tempreg = sdmmc->regs->rspreg[3 - i];\n\t\t\trsp[i] = tempreg << 8;\n\n\t\t\tif (i != 0)\n\t\t\t\trsp[i - 1] |= (tempreg >> 24) & 0xFF;\n\t\t}\n\t\tbreak;\n\n\tdefault:\n\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n\nint sdmmc_get_cached_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 type)\n{\n\tif (sdmmc->expected_rsp_type != type)\n\t\treturn 1;\n\n\tswitch (type)\n\t{\n\tcase SDMMC_RSP_TYPE_1:\n\tcase SDMMC_RSP_TYPE_3:\n\tcase SDMMC_RSP_TYPE_6:\n\tcase SDMMC_RSP_TYPE_7:\n\t\trsp[0] = sdmmc->rsp[0];\n\t\tbreak;\n\n\tcase SDMMC_RSP_TYPE_2:\n\t\tfor (u32 i = 0; i < 4; i++)\n\t\t\trsp[i] = sdmmc->rsp[i];\n\t\tbreak;\n\n\tdefault:\n\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n\nstatic int _sdmmc_wait_cmd_data_inhibit(sdmmc_t *sdmmc, bool wait_dat)\n{\n\t_sdmmc_commit_changes(sdmmc);\n\n\tu32 timeout = get_tmr_ms() + 2000;\n\twhile (sdmmc->regs->prnsts & SDHCI_CMD_INHIBIT)\n\t\tif (get_tmr_ms() > timeout)\n\t\t{\n\t\t\t_sdmmc_reset_cmd_data(sdmmc);\n\t\t\treturn 1;\n\t\t}\n\n\tif (wait_dat)\n\t{\n\t\ttimeout = get_tmr_ms() + 2000;\n\t\twhile (sdmmc->regs->prnsts & SDHCI_DATA_INHIBIT)\n\t\t\tif (get_tmr_ms() > timeout)\n\t\t\t{\n\t\t\t\t_sdmmc_reset_cmd_data(sdmmc);\n\t\t\t\treturn 1;\n\t\t\t}\n\t}\n\n\treturn 0;\n}\n\nstatic int _sdmmc_wait_card_busy(sdmmc_t *sdmmc)\n{\n\t_sdmmc_commit_changes(sdmmc);\n\n\tu32 timeout = get_tmr_ms() + 2000;\n\twhile (!(sdmmc->regs->prnsts & SDHCI_DATA_0_LVL))\n\t\tif (get_tmr_ms() > timeout)\n\t\t{\n\t\t\t_sdmmc_reset_cmd_data(sdmmc);\n\t\t\treturn 1;\n\t\t}\n\n\treturn 0;\n}\n\nstatic int _sdmmc_setup_read_small_block(sdmmc_t *sdmmc)\n{\n\tswitch (sdmmc_get_bus_width(sdmmc))\n\t{\n\tcase SDMMC_BUS_WIDTH_1:\n\t\treturn 1;\n\n\tcase SDMMC_BUS_WIDTH_4:\n\t\tsdmmc->regs->blksize = 64;\n\t\tbreak;\n\n\tcase SDMMC_BUS_WIDTH_8:\n\t\tsdmmc->regs->blksize = 128;\n\t\tbreak;\n\t}\n\n\tsdmmc->regs->blkcnt = 1;\n\tsdmmc->regs->trnmod = SDHCI_TRNS_READ;\n\n\treturn 0;\n}\n\nstatic int _sdmmc_send_cmd(sdmmc_t *sdmmc, const sdmmc_cmd_t *cmd, bool is_data_present)\n{\n\tu16 cmdflags = 0;\n\n\tswitch (cmd->rsp_type)\n\t{\n\tcase SDMMC_RSP_TYPE_0:\n\t\tbreak;\n\n\tcase SDMMC_RSP_TYPE_1:\n\tcase SDMMC_RSP_TYPE_6:\n\tcase SDMMC_RSP_TYPE_7:\n\t\tif (cmd->check_busy)\n\t\t\tcmdflags = SDHCI_CMD_RESP_LEN48_BUSY | SDHCI_CMD_INDEX | SDHCI_CMD_CRC;\n\t\telse\n\t\t\tcmdflags = SDHCI_CMD_RESP_LEN48      | SDHCI_CMD_INDEX | SDHCI_CMD_CRC;\n\t\tbreak;\n\n\tcase SDMMC_RSP_TYPE_2:\n\t\tcmdflags = SDHCI_CMD_RESP_LEN136 | SDHCI_CMD_CRC;\n\t\tbreak;\n\n\tcase SDMMC_RSP_TYPE_3:\n\t\tcmdflags = SDHCI_CMD_RESP_LEN48;\n\t\tbreak;\n\n\tdefault:\n\t\treturn 1;\n\t}\n\n\tif (is_data_present)\n\t\tcmdflags |= SDHCI_CMD_DATA;\n\n\tsdmmc->regs->argument = cmd->arg;\n\tsdmmc->regs->cmdreg   = SDHCI_CMD_IDX(cmd->cmd) | cmdflags;\n\n\treturn 0;\n}\n\nstatic void _sdmmc_send_tuning_cmd(sdmmc_t *sdmmc, u32 cmd)\n{\n\tsdmmc_cmd_t cmdbuf;\n\tcmdbuf.cmd = cmd;\n\tcmdbuf.arg = 0;\n\tcmdbuf.rsp_type = SDMMC_RSP_TYPE_1;\n\tcmdbuf.check_busy = 0;\n\t_sdmmc_send_cmd(sdmmc, &cmdbuf, true);\n}\n\nstatic int _sdmmc_tuning_execute_once(sdmmc_t *sdmmc, u32 cmd, u32 tap)\n{\n\tif (_sdmmc_wait_cmd_data_inhibit(sdmmc, true))\n\t\treturn 1;\n\n\t_sdmmc_setup_read_small_block(sdmmc);\n\n\tsdmmc->regs->norintstsen |= SDHCI_INT_DATA_AVAIL;\n\tsdmmc->regs->norintsts = sdmmc->regs->norintsts;\n\tsdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;\n\n#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT\n\t// Set tap if manual tuning.\n\tif (tap != SDMMC_HW_TAP_TUNING)\n\t{\n\t\tsdmmc->regs->ventunctl0 &= ~SDHCI_TEGRA_TUNING_TAP_HW_UPDATED;\n\t\tsdmmc->regs->venclkctl   = (sdmmc->regs->venclkctl & 0xFF00FFFF) | (tap << 16);\n\t\tsdmmc->regs->ventunctl0 |=  SDHCI_TEGRA_TUNING_TAP_HW_UPDATED;\n\t}\n#endif\n\n\t_sdmmc_send_tuning_cmd(sdmmc, cmd);\n\t_sdmmc_commit_changes(sdmmc);\n\tusleep(1);\n\n\t_sdmmc_reset_cmd_data(sdmmc);\n\n\tsdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;\n\t_sdmmc_commit_changes(sdmmc);\n\n\tu32 timeout = get_tmr_us() + 5000;\n\twhile (get_tmr_us() < timeout)\n\t{\n\t\t// Check if we got valid data.\n\t\tif (sdmmc->regs->norintsts & SDHCI_INT_DATA_AVAIL)\n\t\t{\n\t\t\tsdmmc->regs->norintsts = SDHCI_INT_DATA_AVAIL;\n\t\t\tsdmmc->regs->norintstsen &= ~SDHCI_INT_DATA_AVAIL;\n\t\t\t_sdmmc_commit_changes(sdmmc);\n\t\t\tusleep((8 * 1000 + sdmmc->card_clock - 1) / sdmmc->card_clock); // Wait 8 cycles.\n\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t_sdmmc_reset_cmd_data(sdmmc);\n\n\tsdmmc->regs->norintstsen &= ~SDHCI_INT_DATA_AVAIL;\n\t_sdmmc_commit_changes(sdmmc);\n\tusleep((8 * 1000 + sdmmc->card_clock - 1) / sdmmc->card_clock); // Wait 8 cycles.\n\n\treturn 1;\n}\n\n#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT\ntypedef struct _sdmmc_manual_tuning_t\n{\n\tu32 result[8];\n\tu32 num_iter;\n\tu32 tap_start;\n\tu32 tap_end;\n} sdmmc_manual_tuning_t;\n\nstatic int _sdmmc_manual_tuning_set_tap(sdmmc_t *sdmmc, sdmmc_manual_tuning_t *tuning)\n{\n\tu32 tap_start = SDMMC_INVALID_TAP;\n\tu32 win_size  = 0;\n\tu32 best_tap  = 0;\n\tu32 best_size = 0;\n\n\tfor (u32 i = 0; i < tuning->num_iter; i++)\n\t{\n\t\tu32 iter_end = i == (tuning->num_iter - 1) ? 1 : 0;\n\t\tu32 stable = tuning->result[i / 32] & BIT(i % 32);\n\t\tif (stable && !iter_end)\n\t\t{\n\t\t\tif (tap_start == SDMMC_INVALID_TAP)\n\t\t\t\ttap_start = i;\n\n\t\t\twin_size++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (tap_start != SDMMC_INVALID_TAP)\n\t\t\t{\n\t\t\t\tu32 tap_end = !iter_end ? (i - 1) : i;\n\n\t\t\t\t// Check if window is wider.\n\t\t\t\tif (win_size > best_size)\n\t\t\t\t{\n\t\t\t\t\tbest_tap  = (tap_start + tap_end) / 2;\n\t\t\t\t\tbest_size = win_size + iter_end;\n\t\t\t\t}\n\n\t\t\t\ttap_start = SDMMC_INVALID_TAP;\n\t\t\t\twin_size  = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t// Check if failed or window too small.\n\tif (!best_tap || best_size < SDMMC_SAMPLE_WIN_SIZE_MIN)\n\t\treturn 1;\n\n\tsdmmc->regs->clkcon     &= ~SDHCI_CLOCK_CARD_EN;\n\tsdmmc->regs->ventunctl0 &= ~SDHCI_TEGRA_TUNING_TAP_HW_UPDATED;\n\n\t// Set tap.\n\tsdmmc->regs->venclkctl   = (sdmmc->regs->venclkctl & 0xFF00FFFF) | (best_tap << 16);\n\n\tsdmmc->regs->ventunctl0 |=  SDHCI_TEGRA_TUNING_TAP_HW_UPDATED;\n\tsdmmc->regs->clkcon     |= SDHCI_CLOCK_CARD_EN;\n\n\treturn 0;\n}\n\n/*\n * SD Card DDR200 (DDR208) support\n *\n * On Tegra X1, that can be done with DDR50 host mode.\n * That's because HS400 4-bit or HS400 generally, is not supported on SDMMC1/3.\n * And also, tuning can't be done automatically on any DDR mode.\n * So it needs to be done manually and selected tap will be applied from the biggest\n * sampling window.\n * That allows DDR200 support on every DDR200 sd card, other than the original maker\n * of DDR200, Sandisk. Since Sandisk cards mandate DLL syncing.\n */\nstatic int sdmmc_tuning_execute_ddr200(sdmmc_t *sdmmc)\n{\n\tsdmmc_manual_tuning_t manual_tuning = { 0 };\n\tmanual_tuning.num_iter = 128;\n\n\tsdmmc->regs->ventunctl1  = 0; // step_size 1.\n\tsdmmc->regs->ventunctl0  = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | (2 << 13); // 128 Tries.\n\tsdmmc->regs->ventunctl0  = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | (1 << 6);  // 1x Multiplier.\n\tsdmmc->regs->ventunctl0 |= SDHCI_TEGRA_TUNING_TAP_HW_UPDATED;\n\n\tsdmmc->regs->hostctl2   |= SDHCI_CTRL_EXEC_TUNING;\n\n\tfor (u32 i = 0; i < manual_tuning.num_iter; i++)\n\t{\n\t\t_sdmmc_tuning_execute_once(sdmmc, MMC_SEND_TUNING_BLOCK, i);\n\n\t\t// Save result for manual tuning.\n\t\tint sampled = (sdmmc->regs->hostctl2 >> SDHCI_CTRL_TUNED_CLK_SHIFT) & 1;\n\t\tmanual_tuning.result[i / 32] |= sampled << (i % 32);\n\n\t\tif (!(sdmmc->regs->hostctl2 & SDHCI_CTRL_EXEC_TUNING))\n\t\t\tbreak;\n\t}\n\n\treturn _sdmmc_manual_tuning_set_tap(sdmmc, &manual_tuning);\n}\n#endif\n\nint sdmmc_tuning_execute(sdmmc_t *sdmmc, u32 type, u32 cmd)\n{\n\tu32 num_iter, flag;\n\n\tif (sdmmc->powersave_enabled)\n\t\treturn 1;\n\n\tswitch (type)\n\t{\n\tcase SDHCI_TIMING_MMC_HS200:\n\tcase SDHCI_TIMING_UHS_SDR104:\n\tcase SDHCI_TIMING_UHS_SDR82:\n\t\tnum_iter = 128;\n\t\tflag = (2 << 13); // 128 iterations.\n\t\tbreak;\n\n\tcase SDHCI_TIMING_UHS_SDR50:\n\tcase SDHCI_TIMING_UHS_DDR50: // HW tuning is not supported on DDR modes. But it sets tap to 0 which is proper.\n\tcase SDHCI_TIMING_MMC_HS100:\n\t\tnum_iter = 256;\n\t\tflag = (4 << 13); // 256 iterations.\n\t\tbreak;\n\n\tcase SDHCI_TIMING_MMC_HS400:\n\tcase SDHCI_TIMING_UHS_SDR12:\n\tcase SDHCI_TIMING_UHS_SDR25:\n\t\treturn 0;\n\n#ifdef BDK_SDMMC_UHS_DDR200_SUPPORT\n\tcase SDHCI_TIMING_UHS_DDR200:\n\t\treturn sdmmc_tuning_execute_ddr200(sdmmc);\n#endif\n\n\tdefault:\n\t\treturn 1;\n\t}\n\n\tsdmmc->regs->ventunctl1  = 0; // step_size 1.\n\tsdmmc->regs->ventunctl0  = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | flag;     // Tries.\n\tsdmmc->regs->ventunctl0  = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | (1 << 6); // 1x Multiplier.\n\tsdmmc->regs->ventunctl0 |= SDHCI_TEGRA_TUNING_TAP_HW_UPDATED;\n\n\tsdmmc->regs->hostctl2   |= SDHCI_CTRL_EXEC_TUNING;\n\n\tfor (u32 i = 0; i < num_iter; i++)\n\t{\n\t\t_sdmmc_tuning_execute_once(sdmmc, cmd, SDMMC_HW_TAP_TUNING);\n\n\t\tif (!(sdmmc->regs->hostctl2 & SDHCI_CTRL_EXEC_TUNING))\n\t\t\tbreak;\n\t}\n\n\tif (sdmmc->regs->hostctl2 & SDHCI_CTRL_TUNED_CLK)\n\t\treturn 0;\n\n\treturn 1;\n}\n\nstatic int _sdmmc_enable_internal_clock(sdmmc_t *sdmmc)\n{\n\t//Enable internal clock and wait till it is stable.\n\tsdmmc->regs->clkcon |= SDHCI_CLOCK_INT_EN;\n\t_sdmmc_commit_changes(sdmmc);\n\tu32 timeout = get_tmr_ms() + 2000;\n\twhile (!(sdmmc->regs->clkcon & SDHCI_CLOCK_INT_STABLE))\n\t{\n\t\tif (get_tmr_ms() > timeout)\n\t\t\treturn 1;\n\t}\n\n\tsdmmc->regs->hostctl2 &= ~SDHCI_CTRL_PRESET_VAL_EN;\n\tsdmmc->regs->clkcon   &= ~SDHCI_PROG_CLOCK_MODE;\n\t// Enable 32/64bit addressing if used (sysad. if blkcnt it fallbacks to 16bit).\n\tsdmmc->regs->hostctl2 |= SDHCI_HOST_VERSION_4_EN;\n\n\tif (!(sdmmc->regs->capareg & SDHCI_CAP_64BIT))\n\t\treturn 1;\n\n\tsdmmc->regs->hostctl2  |= SDHCI_ADDRESSING_64BIT_EN;\n\tsdmmc->regs->hostctl   &= ~SDHCI_CTRL_DMA_MASK; // Use SDMA. Host V4 enabled so adma address regs in use.\n\tsdmmc->regs->timeoutcon = (sdmmc->regs->timeoutcon & 0xF0) | 14; // TMCLK * 2^27.\n\n\treturn 0;\n}\n\nstatic int _sdmmc_autocal_config_offset(sdmmc_t *sdmmc, u32 power)\n{\n\tu32 off_pd = 0;\n\tu32 off_pu = 0;\n\n\tswitch (sdmmc->id)\n\t{\n\tcase SDMMC_2:\n\tcase SDMMC_4:\n\t\tif (power != SDMMC_POWER_1_8)\n\t\t\treturn 1;\n\t\toff_pd = 5;\n\t\toff_pu = 5;\n\t\tbreak;\n\n\tcase SDMMC_1:\n\t\tif (power == SDMMC_POWER_1_8)\n\t\t{\n\t\t\tif (!sdmmc->t210b01)\n\t\t\t{\n\t\t\t\toff_pd = 0x7B; // -5.\n\t\t\t\toff_pu = 0x7B; // -5.\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\toff_pd = 6;\n\t\t\t\toff_pu = 6;\n\t\t\t}\n\t\t}\n\t\telse if (power == SDMMC_POWER_3_3)\n\t\t{\n\t\t\tif (!sdmmc->t210b01)\n\t\t\t{\n\t\t\t\toff_pd = 0x7D; // -3.\n\t\t\t\toff_pu = 0;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\treturn 1;\n\t\tbreak;\n\t}\n\n\tsdmmc->regs->autocalcfg = (sdmmc->regs->autocalcfg & 0xFFFF8080) | (off_pd << 8) | off_pu;\n\treturn 0;\n}\n\nstatic void _sdmmc_enable_interrupts(sdmmc_t *sdmmc)\n{\n\tsdmmc->regs->norintstsen |= SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE;\n\tsdmmc->regs->errintstsen |= SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR;\n\tsdmmc->regs->norintsts = sdmmc->regs->norintsts;\n\tsdmmc->regs->errintsts = sdmmc->regs->errintsts;\n\tsdmmc->error_sts = 0;\n}\n\nstatic void _sdmmc_mask_interrupts(sdmmc_t *sdmmc)\n{\n\tsdmmc->regs->errintstsen &= ~SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR;\n\tsdmmc->regs->norintstsen &= ~(SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE);\n}\n\nstatic u32 _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask)\n{\n\tu16 norintsts = sdmmc->regs->norintsts;\n\tu16 errintsts = sdmmc->regs->errintsts;\n\n\tDPRINTF(\"norintsts %08X, errintsts %08X\\n\", norintsts, errintsts);\n\n\tif (pout)\n\t\t*pout = norintsts;\n\n\t// Check for error interrupt.\n\tif (norintsts & SDHCI_INT_ERROR)\n\t{\n#ifdef ERROR_EXTRA_PRINTING\n\t\tEPRINTFARGS(\"SDMMC%d: intsts %08X, errintsts %08X\", sdmmc->id + 1, norintsts, errintsts);\n#endif\n\t\tsdmmc->error_sts = errintsts;\n\t\tsdmmc->regs->errintsts = errintsts;\n\t\treturn SDMMC_MASKINT_ERROR;\n\t}\n\telse if (norintsts & mask)\n\t{\n\t\tsdmmc->regs->norintsts = norintsts & mask;\n\t\treturn SDMMC_MASKINT_MASKED;\n\t}\n\n\treturn SDMMC_MASKINT_NOERROR;\n}\n\nstatic int _sdmmc_wait_response(sdmmc_t *sdmmc)\n{\n\t_sdmmc_commit_changes(sdmmc);\n\n\tu32 timeout = get_tmr_ms() + 2000;\n\twhile (true)\n\t{\n\t\tu32 res = _sdmmc_check_mask_interrupt(sdmmc, NULL, SDHCI_INT_RESPONSE);\n\t\tif (res == SDMMC_MASKINT_MASKED)\n\t\t\tbreak;\n\t\tif (res != SDMMC_MASKINT_NOERROR || get_tmr_ms() > timeout)\n\t\t{\n\t\t\t_sdmmc_reset_cmd_data(sdmmc);\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nstatic int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp)\n{\n\tsdmmc_cmd_t cmd;\n\n\tif (_sdmmc_wait_cmd_data_inhibit(sdmmc, false))\n\t\treturn 1;\n\n\t_sdmmc_enable_interrupts(sdmmc);\n\n\tcmd.cmd = MMC_STOP_TRANSMISSION;\n\tcmd.arg = 0;\n\tcmd.rsp_type = SDMMC_RSP_TYPE_1;\n\tcmd.check_busy = 1;\n\n\t_sdmmc_send_cmd(sdmmc, &cmd, false);\n\n\tint res = _sdmmc_wait_response(sdmmc);\n\t_sdmmc_mask_interrupts(sdmmc);\n\n\tif (res)\n\t\treturn 1;\n\n\t_sdmmc_cache_rsp(sdmmc, rsp, SDMMC_RSP_TYPE_1);\n\n\treturn _sdmmc_wait_card_busy(sdmmc);\n}\n\nint sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp)\n{\n\tif (!sdmmc->card_clock_enabled)\n\t\treturn 1;\n\n\t// Recalibrate periodically if needed.\n\tif (sdmmc->periodic_calibration && sdmmc->powersave_enabled)\n\t\t_sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc));\n\n\tbool should_disable_sd_clock = false;\n\tif (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN))\n\t{\n\t\tshould_disable_sd_clock = true;\n\t\tsdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;\n\t\t_sdmmc_commit_changes(sdmmc);\n\t\tusleep((8 * 1000 + sdmmc->card_clock - 1) / sdmmc->card_clock); // Wait 8 cycles.\n\t}\n\n\tint res = _sdmmc_stop_transmission_inner(sdmmc, rsp);\n\tusleep((8 * 1000 + sdmmc->card_clock - 1) / sdmmc->card_clock); // Wait 8 cycles.\n\n\tif (should_disable_sd_clock)\n\t\tsdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;\n\n\treturn res;\n}\n\nstatic int _sdmmc_config_sdma(sdmmc_t *sdmmc, u32 *blkcnt_out, const sdmmc_req_t *request)\n{\n\tif (!request->blksize || !request->num_sectors)\n\t\treturn 1;\n\n\tu32 blkcnt = request->num_sectors;\n\tif (blkcnt >= SDMMC_HMAX_BLOCKNUM)\n\t\tblkcnt = SDMMC_HMAX_BLOCKNUM;\n\tu32 admaaddr = (u32)request->buf;\n\n\t// Check alignment.\n\tif (admaaddr & 7)\n\t\treturn 1;\n\n\tsdmmc->regs->admaaddr = admaaddr;\n\tsdmmc->regs->admaaddr_hi = 0;\n\n\tsdmmc->dma_addr_next = ALIGN_DOWN((admaaddr + SZ_512K), SZ_512K);\n\n\tsdmmc->regs->blksize = request->blksize | (7u << 12); // SDMA DMA 512KB Boundary (Detects A18 carry out).\n\tsdmmc->regs->blkcnt  = blkcnt;\n\n\tif (blkcnt_out)\n\t\t*blkcnt_out = blkcnt;\n\n\tu32 trnmode = SDHCI_TRNS_DMA | SDHCI_TRNS_RTYPE_R1;\n\n\t// Set multiblock request.\n\tif (request->is_multi_block)\n\t\ttrnmode |= SDHCI_TRNS_MULTI | SDHCI_TRNS_BLK_CNT_EN;\n\n\t// Set request direction.\n\tif (!request->is_write)\n\t\ttrnmode |= SDHCI_TRNS_READ;\n\n\t// Automatic send of stop transmission or set block count cmd.\n\tif (request->is_auto_stop_trn)\n\t\ttrnmode |= SDHCI_TRNS_AUTO_CMD12;\n\t//else if (request->is_auto_set_blkcnt)\n\t//\ttrnmode |= SDHCI_TRNS_AUTO_CMD23;\n\n\tsdmmc->regs->trnmod = trnmode;\n\n\treturn 0;\n}\n\nstatic int _sdmmc_update_sdma(sdmmc_t *sdmmc)\n{\n\tu16 blkcnt = 0;\n\tdo\n\t{\n\t\tblkcnt = sdmmc->regs->blkcnt;\n\t\tu32 timeout = get_tmr_ms() + 1500;\n\t\tdo\n\t\t{\n\t\t\tu32 res = SDMMC_MASKINT_MASKED;\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tu16 intr = 0;\n\t\t\t\tres = _sdmmc_check_mask_interrupt(sdmmc, &intr,\n\t\t\t\t\tSDHCI_INT_DATA_END | SDHCI_INT_DMA_END);\n\t\t\t\tif (res != SDMMC_MASKINT_MASKED)\n\t\t\t\t\tbreak;\n\n\t\t\t\tif (intr & SDHCI_INT_DATA_END)\n\t\t\t\t\treturn 0; // Transfer complete.\n\n\t\t\t\tif (intr & SDHCI_INT_DMA_END)\n\t\t\t\t{\n\t\t\t\t\t// Update DMA.\n\t\t\t\t\tsdmmc->regs->admaaddr = sdmmc->dma_addr_next;\n\t\t\t\t\tsdmmc->regs->admaaddr_hi = 0;\n\t\t\t\t\tsdmmc->dma_addr_next += SZ_512K;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (res != SDMMC_MASKINT_NOERROR)\n\t\t\t{\n#ifdef ERROR_EXTRA_PRINTING\n\t\t\t\tEPRINTFARGS(\"SDMMC%d: int error!\", sdmmc->id + 1);\n#endif\n\t\t\t\t_sdmmc_reset_cmd_data(sdmmc);\n\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t} while (get_tmr_ms() < timeout);\n\t} while (sdmmc->regs->blkcnt != blkcnt);\n\n\t_sdmmc_reset_cmd_data(sdmmc);\n\n\treturn 1;\n}\n\nstatic int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *request, u32 *blkcnt_out)\n{\n\tbool has_req_or_check_busy = request || cmd->check_busy;\n\tif (_sdmmc_wait_cmd_data_inhibit(sdmmc, has_req_or_check_busy))\n\t\treturn 1;\n\n\tu32 blkcnt = 0;\n\tbool is_data_present = false;\n\tif (request)\n\t{\n\t\tif (_sdmmc_config_sdma(sdmmc, &blkcnt, request))\n\t\t{\n#ifdef ERROR_EXTRA_PRINTING\n\t\t\tEPRINTFARGS(\"SDMMC%d: DMA Wrong cfg!\", sdmmc->id + 1);\n#endif\n\t\t\treturn 1;\n\t\t}\n\n\t\t// Flush cache before starting the transfer.\n\t\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_CLEAN_WAY, false);\n\n\t\tis_data_present = true;\n\t}\n\n\t_sdmmc_enable_interrupts(sdmmc);\n\n\tif (_sdmmc_send_cmd(sdmmc, cmd, is_data_present))\n\t{\n#ifdef ERROR_EXTRA_PRINTING\n\t\tEPRINTFARGS(\"SDMMC%d: Wrong Response type %08X!\", sdmmc->id + 1, cmd->rsp_type);\n#endif\n\t\treturn 1;\n\t}\n\n\tint res = _sdmmc_wait_response(sdmmc);\n#ifdef ERROR_EXTRA_PRINTING\n\tif (res)\n\t\tEPRINTFARGS(\"SDMMC%d: Transfer error!\", sdmmc->id + 1);\n#endif\n\tDPRINTF(\"rsp(%d): %08X, %08X, %08X, %08X\\n\", res,\n\t\tsdmmc->regs->rspreg[0], sdmmc->regs->rspreg[1], sdmmc->regs->rspreg[2], sdmmc->regs->rspreg[3]);\n\n\tif (!res)\n\t{\n\t\tif (cmd->rsp_type)\n\t\t{\n\t\t\tsdmmc->expected_rsp_type = cmd->rsp_type;\n\t\t\tres = _sdmmc_cache_rsp(sdmmc, sdmmc->rsp, cmd->rsp_type);\n\t\t}\n\t\tif (request && !res)\n\t\t{\n\t\t\tres = _sdmmc_update_sdma(sdmmc);\n#ifdef ERROR_EXTRA_PRINTING\n\t\t\tif (res)\n\t\t\t\tEPRINTFARGS(\"SDMMC%d: DMA Update failed!\", sdmmc->id + 1);\n#endif\n\t\t}\n\t}\n\n\t_sdmmc_mask_interrupts(sdmmc);\n\n\tif (!res)\n\t{\n\t\tif (request)\n\t\t{\n\t\t\t// Invalidate cache after transfer.\n\t\t\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);\n\n\t\t\tif (blkcnt_out)\n\t\t\t\t*blkcnt_out = blkcnt;\n\n\t\t\tif (request->is_auto_stop_trn)\n\t\t\t\tsdmmc->stop_trn_rsp = sdmmc->regs->rspreg[3];\n\t\t}\n\n\t\tif (has_req_or_check_busy)\n\t\t{\n\t\t\tres = _sdmmc_wait_card_busy(sdmmc);\n#ifdef ERROR_EXTRA_PRINTING\n\t\t\tif (res)\n\t\t\t\tEPRINTFARGS(\"SDMMC%d: Busy timeout!\", sdmmc->id + 1);\n#endif\n\t\t}\n\t}\n\n\treturn res;\n}\n\nbool sdmmc_get_sd_inserted()\n{\n\treturn (!gpio_read(GPIO_PORT_Z, GPIO_PIN_1));\n}\n\nstatic void _sdmmc_config_sdmmc1_schmitt()\n{\n\tPINMUX_AUX(PINMUX_AUX_SDMMC1_CLK)  |= PINMUX_SCHMT;\n\tPINMUX_AUX(PINMUX_AUX_SDMMC1_CMD)  |= PINMUX_SCHMT;\n\tPINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) |= PINMUX_SCHMT;\n\tPINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) |= PINMUX_SCHMT;\n\tPINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) |= PINMUX_SCHMT;\n\tPINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) |= PINMUX_SCHMT;\n}\n\nstatic void _sdmmc_config_sdmmc2_schmitt()\n{\n\tPINMUX_AUX(PINMUX_AUX_SDMMC2_CLK)  |= PINMUX_SCHMT;\n\tPINMUX_AUX(PINMUX_AUX_SDMMC2_CMD)  |= PINMUX_SCHMT;\n\tPINMUX_AUX(PINMUX_AUX_SDMMC2_DAT7) |= PINMUX_SCHMT;\n\tPINMUX_AUX(PINMUX_AUX_SDMMC2_DAT6) |= PINMUX_SCHMT;\n\tPINMUX_AUX(PINMUX_AUX_SDMMC2_DAT5) |= PINMUX_SCHMT;\n\tPINMUX_AUX(PINMUX_AUX_SDMMC2_DAT4) |= PINMUX_SCHMT;\n\tPINMUX_AUX(PINMUX_AUX_SDMMC2_DAT3) |= PINMUX_SCHMT;\n\tPINMUX_AUX(PINMUX_AUX_SDMMC2_DAT2) |= PINMUX_SCHMT;\n\tPINMUX_AUX(PINMUX_AUX_SDMMC2_DAT1) |= PINMUX_SCHMT;\n\tPINMUX_AUX(PINMUX_AUX_SDMMC2_DAT0) |= PINMUX_SCHMT;\n}\n\nstatic void _sdmmc_config_sdmmc1_pads(bool discharge)\n{\n\tu32 sdmmc1_pin_mask = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5;\n\n\t// Set values for Reset state.\n\tu32 function = GPIO_MODE_SPIO;\n\tu32 level    = GPIO_LOW;\n\tu32 output   = GPIO_OUTPUT_DISABLE;\n\n\t// Set values for discharging.\n\tif (discharge)\n\t{\n\t\tfunction = GPIO_MODE_GPIO;\n\t\tlevel    = GPIO_HIGH;\n\t\toutput   = GPIO_OUTPUT_ENABLE;\n\t}\n\n\t// Set all pads function.\n\tgpio_config(GPIO_PORT_M, sdmmc1_pin_mask, function);\n\t// Set all pads output level.\n\tgpio_write(GPIO_PORT_M, sdmmc1_pin_mask, level);\n\t// Set all pads output.\n\tgpio_output_enable(GPIO_PORT_M, sdmmc1_pin_mask, output);\n}\n\nstatic int _sdmmc_config_sdmmc1(bool t210b01)\n{\n\t// Configure SD card detect.\n\tPINMUX_AUX(PINMUX_AUX_GPIO_PZ1) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP | 2; // GPIO control, pull up.\n\tAPB_MISC(APB_MISC_GP_VGPIO_GPIO_MUX_SEL) = 0;\n\tgpio_direction_input(GPIO_PORT_Z, GPIO_PIN_1);\n\tusleep(100);\n\n\t// Check if SD card is inserted.\n\tif (!sdmmc_get_sd_inserted())\n\t\treturn 1;\n\n\t// Enable deep loopback for SDMMC1 CLK pad so reads work.\n\tAPB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1;\n\n\t// Configure SDMMC1 CLK pinmux, based on state and SoC type.\n\tPINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) &= ~PINMUX_SCHMT;\n\tif (PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) != (PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN)) // Check if CLK pad is already configured.\n\t\tPINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | (t210b01 ? PINMUX_PULL_NONE : PINMUX_PULL_DOWN);\n\n\t// Configure reset state of SDMMC1 pins pinmux.\n\tPINMUX_AUX(PINMUX_AUX_SDMMC1_CMD)  = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP;\n\tPINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP;\n\tPINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP;\n\tPINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP;\n\tPINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP;\n\n\t// Force schmitt trigger for T210B01.\n\tif (t210b01)\n\t\t_sdmmc_config_sdmmc1_schmitt();\n\n\t// Make sure the SDMMC1 controller is powered.\n\tPMC(APBDEV_PMC_NO_IOPOWER) |=  PMC_NO_IOPOWER_SDMMC1;\n\tusleep(1000);\n\tPMC(APBDEV_PMC_NO_IOPOWER) &= ~PMC_NO_IOPOWER_SDMMC1;\n\t(void)PMC(APBDEV_PMC_NO_IOPOWER); // Commit write.\n\n\t// Enable SD card power. Powers LDO2 also.\n\tPINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_PULL_DOWN | 2;\n\tgpio_direction_output(GPIO_PORT_E, GPIO_PIN_4, GPIO_HIGH);\n\tusleep(10000); // Minimum 3 to 10 ms.\n\n\t// Inform IO pads that voltage is gonna be 3.3V.\n\tPMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_33V_SDMMC1;\n\t(void)PMC(APBDEV_PMC_PWR_DET_VAL); // Commit write.\n\n\t// Enable SD card IO power.\n\tmax7762x_regulator_set_voltage(REGULATOR_LDO2, 3300000);\n\tmax7762x_regulator_enable(REGULATOR_LDO2, true);\n\tusleep(1000);\n\n\t// Set pad slew codes to get good quality clock.\n\tif (!t210b01)\n\t{\n\t\tAPB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) & 0xFFFFFFF) | 0x50000000;\n\t\t(void)APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL); // Commit write.\n\t\tusleep(1000);\n\t}\n\n\treturn 0;\n}\n\nstatic void _sdmmc_config_emmc(u32 id, bool t210b01)\n{\n\tswitch (id)\n\t{\n\tcase SDMMC_2:\n\t\tif (!t210b01)\n\t\t{\n\t\t\t// Unset park for pads.\n\t\t\tAPB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) &= 0xF8003FFF;\n\t\t\t(void)APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL); // Commit write.\n\t\t}\n\t\telse // Enable schmitt trigger for T210B01.\n\t\t\t_sdmmc_config_sdmmc2_schmitt();\n\t\tbreak;\n\n\tcase SDMMC_4:\n\t\t// Unset park for pads.\n\t\tAPB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) &= 0xF8003FFF;\n\t\t// Set default pad cfg.\n\t\tif (t210b01)\n\t\t\tAPB_MISC(APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL) &= 0xFFBFFFF9; // Unset CMD/CLK/DQS weak pull up/down.\n\t\t// Enable schmitt trigger.\n\t\tAPB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) |= 1;\n\t\t(void)APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL); // Commit write.\n\t\tbreak;\n\t}\n}\n\nint sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type)\n{\n\tu32 clock;\n\tu16 divisor;\n\tu8 vref_sel = 7;\n\n\tstatic const u8 trim_values_t210[4]    = {  2,  8,  3,  8 };\n\tstatic const u8 trim_values_t210b01[4] = { 14, 13, 15, 13 };\n\tconst u8 *trim_values;\n\n\tif (id > SDMMC_4 || id == SDMMC_3)\n\t\treturn 1;\n\n\tmemset(sdmmc, 0, sizeof(sdmmc_t));\n\n\tsdmmc->regs = (t210_sdmmc_t *)(SDMMC_BASE + (u32)_sdmmc_base_offsets[id]);\n\tsdmmc->id = id;\n\tsdmmc->clock_stopped = 1;\n\tsdmmc->t210b01 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01;\n\n\ttrim_values = sdmmc->t210b01 ? trim_values_t210b01 : trim_values_t210;\n\n\t// Do specific SDMMC HW configuration.\n\tswitch (id)\n\t{\n\tcase SDMMC_1:\n\t\tif (_sdmmc_config_sdmmc1(sdmmc->t210b01))\n\t\t\treturn 1;\n\t\tif (sdmmc->t210b01)\n\t\t\tvref_sel = 0;\n\t\telse\n\t\t\tsdmmc->periodic_calibration = 1;\n\t\tbreak;\n\n\tcase SDMMC_2:\n\tcase SDMMC_4:\n\t\t_sdmmc_config_emmc(id, sdmmc->t210b01);\n\t\tbreak;\n\t}\n\n\t// Disable clock if enabled.\n\tif (clock_sdmmc_is_active(id))\n\t{\n\t\t_sdmmc_card_clock_disable(sdmmc);\n\t\t_sdmmc_commit_changes(sdmmc);\n\t}\n\n\t// Configure and enable selected clock.\n\tclock_sdmmc_get_card_clock_div(&clock, &divisor, type);\n\tclock_sdmmc_enable(id, clock);\n\tsdmmc->clock_stopped = 0;\n\n\t// Make sure all sdmmc registers are reset.\n\t_sdmmc_reset_all(sdmmc);\n\n\t// Set default pad IO trimming configuration.\n\tsdmmc->regs->iospare |= BIT(19);      // Enable 1 cycle delayed cmd_oen.\n\tsdmmc->regs->veniotrimctl &= ~BIT(2); // Set Band Gap VREG to supply DLL.\n\tsdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xE0FFFFFB) | ((u32)trim_values[sdmmc->id] << 24);\n\tsdmmc->regs->sdmemcmppadctl = (sdmmc->regs->sdmemcmppadctl & ~SDHCI_TEGRA_PADCTRL_VREF_SEL_MASK) | vref_sel;\n\n\t// Configure auto calibration values.\n\tif (_sdmmc_autocal_config_offset(sdmmc, power))\n\t\treturn 1;\n\n\t_sdmmc_commit_changes(sdmmc);\n\n\t// Calibrate pads.\n\t_sdmmc_autocal_execute(sdmmc, power);\n\n\t// Enable internal clock and power.\n\tif (!_sdmmc_enable_internal_clock(sdmmc))\n\t{\n\t\tsdmmc_set_bus_width(sdmmc, bus_width);\n\t\t_sdmmc_set_io_power(sdmmc, power);\n\n\t\tif (!sdmmc_setup_clock(sdmmc, type))\n\t\t{\n\t\t\tsdmmc_card_clock_powersave(sdmmc, SDMMC_POWER_SAVE_DISABLE);\n\t\t\t_sdmmc_card_clock_enable(sdmmc);\n\t\t\t_sdmmc_commit_changes(sdmmc);\n\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t// Failed to enable clock.\n\treturn 1;\n}\n\nvoid sdmmc1_disable_power()\n{\n\t// T210B01 WAR: Clear pull down from CLK pad.\n\tPINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) &= ~PINMUX_PULL_MASK;\n\n\t// T210B01 WAR: Set pads to discharge state.\n\t_sdmmc_config_sdmmc1_pads(true);\n\n\t// Disable SD card IO power.\n\tmax7762x_regulator_enable(REGULATOR_LDO2, false);\n\tusleep(4000);\n\n\t// Disable SD card power.\n\tgpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_LOW);\n\n\t// T210/T210B01 WAR: Set start timer for IO and Controller power discharge.\n\tsd_power_cycle_time_start = get_tmr_ms();\n\tusleep(10000); // To power cycle, min 1ms without power is needed.\n\n\t// Disable SDMMC1 controller power.\n\tPMC(APBDEV_PMC_NO_IOPOWER) |= PMC_NO_IOPOWER_SDMMC1;\n\t(void)PMC(APBDEV_PMC_NO_IOPOWER); // Commit write.\n\n\t// Inform IO pads that next voltage might be 3.3V.\n\tPMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_33V_SDMMC1;\n\t(void)PMC(APBDEV_PMC_PWR_DET_VAL); // Commit write.\n\n\t// T210B01 WAR: Restore pads to reset state.\n\t_sdmmc_config_sdmmc1_pads(false);\n\n\t// T210B01 WAR: Restore pull down to CLK pad.\n\tPINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) |= PINMUX_PULL_DOWN;\n}\n\nvoid sdmmc_end(sdmmc_t *sdmmc)\n{\n\tif (!sdmmc->clock_stopped)\n\t{\n\t\t_sdmmc_card_clock_disable(sdmmc);\n\t\t// Disable SDMMC power.\n\t\t_sdmmc_set_io_power(sdmmc, SDMMC_POWER_OFF);\n\t\t_sdmmc_commit_changes(sdmmc);\n\n\t\t// Disable SD card power.\n\t\tif (sdmmc->id == SDMMC_1)\n\t\t\tsdmmc1_disable_power();\n\n\t\tclock_sdmmc_disable(sdmmc->id);\n\t\tsdmmc->clock_stopped = 1;\n\t}\n}\n\nvoid sdmmc_init_cmd(sdmmc_cmd_t *cmdbuf, u16 cmd, u32 arg, u32 rsp_type, u32 check_busy)\n{\n\tcmdbuf->cmd = cmd;\n\tcmdbuf->arg = arg;\n\tcmdbuf->rsp_type = rsp_type;\n\tcmdbuf->check_busy = check_busy;\n}\n\nint sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *request, u32 *blkcnt_out)\n{\n\tif (!sdmmc->card_clock_enabled)\n\t\treturn 1;\n\n\t// Recalibrate periodically if needed.\n\tif (sdmmc->periodic_calibration && sdmmc->powersave_enabled)\n\t\t_sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc));\n\n\tint should_disable_sd_clock = 0;\n\tif (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN))\n\t{\n\t\tshould_disable_sd_clock = 1;\n\t\tsdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;\n\t\t_sdmmc_commit_changes(sdmmc);\n\t\tusleep((8 * 1000 + sdmmc->card_clock - 1) / sdmmc->card_clock); // Wait 8 cycles.\n\t}\n\n\tint res = _sdmmc_execute_cmd_inner(sdmmc, cmd, request, blkcnt_out);\n\tusleep((8 * 1000 + sdmmc->card_clock - 1) / sdmmc->card_clock); // Wait 8 cycles.\n\n\tif (should_disable_sd_clock)\n\t\tsdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN;\n\n\treturn res;\n}\n\nint sdmmc_enable_low_voltage(sdmmc_t *sdmmc)\n{\n\tif (sdmmc->id != SDMMC_1)\n\t\treturn 1;\n\n\t_sdmmc_commit_changes(sdmmc);\n\n\t// Switch to 1.8V and wait for regulator to stabilize. Assume max possible wait needed.\n\tmax7762x_regulator_set_voltage(REGULATOR_LDO2, 1800000);\n\tusleep(150);\n\n\t// Inform IO pads that we switched to 1.8V.\n\tPMC(APBDEV_PMC_PWR_DET_VAL) &= ~PMC_PWR_DET_33V_SDMMC1;\n\t(void)PMC(APBDEV_PMC_PWR_DET_VAL); // Commit write.\n\n\t// Enable schmitt trigger for better duty cycle and low jitter clock.\n\t_sdmmc_config_sdmmc1_schmitt();\n\n\t_sdmmc_autocal_config_offset(sdmmc, SDMMC_POWER_1_8);\n\t_sdmmc_autocal_execute(sdmmc, SDMMC_POWER_1_8);\n\t_sdmmc_set_io_power(sdmmc, SDMMC_POWER_1_8);\n\t_sdmmc_commit_changes(sdmmc);\n\tmsleep(5); // Wait minimum 5ms before turning on the card clock.\n\n\t// Turn on SDCLK.\n\tif (sdmmc->regs->hostctl2 & SDHCI_CTRL_VDD_180)\n\t{\n\t\tsdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;\n\t\t_sdmmc_commit_changes(sdmmc);\n\t\tusleep(1000);\n\t\tif ((sdmmc->regs->prnsts & SDHCI_DATA_LVL_MASK) == SDHCI_DATA_LVL_MASK)\n\t\t\treturn 0;\n\t}\n\n\treturn 1;\n}\n"
  },
  {
    "path": "bdk/storage/sdmmc_driver.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _SDMMC_DRIVER_H_\n#define _SDMMC_DRIVER_H_\n\n#include <utils/types.h>\n#include <storage/sdmmc_t210.h>\n\n/*! SDMMC controller IDs. */\n#define SDMMC_1 0 // Version 4.00.\n#define SDMMC_2 1 // Version 5.0 + SW CQE + Enhanced Strobe.\n#define SDMMC_3 2 // Version 4.00.\n#define SDMMC_4 3 // Version 5.0 + SW CQE + Enhanced Strobe.\n\n/*! SDMMC power types. */\n#define SDMMC_POWER_OFF 0\n#define SDMMC_POWER_1_8 1\n#define SDMMC_POWER_3_3 2\n\n/*! SDMMC response types. */\n#define SDMMC_RSP_TYPE_0 0\n#define SDMMC_RSP_TYPE_1 1\n#define SDMMC_RSP_TYPE_2 2\n#define SDMMC_RSP_TYPE_3 3\n#define SDMMC_RSP_TYPE_6 4\n#define SDMMC_RSP_TYPE_7 5\n\n/*! SDMMC bus widths. */\n#define SDMMC_BUS_WIDTH_1 0\n#define SDMMC_BUS_WIDTH_4 1\n#define SDMMC_BUS_WIDTH_8 2\n\n/*! SDMMC mask interrupt status. */\n#define SDMMC_MASKINT_MASKED   0\n#define SDMMC_MASKINT_NOERROR  1\n#define SDMMC_MASKINT_ERROR    2\n\n/*! SDMMC present state. 0x24. */\n#define SDHCI_CMD_INHIBIT      BIT(0)\n#define SDHCI_DATA_INHIBIT     BIT(1)\n#define SDHCI_DAT_LINE_ACTIVE  BIT(2)\n#define SDHCI_RETUNING_REQUEST BIT(3)\n#define SDHCI_EMMC_LINE_LVL_MASK (0xFU << 4)\n#define  SDHCI_DATA_4_LVL      BIT(4)  // eMMC only.\n#define  SDHCI_DATA_5_LVL      BIT(5)  // eMMC only.\n#define  SDHCI_DATA_6_LVL      BIT(6)  // eMMC only.\n#define  SDHCI_DATA_7_LVL      BIT(7)  // eMMC only.\n#define SDHCI_DOING_WRITE      BIT(8)\n#define SDHCI_DOING_READ       BIT(9)  // SD only.\n#define SDHCI_SPACE_AVAILABLE  BIT(10) // Write buffer empty.\n#define SDHCI_DATA_AVAILABLE   BIT(11) // Read buffer has data.\n#define SDHCI_CARD_PRESENT     BIT(16)\n#define SDHCI_CD_STABLE        BIT(17)\n#define SDHCI_CD_LVL           BIT(18)\n#define SDHCI_WRITE_PROTECT    BIT(19)\n#define SDHCI_DATA_LVL_MASK    0xF00000\n#define  SDHCI_DATA_0_LVL      BIT(20)\n#define  SDHCI_DATA_1_LVL      BIT(21)\n#define  SDHCI_DATA_2_LVL      BIT(22)\n#define  SDHCI_DATA_3_LVL      BIT(23)\n#define SDHCI_CMD_LVL          BIT(24)\n\n/*! SDMMC transfer mode. 0x0C. */\n#define SDHCI_TRNS_DMA         BIT(0)\n#define SDHCI_TRNS_BLK_CNT_EN  BIT(1)\n#define SDHCI_TRNS_AUTO_CMD12  (1U << 2)\n#define SDHCI_TRNS_AUTO_CMD23  (2U << 2)\n#define SDHCI_TRNS_WRITE       (0U << 4)\n#define SDHCI_TRNS_READ        BIT(4)\n#define SDHCI_TRNS_MULTI       BIT(5)\n#define SDHCI_TRNS_RTYPE_R1    (0U << 6)\n#define SDHCI_TRNS_RTYPE_R5    BIT(6)\n#define SDHCI_TRNS_RSP_ERR_CHK BIT(7)\n#define SDHCI_TRNS_RSP_INT_DIS BIT(8)\n\n/*! SDMMC command. 0x0E. */\n#define SDHCI_CMD_RESP_MASK       0x3\n#define SDHCI_CMD_RESP_NO_RESP    0x0\n#define SDHCI_CMD_RESP_LEN136     0x1\n#define SDHCI_CMD_RESP_LEN48      0x2\n#define SDHCI_CMD_RESP_LEN48_BUSY 0x3\n#define SDHCI_CMD_CRC             BIT(3)\n#define SDHCI_CMD_INDEX           BIT(4)\n#define SDHCI_CMD_DATA            BIT(5)\n#define SDHCI_CMD_TYPE_NORMAL     (0U << 6)\n#define SDHCI_CMD_TYPE_SUSPEND    (1U << 6)\n#define SDHCI_CMD_TYPE_RESUME     (2U << 6)\n#define SDHCI_CMD_TYPE_ABORT      (3U << 6)\n#define SDHCI_CMD_SPI_CS_LOW      BIT(7)\n#define SDHCI_CMD_IDX(cmd)        ((cmd) << 8)\n\n\n/*! SDMMC host control. 0x28. */\n#define SDHCI_CTRL_LED        BIT(0)\n#define SDHCI_CTRL_4BITBUS    BIT(1) // SD only.\n#define SDHCI_CTRL_HISPD      BIT(2) // SD only.\n#define SDHCI_CTRL_DMA_MASK   (3U << 3)\n#define  SDHCI_CTRL_SDMA      (0U << 3)\n#define  SDHCI_CTRL_ADMA1     (1U << 3)\n#define  SDHCI_CTRL_ADMA32    (2U << 3)\n#define  SDHCI_CTRL_ADMA64    (3U << 3)\n#define SDHCI_CTRL_8BITBUS    BIT(5) // eMMC only (or UHS-II).\n#define SDHCI_CTRL_CDTEST_INS BIT(6)\n#define SDHCI_CTRL_CDTEST_EN  BIT(7)\n\n/*! SDMMC host control 2. 0x3E. */\n#define SDHCI_CTRL_UHS_MASK        0x7\n#define SDHCI_CTRL_VDD_180         BIT(3)\n#define SDHCI_CTRL_DRV_TYPE_MASK   (3U << 4)\n#define SDHCI_CTRL_DRV_TYPE_B      (0U << 4)\n#define SDHCI_CTRL_DRV_TYPE_A      (1U << 4)\n#define SDHCI_CTRL_DRV_TYPE_C      (2U << 4)\n#define SDHCI_CTRL_DRV_TYPE_D      (3U << 4)\n#define SDHCI_CTRL_DRV_TYPE(type)  ((type) << 4)\n#define SDHCI_CTRL_EXEC_TUNING     BIT(6)\n#define SDHCI_CTRL_TUNED_CLK_SHIFT 7\n#define SDHCI_CTRL_TUNED_CLK       BIT(7)\n#define SDHCI_HOST_VERSION_4_EN    BIT(12)\n#define SDHCI_ADDRESSING_64BIT_EN  BIT(13)\n#define SDHCI_CTRL_PRESET_VAL_EN   BIT(15)\n\n/*! SDMMC power control. 0x29. */\n#define SDHCI_POWER_ON   BIT(0)\n#define SDHCI_POWER_180  (5U << 1)\n#define SDHCI_POWER_300  (6U << 1)\n#define SDHCI_POWER_330  (7U << 1)\n#define SDHCI_POWER_MASK 0xF1 // UHS-II only.\n\n/*! SDMMC clock control. 0x2C. */\n#define SDHCI_CLOCK_INT_EN     BIT(0) // Internal Clock.\n#define SDHCI_CLOCK_INT_STABLE BIT(1) // Internal Clock Stable.\n#define SDHCI_CLOCK_CARD_EN    BIT(2)\n#define SDHCI_PROG_CLOCK_MODE  BIT(5)\n#define SDHCI_DIV_HI_SHIFT     6\n#define SDHCI_DIV_HI_MASK      (3U << SDHCI_DIV_HI_SHIFT)\n#define SDHCI_DIV_LO_SHIFT     8\n#define SDHCI_DIV_MASK         (0xFFU << SDHCI_DIV_LO_SHIFT)\n\n\n/*! SDMMC software reset. 0x2F. */\n#define SDHCI_RESET_ALL  BIT(0)\n#define SDHCI_RESET_CMD  BIT(1)\n#define SDHCI_RESET_DATA BIT(2)\n\n/*! SDMMC interrupt status and control. 0x30/0x34. */\n#define SDHCI_INT_RESPONSE     BIT(0)\n#define SDHCI_INT_DATA_END     BIT(1)\n#define SDHCI_INT_BLK_GAP      BIT(2)\n#define SDHCI_INT_DMA_END      BIT(3)\n#define SDHCI_INT_SPACE_AVAIL  BIT(4) // Write buffer empty.\n#define SDHCI_INT_DATA_AVAIL   BIT(5) // Read buffer has data.\n#define SDHCI_INT_CARD_INSERT  BIT(6)\n#define SDHCI_INT_CARD_REMOVE  BIT(7)\n#define SDHCI_INT_CARD_INT     BIT(8)\n#define SDHCI_INT_RETUNE       BIT(12)\n#define SDHCI_INT_ERROR        BIT(15)\n\n/*! SDMMC error interrupt status and control. 0x32/0x36. */\n#define SDHCI_ERR_INT_CMD_TIMEOUT  BIT(0)\n#define SDHCI_ERR_INT_CMD_CRC      BIT(1)\n#define SDHCI_ERR_INT_CMD_END_BIT  BIT(2)\n#define SDHCI_ERR_INT_CMD_INDEX    BIT(3)\n#define SDHCI_ERR_INT_DATA_TIMEOUT BIT(4)\n#define SDHCI_ERR_INT_DATA_CRC     BIT(5)\n#define SDHCI_ERR_INT_DATA_END_BIT BIT(6)\n#define SDHCI_ERR_INT_BUS_POWER    BIT(7)\n#define SDHCI_ERR_INT_AUTO_CMD12   BIT(8)\n#define SDHCI_ERR_INT_ADMA         BIT(9)\n#define SDHCI_ERR_INT_TUNE         BIT(10)\n#define SDHCI_ERR_INT_RSP          BIT(11)\n#define SDHCI_ERR_INT_TARGET_RSP   BIT(12)\n#define SDHCI_ERR_INT_SPI          BIT(13)\n#define SDHCI_ERR_INT_VND_BOOT_TMO BIT(14)\n#define SDHCI_ERR_INT_VND_BOOT_ACK BIT(15)\n\n#define SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR \\\n\t(SDHCI_ERR_INT_AUTO_CMD12 | SDHCI_ERR_INT_DATA_END_BIT | \\\n\t SDHCI_ERR_INT_DATA_CRC   | SDHCI_ERR_INT_DATA_TIMEOUT | \\\n\t SDHCI_ERR_INT_CMD_INDEX  | SDHCI_ERR_INT_CMD_END_BIT  | \\\n\t SDHCI_ERR_INT_CMD_CRC    | SDHCI_ERR_INT_CMD_TIMEOUT)\n\n/*! Host Capability 1. 0x40. */\n#define SDHCI_CAP_TM_CLK_FREQ_MASK    0x3F\n#define SDHCI_CAP_TM_UNIT_MHZ         BIT(7)\n#define SDHCI_CAP_BASE_CLK_FREQ_MASK  (0xFFU << 8)\n#define SDHCI_CAP_MAX_BLK_LEN_MASK    (3U << 16)\n#define SDHCI_CAP_EMMC_8BIT           BIT(18)\n#define SDHCI_CAP_ADMA2               BIT(19)\n#define SDHCI_CAP_HISPD               BIT(21)\n#define SDHCI_CAP_SDMA                BIT(22)\n#define SDHCI_CAP_SUSPEND_RESUME      BIT(23)\n#define SDHCI_CAP_3_3_V               BIT(24)\n#define SDHCI_CAP_3_0_V               BIT(25)\n#define SDHCI_CAP_1_8_V               BIT(26)\n#define SDHCI_CAP_64BIT               BIT(28)\n#define SDHCI_CAP_ASYNC_INT           BIT(29)\n#define SDHCI_CAP_SLOT_TYPE_MASK      (3U << 30)\n#define SDHCI_CAP_SLOT_TYPE_REMOVABLE (0U << 30)\n#define SDHCI_CAP_SLOT_TYPE_EMBEDDED  (1U << 30)\n#define SDHCI_CAP_SLOT_TYPE_SHARED    (2U << 30)\n#define SDHCI_CAP_SLOT_TYPE_UHS2      (3U << 30)\n\n/*! Host Capability 2. 0x44. */\n#define SDHCI_CAP_SDR50              BIT(0)\n#define SDHCI_CAP_SDR5104            BIT(1)\n#define SDHCI_CAP_DDR50              BIT(2)\n#define SDHCI_CAP_UHS2               BIT(3)\n#define SDHCI_CAP_DRV_TYPE_A         BIT(4)\n#define SDHCI_CAP_DRV_TYPE_C         BIT(5)\n#define SDHCI_CAP_DRV_TYPE_D         BIT(6)\n#define SDHCI_CAP_RSP_TIMER_CNT_MASK (0xFU << 8)\n#define SDHCI_CAP_SDR50_TUNING       BIT(13)\n#define SDHCI_CAP_RSP_MODES_MASK     (3U << 14)\n#define SDHCI_CAP_CLK_MULT           (0xFFU << 16)\n#define SDHCI_CAP_ADMA3              BIT(27)\n#define SDHCI_CAP_VDD2_1_8V          BIT(28)\n\n/*! SDMMC max current. 0x48 */\n#define SDHCI_MAX_CURRENT_3_3_V_MASK (0xFFU << 0)\n#define SDHCI_MAX_CURRENT_3_0_V_MASK (0xFFU << 8)\n#define SDHCI_MAX_CURRENT_1_8_V_MASK (0xFFU << 16)\n#define SDHCI_MAX_CURRENT_MULTIPLIER 4\n\n/*! SDMMC max current. 0x4C */\n#define SDHCI_MAX_CURRENT_1_8_V_VDD2_MASK (0xFFU << 0)\n\n/*! SD bus speeds. */\n#define UHS_SDR12_BUS_SPEED  0\n#define HIGH_SPEED_BUS_SPEED 1\n#define UHS_SDR25_BUS_SPEED  1\n#define UHS_SDR50_BUS_SPEED  2\n#define UHS_SDR104_BUS_SPEED 3\n#define UHS_DDR50_BUS_SPEED  4\n#define HS400_BUS_SPEED      5\n\n/*! SDMMC timmings. */\n#define SDHCI_TIMING_MMC_ID     0\n#define SDHCI_TIMING_MMC_LS26   1\n#define SDHCI_TIMING_MMC_HS52   2\n#define SDHCI_TIMING_MMC_HS200  3\n#define SDHCI_TIMING_MMC_HS400  4\n#define SDHCI_TIMING_SD_ID      5\n#define SDHCI_TIMING_SD_DS12    6\n#define SDHCI_TIMING_SD_HS25    7\n#define SDHCI_TIMING_UHS_SDR12  8\n#define SDHCI_TIMING_UHS_SDR25  9\n#define SDHCI_TIMING_UHS_SDR50  10\n#define SDHCI_TIMING_UHS_SDR104 11\n#define SDHCI_TIMING_UHS_DDR50  12\n// SDR104 with a 163.2MHz -> 81.6MHz clock.\n#define SDHCI_TIMING_UHS_SDR82  13 // GC FPGA. Obsolete and Repurposed. MMC_HS50 -> SDR82.\n#define SDHCI_TIMING_MMC_HS100  14 // GC ASIC.\n#define SDHCI_TIMING_UHS_DDR200 15\n\n/*! SDMMC Low power features. */\n#define SDMMC_POWER_SAVE_DISABLE 0\n#define SDMMC_POWER_SAVE_ENABLE  1\n\n/*! Helper for SWITCH command argument. */\n#define SDMMC_SWITCH(mode, index, value) (((mode) << 24) | ((index) << 16) | ((value) << 8))\n\n#define SDMMC_HW_TAP_TUNING       0x100\n#define SDMMC_INVALID_TAP         0x100\n#define SDMMC_SAMPLE_WIN_SIZE_MIN 8\n\n#define SDMMC_ADMA_ADDR_ALIGN 8\n\n/*! SDMMC controller context. */\ntypedef struct _sdmmc_t\n{\n\tt210_sdmmc_t *regs;\n\tu32 id;\n\tu32 card_clock;\n\tu32 clock_stopped;\n\tint powersave_enabled;\n\tint periodic_calibration;\n\tint card_clock_enabled;\n\tint venclkctl_set;\n\tu32 venclkctl_tap;\n\tu32 expected_rsp_type;\n\tu32 dma_addr_next;\n\tu32 rsp[4];\n\tu32 stop_trn_rsp;\n\tu32 error_sts;\n\tint t210b01;\n} sdmmc_t;\n\n/*! SDMMC command. */\ntypedef struct _sdmmc_cmd_t\n{\n\tu16 cmd;\n\tu32 arg;\n\tu32 rsp_type;\n\tu32 check_busy;\n} sdmmc_cmd_t;\n\n/*! SDMMC request. */\ntypedef struct _sdmmc_req_t\n{\n\tvoid *buf;\n\tu32 blksize;\n\tu32 num_sectors;\n\tint is_write;\n\tint is_multi_block;\n\tint is_auto_stop_trn;\n} sdmmc_req_t;\n\nint  sdmmc_get_io_power(sdmmc_t *sdmmc);\nu32  sdmmc_get_bus_width(sdmmc_t *sdmmc);\nvoid sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width);\nvoid sdmmc_save_tap_value(sdmmc_t *sdmmc);\nvoid sdmmc_setup_drv_type(sdmmc_t *sdmmc, u32 type);\nint  sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type);\nvoid sdmmc_card_clock_powersave(sdmmc_t *sdmmc, int powersave_enable);\nint  sdmmc_get_cached_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 type);\nint  sdmmc_tuning_execute(sdmmc_t *sdmmc, u32 type, u32 cmd);\nint  sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp);\nbool sdmmc_get_sd_inserted();\nint  sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type);\nvoid sdmmc_end(sdmmc_t *sdmmc);\nvoid sdmmc_init_cmd(sdmmc_cmd_t *cmdbuf, u16 cmd, u32 arg, u32 rsp_type, u32 check_busy);\nint  sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *request, u32 *blkcnt_out);\nint  sdmmc_enable_low_voltage(sdmmc_t *sdmmc);\n\n#endif\n"
  },
  {
    "path": "bdk/storage/sdmmc_t210.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _SDMMC_T210_H_\n#define _SDMMC_T210_H_\n\n#include <assert.h>\n#include <utils/types.h>\n\n#define SDHCI_TEGRA_TUNING_TAP_HW_UPDATED BIT(17)\n#define SDHCI_TEGRA_DLLCAL_CALIBRATE      BIT(31)\n#define SDHCI_TEGRA_DLLCAL_ACTIVE         BIT(31)\n#define SDHCI_TEGRA_PADCTRL_E_INPUT_PWRD  BIT(31)\n#define SDHCI_TEGRA_PADCTRL_VREF_SEL_MASK 0xF\n#define SDHCI_TEGRA_AUTOCAL_SLW_OVERRIDE  BIT(28)\n#define SDHCI_TEGRA_AUTOCAL_ENABLE        BIT(29)\n#define SDHCI_TEGRA_AUTOCAL_START         BIT(31)\n#define SDHCI_TEGRA_AUTOCAL_ACTIVE        BIT(31)\n\ntypedef struct _t210_sdmmc_t\n{\n/*  0x00 */ vu32 sysad;  // sdma system address.\n/*  0x04 */ vu16 blksize;\n/*  0x06 */ vu16 blkcnt;\n/*  0x08 */ vu32 argument;\n/*  0x0C */ vu16 trnmod;\n/*  0x0E */ vu16 cmdreg;\n/*  0x10 */ vu32 rspreg[4];\n/*  0x20 */ vu32 bdata; // Buffer data port.\n/*  0x24 */ vu32 prnsts;\n/*  0x28 */ vu8  hostctl;\n/*  0x29 */ vu8  pwrcon;\n/*  0x2A */ vu8  blkgap;\n/*  0x2B */ vu8  wakcon;\n/*  0x2C */ vu16 clkcon;\n/*  0x2E */ vu8  timeoutcon;\n/*  0x2F */ vu8  swrst;\n/*  0x30 */ vu16 norintsts;   // Normal interrupt status.\n/*  0x32 */ vu16 errintsts;   // Error  interrupt status.\n/*  0x34 */ vu16 norintstsen; // Enable irq status.\n/*  0x36 */ vu16 errintstsen; // Enable irq status.\n/*  0x38 */ vu16 norintsigen; // Enable irq signal to LIC/GIC.\n/*  0x3A */ vu16 errintsigen; // Enable irq signal to LIC/GIC.\n/*  0x3C */ vu16 acmd12errsts;\n/*  0x3E */ vu16 hostctl2;\n\n// CAP0: 0x376CD08C.\n//       12 MHz timeout clock. 208 MHz max base clock. 512B max block length. 8-bit support.\n//       ADMA2 support. HS25 support. SDMA support. No suspend/resume support. 3.3/3.0/1.8V support.\n//       64bit addressing for V3/V4 support. Async IRQ support. All report as removable.\n/*  0x40 */ vu32 capareg;\n// CAP1: 0x10002F73.\n//       SDR50/SDR104 support. No DDR50 support. Drive A/B/C/D support.\n//       Timer re-tuning info from other source. SDR50 requires re-tuning.\n//       Tuning uses timer and transfers should be 4MB limited.\n//       ADMA3 not supported. 1.8V VDD2 supported.\n/*  0x44 */ vu32 capareg_hi;\n\n/*  0x48 */ vu32 maxcurr;      // Get information by another method. Can be overriden via maxcurrover and maxcurrover_hi.\n/*  0x4C */ vu32 maxcurr_hi;\n/*  0x50 */ vu16 setacmd12err; // Force error in acmd12errsts.\n/*  0x52 */ vu16 setinterr;\n/*  0x54 */ vu8  admaerr;\n/*  0x55 */ vu8  rsvd1[3];     // 55-57 reserved.\n/*  0x58 */ vu32 admaaddr;\n/*  0x5C */ vu32 admaaddr_hi;\n/*  0x60 */ vu16 presets[11];\n/*  0x76 */ vu16 rsvd2;\n/*  0x78 */ vu32 adma3addr;\n/*  0x7C */ vu32 adma3addr_hi;\n/*  0x80 */ vu8  uhs2[124];    // 80-FB UHS-II.\n/*  0xFC */ vu16 slotintsts;\n/*  0xFE */ vu16 hcver;        // 0x303 (4.00).\n\n/* UHS-II range. Used for Vendor registers here */\n/* 0x100 */ vu32 venclkctl;\n/* 0x104 */ vu32 vensysswctl;\n/* 0x108 */ vu32 venerrintsts;\n/* 0x10C */ vu32 vencapover;\n/* 0x110 */ vu32 venbootctl;\n/* 0x114 */ vu32 venbootacktout;\n/* 0x118 */ vu32 venbootdattout;\n/* 0x11C */ vu32 vendebouncecnt;\n/* 0x120 */ vu32 venmiscctl;\n/* 0x124 */ vu32 maxcurrover;\n/* 0x128 */ vu32 maxcurrover_hi;\n/* 0x12C */ vu32 unk0[32]; // 0x12C\n/* 0x1AC */ vu32 veniotrimctl;\n/* 0x1B0 */ vu32 vendllcalcfg;\n/* 0x1B4 */ vu32 vendllctl0;\n/* 0x1B8 */ vu32 vendllctl1;\n/* 0x1BC */ vu32 vendllcalcfgsts;\n/* 0x1C0 */ vu32 ventunctl0;\n/* 0x1C4 */ vu32 ventunctl1;\n/* 0x1C8 */ vu32 ventunsts0;\n/* 0x1CC */ vu32 ventunsts1;\n/* 0x1D0 */ vu32 venclkgatehystcnt;\n/* 0x1D4 */ vu32 venpresetval0;\n/* 0x1D8 */ vu32 venpresetval1;\n/* 0x1DC */ vu32 venpresetval2;\n/* 0x1E0 */ vu32 sdmemcmppadctl;\n/* 0x1E4 */ vu32 autocalcfg;\n/* 0x1E8 */ vu32 autocalintval;\n/* 0x1EC */ vu32 autocalsts;\n/* 0x1F0 */ vu32 iospare;\n/* 0x1F4 */ vu32 mcciffifoctl;\n/* 0x1F8 */ vu32 timeoutwcoal;\n} t210_sdmmc_t;\n\nstatic_assert(sizeof(t210_sdmmc_t) == 0x1FC, \"T210 SDMMC REG size is wrong!\");\n\n#endif\n"
  },
  {
    "path": "bdk/thermal/fan.c",
    "content": "/*\n * Fan driver for Nintendo Switch\n *\n * Copyright (c) 2018-2024 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <thermal/fan.h>\n#include <power/regulator_5v.h>\n#include <soc/bpmp.h>\n#include <soc/clock.h>\n#include <soc/fuse.h>\n#include <soc/gpio.h>\n#include <soc/hw_init.h>\n#include <soc/pinmux.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n\nvoid fan_set_duty(u32 duty)\n{\n\tstatic bool fan_init = false;\n\tstatic u16  curr_duty = -1;\n\n\tif (duty > 236)\n\t\tduty = 236;\n\n\tif (curr_duty == duty)\n\t\treturn;\n\n\tcurr_duty = duty;\n\n\tif (!fan_init)\n\t{\n\t\t// Fan tachometer.\n\t\tu32 pull_resistor = hw_get_chip_id() == GP_HIDREV_MAJOR_T210 ? PINMUX_PULL_UP : 0;\n\t\tPINMUX_AUX(PINMUX_AUX_CAM1_PWDN) = PINMUX_TRISTATE | PINMUX_INPUT_ENABLE | pull_resistor | 1;\n\t\tgpio_direction_input(GPIO_PORT_S, GPIO_PIN_7);\n\n\t\t// Enable PWM if disabled.\n\t\tif (fuse_read_hw_type() == FUSE_NX_HW_TYPE_AULA)\n\t\t\tclock_enable_pwm();\n\n\t\tPWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (0x100 << 16); // Max PWM to disable fan.\n\n\t\tPINMUX_AUX(PINMUX_AUX_LCD_GPIO2) = 1; // Set source to PWM1.\n\t\tgpio_config(GPIO_PORT_V, GPIO_PIN_4, GPIO_MODE_SPIO); // Fan power mode.\n\n\t\tfan_init = true;\n\t}\n\n\t// Inverted polarity.\n\tu32 inv_duty = 236 - duty;\n\n\t// If disabled send a 0 duty.\n\tif (inv_duty == 236)\n\t{\n\t\tPWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (0x100 << 16); // Bit 24 is absolute 0%.\n\t\tregulator_5v_disable(REGULATOR_5V_FAN);\n\n\t\t// Disable fan.\n\t\tPINMUX_AUX(PINMUX_AUX_LCD_GPIO2) = PINMUX_INPUT_ENABLE | PINMUX_PARKED    |\n\t\t\t\t\t\t\t\t\t\t   PINMUX_TRISTATE     | PINMUX_PULL_DOWN; // Set source to PWM1.\n\t}\n\telse // Set PWM duty.\n\t{\n\t\t// Fan power supply.\n\t\tregulator_5v_enable(REGULATOR_5V_FAN);\n\t\tPWM(PWM_CONTROLLER_PWM_CSR_1) = PWM_CSR_EN | (inv_duty << 16);\n\n\t\t// Enable fan.\n\t\tPINMUX_AUX(PINMUX_AUX_LCD_GPIO2) = 1; // Set source to PWM1.\n\t}\n}\n\nvoid fan_get_speed(u32 *duty, u32 *rpm)\n{\n\tif (rpm)\n\t{\n\t\tu32  irq_count = 0;\n\t\tbool should_read = true;\n\n\t\t// Poll irqs for 2 seconds. (5 seconds for accurate count).\n\t\tint  timer = get_tmr_us() + 2000000;\n\t\twhile ((timer - get_tmr_us()) > 0)\n\t\t{\n\t\t\tbool irq_val = gpio_read(GPIO_PORT_S, GPIO_PIN_7);\n\t\t\tif (irq_val && should_read)\n\t\t\t{\n\t\t\t\tirq_count++;\n\t\t\t\tshould_read = false;\n\t\t\t}\n\t\t\telse if (!irq_val)\n\t\t\t\tshould_read = true;\n\t\t}\n\n\t\t// Halve the irq count.\n\t\tirq_count /= 2;\n\n\t\t// Calculate rpm based on triggered interrupts.\n\t\t*rpm = irq_count * (60 / 2);\n\t}\n\n\tif (duty)\n\t\t*duty = 236 - ((PWM(PWM_CONTROLLER_PWM_CSR_1) >> 16) & 0xFF);\n}\n\nvoid fan_set_from_temp(u32 temp)\n{\n\tif (temp >= 52)\n\t\tfan_set_duty(102);\n\telse if (temp >= 47)\n\t\tfan_set_duty(76);\n\telse if (temp >= 42)\n\t\tfan_set_duty(51);\n\telse if (temp <= 39)\n\t\tfan_set_duty(0);\n}\n"
  },
  {
    "path": "bdk/thermal/fan.h",
    "content": "/*\n * Fan driver for Nintendo Switch\n *\n * Copyright (c) 2018-2024 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef __FAN_H_\n#define __FAN_H_\n\n#include <utils/types.h>\n\n// Disable: 0 (0 RPM), min duty: 1 (960 RPM), max duty 235 (11000 RPM).\nvoid fan_set_duty(u32 duty);\n// Passing NULL ptr on either of the two, disables results.\nvoid fan_get_speed(u32 *duty, u32 *rpm);\n\nvoid fan_set_from_temp(u32 temp);\n\n#endif /* __FAN_H_ */\n"
  },
  {
    "path": "bdk/thermal/tmp451.c",
    "content": "/*\n * SOC/PCB Temperature driver for Nintendo Switch's TI TMP451\n *\n * Copyright (c) 2018-2020 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <soc/hw_init.h>\n#include <soc/i2c.h>\n#include <soc/t210.h>\n#include <thermal/tmp451.h>\n\n// Remote Sensor.\nu16 tmp451_get_soc_temp(bool intenger)\n{\n\tu8 val;\n\tu16 temp = 0;\n\n\tval = i2c_recv_byte(I2C_1, TMP451_I2C_ADDR, TMP451_SOC_TEMP_REG);\n\tif (intenger)\n\t\treturn val;\n\n\ttemp = val << 8;\n\tval = i2c_recv_byte(I2C_1, TMP451_I2C_ADDR, TMP451_SOC_TMP_DEC_REG);\n\ttemp |= ((val >> 4) * 625) / 100;\n\n\treturn temp;\n}\n\n// Local Sensor.\nu16 tmp451_get_pcb_temp(bool intenger)\n{\n\tu8 val;\n\tu16 temp = 0;\n\n\tval = i2c_recv_byte(I2C_1, TMP451_I2C_ADDR, TMP451_PCB_TEMP_REG);\n\tif (intenger)\n\t\treturn val;\n\n\ttemp = val << 8;\n\tval = i2c_recv_byte(I2C_1, TMP451_I2C_ADDR, TMP451_PCB_TMP_DEC_REG);\n\ttemp |= ((val >> 4) * 625) / 100;\n\n\treturn temp;\n}\n\nvoid tmp451_init()\n{\n\t// Disable ALARM and Range to 0 - 127 oC.\n\ti2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_CONFIG_REG, 0x80);\n\n\t// Set remote sensor offsets based on SoC.\n\tif (hw_get_chip_id() == GP_HIDREV_MAJOR_T210)\n\t{\n\t\t// Set offset to 0 oC for Erista.\n\t\ti2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_SOC_TMP_OFH_REG, 0);\n\t\ti2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_SOC_TMP_OFL_REG, 0);\n\t}\n\telse\n\t{\n\t\t// Set offset to -12.5 oC for Mariko.\n\t\ti2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_SOC_TMP_OFH_REG, 0xF3); // - 13  oC.\n\t\ti2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_SOC_TMP_OFL_REG, 0x80); // + 0.5 oC.\n\t}\n\n\t// Set conversion rate to 31 ms and make a read to update the reg.\n\ti2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_CNV_RATE_REG, 9);\n\ttmp451_get_soc_temp(false);\n\n\t// Set rate to every 4 seconds.\n\ti2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_CNV_RATE_REG, 2);\n}\n\nvoid tmp451_end()\n{\n\t// Place into shutdown mode to conserve power.\n\ti2c_send_byte(I2C_1, TMP451_I2C_ADDR, TMP451_CONFIG_REG, 0xC0);\n}\n"
  },
  {
    "path": "bdk/thermal/tmp451.h",
    "content": "/*\n * SOC/PCB Temperature driver for Nintendo Switch's TI TMP451\n *\n * Copyright (c) 2018 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef __TMP451_H_\n#define __TMP451_H_\n\n#include <utils/types.h>\n\n#define TMP451_I2C_ADDR 0x4C\n\n#define TMP451_PCB_TEMP_REG    0x00\n#define TMP451_SOC_TEMP_REG    0x01\n\n#define TMP451_CONFIG_REG      0x09\n#define TMP451_CNV_RATE_REG    0x0A\n\n#define TMP451_SOC_TMP_DEC_REG 0x10\n#define TMP451_PCB_TMP_DEC_REG 0x15\n\n#define TMP451_SOC_TMP_OFH_REG 0x11\n#define TMP451_SOC_TMP_OFL_REG 0x12\n\n// If input is false, the return value is packed. MSByte is the integer in oC\n// and the LSByte is the decimal point truncated to 2 decimal places.\n// Otherwise it's an integer oC.\nu16 tmp451_get_soc_temp(bool integer);\nu16 tmp451_get_pcb_temp(bool integer);\nvoid tmp451_init();\nvoid tmp451_end();\n\n#endif /* __TMP451_H_ */\n"
  },
  {
    "path": "bdk/usb/usb_descriptor_types.h",
    "content": "/*\n * USB driver for Tegra X1\n *\n * Copyright (c) 2019-2020 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _USB_DESCRIPTORS_TYPES_H_\n#define _USB_DESCRIPTORS_TYPES_H_\n\n#include <utils/types.h>\n\ntypedef enum {\n\tUSB_DESCRIPTOR_DEVICE                    = 1,\n\tUSB_DESCRIPTOR_CONFIGURATION             = 2,\n\tUSB_DESCRIPTOR_STRING                    = 3,\n\tUSB_DESCRIPTOR_INTERFACE                 = 4,\n\tUSB_DESCRIPTOR_ENDPOINT                  = 5,\n\tUSB_DESCRIPTOR_DEVICE_QUALIFIER          = 6,\n\tUSB_DESCRIPTOR_OTHER_SPEED_CONFIGURATION = 7,\n\tUSB_DESCRIPTOR_INTERFACE_POWER           = 8,\n\tUSB_DESCRIPTOR_INTERFACE_OTG             = 9,\n\tUSB_DESCRIPTOR_DEVICE_BINARY_OBJECT      = 15,\n\tUSB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP  = 16,\n\tUSB_DESCRIPTOR_HID                       = 33,\n\tUSB_DESCRIPTOR_HID_REPORT                = 34\n} usb_desc_type_t;\n\ntypedef enum {\n\tUSB_DESCRIPTOR_MS_COMPAT_ID           = 4,\n\tUSB_DESCRIPTOR_MS_EXTENDED_PROPERTIES = 5\n} usb_vendor_desc_type_t;\n\ntypedef enum {\n\tUSB_ATTR_REMOTE_WAKE_UP   = 0x20,\n\tUSB_ATTR_SELF_POWERED     = 0x40,\n\tUSB_ATTR_BUS_POWERED_RSVD = 0x80\n} usb_cfg_attr_type_t;\n\ntypedef enum\n{\n\tUSB_EP_TYPE_CTRL = 0,\n\tUSB_EP_TYPE_ISO  = 1,\n\tUSB_EP_TYPE_BULK = 2,\n\tUSB_EP_TYPE_INTR = 3\n} usb_cfg_ep_type_t;\n\n/* Device descriptor structure */\ntypedef struct _usb_dev_descr_t\n{\n\tu8  bLength;         // Size of this descriptor in bytes.\n\tu8  bDescriptorType; // Device Descriptor Type. (USB_DESCRIPTOR_DEVICE)\n\tu16 bcdUSB;          // USB Spec. Release number (2.1).\n\tu8  bDeviceClass;    // Class is specified in the interface descriptor.\n\tu8  bDeviceSubClass; // SubClass is specified in the interface descriptor.\n\tu8  bDeviceProtocol; // Protocol is specified in the interface descriptor.\n\tu8  bMaxPacketSize;  // Maximum packet size for EP0.\n\tu16 idVendor;        // Vendor ID assigned by USB forum.\n\tu16 idProduct;       // Product ID assigned by Organization.\n\tu16 bcdDevice;       // Device Release number in BCD.\n\tu8  iManufacturer;   // Index of String descriptor describing Manufacturer.\n\tu8  iProduct;        // Index of String descriptor describing Product.\n\tu8  iSerialNumber;   // Index of String descriptor describing Serial number.\n\tu8  bNumConfigs;     // Number of possible configuration.\n} __attribute__((packed)) usb_dev_descr_t;\n\n/* Device Qualifier descriptor structure */\ntypedef struct _usb_dev_qual_descr_t\n{\n\tu8  bLength;          // Size of this descriptor in bytes.\n\tu8  bDescriptorType;  // Device Descriptor Type. (USB_DESCRIPTOR_DEVICE_QUALIFIER)\n\tu16 bcdUSB;           // USB Spec. Release number (2.1).\n\tu8  bDeviceClass;     // Class is specified in the interface descriptor.\n\tu8  bDeviceSubClass;  // SubClass is specified in the interface descriptor.\n\tu8  bDeviceProtocol;  // Protocol is specified in the interface descriptor.\n\tu8  bMaxPacketSize;   // Maximum packet size for EP0.\n\tu8  bNumOtherConfigs; // Number of possible other-speed configurations.\n\tu8  bReserved;        // Reserved for future use, must be zero\n} __attribute__((packed)) usb_dev_qual_descr_t;\n\n/* Configuration descriptor structure */\ntypedef struct _usb_cfg_descr_t\n{\n\tu8  bLength;             // Length of this descriptor.\n\tu8  bDescriptorType;     // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION).\n\tu16 wTotalLength;        // Total length of all descriptors for this configuration.\n\tu8  bNumInterfaces;      // Number of interfaces in this configuration.\n\tu8  bConfigurationValue; // Value of this configuration (1 based).\n\tu8  iConfiguration;      // Index of String Descriptor describing the configuration.\n\tu8  bmAttributes;        // Configuration characteristics.\n\tu8  bMaxPower;           // Maximum power consumed by this configuration. In 2mA (usb2) or 8mA (usb3).\n} __attribute__((packed)) usb_cfg_descr_t;\n\n/* Interface descriptor structure */\ntypedef struct _usb_inter_descr_t\n{\n\tu8 bLength;            // Length of this descriptor.\n\tu8 bDescriptorType;    // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE).\n\tu8 bInterfaceNumber;   // Number of this interface (0 based).\n\tu8 bAlternateSetting;  // Value of this alternate interface setting.\n\tu8 bNumEndpoints;      // Number of endpoints in this interface.\n\tu8 bInterfaceClass;    // Class code (assigned by the USB-IF).\n\tu8 bInterfaceSubClass; // Subclass code (assigned by the USB-IF).\n\tu8 bInterfaceProtocol; // Protocol code (assigned by the USB-IF).\n\tu8 iInterface;         // Index of String Descriptor describing the interface.\n} __attribute__((packed)) usb_inter_descr_t;\n\n/* HID descriptor structure */\ntypedef struct _usb_hid_descr_t\n{\n\tu8  bLength;              // Length of this descriptor.\n\tu8  bDescriptorType;      // INTERFACE descriptor type (USB_DESCRIPTOR_HID).\n\tu16 bcdHID;               // HID class specification release\n\tu8  bCountryCode;         // Country code.\n\tu8  bNumDescriptors;      // Number of descriptors.\n\tu8  bClassDescriptorType; // Type of class descriptor (USB_DESCRIPTOR_HID_REPORT).\n\tu16 bDescriptorLength;    // Report descriptor length.\n} __attribute__((packed)) usb_hid_descr_t;\n\n/* Endpoint descriptor structure */\ntypedef struct _usb_ep_descr_t\n{\n\tu8  bLength;          // Length of this descriptor.\n\tu8  bDescriptorType;  // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT).\n\tu8  bEndpointAddress; // Endpoint address. bit7 indicates direction (0=OUT, 1=IN).\n\tu8  bmAttributes;     // Endpoint transfer type.\n\tu16 wMaxPacketSize;   // Maximum packet size.\n\tu8  bInterval;        // Polling interval in frames. For Interrupt and Isochronous data transfer only.\n} __attribute__((packed)) usb_ep_descr_t;\n\ntypedef struct _usb_cfg_simple_descr_t\n{\n\tusb_cfg_descr_t   config;\n\tusb_inter_descr_t interface;\n\tusb_ep_descr_t    endpoint[2];\n} __attribute__((packed)) usb_cfg_simple_descr_t;\n\ntypedef struct _usb_cfg_hid_descr_t\n{\n\tusb_cfg_descr_t   config;\n\tusb_inter_descr_t interface;\n\tusb_hid_descr_t   hid;\n\tusb_ep_descr_t    endpoint[1];\n} __attribute__((packed)) usb_cfg_hid_descr_t;\n\ntypedef struct _usb_dev_bot_t\n{\n\tu8  bLength;                // Size of this descriptor in bytes.\n\tu8  bDescriptorType;        // Device Descriptor Type. (USB_DESCRIPTOR_DEVICE_BINARY_OBJECT)\n\tu16 wTotalLength;           // Size of this descriptor in bytes.\n\tu8  bNumDeviceCaps;         // Number of device capabilities in this descriptor.\n\n\t/* Device Capability USB 2.0 Extension Descriptor */\n\t/* Needed for a USB2.10 device. */\n\tu8  bLengthCap0;            // Size of this capability descriptor in bytes.\n\tu8  bDescriptorTypeCap0;    // Device Capability Descriptor Type. (USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP)\n\tu8  bDevCapabilityTypeCap0; // USB2: 2.\n\tu32 bmAttributesCap0;       // bit1: Link Power Management (LPM).\n\n\tu8  bLengthCap1;            // Size of this capability descriptor in bytes.\n\tu8  bDescriptorTypeCap1;    // Device Capability Descriptor Type. (USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP)\n\tu8  bDevCapabilityTypeCap1; // USB3: 3.\n\tu8  bmAttributesCap1;       // bit1: Latency Tolerance Messaging (LTM).\n\tu16 wSpeedsSupported;       // Supported bus speeds. 1: Low Speed, 2: Full Speed, 4: High Speed, 8: Super Speed.\n\tu8  bFunctionalitySupport;  // Lowest speed at which all the functionality is available. 1: Full speed and above.\n\tu8  bU1DevExitLat;          // USB3.0 U1 exit latency.\n\tu16 wU2DevExitLat;          // USB3.0 U2 exit latency.\n\n} __attribute__((packed)) usb_dev_bot_t;\n\n/* Microsoft OS String descriptor structure */\ntypedef struct _usb_ms_os_descr_t\n{\n\tu8 bLength; // 0x12\n\tu8 bDescriptorType; // 3\n\tu16 wSignature[7]; // \"MSFT100\" UTF16 LE\n\tu8 bVendorCode; //\n\tu8 bPadding;\n} __attribute__((packed)) usb_ms_os_descr_t;\n\n/* Microsoft Compatible ID Feature descriptor structure */\ntypedef struct _usb_ms_cid_descr_t\n{\n\tu32 dLength;\n\tu16 wVersion;\n\tu16 wCompatibilityId;\n\tu8 bSections;\n\tu8 bReserved0[7];\n\tu8 bInterfaceNumber;\n\tu8 bReserved1;\n\tu8 bCompatibleId[8];\n\tu8 bSubCompatibleId[8];\n\tu8 bReserved2[6];\n} __attribute__((packed)) usb_ms_cid_descr_t;\n\n/* Microsoft Extended Properties Feature descriptor structure */\ntypedef struct _usb_ms_ext_prop_descr_t\n{\n\tu32 dLength;\n\tu16 wVersion;\n\tu16 wExtendedProperty;\n\tu16 wSections;\n\tu32 dPropertySize;\n\tu32 dPropertyType;\n\tu16 wPropertyNameLength;\n\tu16 wPropertyName[22];   // UTF16 LE\n\tu32 dPropertyDataLength;\n\tu16 wPropertyData[2];    // UTF16 LE\n} __attribute__((packed)) usb_ms_ext_prop_descr_t;\n\ntypedef struct _usb_desc_t\n{\n\tusb_dev_descr_t *dev;\n\tusb_dev_qual_descr_t *dev_qual;\n\tusb_cfg_simple_descr_t *cfg;\n\tusb_cfg_simple_descr_t *cfg_other;\n\tusb_dev_bot_t *dev_bot;\n\tu8 *vendor;\n\tu8 *product;\n\tu8 *serial;\n\tu8 *lang_id;\n\tusb_ms_os_descr_t *ms_os;\n\tusb_ms_cid_descr_t *ms_cid;\n\tusb_ms_ext_prop_descr_t *mx_ext;\n} usb_desc_t;\n\n#endif\n"
  },
  {
    "path": "bdk/usb/usb_descriptors.c",
    "content": "/*\n * USB driver for Tegra X1\n *\n * Copyright (c) 2019-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <usb/usb_descriptor_types.h>\n#include <utils/types.h>\n\nstatic usb_dev_descr_t usb_device_descriptor_ums =\n{\n\t.bLength         = 18,\n\t.bDescriptorType = USB_DESCRIPTOR_DEVICE,\n\t.bcdUSB          = 0x210,\n\t.bDeviceClass    = 0x00,\n\t.bDeviceSubClass = 0x00,\n\t.bDeviceProtocol = 0x00,\n\t.bMaxPacketSize  = 0x40,\n\t.idVendor        = 0x11EC, // Nintendo: 0x057E, Nvidia: 0x0955\n\t.idProduct       = 0xA7E0, // Switch:   0x2000, usbd:   0x3000\n\t.bcdDevice       = 0x0101,\n\t.iManufacturer   = 1,\n\t.iProduct        = 2,\n\t.iSerialNumber   = 3,\n\t.bNumConfigs     = 1\n};\n\nstatic usb_dev_qual_descr_t usb_device_qualifier_descriptor =\n{\n\t.bLength          = 10,\n\t.bDescriptorType  = USB_DESCRIPTOR_DEVICE_QUALIFIER,\n\t.bcdUSB           = 0x210,\n\t.bDeviceClass     = 0x00,\n\t.bDeviceSubClass  = 0x00,\n\t.bDeviceProtocol  = 0x00,\n\t.bMaxPacketSize   = 0x40,\n\t.bNumOtherConfigs = 0x01,\n\t.bReserved        = 0x00\n};\n\nstatic usb_cfg_simple_descr_t usb_configuration_descriptor_ums =\n{\n\t/* Configuration descriptor structure */\n\t.config.bLength               = 9,\n\t.config.bDescriptorType       = USB_DESCRIPTOR_CONFIGURATION,\n\t.config.wTotalLength          = 0x20,\n\t.config.bNumInterfaces        = 0x01,\n\t.config.bConfigurationValue   = 0x01,\n\t.config.iConfiguration        = 0x00,\n\t.config.bmAttributes          = USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED_RSVD,\n\t.config.bMaxPower             = 32 / 2,\n\n\t/* Interface descriptor structure */\n\t.interface.bLength            = 9,\n\t.interface.bDescriptorType    = USB_DESCRIPTOR_INTERFACE,\n\t.interface.bInterfaceNumber   = 0,\n\t.interface.bAlternateSetting  = 0,\n\t.interface.bNumEndpoints      = 2,\n\t.interface.bInterfaceClass    = 0x08, // Mass Storage Class.\n\t.interface.bInterfaceSubClass = 0x06, // SCSI Transparent Command Set.\n\t.interface.bInterfaceProtocol = 0x50, // Bulk-Only Transport.\n\t.interface.iInterface         = 0x00,\n\n\t/* Endpoint descriptor structure EP1 IN */\n\t.endpoint[0].bLength          = 7,\n\t.endpoint[0].bDescriptorType  = USB_DESCRIPTOR_ENDPOINT,\n\t.endpoint[0].bEndpointAddress = 0x81, // USB_EP_ADDR_BULK_IN.\n\t.endpoint[0].bmAttributes     = USB_EP_TYPE_BULK,\n\t.endpoint[0].wMaxPacketSize   = 0x200,\n\t.endpoint[0].bInterval        = 0x00,\n\n\t/* Endpoint descriptor structure EP1 OUT */\n\t.endpoint[1].bLength          = 7,\n\t.endpoint[1].bDescriptorType  = USB_DESCRIPTOR_ENDPOINT,\n\t.endpoint[1].bEndpointAddress = 0x01, // USB_EP_ADDR_BULK_OUT.\n\t.endpoint[1].bmAttributes     = USB_EP_TYPE_BULK,\n\t.endpoint[1].wMaxPacketSize   = 0x200,\n\t.endpoint[1].bInterval        = 0x00\n};\n\nstatic usb_cfg_simple_descr_t usb_other_speed_config_descriptor_ums =\n{\n\t/* Other Speed Configuration descriptor structure */\n\t.config.bLength               = 9,\n\t.config.bDescriptorType       = USB_DESCRIPTOR_OTHER_SPEED_CONFIGURATION,\n\t.config.wTotalLength          = 0x20,\n\t.config.bNumInterfaces        = 0x01,\n\t.config.bConfigurationValue   = 0x01,\n\t.config.iConfiguration        = 0x00,\n\t.config.bmAttributes          = USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED_RSVD,\n\t.config.bMaxPower             = 32 / 2,\n\n\t/* Interface descriptor structure */\n\t.interface.bLength            = 9,\n\t.interface.bDescriptorType    = USB_DESCRIPTOR_INTERFACE,\n\t.interface.bInterfaceNumber   = 0x00,\n\t.interface.bAlternateSetting  = 0x00,\n\t.interface.bNumEndpoints      = 2,\n\t.interface.bInterfaceClass    = 0x08, // Mass Storage Class.\n\t.interface.bInterfaceSubClass = 0x06, // SCSI Transparent Command Set.\n\t.interface.bInterfaceProtocol = 0x50, // Bulk-Only Transport.\n\t.interface.iInterface         = 0x00,\n\n\t/* Endpoint descriptor structure EP1 IN */\n\t.endpoint[0].bLength          = 7,\n\t.endpoint[0].bDescriptorType  = USB_DESCRIPTOR_ENDPOINT,\n\t.endpoint[0].bEndpointAddress = 0x81, // USB_EP_ADDR_BULK_IN.\n\t.endpoint[0].bmAttributes     = USB_EP_TYPE_BULK,\n\t.endpoint[0].wMaxPacketSize   = 0x40,\n\t.endpoint[0].bInterval        = 0,\n\n\t/* Endpoint descriptor structure EP1 OUT */\n\t.endpoint[1].bLength          = 7,\n\t.endpoint[1].bDescriptorType  = USB_DESCRIPTOR_ENDPOINT,\n\t.endpoint[1].bEndpointAddress = 0x01, // USB_EP_ADDR_BULK_OUT.\n\t.endpoint[1].bmAttributes     = USB_EP_TYPE_BULK,\n\t.endpoint[1].wMaxPacketSize   = 0x40,\n\t.endpoint[1].bInterval        = 0\n};\n\nstatic usb_dev_bot_t usb_device_binary_object_descriptor =\n{\n\t.bLength                = 5,\n\t.bDescriptorType        = USB_DESCRIPTOR_DEVICE_BINARY_OBJECT,\n\t.wTotalLength           = 22,\n\t.bNumDeviceCaps         = 2,\n\n\t/* Device Capability USB 2.0 Extension Descriptor */\n\t.bLengthCap0            = 7,\n\t.bDescriptorTypeCap0    = USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP,\n\t.bDevCapabilityTypeCap0 = 2, // USB2.\n\t.bmAttributesCap0       = 0,\n\n\t/* Device Capability SuperSpeed Descriptor */\n\t/* Needed for a USB2.10 device. */\n\t.bLengthCap1            = 10,\n\t.bDescriptorTypeCap1    = USB_DESCRIPTOR_DEVICE_BINARY_OBJECT_CAP,\n\t.bDevCapabilityTypeCap1 = 3,   // USB3.\n\t.bmAttributesCap1       = 0,\n\t.wSpeedsSupported       = 0x6, // FS | HS.\n\t.bFunctionalitySupport  = 1,   // FS and above.\n\t.bU1DevExitLat          = 0,\n\t.wU2DevExitLat          = 0\n};\n\nstatic u8 usb_lang_id_string_descriptor[4] =\n{\n\t4, 3,\n\t0x09, 0x04\n};\n\nstatic u8 usb_serial_string_descriptor[26] =\n{\n\t26, 0x03,\n\t'C', 0x00, '7', 0x00, 'C', 0x00, '0', 0x00,\n\t'9', 0x00, '2', 0x00, '4', 0x00, '2', 0x00, 'F', 0x00, '7', 0x00, '0', 0x00, '3', 0x00\n};\n\nstatic u8 usb_vendor_string_descriptor_ums[32] =\n{\n\t26, 0x03,\n\t'N', 0, 'y', 0, 'x', 0, ' ', 0, 'U', 0, 'S', 0, 'B', 0, ' ', 0,\n\t'D', 0, 'i', 0, 's', 0, 'k', 0\n};\n\nstatic u8 usb_product_string_descriptor_ums[22] =\n{\n\t8, 0x03,\n\t'U', 0, 'M', 0, 'S', 0\n};\n\nstatic usb_ms_os_descr_t usb_ms_os_descriptor =\n{\n\t.bLength         = 0x28,\n\t.bDescriptorType = 0x03,\n\t.wSignature[0]   = 'M',\n\t.wSignature[1]   = 'S',\n\t.wSignature[2]   = 'F',\n\t.wSignature[3]   = 'T',\n\t.wSignature[4]   = '1',\n\t.wSignature[5]   = '0',\n\t.wSignature[6]   = '0',\n\t.bVendorCode     = 0x99,\n};\n\nstatic usb_ms_cid_descr_t usb_ms_cid_descriptor =\n{\n\t.dLength          = 0x28,\n\t.wVersion         = 0x100,\n\t.wCompatibilityId = USB_DESCRIPTOR_MS_COMPAT_ID,\n\t.bSections        = 1,\n\t.bInterfaceNumber = 0,\n\t.bReserved1       = 1,\n\n\t.bCompatibleId[0] = 'N',\n\t.bCompatibleId[1] = 'Y',\n\t.bCompatibleId[2] = 'X',\n\t.bCompatibleId[3] = 'U',\n\t.bCompatibleId[4] = 'S',\n\t.bCompatibleId[5] = 'B',\n};\n\nstatic usb_ms_ext_prop_descr_t usb_ms_ext_prop_descriptor_ums =\n{\n\t.dLength             = 0x48,\n\t.wVersion            = 0x100,\n\t.wExtendedProperty   = USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES,\n\t.wSections           = 1,\n\n\t.dPropertySize       = 0x3E,\n\t.dPropertyType       = 4, // DWORD\n\n\t.wPropertyNameLength = 0x2C,\n\t.wPropertyName[0]    = 'M', // MaximumTransferLength.\n\t.wPropertyName[1]    = 'a',\n\t.wPropertyName[2]    = 'x',\n\t.wPropertyName[3]    = 'i',\n\t.wPropertyName[4]    = 'm',\n\t.wPropertyName[5]    = 'u',\n\t.wPropertyName[6]    = 'm',\n\t.wPropertyName[7]    = 'T',\n\t.wPropertyName[8]    = 'r',\n\t.wPropertyName[9]    = 'a',\n\t.wPropertyName[10]   = 'n',\n\t.wPropertyName[11]   = 's',\n\t.wPropertyName[12]   = 'f',\n\t.wPropertyName[13]   = 'e',\n\t.wPropertyName[14]   = 'r',\n\t.wPropertyName[15]   = 'L',\n\t.wPropertyName[16]   = 'e',\n\t.wPropertyName[17]   = 'n',\n\t.wPropertyName[18]   = 'g',\n\t.wPropertyName[19]   = 't',\n\t.wPropertyName[20]   = 'h',\n\t.wPropertyName[21]   = 0,\n\n\t.dPropertyDataLength = 0x4,\n\t.wPropertyData[0]    = 0x00, // 1MB.\n\t.wPropertyData[1]    = 0x10,\n};\n\nstatic usb_ms_ext_prop_descr_t usb_ms_ext_prop_descriptor_hid =\n{\n\t.dLength             = 7,\n\t.wVersion            = 0x100,\n\t.wExtendedProperty   = USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES,\n\t.wSections           = 0,\n};\n\nstatic usb_dev_descr_t usb_device_descriptor_hid_jc =\n{\n\t.bLength         = 18,\n\t.bDescriptorType = USB_DESCRIPTOR_DEVICE,\n\t.bcdUSB          = 0x210,\n\t.bDeviceClass    = 0x00,\n\t.bDeviceSubClass = 0x00,\n\t.bDeviceProtocol = 0x00,\n\t.bMaxPacketSize  = 0x40,\n\t.idVendor        = 0x11EC, // Nintendo: 0x057E, Nvidia: 0x0955\n\t.idProduct       = 0xA7E1, // Switch:   0x2000, usbd:   0x3000\n\t.bcdDevice       = 0x0101,\n\t.iManufacturer   = 1,\n\t.iProduct        = 2,\n\t.iSerialNumber   = 3,\n\t.bNumConfigs     = 1\n};\n\nstatic usb_dev_descr_t usb_device_descriptor_hid_touch =\n{\n\t.bLength         = 18,\n\t.bDescriptorType = USB_DESCRIPTOR_DEVICE,\n\t.bcdUSB          = 0x210,\n\t.bDeviceClass    = 0x00,\n\t.bDeviceSubClass = 0x00,\n\t.bDeviceProtocol = 0x00,\n\t.bMaxPacketSize  = 0x40,\n\t.idVendor        = 0x11EC, // Nintendo: 0x057E, Nvidia: 0x0955\n\t.idProduct       = 0xA7E2, // Switch:   0x2000, usbd:   0x3000\n\t.bcdDevice       = 0x0101,\n\t.iManufacturer   = 1,\n\t.iProduct        = 2,\n\t.iSerialNumber   = 3,\n\t.bNumConfigs     = 1\n};\n\nu8 hid_report_descriptor_jc[] =\n{\n\t0x05, 0x01,                // USAGE_PAGE (Generic Desktop),\n\t0x09, 0x04,                // USAGE (Joystick),\n\t0xa1, 0x01,                // COLLECTION (Application),\n\t0xa1, 0x02,                //   COLLECTION (Logical),\n\t0x75, 0x08,                //     REPORT_SIZE (8),\n\t0x95, 0x04,                //     REPORT_COUNT (4),\n\t0x15, 0x00,                //     LOGICAL_MINIMUM (0),\n\t0x26, 0xff, 0x00,          //     LOGICAL_MAXIMUM (255),\n\t0x35, 0x00,                //     PHYSICAL_MINIMUM (0),\n\t0x46, 0xff, 0x00,          //     PHYSICAL_MAXIMUM (255),\n\t0x09, 0x30,                //     USAGE (X_ID),\n\t0x09, 0x31,                //     USAGE (Y_ID),\n\t0x09, 0x32,                //     USAGE (Z_ID),\n\t0x09, 0x35,                //     USAGE (Rz_ID),\n\t0x81, 0x02,                //     INPUT (IOF_Variable),\n\t0x75, 0x04,                //     REPORT_SIZE (4),\n\t0x95, 0x01,                //     REPORT_COUNT (1),\n\t0x25, 0x07,                //     LOGICAL_MAXIMUM (7),\n\t0x46, 0x3b, 0x01,          //     PHYSICAL_MAXIMUM (315),\n\t0x65, 0x14,                //     UNIT (Eng_Rot_Angular_Pos),\n\t0x09, 0x39,                //     USAGE (Hat_Switch),\n\t0x81, 0x42,                //     INPUT (IOF_NullposVar),\n\t0x65, 0x00,                //     UNIT (Unit_None),\n\t0x75, 0x01,                //     REPORT_SIZE (1),\n\t0x95, 0x0c,                //     REPORT_COUNT (12),\n\t0x25, 0x01,                //     LOGICAL_MAXIMUM (1),\n\t0x45, 0x01,                //     PHYSICAL_MAXIMUM (1),\n\t0x05, 0x09,                //     USAGE_PAGE (Button_ID),\n\t0x19, 0x01,                //     USAGE_MINIMUM (1),\n\t0x29, 0x0c,                //     USAGE_MAXIMUM (12),\n\t0x81, 0x02,                //     INPUT (IOF_Variable),\n\t0xc0,                      //   END_COLLECTION(),\n\t0xc0                       // END_COLLECTION(),\n};\n\nu32 hid_report_descriptor_jc_size = sizeof(hid_report_descriptor_jc);\n\nu8 hid_report_descriptor_touch[] =\n{\n\t0x05, 0x0d,                         // USAGE_PAGE (Digitizers)\n\t0x09, 0x05,                         // USAGE (Touch Pad)\n\t0xa1, 0x01,                         // COLLECTION (Application)\n\t0x85, 0x05,                         //   REPORT_ID (Touch pad)\n\t0x09, 0x22,                         //   USAGE (Finger)\n\t0xa1, 0x02,                         //   COLLECTION (Logical)\n\t0x15, 0x00,                         //     LOGICAL_MINIMUM (0)\n\t0x25, 0x01,                         //     LOGICAL_MAXIMUM (1)\n\t0x09, 0x42,                         //     USAGE (Tip switch)\n\t0x95, 0x01,                         //     REPORT_COUNT (1)\n\t0x75, 0x01,                         //     REPORT_SIZE (1)\n\t0x81, 0x02,                         //     INPUT (Data,Var,Abs)\n\n\t0x15, 0x00,                         //     LOGICAL_MINIMUM (1)\n\t0x25, 0x01,                         //     LOGICAL_MAXIMUM (1)\n\t0x75, 0x01,                         //     REPORT_SIZE (1)\n\t0x95, 0x07,                         //     REPORT_COUNT (7)\n\t0x09, 0x54,                         //     USAGE (Contact Count)\n\t0x81, 0x02,                         //     INPUT (Data,Var,Abs)\n\n\t0x95, 0x01,                         //     REPORT_COUNT (1)\n\t0x75, 0x08,                         //     REPORT_SIZE (8)\n\t0x15, 0x00,                         //     LOGICAL_MINIMUM (0)\n\t0x25, 0x0A,                         //     LOGICAL_MAXIMUM (10)\n\t0x09, 0x51,                         //     USAGE (Contact Identifier)\n\t0x81, 0x02,                         //     INPUT (Data,Var,Abs)\n\n\t// 0x15, 0x00,                         //     LOGICAL_MINIMUM (0)\n\t// 0x26, 0xF8, 0x2A,                   //     LOGICAL_MAXIMUM (11000)\n\t// 0x95, 0x01,                         //     REPORT_COUNT (1)\n\t// 0x75, 0x08,                         //     REPORT_SIZE (16)\n\t// 0x09, 0x30,                         //     USAGE (Pressure)\n\t// 0x81, 0x02,                         //     INPUT (Data,Var,Abs)\n\n\t0x05, 0x01,                         //     USAGE_PAGE (Generic Desk..\n\t0x15, 0x00,                         //     LOGICAL_MINIMUM (0)\n\t0x26, 0xff, 0x04,                   //     LOGICAL_MAXIMUM (1279)\n\t0x75, 0x10,                         //     REPORT_SIZE (16)\n\t0x55, 0x0e,                         //     UNIT_EXPONENT (-2)\n\t0x65, 0x13,                         //     UNIT(Inch,EngLinear)\n\t0x09, 0x30,                         //     USAGE (X)\n\t0x35, 0x00,                         //     PHYSICAL_MINIMUM (0)\n\t0x46, 0xFF, 0x04,                   //     PHYSICAL_MAXIMUM (1279)\n\t0x95, 0x01,                         //     REPORT_COUNT (1)\n\t0x81, 0x02,                         //     INPUT (Data,Var,Abs)\n\t0x26, 0xCF, 0x02,                   //     LOGICAL_MAXIMUM (719)\n\t0x46, 0xCF, 0x02,                   //     PHYSICAL_MAXIMUM (719)\n\t0x09, 0x31,                         //     USAGE (Y)\n\t0x81, 0x02,                         //     INPUT (Data,Var,Abs)\n\n\t0x05, 0x0d,                         //     USAGE PAGE (Digitizers)\n\t0xc0,                               //    END_COLLECTION\n\t0xc0,                               // END_COLLECTION\n};\nu32 hid_report_descriptor_touch_size = sizeof(hid_report_descriptor_touch);\n\nstatic usb_cfg_hid_descr_t usb_configuration_descriptor_hid_jc =\n{\n\t/* Configuration descriptor structure */\n\t.config.bLength               = 9,\n\t.config.bDescriptorType       = USB_DESCRIPTOR_CONFIGURATION,\n\t.config.wTotalLength          = sizeof(usb_cfg_hid_descr_t),\n\t.config.bNumInterfaces        = 0x01,\n\t.config.bConfigurationValue   = 0x01,\n\t.config.iConfiguration        = 0x00,\n\t.config.bmAttributes          = USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED_RSVD,\n\t.config.bMaxPower             = 32 / 2,\n\n\t/* Interface descriptor structure */\n\t.interface.bLength            = 9,\n\t.interface.bDescriptorType    = USB_DESCRIPTOR_INTERFACE,\n\t.interface.bInterfaceNumber   = 0,\n\t.interface.bAlternateSetting  = 0,\n\t.interface.bNumEndpoints      = 1,\n\t.interface.bInterfaceClass    = 0x03, // Human Interface Device Class.\n\t.interface.bInterfaceSubClass = 0x00, // No Subclass.\n\t.interface.bInterfaceProtocol = 0x00, // None.\n\t.interface.iInterface         = 0x00,\n\n\t.hid.bLength                  = 9,\n\t.hid.bDescriptorType          = USB_DESCRIPTOR_HID,\n\t.hid.bcdHID                   = 0x110,\n\t.hid.bCountryCode             = 0,\n\t.hid.bNumDescriptors          = 1,\n\t.hid.bClassDescriptorType     = USB_DESCRIPTOR_HID_REPORT,\n\t.hid.bDescriptorLength        = sizeof(hid_report_descriptor_jc),\n\n\t/* Endpoint descriptor structure EP1 IN */\n\t.endpoint[0].bLength          = 7,\n\t.endpoint[0].bDescriptorType  = USB_DESCRIPTOR_ENDPOINT,\n\t.endpoint[0].bEndpointAddress = 0x81, // USB_EP_ADDR_BULK_IN.\n\t.endpoint[0].bmAttributes     = USB_EP_TYPE_INTR,\n\t.endpoint[0].wMaxPacketSize   = 0x200,\n\t.endpoint[0].bInterval        = 4,   // 8ms on HS.\n};\n\nstatic u8 usb_vendor_string_descriptor_hid[22] =\n{\n\t16, 0x03,\n\t'N', 0, 'y', 0, 'x', 0, ' ', 0,\n\t'U', 0, 'S', 0, 'B', 0\n};\n\nstatic u8 usb_product_string_descriptor_hid_jc[24] =\n{\n\t24, 0x03,\n\t'N', 0, 'y', 0, 'x', 0, ' ', 0,\n\t'J', 0, 'o', 0, 'y', 0, '-', 0, 'C', 0, 'o', 0, 'n', 0\n};\n\nstatic u8 usb_product_string_descriptor_hid_touch[26] =\n{\n\t26, 0x03,\n\t'N', 0, 'y', 0, 'x', 0, ' ', 0,\n\t'T', 0, 'o', 0, 'u', 0, 'c', 0, 'h', 0, 'p', 0, 'a', 0, 'd', 0\n};\n\nstatic usb_cfg_hid_descr_t usb_configuration_descriptor_hid_touch =\n{\n\t/* Configuration descriptor structure */\n\t.config.bLength               = 9,\n\t.config.bDescriptorType       = USB_DESCRIPTOR_CONFIGURATION,\n\t.config.wTotalLength          = sizeof(usb_cfg_hid_descr_t),\n\t.config.bNumInterfaces        = 0x01,\n\t.config.bConfigurationValue   = 0x01,\n\t.config.iConfiguration        = 0x00,\n\t.config.bmAttributes          = USB_ATTR_SELF_POWERED | USB_ATTR_BUS_POWERED_RSVD,\n\t.config.bMaxPower             = 32 / 2,\n\n\t/* Interface descriptor structure */\n\t.interface.bLength            = 9,\n\t.interface.bDescriptorType    = USB_DESCRIPTOR_INTERFACE,\n\t.interface.bInterfaceNumber   = 0,\n\t.interface.bAlternateSetting  = 0,\n\t.interface.bNumEndpoints      = 1,\n\t.interface.bInterfaceClass    = 0x03, // Human Interface Device Class.\n\t.interface.bInterfaceSubClass = 0x00, // No Subclass.\n\t.interface.bInterfaceProtocol = 0x00, // None.\n\t.interface.iInterface         = 0x00,\n\n\t.hid.bLength                  = 9,\n\t.hid.bDescriptorType          = USB_DESCRIPTOR_HID,\n\t.hid.bcdHID                   = 0x111,\n\t.hid.bCountryCode             = 0,\n\t.hid.bNumDescriptors          = 1,\n\t.hid.bClassDescriptorType     = USB_DESCRIPTOR_HID_REPORT,\n\t.hid.bDescriptorLength        = sizeof(hid_report_descriptor_touch),\n\n\t/* Endpoint descriptor structure EP1 IN */\n\t.endpoint[0].bLength          = 7,\n\t.endpoint[0].bDescriptorType  = USB_DESCRIPTOR_ENDPOINT,\n\t.endpoint[0].bEndpointAddress = 0x81, // USB_EP_ADDR_BULK_IN.\n\t.endpoint[0].bmAttributes     = USB_EP_TYPE_INTR,\n\t.endpoint[0].wMaxPacketSize   = 0x200,\n\t.endpoint[0].bInterval        = 3,   // 4ms on HS.\n};\n\nusb_desc_t usb_gadget_ums_descriptors =\n{\n\t.dev       = &usb_device_descriptor_ums,\n\t.dev_qual  = &usb_device_qualifier_descriptor,\n\t.cfg       = &usb_configuration_descriptor_ums,\n\t.cfg_other = &usb_other_speed_config_descriptor_ums,\n\t.dev_bot   = &usb_device_binary_object_descriptor,\n\t.vendor    = usb_vendor_string_descriptor_ums,\n\t.product   = usb_product_string_descriptor_ums,\n\t.serial    = usb_serial_string_descriptor,\n\t.lang_id   = usb_lang_id_string_descriptor,\n\t.ms_os     = &usb_ms_os_descriptor,\n\t.ms_cid    = &usb_ms_cid_descriptor,\n\t.mx_ext    = &usb_ms_ext_prop_descriptor_ums\n};\n\nusb_desc_t usb_gadget_hid_jc_descriptors =\n{\n\t.dev       = &usb_device_descriptor_hid_jc,\n\t.dev_qual  = &usb_device_qualifier_descriptor,\n\t.cfg       = (usb_cfg_simple_descr_t *)&usb_configuration_descriptor_hid_jc,\n\t.cfg_other = NULL,\n\t.dev_bot   = &usb_device_binary_object_descriptor,\n\t.vendor    = usb_vendor_string_descriptor_hid,\n\t.product   = usb_product_string_descriptor_hid_jc,\n\t.serial    = usb_serial_string_descriptor,\n\t.lang_id   = usb_lang_id_string_descriptor,\n\t.ms_os     = &usb_ms_os_descriptor,\n\t.ms_cid    = &usb_ms_cid_descriptor,\n\t.mx_ext    = &usb_ms_ext_prop_descriptor_hid\n};\n\nusb_desc_t usb_gadget_hid_touch_descriptors =\n{\n\t.dev       = &usb_device_descriptor_hid_touch,\n\t.dev_qual  = &usb_device_qualifier_descriptor,\n\t.cfg       = (usb_cfg_simple_descr_t *)&usb_configuration_descriptor_hid_touch,\n\t.cfg_other = NULL,\n\t.dev_bot   = &usb_device_binary_object_descriptor,\n\t.vendor    = usb_vendor_string_descriptor_hid,\n\t.product   = usb_product_string_descriptor_hid_touch,\n\t.serial    = usb_serial_string_descriptor,\n\t.lang_id   = usb_lang_id_string_descriptor,\n\t.ms_os     = &usb_ms_os_descriptor,\n\t.ms_cid    = &usb_ms_cid_descriptor,\n\t.mx_ext    = &usb_ms_ext_prop_descriptor_hid\n};\n"
  },
  {
    "path": "bdk/usb/usb_gadget_hid.c",
    "content": "/*\n * USB Gadget HID driver for Tegra X1\n *\n * Copyright (c) 2019-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <usb/usbd.h>\n#include <gfx_utils.h>\n#include <input/joycon.h>\n#include <input/touch.h>\n#include <soc/hw_init.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n\n#include <memory_map.h>\n\n//#define DPRINTF(...) gfx_printf(__VA_ARGS__)\n#define DPRINTF(...)\n\ntypedef struct _gamepad_report_t\n{\n\tu8 x;\n\tu8 y;\n\tu8 z;\n\tu8 rz;\n\n\tu8 hat:4;\n\tu8 btn1:1;\n\tu8 btn2:1;\n\tu8 btn3:1;\n\tu8 btn4:1;\n\n\tu8 btn5:1;\n\tu8 btn6:1;\n\tu8 btn7:1;\n\tu8 btn8:1;\n\tu8 btn9:1;\n\tu8 btn10:1;\n\tu8 btn11:1;\n\tu8 btn12:1;\n} __attribute__((packed)) gamepad_report_t;\n\ntypedef struct _jc_cal_t\n{\n// 15ms * JC_CAL_MAX_STEPS = 240 ms.\n#define JC_CAL_MAX_STEPS 16\n\tu32 cl_step;\n\tu32 cr_step;\n\n\tu16 clx_max;\n\tu16 clx_min;\n\tu16 cly_max;\n\tu16 cly_min;\n\tu16 crx_max;\n\tu16 crx_min;\n\tu16 cry_max;\n\tu16 cry_min;\n} jc_cal_t;\n\nenum {\n\tINPUT_POLL_HAS_PACKET,\n\tINPUT_POLL_NO_PACKET,\n\tINPUT_POLL_EXIT,\n};\n\nstatic jc_cal_t jc_cal_ctx;\nstatic usb_ops_t usb_ops;\n\nstatic void *rpt_buffer = (u8 *)USB_EP_BULK_IN_BUF_ADDR;\n\nstatic bool _jc_calibration(const jc_gamepad_rpt_t *jc_pad)\n{\n\t// Calibrate left stick.\n\tif (jc_cal_ctx.cl_step != JC_CAL_MAX_STEPS)\n\t{\n\t\tif (jc_pad->conn_l\n\t\t\t&& jc_pad->lstick_x > 0x400 && jc_pad->lstick_y > 0x400\n\t\t\t&& jc_pad->lstick_x < 0xC00 && jc_pad->lstick_y < 0xC00)\n\t\t{\n\t\t\tjc_cal_ctx.cl_step++;\n\t\t\tjc_cal_ctx.clx_max = jc_pad->lstick_x + 0x72;\n\t\t\tjc_cal_ctx.clx_min = jc_pad->lstick_x - 0x72;\n\t\t\tjc_cal_ctx.cly_max = jc_pad->lstick_y + 0x72;\n\t\t\tjc_cal_ctx.cly_min = jc_pad->lstick_y - 0x72;\n\n\t\t\tif (jc_cal_ctx.cl_step != JC_CAL_MAX_STEPS)\n\t\t\t\treturn false;\n\t\t}\n\t\telse\n\t\t\treturn false;\n\t}\n\n\t// Calibrate right stick.\n\tif (jc_cal_ctx.cr_step != JC_CAL_MAX_STEPS)\n\t{\n\t\tif (jc_pad->conn_r\n\t\t\t&& jc_pad->rstick_x > 0x400 && jc_pad->rstick_y > 0x400\n\t\t\t&& jc_pad->rstick_x < 0xC00 && jc_pad->rstick_y < 0xC00)\n\t\t{\n\t\t\tjc_cal_ctx.cr_step++;\n\t\t\tjc_cal_ctx.crx_max = jc_pad->rstick_x + 0x72;\n\t\t\tjc_cal_ctx.crx_min = jc_pad->rstick_x - 0x72;\n\t\t\tjc_cal_ctx.cry_max = jc_pad->rstick_y + 0x72;\n\t\t\tjc_cal_ctx.cry_min = jc_pad->rstick_y - 0x72;\n\n\t\t\tif (jc_cal_ctx.cr_step != JC_CAL_MAX_STEPS)\n\t\t\t\treturn false;\n\t\t}\n\t\telse\n\t\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nstatic int _jc_poll(gamepad_report_t *rpt)\n{\n\tstatic gamepad_report_t prev_rpt = {0};\n\n\t// Poll Joy-Con.\n\tjc_gamepad_rpt_t *jc_pad = joycon_poll();\n\n\tif (!jc_pad)\n\t\treturn INPUT_POLL_NO_PACKET;\n\n\t// Exit emulation if Left stick and Home are pressed.\n\tif (jc_pad->l3 && jc_pad->home)\n\t\treturn INPUT_POLL_EXIT;\n\n\tif (jc_cal_ctx.cl_step != JC_CAL_MAX_STEPS || jc_cal_ctx.cr_step != JC_CAL_MAX_STEPS)\n\t{\n\t\tif (!_jc_calibration(jc_pad))\n\t\t\treturn INPUT_POLL_NO_PACKET;\n\t}\n\n\t// Re-calibrate on disconnection.\n\tif (!jc_pad->conn_l)\n\t\tjc_cal_ctx.cl_step = 0;\n\tif (!jc_pad->conn_r)\n\t\tjc_cal_ctx.cr_step = 0;\n\n\t// Calculate left analog stick.\n\tif (jc_pad->lstick_x <= jc_cal_ctx.clx_max && jc_pad->lstick_x >= jc_cal_ctx.clx_min)\n\t\trpt->x = 0x7F;\n\telse if (jc_pad->lstick_x > jc_cal_ctx.clx_max)\n\t{\n\t\tu16 x_raw = (jc_pad->lstick_x - jc_cal_ctx.clx_max) / 7;\n\t\tif (x_raw > 0x7F)\n\t\t\tx_raw = 0x7F;\n\t\trpt->x = 0x7F + x_raw;\n\t}\n\telse\n\t{\n\t\tu16 x_raw = (jc_cal_ctx.clx_min - jc_pad->lstick_x) / 7;\n\t\tif (x_raw > 0x7F)\n\t\t\tx_raw = 0x7F;\n\t\trpt->x = 0x7F - x_raw;\n\t}\n\n\tif (jc_pad->lstick_y <= jc_cal_ctx.cly_max && jc_pad->lstick_y >= jc_cal_ctx.cly_min)\n\t\trpt->y = 0x7F;\n\telse if (jc_pad->lstick_y > jc_cal_ctx.cly_max)\n\t{\n\t\tu16 y_raw = (jc_pad->lstick_y - jc_cal_ctx.cly_max) / 7;\n\t\tif (y_raw > 0x7F)\n\t\t\ty_raw = 0x7F;\n\t\t// Hoag has inverted Y axis.\n\t\tif (!jc_pad->sio_mode)\n\t\t\trpt->y = 0x7F - y_raw;\n\t\telse\n\t\t\trpt->y = 0x7F + y_raw;\n\t}\n\telse\n\t{\n\t\tu16 y_raw = (jc_cal_ctx.cly_min - jc_pad->lstick_y) / 7;\n\t\tif (y_raw > 0x7F)\n\t\t\ty_raw = 0x7F;\n\t\t// Hoag has inverted Y axis.\n\t\tif (!jc_pad->sio_mode)\n\t\t\trpt->y = 0x7F + y_raw;\n\t\telse\n\t\t\trpt->y = 0x7F - y_raw;\n\t}\n\n\t// Calculate right analog stick.\n\tif (jc_pad->rstick_x <= jc_cal_ctx.crx_max && jc_pad->rstick_x >= jc_cal_ctx.crx_min)\n\t\trpt->z = 0x7F;\n\telse if (jc_pad->rstick_x > jc_cal_ctx.crx_max)\n\t{\n\t\tu16 x_raw = (jc_pad->rstick_x - jc_cal_ctx.crx_max) / 7;\n\t\tif (x_raw > 0x7F)\n\t\t\tx_raw = 0x7F;\n\t\trpt->z = 0x7F + x_raw;\n\t}\n\telse\n\t{\n\t\tu16 x_raw = (jc_cal_ctx.crx_min - jc_pad->rstick_x) / 7;\n\t\tif (x_raw > 0x7F)\n\t\t\tx_raw = 0x7F;\n\t\trpt->z = 0x7F - x_raw;\n\t}\n\n\tif (jc_pad->rstick_y <= jc_cal_ctx.cry_max && jc_pad->rstick_y >= jc_cal_ctx.cry_min)\n\t\trpt->rz = 0x7F;\n\telse if (jc_pad->rstick_y > jc_cal_ctx.cry_max)\n\t{\n\t\tu16 y_raw = (jc_pad->rstick_y - jc_cal_ctx.cry_max) / 7;\n\t\tif (y_raw > 0x7F)\n\t\t\ty_raw = 0x7F;\n\t\t// Hoag has inverted Y axis.\n\t\tif (!jc_pad->sio_mode)\n\t\t\trpt->rz = 0x7F - y_raw;\n\t\telse\n\t\t\trpt->rz = 0x7F + y_raw;\n\t}\n\telse\n\t{\n\t\tu16 y_raw = (jc_cal_ctx.cry_min - jc_pad->rstick_y) / 7;\n\t\tif (y_raw > 0x7F)\n\t\t\ty_raw = 0x7F;\n\t\t// Hoag has inverted Y axis.\n\t\tif (!jc_pad->sio_mode)\n\t\t\trpt->rz = 0x7F + y_raw;\n\t\telse\n\t\t\trpt->rz = 0x7F - y_raw;\n\t}\n\n\t// Set D-pad.\n\tswitch ((jc_pad->buttons >> 16) & 0xF)\n\t{\n\tcase 0: // none\n\t\trpt->hat = 0xF;\n\t\tbreak;\n\tcase 1: // down\n\t\trpt->hat = 4;\n\t\tbreak;\n\tcase 2: // up\n\t\trpt->hat = 0;\n\t\tbreak;\n\tcase 4: // right\n\t\trpt->hat = 2;\n\t\tbreak;\n\tcase 5: // down + right\n\t\trpt->hat = 3;\n\t\tbreak;\n\tcase 6: // up + right\n\t\trpt->hat = 1;\n\t\tbreak;\n\tcase 8: // left\n\t\trpt->hat = 6;\n\t\tbreak;\n\tcase 9: // down + left\n\t\trpt->hat = 5;\n\t\tbreak;\n\tcase 10: // up + left\n\t\trpt->hat = 7;\n\t\tbreak;\n\tdefault:\n\t\trpt->hat = 0xF;\n\t\tbreak;\n\t}\n\n\t// Set buttons.\n\trpt->btn1 = jc_pad->b; // x.\n\trpt->btn2 = jc_pad->a; // a.\n\trpt->btn3 = jc_pad->y; // b.\n\trpt->btn4 = jc_pad->x; // y.\n\n\trpt->btn5  = jc_pad->l;\n\trpt->btn6  = jc_pad->r;\n\trpt->btn7  = jc_pad->zl;\n\trpt->btn8  = jc_pad->zr;\n\trpt->btn9  = jc_pad->minus;\n\trpt->btn10 = jc_pad->plus;\n\trpt->btn11 = jc_pad->l3;\n\trpt->btn12 = jc_pad->r3;\n\n\t//rpt->btn13 = jc_pad->cap;\n\t//rpt->btn14 = jc_pad->home;\n\n\tif (!memcmp(rpt, &prev_rpt, sizeof(gamepad_report_t)))\n\t\treturn INPUT_POLL_NO_PACKET;\n\n\tmemcpy(&prev_rpt, rpt, sizeof(gamepad_report_t));\n\n\treturn INPUT_POLL_HAS_PACKET;\n}\n\ntypedef struct _touchpad_report_t\n{\n\tu8  rpt_id;\n\tu8  tip_switch:1;\n\tu8  count:7;\n\n\tu8  id;\n\n\t//u16 z;\n\tu16 x;\n\tu16 y;\n} __attribute__((packed)) touchpad_report_t;\n\nstatic bool _fts_touch_read(touchpad_report_t *rpt)\n{\n\tstatic touch_event_t touchpad;\n\n\tif (touch_poll(&touchpad))\n\t\treturn false;\n\n\trpt->rpt_id = 5;\n\trpt->count = 1;\n\n\t// Decide touch enable.\n\tif (touchpad.touch)\n\t{\n\t\trpt->x = touchpad.x;\n\t\trpt->y = touchpad.y;\n\t\t//rpt->z = touchpad.z;\n\t\trpt->id = touchpad.finger;\n\t\trpt->tip_switch = 1;\n\t}\n\telse\n\t{\n\t\trpt->x = touchpad.x;\n\t\trpt->y = touchpad.y;\n\t\t//rpt->z = touchpad.z;\n\t\trpt->id = touchpad.finger;\n\t\trpt->tip_switch = 0;\n\t}\n\n\treturn true;\n}\n\nstatic u8 _hid_transfer_start(usb_ctxt_t *usbs, u32 len)\n{\n\tu8 status = usb_ops.usb_device_ep1_in_write(rpt_buffer, len, NULL, USB_XFER_SYNCED_CMD);\n\tif (status == USB_ERROR_XFER_ERROR)\n\t{\n\t\tusbs->set_text(usbs->label, \"#FFDD00 Error:# EP IN transfer!\");\n\t\tif (usb_ops.usbd_flush_endpoint)\n\t\t\tusb_ops.usbd_flush_endpoint(USB_EP_BULK_IN);\n\t}\n\n\t// Linux mitigation: If timed out, clear status.\n\tif (status == USB_ERROR_TIMEOUT)\n\t\treturn 0;\n\n\treturn status;\n}\n\nstatic bool _hid_poll_jc(usb_ctxt_t *usbs)\n{\n\tint res = _jc_poll(rpt_buffer);\n\tif (res == INPUT_POLL_EXIT)\n\t\treturn true;\n\n\t// Send HID report.\n\tif (res == INPUT_POLL_HAS_PACKET || usbs->idle)\n\t\tif (_hid_transfer_start(usbs, sizeof(gamepad_report_t)))\n\t\t\treturn true; // EP Error.\n\n\treturn false;\n}\n\nstatic bool _hid_poll_touch(usb_ctxt_t *usbs)\n{\n\t_fts_touch_read(rpt_buffer);\n\n\t// Send HID report.\n\tif (_hid_transfer_start(usbs, sizeof(touchpad_report_t)))\n\t\treturn true; // EP Error.\n\n\treturn false;\n}\n\nint usb_device_gadget_hid(usb_ctxt_t *usbs)\n{\n\tint res = 0;\n\tu32 gadget_type;\n\tu32 polling_time;\n\n\t// Get USB Controller ops.\n\tif (hw_get_chip_id() == GP_HIDREV_MAJOR_T210)\n\t\tusb_device_get_ops(&usb_ops);\n\telse\n\t\txusb_device_get_ops(&usb_ops);\n\n\t// Always push packets by default.\n\t//! TODO: For now only per polling rate or on change is supported.\n\tusbs->idle = 1;\n\n\tif (usbs->type == USB_HID_GAMEPAD)\n\t{\n\t\tpolling_time = 15000;\n\t\tgadget_type = USB_GADGET_HID_GAMEPAD;\n\t}\n\telse\n\t{\n\t\tpolling_time = 4000;\n\t\tgadget_type = USB_GADGET_HID_TOUCHPAD;\n\t}\n\n\tusbs->set_text(usbs->label, \"#C7EA46 Status:# Started USB\");\n\n\tif (usb_ops.usb_device_init())\n\t{\n\t\tusb_ops.usbd_end(false, true);\n\t\treturn 1;\n\t}\n\n\tusbs->set_text(usbs->label, \"#C7EA46 Status:# Waiting for connection\");\n\n\t// Initialize Control Endpoint.\n\tif (usb_ops.usb_device_enumerate(gadget_type))\n\t\tgoto error;\n\n\tusbs->set_text(usbs->label, \"#C7EA46 Status:# Waiting for HID report request\");\n\n\tu32 rpt_size = usbs->type == USB_HID_GAMEPAD ? sizeof(gamepad_report_t) : sizeof(touchpad_report_t);\n\tif (usb_ops.usb_device_class_send_hid_report(rpt_buffer, rpt_size))\n\t\tgoto error;\n\n\tusbs->set_text(usbs->label, \"#C7EA46 Status:# Started HID emulation\");\n\n\tu32 timer_sys = get_tmr_ms() + 5000;\n\twhile (true)\n\t{\n\t\tu32 timer = get_tmr_us();\n\n\t\t// Check for suspended USB in case the cable was pulled.\n\t\tif (usb_ops.usb_device_get_suspended())\n\t\t\tbreak; // Disconnected.\n\n\t\t// Handle control endpoint.\n\t\tusb_ops.usbd_handle_ep0_ctrl_setup(&usbs->idle);\n\n\t\t// Parse input device.\n\t\tif (usbs->type == USB_HID_GAMEPAD)\n\t\t{\n\t\t\tif (_hid_poll_jc(usbs))\n\t\t\t\tbreak;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (_hid_poll_touch(usbs))\n\t\t\t\tbreak;\n\t\t}\n\n\t\t// Wait max gadget timing.\n\t\ttimer = get_tmr_us() - timer;\n\t\tif (timer < polling_time)\n\t\t\tusleep(polling_time - timer);\n\n\t\tif (timer_sys < get_tmr_ms())\n\t\t{\n\t\t\tusbs->system_maintenance(true);\n\t\t\ttimer_sys = get_tmr_ms() + 5000;\n\t\t}\n\t}\n\n\tusbs->set_text(usbs->label, \"#C7EA46 Status:# HID ended\");\n\tgoto exit;\n\nerror:\n\tusbs->set_text(usbs->label, \"#FFDD00 Error:# Timed out or canceled\");\n\tres = 1;\n\nexit:\n\tusb_ops.usbd_end(true, false);\n\n\treturn res;\n}\n"
  },
  {
    "path": "bdk/usb/usb_gadget_ums.c",
    "content": "/*\n * USB Gadget UMS driver for Tegra X1\n *\n * Copyright (c) 2003-2008 Alan Stern\n * Copyright (c) 2009 Samsung Electronics\n *                    Author: Michal Nazarewicz <m.nazarewicz@samsung.com>\n * Copyright (c) 2019-2024 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <usb/usbd.h>\n#include <gfx_utils.h>\n#include <soc/hw_init.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n#include <storage/sd.h>\n#include <storage/sdmmc.h>\n#include <storage/sdmmc_driver.h>\n#include <utils/btn.h>\n#include <utils/sprintf.h>\n\n#include <memory_map.h>\n\n//#define DPRINTF(...) gfx_printf(__VA_ARGS__)\n#define DPRINTF(...)\n\n#define UMS_MAX_LUN 1 // Only 1 disk/partition for now.\n\n#define USB_BULK_CB_WRAP_LEN 31\n#define USB_BULK_CB_SIG      0x43425355 // USBC.\n#define USB_BULK_IN_FLAG     0x80\n\n#define USB_BULK_CS_WRAP_LEN 13\n#define USB_BULK_CS_SIG      0x53425355 // USBS.\n\n#define USB_STATUS_PASS        0\n#define USB_STATUS_FAIL        1\n#define USB_STATUS_PHASE_ERROR 2\n\n#define UMS_DISK_LBA_SHIFT 9\n#define UMS_DISK_LBA_SIZE  (1 << UMS_DISK_LBA_SHIFT)\n\n#define UMS_DISK_MAX_IO_TRANSFER_64K (USB_EP_BUFFER_MAX_SIZE >> UMS_DISK_LBA_SHIFT)\n#define UMS_DISK_MAX_IO_TRANSFER_32K (UMS_DISK_MAX_IO_TRANSFER_64K / 2)\n\n#define UMS_SCSI_TRANSFER_512K (0x80000 >> UMS_DISK_LBA_SHIFT)\n\n#define UMS_EP_OUT_MAX_XFER (USB_EP_BULK_OUT_MAX_XFER)\n\n// Length of a SCSI Command Data Block.\n#define SCSI_MAX_CMD_SZ 16\n\n// SCSI device types\n#define SCSI_TYPE_DISK  0x00\n\n// SCSI commands.\n#define SC_FORMAT_UNIT        0x04\n#define SC_INQUIRY            0x12\n#define SC_LOG_SENSE          0x4D\n#define SC_MODE_SELECT_6      0x15\n#define SC_MODE_SELECT_10     0x55\n#define SC_MODE_SENSE_6       0x1A\n#define SC_MODE_SENSE_10      0x5A\n#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E\n#define SC_READ_6             0x08\n#define SC_READ_10            0x28\n#define SC_READ_12            0xA8\n#define SC_READ_CAPACITY      0x25\n#define SC_READ_FORMAT_CAPACITIES 0x23\n#define SC_READ_HEADER        0x44\n#define SC_READ_TOC           0x43\n#define SC_RELEASE            0x17\n#define SC_REQUEST_SENSE      0x03\n#define SC_RESERVE            0x16\n#define SC_SEND_DIAGNOSTIC    0x1D\n#define SC_START_STOP_UNIT    0x1B\n#define SC_SYNCHRONIZE_CACHE  0x35\n#define SC_TEST_UNIT_READY    0x00\n#define SC_VERIFY             0x2F\n#define SC_WRITE_6            0x0A\n#define SC_WRITE_10           0x2A\n#define SC_WRITE_12           0xAA\n\n// SCSI Sense Key/Additional Sense Code/ASC Qualifier values.\n#define SS_NO_SENSE                           0x0\n#define SS_COMMUNICATION_FAILURE              0x40800\n#define SS_INVALID_COMMAND                    0x52000\n#define SS_INVALID_FIELD_IN_CDB               0x52400\n#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x52100\n#define SS_MEDIUM_NOT_PRESENT                 0x23A00\n#define SS_MEDIUM_REMOVAL_PREVENTED           0x55302\n#define SS_NOT_READY_TO_READY_TRANSITION      0x62800\n#define SS_RESET_OCCURRED                     0x62900\n#define SS_SAVING_PARAMETERS_NOT_SUPPORTED    0x53900\n#define SS_UNRECOVERED_READ_ERROR             0x31100\n#define SS_WRITE_ERROR                        0x30C02\n#define SS_WRITE_PROTECTED                    0x72700\n\n#define SK(x)   ((u8) ((x) >> 16)) // Sense Key byte, etc.\n#define ASC(x)  ((u8) ((x) >> 8))\n#define ASCQ(x) ((u8) (x))\n\nenum ums_state {\n\tUMS_STATE_NORMAL = 0,\n\tUMS_STATE_ABORT_BULK_OUT,\n\tUMS_STATE_PROTOCOL_RESET,\n\tUMS_STATE_EXIT,\n\tUMS_STATE_TERMINATED\n};\n\nenum ums_result {\n\tUMS_RES_OK          = 0,\n\tUMS_RES_IO_ERROR    = -5,\n\tUMS_RES_TIMEOUT     = -3,\n\tUMS_RES_PROT_FATAL  = -4,\n\tUMS_RES_INVALID_ARG = -22\n};\n\n\nenum data_direction {\n\tDATA_DIR_UNKNOWN = 0,\n\tDATA_DIR_FROM_HOST,\n\tDATA_DIR_TO_HOST,\n\tDATA_DIR_NONE\n};\n\nenum buffer_state {\n\tBUF_STATE_EMPTY = 0,\n\tBUF_STATE_FULL,\n\tBUF_STATE_BUSY\n};\n\ntypedef struct _bulk_recv_pkt_t {\n\tu32 Signature;          // 'USBC'.\n\tu32 Tag;                // Unique per command id.\n\tu32 DataTransferLength; // Size of the data.\n\tu8  Flags;              // Direction in bit 7.\n\tu8  Lun;                // LUN (normally 0).\n\tu8  Length;             // Of the CDB, <= SCSI_MAX_CMD_SZ.\n\tu8  CDB[16];            // Command Data Block.\n} bulk_recv_pkt_t;\n\ntypedef struct _bulk_send_pkt_t {\n\tu32 Signature; // 'USBS'.\n\tu32 Tag;       // Same as original command.\n\tu32 Residue;   // Amount not transferred.\n\tu8  Status;\n} bulk_send_pkt_t;\n\ntypedef struct _logical_unit_t\n{\n\tsdmmc_t *sdmmc;\n\tsdmmc_storage_t *storage;\n\n\tu32 num_sectors;\n\tu32 offset;\n\n\tint unmounted;\n\n\tu32 ro;\n\tu32 type;\n\tu32 partition;\n\tu32 removable;\n\tu32 prevent_medium_removal;\n\n\tu32 info_valid;\n\n\tu32 sense_data;\n\tu32 sense_data_info;\n\tu32 unit_attention_data;\n} logical_unit_t;\n\ntypedef struct _bulk_ctxt_t {\n\tu32  bulk_in;\n\tint  bulk_in_status;\n\tu32  bulk_in_length;\n\tu32  bulk_in_length_actual;\n\tu8  *bulk_in_buf;\n\tenum buffer_state bulk_in_buf_state;\n\n\tu32  bulk_out;\n\tint  bulk_out_status;\n\tu32  bulk_out_length;\n\tu32  bulk_out_length_actual;\n\tint  bulk_out_ignore;\n\tu8  *bulk_out_buf;\n\tenum buffer_state bulk_out_buf_state;\n} bulk_ctxt_t;\n\ntypedef struct _usbd_gadget_ums_t {\n\tbulk_ctxt_t bulk_ctxt;\n\n\tu32  cmnd_size;\n\tu8   cmnd[SCSI_MAX_CMD_SZ];\n\n\tu32  lun_idx; // lun index\n\tlogical_unit_t lun;\n\n\tenum ums_state state; // For exception handling.\n\n\tenum data_direction data_dir;\n\tu32  data_size;\n\tu32  data_size_from_cmnd;\n\tu32  tag;\n\tu32  residue;\n\tu32  usb_amount_left;\n\tbool cbw_req_queued;\n\n\tu32  phase_error;\n\tu32  short_packet_received;\n\n\tint  thread_wakeup_needed;\n\tint  can_stall;\n\n\tu32 timeouts;\n\tbool xusb;\n\n\tvoid (*system_maintenance)(bool);\n\tvoid *label;\n\tvoid (*set_text)(void *, const char *);\n} usbd_gadget_ums_t;\n\nstatic usb_ops_t usb_ops;\n\nstatic inline void put_array_le_to_be16(u16 val, void *p)\n{\n\tu8 *_p = p;\n\t_p[0] = val >> 8;\n\t_p[1] = val;\n}\n\nstatic inline void put_array_le_to_be32(u32 val, void *p)\n{\n\tu8 *_p = p;\n\t_p[0] = val >> 24;\n\t_p[1] = val >> 16;\n\t_p[2] = val >> 8;\n\t_p[3] = val;\n}\n\nstatic inline u16 get_array_be_to_le16(const void *p)\n{\n\tconst u8 *_p = p;\n\tu16 val = _p[0] << 8 | _p[1];\n\treturn val;\n}\n\nstatic inline u32 get_array_be_to_le24(const void *p)\n{\n\tconst u8 *_p = p;\n\tu32 val = (_p[0] << 16) | (_p[1] << 8) | _p[2];\n\treturn val;\n}\n\nstatic inline u32 get_array_be_to_le32(const void *p)\n{\n\tconst u8 *_p = p;\n\tu32 val = (_p[0] << 24) | (_p[1] << 16) | (_p[2] << 8) | _p[3];\n\treturn val;\n}\n\nstatic void raise_exception(usbd_gadget_ums_t *ums, enum ums_state new_state)\n{\n\t/* Do nothing if a higher-priority exception is already in progress.\n\t * If a lower-or-equal priority exception is in progress, preempt it\n\t * and notify the main thread by sending it a signal. */\n\tif (ums->state <= new_state) {\n\t\tums->state = new_state;\n\t\tums->thread_wakeup_needed = 1;\n\t}\n}\n\nstatic void _handle_ep0_ctrl(usbd_gadget_ums_t *ums)\n{\n\tif (usb_ops.usbd_handle_ep0_ctrl_setup(NULL))\n\t\traise_exception(ums, UMS_STATE_PROTOCOL_RESET);\n}\n\nstatic int _wedge_bulk_in_endpoint(usbd_gadget_ums_t *ums)\n{\n\t/* usbd_set_ep_wedge(bulk_ctxt->bulk_in); */\n\n\treturn UMS_RES_OK;\n}\n\nstatic int _set_ep_stall(u32 ep)\n{\n\tusb_ops.usbd_set_ep_stall(ep, USB_EP_CFG_STALL);\n\n\treturn UMS_RES_OK;\n}\n\nstatic int _clear_ep_stall(u32 ep)\n{\n\tusb_ops.usbd_set_ep_stall(ep, USB_EP_CFG_CLEAR);\n\n\treturn UMS_RES_OK;\n}\n\nstatic void _flush_endpoint(u32 ep)\n{\n\tif (usb_ops.usbd_flush_endpoint)\n\t\tusb_ops.usbd_flush_endpoint(ep);\n}\n\nstatic void _transfer_start(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, u32 ep, u32 sync_timeout)\n{\n\tif (ep == bulk_ctxt->bulk_in)\n\t{\n\t\tbulk_ctxt->bulk_in_status = usb_ops.usb_device_ep1_in_write(\n\t\t\tbulk_ctxt->bulk_in_buf, bulk_ctxt->bulk_in_length,\n\t\t\t&bulk_ctxt->bulk_in_length_actual, sync_timeout);\n\n\t\tif (bulk_ctxt->bulk_in_status == USB_ERROR_XFER_ERROR)\n\t\t{\n\t\t\tums->set_text(ums->label, \"#FFDD00 Error:# EP IN transfer!\");\n\t\t\t_flush_endpoint(bulk_ctxt->bulk_in);\n\t\t}\n\t\telse if (bulk_ctxt->bulk_in_status == USB2_ERROR_XFER_NOT_ALIGNED)\n\t\t\tums->set_text(ums->label, \"#FFDD00 Error:# EP IN Buffer not aligned!\");\n\n\t\tif (sync_timeout)\n\t\t\tbulk_ctxt->bulk_in_buf_state = BUF_STATE_EMPTY;\n\t}\n\telse\n\t{\n\t\tbulk_ctxt->bulk_out_status = usb_ops.usb_device_ep1_out_read(\n\t\t\tbulk_ctxt->bulk_out_buf, bulk_ctxt->bulk_out_length,\n\t\t\t&bulk_ctxt->bulk_out_length_actual, sync_timeout);\n\n\t\tif (bulk_ctxt->bulk_out_status == USB_ERROR_XFER_ERROR)\n\t\t{\n\t\t\tums->set_text(ums->label, \"#FFDD00 Error:# EP OUT transfer!\");\n\t\t\t_flush_endpoint(bulk_ctxt->bulk_out);\n\t\t}\n\t\telse if (bulk_ctxt->bulk_out_status == USB2_ERROR_XFER_NOT_ALIGNED)\n\t\t\tums->set_text(ums->label, \"#FFDD00 Error:# EP OUT Buffer not aligned!\");\n\n\t\tif (sync_timeout)\n\t\t\tbulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL;\n\t}\n}\n\nstatic void _transfer_out_big_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)\n{\n\t\tbulk_ctxt->bulk_out_status = usb_ops.usb_device_ep1_out_read_big(\n\t\t\tbulk_ctxt->bulk_out_buf, bulk_ctxt->bulk_out_length,\n\t\t\t&bulk_ctxt->bulk_out_length_actual);\n\n\t\tif (bulk_ctxt->bulk_out_status == USB_ERROR_XFER_ERROR)\n\t\t{\n\t\t\tums->set_text(ums->label, \"#FFDD00 Error:# EP OUT transfer!\");\n\t\t\t_flush_endpoint(bulk_ctxt->bulk_out);\n\t\t}\n\n\t\tbulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL;\n}\n\nstatic void _transfer_finish(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt, u32 ep, u32 sync_timeout)\n{\n\tif (ep == bulk_ctxt->bulk_in)\n\t{\n\t\tbulk_ctxt->bulk_in_status = usb_ops.usb_device_ep1_in_writing_finish(\n\t\t\t&bulk_ctxt->bulk_in_length_actual, sync_timeout);\n\n\t\tif (bulk_ctxt->bulk_in_status == USB_ERROR_XFER_ERROR)\n\t\t{\n\t\t\tums->set_text(ums->label, \"#FFDD00 Error:# EP IN transfer!\");\n\t\t\t_flush_endpoint(bulk_ctxt->bulk_in);\n\t\t}\n\n\t\tbulk_ctxt->bulk_in_buf_state = BUF_STATE_EMPTY;\n\t}\n\telse\n\t{\n\t\tbulk_ctxt->bulk_out_status = usb_ops.usb_device_ep1_out_reading_finish(\n\t\t\t&bulk_ctxt->bulk_out_length_actual, sync_timeout);\n\n\t\tif (bulk_ctxt->bulk_out_status == USB_ERROR_XFER_ERROR)\n\t\t{\n\t\t\tums->set_text(ums->label, \"#FFDD00 Error:# EP OUT transfer!\");\n\t\t\t_flush_endpoint(bulk_ctxt->bulk_out);\n\t\t}\n\n\t\tbulk_ctxt->bulk_out_buf_state = BUF_STATE_FULL;\n\t}\n}\n\nstatic void _reset_buffer(bulk_ctxt_t *bulk_ctxt, u32 ep)\n{\n\tif (ep == bulk_ctxt->bulk_in)\n\t\tbulk_ctxt->bulk_in_buf  = (u8 *)USB_EP_BULK_IN_BUF_ADDR;\n\telse\n\t\tbulk_ctxt->bulk_out_buf = (u8 *)USB_EP_BULK_OUT_BUF_ADDR;\n}\n\n/*\n * The following are old data based on max 64KB SCSI transfers.\n * The endpoint xfer is actually 41.2 MB/s and SD card max 39.2 MB/s, with higher SCSI\n * transfers, but the concurrency still helps and increases speeds by 20%.\n *\n * Concurrency of the SDMMC and USB xfers is very important with no cache.\n * The worst offender being the SD card. We are already limited by bus, so\n * concurrency helps minimize the SDMMC overhead.\n * Max achieved bulk endpoint rate on a Tegra X1 and USB2.0 is 39.4 MB/s.\n *\n * USB bulk endpoint raw max transfer rate:\n * 39.4MB/S - SCSI 128KB.\n * 38.2MB/s - SCSI  64KB.\n *\n *     128 KB,      64 KB,      32 KB,     16 KB,      8 KB - Internal SDMMC I\\O Sizes\n * -------------------------------------------------------------------------------------\n * eMMC - Toshiba - 4MB reads: 314.8 MB/s:\n * 225.9 MB/s, 168.6 MB/s, 114.7 MB/s, 86.4 MB/s, 50.3 MB/s - RAW SDMMC.\n *  33.5 MB/s,  31.9 MB/s,  29.3 MB/s, 27.1 MB/s, 22.1 MB/s - SCSI 128KB, No concurrency.\n *  33.5 MB/s,  35.3 MB/s,  36.3 MB/s, 37.3 MB/s, 37.8 MB/s - SCSI 128KB, Concurrency.\n *  --.- --/-,  31.1 MB/s,  28.7 MB/s, 26.5 MB/s, 21.7 MB/s - SCSI  64KB, No concurrency.\n *  --.- --/-,  31.1 MB/s,  32.7 MB/s, 34.4 MB/s, 35.0 MB/s - SCSI  64KB, Concurrency.\n *\n * SD Card - Samsung Evo+ 128GB - 4MB reads: 91.6 MB/s:\n *  72.6 MB/s,  62.8 MB/s,  47.4 MB/s, 31.1 MB/s, 18.5 MB/s - RAW SDMMC.\n *  25.5 MB/s,  24.2 MB/s,  21.5 MB/s, 17.4 MB/s, 12.6 MB/s - SCSI 128KB, No concurrency.\n *  25.5 MB/s,  30.0 MB/s,  32.6 MB/s, 28.3 MB/s, 18.0 MB/s - SCSI 128KB, Concurrency.\n *  --.- --/-,  23.8 MB/s,  21.2 MB/s, 17.1 MB/s, 12.5 MB/s - SCSI  64KB, No concurrency.\n *  --.- --/-,  23.8 MB/s,  27.2 MB/s, 25.8 MB/s, 17.5 MB/s - SCSI  64KB, Concurrency.\n */\n\nstatic int _scsi_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)\n{\n\tu32 lba_offset;\n\tbool first_read = true;\n\tu8 *sdmmc_buf = (u8 *)SDXC_BUF_ALIGNED;\n\n\t// Get the starting LBA and check that it's not too big.\n\tif (ums->cmnd[0] == SC_READ_6)\n\t\tlba_offset = get_array_be_to_le24(&ums->cmnd[1]);\n\telse\n\t{\n\t\tlba_offset = get_array_be_to_le32(&ums->cmnd[2]);\n\n\t\t// We allow DPO and FUA bypass cache bits, but we don't use them.\n\t\tif ((ums->cmnd[1] & ~0x18) != 0)\n\t\t{\n\t\t\tums->lun.sense_data = SS_INVALID_FIELD_IN_CDB;\n\n\t\t\treturn UMS_RES_INVALID_ARG;\n\t\t}\n\t}\n\tif (lba_offset >= ums->lun.num_sectors)\n\t{\n\t\tums->set_text(ums->label, \"#FF8000 Warn:# Read - Out of range! Host notified.\");\n\t\tums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\t// Check that request data size is not 0.\n\tu32 amount_left = ums->data_size_from_cmnd >> UMS_DISK_LBA_SHIFT;\n\tif (!amount_left)\n\t\treturn UMS_RES_IO_ERROR; // No default reply.\n\n\t// Limit IO transfers based on request for faster concurrent reads.\n\tu32 max_io_transfer = (amount_left >= UMS_SCSI_TRANSFER_512K) ?\n\t\t\t\t\t\t  UMS_DISK_MAX_IO_TRANSFER_64K : UMS_DISK_MAX_IO_TRANSFER_32K;\n\n\twhile (true)\n\t{\n\t\t// Max io size and end sector limits.\n\t\tu32 amount = MIN(amount_left, max_io_transfer);\n\t\tamount     = MIN(amount, ums->lun.num_sectors - lba_offset);\n\n\t\t// Check if it is a read past the end sector.\n\t\tif (!amount)\n\t\t{\n\t\t\tums->lun.sense_data      = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;\n\t\t\tums->lun.sense_data_info = lba_offset;\n\t\t\tums->lun.info_valid      = 1;\n\n\t\t\tbulk_ctxt->bulk_in_length = 0;\n\t\t\tbulk_ctxt->bulk_in_buf_state = BUF_STATE_FULL;\n\t\t\tbreak;\n\t\t}\n\n\t\t// Do the SDMMC read.\n\t\tif (sdmmc_storage_read(ums->lun.storage, ums->lun.offset + lba_offset, amount, sdmmc_buf))\n\t\t\tamount = 0;\n\n\t\t// Wait for the async USB transfer to finish.\n\t\tif (!first_read)\n\t\t\t_transfer_finish(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED);\n\n\t\tlba_offset   += amount;\n\t\tamount_left  -= amount;\n\t\tums->residue -= amount << UMS_DISK_LBA_SHIFT;\n\n\t\tbulk_ctxt->bulk_in_length    = amount << UMS_DISK_LBA_SHIFT;\n\t\tbulk_ctxt->bulk_in_buf_state = BUF_STATE_FULL;\n\t\tbulk_ctxt->bulk_in_buf       = sdmmc_buf;\n\n\t\t// If an error occurred, report it and its position.\n\t\tif (!amount)\n\t\t{\n\t\t\tums->set_text(ums->label, \"#FFDD00 Error:# SDMMC Read!\");\n\t\t\tums->lun.sense_data      = SS_UNRECOVERED_READ_ERROR;\n\t\t\tums->lun.sense_data_info = lba_offset;\n\t\t\tums->lun.info_valid      = 1;\n\t\t\tbreak;\n\t\t}\n\n\t\t// Last SDMMC read. Last part will be sent by the finish reply function.\n\t\tif (!amount_left)\n\t\t\tbreak;\n\n\t\t// Start the USB transfer.\n\t\t_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_START);\n\t\tfirst_read = false;\n\n\t\t// Increment our buffer to read new data.\n\t\tsdmmc_buf += amount << UMS_DISK_LBA_SHIFT;\n\t}\n\n\treturn UMS_RES_IO_ERROR; // No default reply.\n}\n\n/*\n * Writes are another story.\n * Tests showed that big writes are faster than concurrent 32K usb reads + writes.\n * The only thing that can help here is caching the writes. But for the simplicity\n * of this implementation it will not be implemented yet.\n */\n\nstatic int _scsi_write(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)\n{\n\tstatic char txt_buf[256];\n\tu32 amount_left_to_req, amount_left_to_write;\n\tu32 usb_lba_offset, lba_offset;\n\tu32 amount;\n\n\tif (ums->lun.ro)\n\t{\n\t\tums->set_text(ums->label, \"#FF8000 Warn:# Write - Read only! Host notified.\");\n\t\tums->lun.sense_data = SS_WRITE_PROTECTED;\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\tif (ums->cmnd[0] == SC_WRITE_6)\n\t\tlba_offset = get_array_be_to_le24(&ums->cmnd[1]);\n\telse\n\t{\n\t\tlba_offset = get_array_be_to_le32(&ums->cmnd[2]);\n\n\t\t// We allow DPO and FUA bypass cache bits. We only implement FUA by performing synchronous output.\n\t\tif (ums->cmnd[1] & ~0x18)\n\t\t{\n\t\t\tums->lun.sense_data = SS_INVALID_FIELD_IN_CDB;\n\n\t\t\treturn UMS_RES_INVALID_ARG;\n\t\t}\n\t}\n\n\t// Check that starting LBA is not past the end sector offset.\n\tif (lba_offset >= ums->lun.num_sectors)\n\t{\n\t\tums->set_text(ums->label, \"#FF8000 Warn:# Write - Out of range! Host notified.\");\n\t\tums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\t// Carry out the file writes.\n\tusb_lba_offset       = lba_offset;\n\tamount_left_to_req   = ums->data_size_from_cmnd;\n\tamount_left_to_write = ums->data_size_from_cmnd;\n\n\twhile (amount_left_to_write > 0)\n\t{\n\t\t// Queue a request for more data from the host.\n\t\tif (amount_left_to_req > 0)\n\t\t{\n\n\t\t\t// Limit write to max supported read from EP OUT.\n\t\t\tamount = MIN(amount_left_to_req, UMS_EP_OUT_MAX_XFER);\n\n\t\t\tif (usb_lba_offset >= ums->lun.num_sectors)\n\t\t\t{\n\t\t\t\tums->set_text(ums->label, \"#FFDD00 Error:# Write - Past last sector!\");\n\t\t\t\tums->lun.sense_data      = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;\n\t\t\t\tums->lun.sense_data_info = usb_lba_offset;\n\t\t\t\tums->lun.info_valid      = 1;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Get the next buffer.\n\t\t\tusb_lba_offset       += amount >> UMS_DISK_LBA_SHIFT;\n\t\t\tums->usb_amount_left -= amount;\n\t\t\tamount_left_to_req   -= amount;\n\n\t\t\tbulk_ctxt->bulk_out_length = amount;\n\n\t\t\t_transfer_out_big_read(ums, bulk_ctxt);\n\t\t}\n\n\t\tif (bulk_ctxt->bulk_out_buf_state == BUF_STATE_FULL)\n\t\t{\n\t\t\tbulk_ctxt->bulk_out_buf_state = BUF_STATE_EMPTY;\n\n\t\t\t// Did something go wrong with the transfer?.\n\t\t\tif (bulk_ctxt->bulk_out_status != 0)\n\t\t\t{\n\t\t\t\tums->lun.sense_data      = SS_COMMUNICATION_FAILURE;\n\t\t\t\tums->lun.sense_data_info = lba_offset;\n\t\t\t\tums->lun.info_valid      = 1;\n\n\t\t\t\ts_printf(txt_buf, \"#FFDD00 Error:# Write - Comm failure %d!\", bulk_ctxt->bulk_out_status);\n\t\t\t\tums->set_text(ums->label, txt_buf);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tamount = bulk_ctxt->bulk_out_length_actual;\n\n\t\t\tif ((ums->lun.num_sectors - lba_offset) < (amount >> UMS_DISK_LBA_SHIFT))\n\t\t\t{\n\t\t\t\tDPRINTF(\"write %X @ %X beyond end %X\\n\", amount, lba_offset, ums->lun.num_sectors);\n\t\t\t\tamount = (ums->lun.num_sectors - lba_offset) << UMS_DISK_LBA_SHIFT;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t * Don't accept excess data.  The spec doesn't say\n\t\t\t * what to do in this case.  We'll ignore the error.\n\t\t\t */\n\t\t\tamount = MIN(amount, bulk_ctxt->bulk_out_length);\n\n\t\t\t// Don't write a partial block.\n\t\t\tamount -= (amount & 511);\n\t\t\tif (amount == 0)\n\t\t\t\tgoto empty_write;\n\n\t\t\t// Perform the write.\n\t\t\tif (sdmmc_storage_write(ums->lun.storage, ums->lun.offset + lba_offset,\n\t\t\t\tamount >> UMS_DISK_LBA_SHIFT, (u8 *)bulk_ctxt->bulk_out_buf))\n\t\t\t\tamount = 0;\n\nDPRINTF(\"file write %X @ %X\\n\", amount, lba_offset);\n\n\t\t\tlba_offset           += amount >> UMS_DISK_LBA_SHIFT;\n\t\t\tamount_left_to_write -= amount;\n\t\t\tums->residue         -= amount;\n\n\t\t\t// If an error occurred, report it and its position.\n\t\t\tif (!amount)\n\t\t\t{\n\t\t\t\tums->set_text(ums->label, \"#FFDD00 Error:# SDMMC Write!\");\n\t\t\t\tums->lun.sense_data      = SS_WRITE_ERROR;\n\t\t\t\tums->lun.sense_data_info = lba_offset;\n\t\t\t\tums->lun.info_valid      = 1;\n\t\t\t\tbreak;\n\t\t\t}\n\n empty_write:\n\t\t\t// Did the host decide to stop early?\n\t\t\tif (bulk_ctxt->bulk_out_length_actual < bulk_ctxt->bulk_out_length)\n\t\t\t{\n\t\t\t\tums->set_text(ums->label, \"#FFDD00 Error:# Empty Write!\");\n\t\t\t\tums->short_packet_received = 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn UMS_RES_IO_ERROR; // No default reply.\n}\n\nstatic int _scsi_verify(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)\n{\n\t// Check that start LBA is past the end sector offset.\n\tu32 lba_offset = get_array_be_to_le32(&ums->cmnd[2]);\n\tif (lba_offset >= ums->lun.num_sectors)\n\t{\n\t\tums->set_text(ums->label, \"#FF8000 Warn:# Verif - Out of range! Host notified.\");\n\t\tums->lun.sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\t// We allow DPO but we don't implement it. Check that nothing else is enabled.\n\tif (ums->cmnd[1] & ~0x10)\n\t{\n\t\tums->lun.sense_data = SS_INVALID_FIELD_IN_CDB;\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\tu32  verification_length = get_array_be_to_le16(&ums->cmnd[7]);\n\tif (verification_length == 0)\n\t\treturn UMS_RES_IO_ERROR; // No default reply.\n\n\tu32 amount;\n\twhile (verification_length > 0)\n\t{\n\n\t\t// Limit to EP buffer size and end sector offset.\n\t\tamount = MIN(verification_length, USB_EP_BUFFER_MAX_SIZE >> UMS_DISK_LBA_SHIFT);\n\t\tamount = MIN(amount, ums->lun.num_sectors - lba_offset);\n\t\tif (amount == 0) {\n\t\t\tums->lun.sense_data      = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;\n\t\t\tums->lun.sense_data_info = lba_offset;\n\t\t\tums->lun.info_valid      = 1;\n\t\t\tbreak;\n\t\t}\n\n\t\tif (sdmmc_storage_read(ums->lun.storage, ums->lun.offset + lba_offset, amount, bulk_ctxt->bulk_in_buf))\n\t\t\tamount = 0;\n\nDPRINTF(\"File read %X @ %X\\n\", amount, lba_offset);\n\n\t\tif (!amount)\n\t\t{\n\t\t\tums->set_text(ums->label, \"#FFDD00 Error:# File verify!\");\n\t\t\tums->lun.sense_data      = SS_UNRECOVERED_READ_ERROR;\n\t\t\tums->lun.sense_data_info = lba_offset;\n\t\t\tums->lun.info_valid      = 1;\n\t\t\tbreak;\n\t\t}\n\t\tlba_offset += amount;\n\t\tverification_length -= amount;\n\t}\n\treturn UMS_RES_OK;\n}\n\nstatic int _scsi_inquiry(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)\n{\n\tu8 *buf = (u8 *)bulk_ctxt->bulk_in_buf;\n\n\tmemset(buf, 0, 36);\n\n\t// Enable Vital Product Data (EVPD) and Unit Serial Number.\n\tif (ums->cmnd[1] == 1 && ums->cmnd[2] == 0x80)\n\t{\n\t\tbuf[0] = 0;\n\t\tbuf[1] = ums->cmnd[2];\n\t\tbuf[2] = 0;\n\t\tbuf[3] = 20;  // Additional length.\n\n\t\tbuf += 4;\n\t\ts_printf((char *)buf, \"%04X%s\",\n\t\t\tums->lun.storage->cid.serial, ums->lun.type == MMC_SD ? \" SD \" : \" eMMC \");\n\n\t\tswitch (ums->lun.partition)\n\t\t{\n\t\tcase 0:\n\t\t\tstrcpy((char *)buf + strlen((char *)buf), \"RAW\");\n\t\t\tbreak;\n\t\tcase EMMC_GPP + 1:\n\t\t\ts_printf((char *)buf + strlen((char *)buf), \"GPP\");\n\t\t\tbreak;\n\t\tcase EMMC_BOOT0 + 1:\n\t\t\ts_printf((char *)buf + strlen((char *)buf), \"BOOT0\");\n\t\t\tbreak;\n\t\tcase EMMC_BOOT1 + 1:\n\t\t\ts_printf((char *)buf + strlen((char *)buf), \"BOOT1\");\n\t\t\tbreak;\n\t\t}\n\n\t\tfor (u32 i = strlen((char *)buf); i < 20; i++)\n\t\t\tbuf[i] = ' ';\n\n\t\treturn 24;\n\t}\n\telse /* if (ums->cmnd[1] == 0 && ums->cmnd[2] == 0) */ // Standard inquiry.\n\t{\n\t\tbuf[0] = SCSI_TYPE_DISK;\n\t\tbuf[1] = ums->lun.removable ? 0x80 : 0;\n\t\tbuf[2] = 6;  // ANSI INCITS 351-2001 (SPC-2).////////SPC2: 4, SPC4: 6\n\t\tbuf[3] = 2;  // SCSI-2 INQUIRY data format.\n\t\tbuf[4] = 31; // Additional length.\n\t\t// buf5-7: No special options.\n\n\t\t// Vendor ID. Max 8 chars.\n\t\tbuf += 8;\n\t\tstrcpy((char *)buf, \"hekate\");\n\n\t\t// Product ID. Max 16 chars.\n\t\tbuf += 8;\n\t\tswitch (ums->lun.partition)\n\t\t{\n\t\tcase 0:\n\t\t\ts_printf((char *)buf, \"%s\", \"SD RAW\");\n\t\t\tbreak;\n\t\tcase EMMC_GPP + 1:\n\t\t\ts_printf((char *)buf, \"%s%s\",\n\t\t\t\tums->lun.type == MMC_SD ? \"SD \" : \"eMMC \", \"GPP\");\n\t\t\tbreak;\n\t\tcase EMMC_BOOT0 + 1:\n\t\t\ts_printf((char *)buf, \"%s%s\",\n\t\t\t\tums->lun.type == MMC_SD ? \"SD \" : \"eMMC \", \"BOOT0\");\n\t\t\tbreak;\n\t\tcase EMMC_BOOT1 + 1:\n\t\t\ts_printf((char *)buf, \"%s%s\",\n\t\t\t\tums->lun.type == MMC_SD ? \"SD \" : \"eMMC \", \"BOOT1\");\n\t\t\tbreak;\n\t\t}\n\n\t\t// Rev ID. Max 4 chars.\n\t\tbuf += 16;\n\t\tstrcpy((char *)buf, \"1.00\");\n\n\t\treturn 36;\n\t}\n}\n\nstatic int _scsi_request_sense(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)\n{\n\tu8 *buf = (u8 *)bulk_ctxt->bulk_in_buf;\n\tu32 sd, sdinfo;\n\tint valid;\n\n\tsd = ums->lun.sense_data;\n\tsdinfo = ums->lun.sense_data_info;\n\tvalid = ums->lun.info_valid << 7;\n\tums->lun.sense_data = SS_NO_SENSE;\n\tums->lun.sense_data_info = 0;\n\tums->lun.info_valid = 0;\n\n\tmemset(buf, 0, 18);\n\tbuf[0]  = valid | 0x70; // Valid, current error.\n\tbuf[2]  = SK(sd);\n\tput_array_le_to_be32(sdinfo, &buf[3]); // Sense information.\n\tbuf[7]  = 18 - 8; // Additional sense length.\n\tbuf[12] = ASC(sd);\n\tbuf[13] = ASCQ(sd);\n\n\treturn 18;\n}\n\nstatic int _scsi_read_capacity(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)\n{\n\tu8 *buf = (u8 *)bulk_ctxt->bulk_in_buf;\n\tu32 lba = get_array_be_to_le32(&ums->cmnd[2]);\n\tint pmi = ums->cmnd[8];\n\n\t// Check the PMI and LBA fields.\n\tif (pmi > 1 || (pmi == 0 && lba != 0))\n\t{\n\t\tums->lun.sense_data = SS_INVALID_FIELD_IN_CDB;\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\tput_array_le_to_be32(ums->lun.num_sectors - 1, &buf[0]); // Max logical block.\n\tput_array_le_to_be32(UMS_DISK_LBA_SIZE, &buf[4]);        // Block length.\n\n\treturn 8;\n}\n\nstatic int _scsi_log_sense(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)\n{\n\tu8  *buf = (u8 *)bulk_ctxt->bulk_in_buf;\n\tu8  *buf0 = buf;\n\tbool valid_page = false;\n\n\tu8 pc = ums->cmnd[2] >> 6;\n\tu8 page_code = ums->cmnd[2] & 0x3F;\n\tu8 sub_page_code = ums->cmnd[3];\n\n\tif (ums->cmnd[1] & 1)\n\t{\n\t\tums->lun.sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\tif (pc != 1) // Current cumulative values.\n\t{\n\t\tums->lun.sense_data = SS_INVALID_FIELD_IN_CDB;\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\tmemset(buf, 0, 8);\n\tif (page_code == 0x00 && !sub_page_code) // Supported pages.\n\t{\n\t\tvalid_page = true;\n\t\tbuf[0] = 0x00; // Page code.\n\t\tbuf += 4;\n\n\t\tbuf[0] = 0x00; // Page 0.\n\t\tbuf[1] = 0x0D; // Page 1.\n\n\t\tbuf += 2;\n\t}\n\telse if (page_code == 0x0d && !sub_page_code) // Temperature.\n\t{\n\t\tvalid_page = true;\n\t\tbuf[0] = 0x0D;\n\t\tbuf += 4;\n\n\t\tput_array_le_to_be16(0, &buf[0]); // Param code.\n\t\tbuf[2] = 1;  // Param control byte.\n\t\tbuf[3] = 2;  // Param length.\n\t\tbuf[4] = 0;  // Reserved.\n\t\tbuf[5] = 35; // Temperature (C) current (PCB here).\n\n\t\tput_array_le_to_be16(0, &buf[6]); // PARAMETER CODE\n\t\tbuf[8] = 1;   // Param control byte.\n\t\tbuf[9] = 2;   // Param length.\n\t\tbuf[10] = 0;  // Reserved.\n\t\tbuf[11] = 60; // Temperature (C) reference.\n\n\t\tbuf += 12;\n\t}\n\n\t// Check that a valid page mode data length was requested.\n\tu32 len = buf - buf0;\n\tif (!valid_page)\n\t{\n\t\tums->lun.sense_data = SS_INVALID_FIELD_IN_CDB;\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\tput_array_le_to_be16(len - 4, &buf0[2]);\n\n\treturn len;\n}\n\nstatic int _scsi_mode_sense(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)\n{\n\tu8  *buf = (u8 *)bulk_ctxt->bulk_in_buf;\n\tu8  *buf0 = buf;\n\tbool valid_page = false;\n\n\tu8 pc = ums->cmnd[2] >> 6;\n\tu8 page_code = ums->cmnd[2] & 0x3F;\n\tbool changeable_values = pc == 1;\n\tbool all_pages = page_code == 0x3F;\n\n\tif ((ums->cmnd[1] & ~0x08) != 0) // Mask away DBD.\n\t{\n\t\tums->lun.sense_data = SS_INVALID_FIELD_IN_CDB;\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\tif (pc == 3)\n\t{\n\t\tums->lun.sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\t/* Write the mode parameter header.  Fixed values are: default\n\t * medium type, no cache control (DPOFUA), and no block descriptors.\n\t * The only variable value is the WriteProtect bit.  We will fill in\n\t * the mode data length later. */\n\tmemset(buf, 0, 8);\n\tif (ums->cmnd[0] == SC_MODE_SENSE_6)\n\t{\n\t\tbuf[2] = (ums->lun.ro ? 0x80 : 0x00); // WP, DPOFUA.\n\t\tbuf += 4;\n\t}\n\telse // SC_MODE_SENSE_10.\n\t{\n\t\tbuf[3] = (ums->lun.ro ? 0x80 : 0x00); // WP, DPOFUA.\n\t\tbuf += 8;\n\t}\n\n\t// The only page we support is the Caching page.\n\t// What about x1C\n\tif (page_code == 0x08 || all_pages)\n\t{\n\t\tvalid_page = true;\n\t\tbuf[0] = 0x08; // Page code.\n\t\tbuf[1] = 18;   // Page length.\n\t\tmemset(buf + 2, 0, 18); // Set all parameters to 0.\n\n\t\t// None of the fields are changeable.\n\t\tif (!changeable_values)\n\t\t{\n\t\t\t// Write Cache enable, Read Cache not disabled, Multiplication Factor off.\n\t\t\tbuf[2] = 0x04;\n\n\t\t\t// Multiplication Factor is disabled, so all values below are 1x LBA.\n\t\t\tput_array_le_to_be16(0xFFFF, &buf[4]);  // Disable Prefetch if >32MB.\n\t\t\tput_array_le_to_be16(0x0000, &buf[6]);  // Minimum Prefetch 0MB.\n\t\t\tput_array_le_to_be16(0xFFFF, &buf[8]);  // Maximum Prefetch 32MB.\n\t\t\tput_array_le_to_be16(0xFFFF, &buf[10]); // Maximum Prefetch ceiling 32MB.\n\t\t}\n\n\t\tbuf += 20;\n\t}\n\n\t// Check that a valid page mode data length was requested.\n\tu32 len = buf - buf0;\n\tif (!valid_page)\n\t{\n\t\tums->lun.sense_data = SS_INVALID_FIELD_IN_CDB;\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\t//  Store the mode data length.\n\tif (ums->cmnd[0] == SC_MODE_SENSE_6)\n\t\tbuf0[0] = len - 1;\n\telse\n\t\tput_array_le_to_be16(len - 2, buf0);\n\n\treturn len;\n}\n\nstatic int _scsi_start_stop(usbd_gadget_ums_t *ums)\n{\n\tint loej, start;\n\n\tif (!ums->lun.removable)\n\t{\n\t\tums->lun.sense_data = SS_INVALID_COMMAND;\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\telse if ((ums->cmnd[1] & ~0x01) != 0 || // Mask away Immed.\n\t\t(ums->cmnd[4] & ~0x03) != 0)        // Mask LoEj, Start.\n\t{\n\t\tums->lun.sense_data = SS_INVALID_FIELD_IN_CDB;\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\tloej  = ums->cmnd[4] & 0x02;\n\tstart = ums->cmnd[4] & 0x01;\n\n\t// We do not support re-mounting.\n\tif (start)\n\t{\n\t\tif (ums->lun.unmounted)\n\t\t{\n\t\t\tums->lun.sense_data = SS_MEDIUM_NOT_PRESENT;\n\n\t\t\treturn UMS_RES_INVALID_ARG;\n\t\t}\n\n\t\treturn UMS_RES_OK;\n\t}\n\n\t// Check if we are allowed to unload the media.\n\tif (ums->lun.prevent_medium_removal)\n\t{\n\t\tums->set_text(ums->label, \"#C7EA46 Status:# Unload attempt prevented\");\n\t\tums->lun.sense_data = SS_MEDIUM_REMOVAL_PREVENTED;\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\tif (!loej)\n\t\treturn UMS_RES_OK;\n\n\t// Unmount means we exit UMS because of ejection.\n\tums->lun.unmounted = 1;\n\n\treturn UMS_RES_OK;\n}\n\nstatic int _scsi_prevent_allow_removal(usbd_gadget_ums_t *ums)\n{\n\tint prevent;\n\n\tif (!ums->lun.removable)\n\t{\n\t\tums->lun.sense_data = SS_INVALID_COMMAND;\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\tprevent = ums->cmnd[4] & 0x01;\n\tif ((ums->cmnd[4] & ~0x01) != 0) // Mask away Prevent.\n\t{\n\t\tums->lun.sense_data = SS_INVALID_FIELD_IN_CDB;\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\t// Notify for possible unmounting?\n\t// Normally we sync here but we do synced writes to SDMMC.\n\tif (ums->lun.prevent_medium_removal && !prevent) { /* Do nothing */ }\n\n\tums->lun.prevent_medium_removal = prevent;\n\n\treturn UMS_RES_OK;\n}\n\nstatic int _scsi_read_format_capacities(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)\n{\n\tu8 *buf = (u8 *)bulk_ctxt->bulk_in_buf;\n\n\tbuf[0] = buf[1] = buf[2] = 0;\n\tbuf[3] = 8; // Only the Current/Maximum Capacity Descriptor.\n\tbuf += 4;\n\n\tput_array_le_to_be32(ums->lun.num_sectors, &buf[0]); // Number of blocks.\n\tput_array_le_to_be32(UMS_DISK_LBA_SIZE, &buf[4]);    // Block length.\n\tbuf[4] = 0x02; // Current capacity.\n\n\treturn 12;\n}\n\n// Check whether the command is properly formed and whether its data size\n// and direction agree with the values we already have.\nstatic int _check_scsi_cmd(usbd_gadget_ums_t *ums, u32 cmnd_size,\n\t\t\t\t\t\t   enum data_direction data_dir, u32 mask,\n\t\t\t\t\t\t   int needs_medium)\n{\n//const char dirletter[4] = {'u', 'o', 'i', 'n'};\nDPRINTF(\"SCSI command: %X;  Dc=%d, D%c=%X;  Hc=%d, H%c=%X\\n\",\n\t\tums->cmnd[0], cmnd_size, dirletter[(int)ums->data_dir],\n\t\tums->data_size_from_cmnd, ums->cmnd_size,\n\t\tdirletter[(int)data_dir], ums->data_size);\n\n\t// We can't reply if we don't know the direction and size.\n\tif (ums->data_size_from_cmnd == 0)\n\t\tdata_dir = DATA_DIR_NONE;\n\n\t// This is a phase error but we continue and only transfer as much we can.\n\tif (ums->data_size < ums->data_size_from_cmnd)\n\t{\n\t\tums->data_size_from_cmnd = ums->data_size;\n\t\tums->phase_error = 1;\n\t}\n\n\tums->residue = ums->data_size;\n\tums->usb_amount_left = ums->data_size;\n\n\tif (ums->data_dir != data_dir && ums->data_size_from_cmnd > 0)\n\t{\n\t\tums->phase_error = 1;\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\t// Cmd length verification.\n\tif (cmnd_size != ums->cmnd_size)\n\t{\n\n\t\t// Special case workaround for Windows and Xbox 360.\n\t\tif (cmnd_size <= ums->cmnd_size)\n\t\t\tcmnd_size = ums->cmnd_size;\n\t\telse\n\t\t{\n\t\t\tums->phase_error = 1;\n\n\t\t\treturn UMS_RES_INVALID_ARG;\n\t\t}\n\t}\n\n\t// check that LUN ums->cmnd[1] >> 5 is 0 because of only one.\n\n\tif (ums->cmnd[0] != SC_REQUEST_SENSE)\n\t{\n\t\tums->lun.sense_data      = SS_NO_SENSE;\n\t\tums->lun.sense_data_info = 0;\n\t\tums->lun.info_valid      = 0;\n\t}\n\n\t// If a unit attention condition exists, only INQUIRY and REQUEST SENSE\n\t// commands are allowed.\n\tif (ums->lun.unit_attention_data != SS_NO_SENSE && ums->cmnd[0] != SC_INQUIRY &&\n\t\tums->cmnd[0] != SC_REQUEST_SENSE)\n\t{\n\t\tums->lun.sense_data = ums->lun.unit_attention_data;\n\t\tums->lun.unit_attention_data = SS_NO_SENSE;\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\t// Check that only command bytes listed in the mask are set.\n\tums->cmnd[1] &= 0x1F; // Mask away the LUN.\n\tfor (u32 i = 1; i < cmnd_size; ++i)\n\t{\n\t\tif (ums->cmnd[i] && !(mask & BIT(i)))\n\t\t{\n\t\t\tums->lun.sense_data = SS_INVALID_FIELD_IN_CDB;\n\n\t\t\treturn UMS_RES_INVALID_ARG;\n\t\t}\n\t}\n\n\t// If the medium isn't mounted and the command needs to access it, return an error.\n\tif (ums->lun.unmounted && needs_medium)\n\t{\n\t\tums->lun.sense_data = SS_MEDIUM_NOT_PRESENT;\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\treturn UMS_RES_OK;\n}\n\nstatic int _parse_scsi_cmd(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)\n{\n\tu32 len;\n\tint reply = UMS_RES_INVALID_ARG;\n\n\tums->phase_error = 0;\n\tums->short_packet_received = 0;\n\n\tswitch (ums->cmnd[0])\n\t{\n\tcase SC_INQUIRY:\n\t\tums->data_size_from_cmnd = ums->cmnd[4];\n\t\tu32 mask = (1<<4);\n\t\tif (ums->cmnd[1] == 1 && ums->cmnd[2] == 0x80) // Inquiry S/N.\n\t\t\tmask = (1<<1) | (1<<2) | (1<<4);\n\t\treply = _check_scsi_cmd(ums, 6, DATA_DIR_TO_HOST, mask, 0);\n\t\tif (reply == 0)\n\t\t\treply = _scsi_inquiry(ums, bulk_ctxt);\n\t\tbreak;\n\n\tcase SC_LOG_SENSE:\n\t\tums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]);\n\t\treply = _check_scsi_cmd(ums, 10, DATA_DIR_TO_HOST, (1<<1) | (1<<2) | (3<<7), 0);\n\t\tif (reply == 0)\n\t\t\treply = _scsi_log_sense(ums, bulk_ctxt);\n\t\tbreak;\n\n\tcase SC_MODE_SELECT_6:\n\t\tums->data_size_from_cmnd = ums->cmnd[4];\n\t\treply = _check_scsi_cmd(ums, 6, DATA_DIR_FROM_HOST, (1<<1) | (1<<4), 0);\n\t\tif (reply == 0)\n\t\t{\n\t\t\t// We don't support MODE SELECT.\n\t\t\tums->lun.sense_data = SS_INVALID_COMMAND;\n\t\t\treply = UMS_RES_INVALID_ARG;\n\t\t}\n\t\tbreak;\n\n\tcase SC_MODE_SELECT_10:\n\t\tums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]);\n\t\treply = _check_scsi_cmd(ums, 10, DATA_DIR_FROM_HOST, (1<<1) | (3<<7), 0);\n\t\tif (reply == 0)\n\t\t{\n\t\t\t// We don't support MODE SELECT.\n\t\t\tums->lun.sense_data = SS_INVALID_COMMAND;\n\t\t\treply = UMS_RES_INVALID_ARG;\n\t\t}\n\t\tbreak;\n\n\tcase SC_MODE_SENSE_6:\n\t\tums->data_size_from_cmnd = ums->cmnd[4];\n\t\treply = _check_scsi_cmd(ums, 6, DATA_DIR_TO_HOST,  (1<<1) | (1<<2) | (1<<4), 0);\n\t\tif (reply == 0)\n\t\t\treply = _scsi_mode_sense(ums, bulk_ctxt);\n\t\tbreak;\n\n\tcase SC_MODE_SENSE_10:\n\t\tums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]);\n\t\treply = _check_scsi_cmd(ums, 10, DATA_DIR_TO_HOST, (1<<1) | (1<<2) | (3<<7), 0);\n\t\tif (reply == 0)\n\t\t\treply = _scsi_mode_sense(ums, bulk_ctxt);\n\t\tbreak;\n\n\tcase SC_PREVENT_ALLOW_MEDIUM_REMOVAL:\n\t\tums->data_size_from_cmnd = 0;\n\t\treply = _check_scsi_cmd(ums, 6, DATA_DIR_NONE, (1<<4), 0);\n\t\tif (reply == 0)\n\t\t\treply = _scsi_prevent_allow_removal(ums);\n\t\tbreak;\n\n\tcase SC_READ_6:\n\t\tlen = ums->cmnd[4];\n\t\tums->data_size_from_cmnd = (len == 0 ? 256 : len) << UMS_DISK_LBA_SHIFT;\n\t\treply = _check_scsi_cmd(ums, 6, DATA_DIR_TO_HOST, (7<<1) | (1<<4), 1);\n\t\tif (reply == 0)\n\t\t\treply = _scsi_read(ums, bulk_ctxt);\n\t\tbreak;\n\n\tcase SC_READ_10:\n\t\tums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]) << UMS_DISK_LBA_SHIFT;\n\t\treply = _check_scsi_cmd(ums, 10, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (3<<7), 1);\n\t\tif (reply == 0)\n\t\t\treply = _scsi_read(ums, bulk_ctxt);\n\t\tbreak;\n\n\tcase SC_READ_12:\n\t\tums->data_size_from_cmnd = get_array_be_to_le32(&ums->cmnd[6]) << UMS_DISK_LBA_SHIFT;\n\t\treply = _check_scsi_cmd(ums, 12, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1);\n\t\tif (reply == 0)\n\t\t\treply = _scsi_read(ums, bulk_ctxt);\n\t\tbreak;\n\n\tcase SC_READ_CAPACITY:\n\t\tums->data_size_from_cmnd = 8;\n\t\treply = _check_scsi_cmd(ums, 10, DATA_DIR_TO_HOST, (0xf<<2) | (1<<8), 1);\n\t\tif (reply == 0)\n\t\t\treply = _scsi_read_capacity(ums, bulk_ctxt);\n\t\tbreak;\n\tcase SC_READ_FORMAT_CAPACITIES:\n\t\tums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]);\n\t\treply = _check_scsi_cmd(ums, 10, DATA_DIR_TO_HOST, (3<<7), 1);\n\t\tif (reply == 0)\n\t\t\treply = _scsi_read_format_capacities(ums, bulk_ctxt);\n\t\tbreak;\n\n\tcase SC_REQUEST_SENSE:\n\t\tums->data_size_from_cmnd = ums->cmnd[4];\n\t\treply = _check_scsi_cmd(ums, 6, DATA_DIR_TO_HOST, (1<<4), 0);\n\t\tif (reply == 0)\n\t\t\treply = _scsi_request_sense(ums, bulk_ctxt);\n\t\tbreak;\n\n\tcase SC_START_STOP_UNIT:\n\t\tums->data_size_from_cmnd = 0;\n\t\treply = _check_scsi_cmd(ums, 6, DATA_DIR_NONE, (1<<1) | (1<<4), 0);\n\t\tif (reply == 0)\n\t\t\treply = _scsi_start_stop(ums);\n\t\tbreak;\n\n\tcase SC_SYNCHRONIZE_CACHE:\n\t\tums->data_size_from_cmnd = 0;\n\t\treply = _check_scsi_cmd(ums, 10, DATA_DIR_NONE, (0xf<<2) | (3<<7), 1);\n\t\tif (reply == 0)\n\t\t\treply = 0; // Don't bother\n\t\tbreak;\n\n\tcase SC_TEST_UNIT_READY:\n\t\tums->data_size_from_cmnd = 0;\n\t\treply = _check_scsi_cmd(ums, 6, DATA_DIR_NONE, 0, 1);\n\t\tbreak;\n\n\t// This command is used by Windows. We support a minimal version and BytChk must be 0.\n\tcase SC_VERIFY:\n\t\tums->data_size_from_cmnd = 0;\n\t\treply = _check_scsi_cmd(ums, 10, DATA_DIR_NONE, (1<<1) | (0xf<<2) | (3<<7), 1);\n\t\tif (reply == 0)\n\t\t\treply = _scsi_verify(ums, bulk_ctxt);\n\t\tbreak;\n\n\tcase SC_WRITE_6:\n\t\tlen = ums->cmnd[4];\n\t\tums->data_size_from_cmnd = (len == 0 ? 256 : len) << UMS_DISK_LBA_SHIFT;\n\t\treply = _check_scsi_cmd(ums, 6, DATA_DIR_FROM_HOST, (7<<1) | (1<<4), 1);\n\t\tif (reply == 0)\n\t\t\treply = _scsi_write(ums, bulk_ctxt);\n\t\tbreak;\n\n\tcase SC_WRITE_10:\n\t\tums->data_size_from_cmnd = get_array_be_to_le16(&ums->cmnd[7]) << UMS_DISK_LBA_SHIFT;\n\t\treply = _check_scsi_cmd(ums, 10, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (3<<7), 1);\n\t\tif (reply == 0)\n\t\t\treply = _scsi_write(ums, bulk_ctxt);\n\t\tbreak;\n\n\tcase SC_WRITE_12:\n\t\tums->data_size_from_cmnd = get_array_be_to_le32(&ums->cmnd[6]) << UMS_DISK_LBA_SHIFT;\n\t\treply = _check_scsi_cmd(ums, 12, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1);\n\t\tif (reply == 0)\n\t\t\treply = _scsi_write(ums, bulk_ctxt);\n\t\tbreak;\n\n\t// Mandatory commands that we don't implement. No need.\n\tcase SC_READ_HEADER:\n\tcase SC_READ_TOC:\n\tcase SC_FORMAT_UNIT:\n\tcase SC_RELEASE:\n\tcase SC_RESERVE:\n\tcase SC_SEND_DIAGNOSTIC:\n\tdefault:\n\t\tums->data_size_from_cmnd = 0;\n\t\treply = _check_scsi_cmd(ums, ums->cmnd_size, DATA_DIR_UNKNOWN, 0xFF, 0);\n\t\tif (reply == 0)\n\t\t{\n\t\t\tums->lun.sense_data = SS_INVALID_COMMAND;\n\t\t\treply = UMS_RES_INVALID_ARG;\n\t\t}\n\t\tbreak;\n\t}\n\n\tif (reply == UMS_RES_INVALID_ARG)\n\t\treply = 0;    // Error reply length.\n\n\t// Set up reply buffer for _finish_reply(). Otherwise it's already set.\n\tif (reply >= 0 && ums->data_dir == DATA_DIR_TO_HOST)\n\t{\n\t\treply = MIN((u32)reply, ums->data_size_from_cmnd);\n\t\tbulk_ctxt->bulk_in_length = reply;\n\t\tbulk_ctxt->bulk_in_buf_state = BUF_STATE_FULL;\n\t\tums->residue -= reply;\n\t}\n\n\treturn UMS_RES_OK;\n}\n\nstatic int _pad_with_zeros(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)\n{\n\tbulk_ctxt->bulk_in_buf_state = BUF_STATE_EMPTY; // For the first iteration.\n\tu32 current_len_to_keep = bulk_ctxt->bulk_in_length;\n\tums->usb_amount_left = current_len_to_keep + ums->residue;\n\n\twhile (ums->usb_amount_left > 0)\n\t{\n\t\tu32 nsend = MIN(ums->usb_amount_left, USB_EP_BUFFER_MAX_SIZE);\n\t\tmemset(bulk_ctxt->bulk_in_buf + current_len_to_keep, 0, nsend - current_len_to_keep);\n\t\tbulk_ctxt->bulk_in_length = nsend;\n\t\t_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED_DATA);\n\t\tums->usb_amount_left -= nsend;\n\t\tcurrent_len_to_keep = 0;\n\t}\n\n\treturn UMS_RES_OK;\n}\n\nstatic int _throw_away_data(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)\n{\n\tif (bulk_ctxt->bulk_out_buf_state != BUF_STATE_EMPTY || ums->usb_amount_left > 0)\n\t{\n\t\t// Try to submit another request if we need one.\n\t\tif (bulk_ctxt->bulk_out_buf_state == BUF_STATE_EMPTY && ums->usb_amount_left > 0)\n\t\t{\n\t\t\tu32 amount = MIN(ums->usb_amount_left, USB_EP_BUFFER_MAX_SIZE);\n\n\t\t\tbulk_ctxt->bulk_out_length = amount;\n\t\t\t_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_out, USB_XFER_SYNCED_DATA);\n\t\t\tums->usb_amount_left -= amount;\n\n\t\t\treturn UMS_RES_OK;\n\t\t}\n\n\t\t// Throw away the data in a filled buffer.\n\t\tif (bulk_ctxt->bulk_out_buf_state == BUF_STATE_FULL)\n\t\t\tbulk_ctxt->bulk_out_buf_state = BUF_STATE_EMPTY;\n\n\t\t// A short packet or an error ends everything.\n\t\tif (bulk_ctxt->bulk_out_length_actual != bulk_ctxt->bulk_out_length ||\n\t\t\tbulk_ctxt->bulk_out_status != USB_RES_OK)\n\t\t{\n\t\t\traise_exception(ums, UMS_STATE_ABORT_BULK_OUT);\n\t\t\treturn UMS_RES_PROT_FATAL;\n\t\t}\n\t}\n\treturn UMS_RES_OK;\n}\n\nstatic int _finish_reply(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)\n{\n\tint rc = UMS_RES_OK;\n\n\tswitch (ums->data_dir) {\n\tcase DATA_DIR_NONE:\n\t\tbreak; // Nothing to send.\n\n\t// If this is a CB or CBI with an unknown command, we mustn't\n\t// try to send or receive any data. Stall if we can and wait reset.\n\tcase DATA_DIR_UNKNOWN:\n\t\tif (ums->can_stall)\n\t\t{\n\t\t\t_set_ep_stall(bulk_ctxt->bulk_out);\n\t\t\trc = _set_ep_stall(bulk_ctxt->bulk_in);\n\t\t\tums->set_text(ums->label, \"#FFDD00 Error:# Direction unknown. Stalled both EP!\");\n\t\t} // Else do nothing.\n\t\tbreak;\n\n\t// All but the last buffer of data have already been sent.\n\tcase DATA_DIR_TO_HOST:\n\t\tif (ums->data_size)\n\t\t{\n\t\t\t// If there's no residue, simply send the last buffer.\n\t\t\tif (!ums->residue)\n\t\t\t{\n\t\t\t\t_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED_DATA);\n\n\t\t\t/* For Bulk-only, if we're allowed to stall then send the\n\t\t\t * short packet and halt the bulk-in endpoint.  If we can't\n\t\t\t * stall, pad out the remaining data with 0's. */\n\t\t\t}\n\t\t\telse if (ums->can_stall)\n\t\t\t{\n\t\t\t\t_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED_DATA);\n\t\t\t\trc = _set_ep_stall(bulk_ctxt->bulk_in);\n\t\t\t\tums->set_text(ums->label, \"#FFDD00 Error:# Residue. Stalled EP IN!\");\n\t\t\t}\n\t\t\telse\n\t\t\t\trc = _pad_with_zeros(ums, bulk_ctxt);\n\t\t}\n\n\t\t// In case we used SDMMC transfer, reset the buffer address.\n\t\t_reset_buffer(bulk_ctxt, bulk_ctxt->bulk_in);\n\t\tbreak;\n\n\t// We have processed all we want from the data the host has sent.\n\t// There may still be outstanding bulk-out requests.\n\tcase DATA_DIR_FROM_HOST:\n\t\tif (ums->residue)\n\t\t{\n\t\t\tif (ums->short_packet_received) // Did the host stop sending unexpectedly early?\n\t\t\t{\n\t\t\t\traise_exception(ums, UMS_STATE_ABORT_BULK_OUT);\n\t\t\t\trc = UMS_RES_PROT_FATAL;\n\t\t\t}\n\t\t\telse // We can't stall. Read in the excess data and throw it away.\n\t\t\t\trc = _throw_away_data(ums, bulk_ctxt);\n\t\t}\n\n\t\tbreak;\n\t}\n\n\treturn rc;\n}\n\n/*\n * Medium ejection heuristics.\n *\n * Windows:\n * Uses Start/Stop Unit. Only Stop with LoEj. Observed ONLY on very specific windows machines.\n * Uses Prevent/Allow Medium Removal. (For big reads and ANY write.) //////Except trivial writes. Needs check with prefetch ON\n * Sends Test Unit Ready every 1s at idle. (Needs 1 EP Timeout protection: 2s)\n * Does not send data when ejects. In the case it does,\n *  it loops into Request Sense and Test Unit Ready when ejects.\n * Line always at SE0 and only goes in J-State when it ejects.\n *\n * Linux:\n * Uses Start/Stop Unit. Stops with LoEj when Media prevention is off.\n * Uses Prevent/Allow Medium Removal. (For big read and any write.)\n * Sends Test Unit Ready every 2s at idle. (Needs 2 EP Timeouts protection: 4s)\n * Loops into Request Sense and Test Unit Ready when ejects.\n * Line always at SE0.\n *\n * Mac OS:\n * Uses Start/Stop. Stops with LoEj when Allow Medium Removal is enabled.\n * Uses Prevent/Allow Medium Removal. (Properly. Enables at mount and only disables it when ejects.)\n * Does not send Test Unit Ready at idle. But Prevent Medium Removal is enabled.\n * Loops into Request Sense and Test Unit Ready when ejects.\n * Line always at SE0.\n */\n\nstatic int _received_cbw(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)\n{\n\t// Was this a real packet?  Should it be ignored?\n\tif (bulk_ctxt->bulk_out_status || bulk_ctxt->bulk_out_ignore || ums->lun.unmounted)\n\t{\n\t\tif (bulk_ctxt->bulk_out_status || ums->lun.unmounted)\n\t\t{\n\t\t\tDPRINTF(\"USB: EP timeout (%d)\\n\", bulk_ctxt->bulk_out_status);\n\t\t\t// In case we disconnected, exit UMS.\n\t\t\t// Raise timeout if removable and didn't got a unit ready command inside 4s.\n\t\t\tif (bulk_ctxt->bulk_out_status == USB2_ERROR_XFER_EP_DISABLED ||\n\t\t\t\t(bulk_ctxt->bulk_out_status == USB_ERROR_TIMEOUT && ums->lun.removable && !ums->lun.prevent_medium_removal))\n\t\t\t{\n\t\t\t\tif (bulk_ctxt->bulk_out_status == USB_ERROR_TIMEOUT)\n\t\t\t\t{\n\t\t\t\t\tif (usb_ops.usb_device_get_port_in_sleep())\n\t\t\t\t\t{\n\t\t\t\t\t\tums->set_text(ums->label, \"#C7EA46 Status:# EP in sleep\");\n\t\t\t\t\t\tums->timeouts += 14;\n\t\t\t\t\t}\n\t\t\t\t\telse if (!ums->xusb) // Timeout only on USB2.\n\t\t\t\t\t{\n\t\t\t\t\t\tums->timeouts += 4;\n\t\t\t\t\t\tDPRINTF(\"USB: EP removable\\n\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tgfx_printf(\"USB: EP disabled\\n\");\n\t\t\t\t\tmsleep(500);\n\t\t\t\t\tums->timeouts += 4;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (ums->lun.unmounted)\n\t\t\t{\n\t\t\t\tums->set_text(ums->label, \"#C7EA46 Status:# Medium unmounted\");\n\t\t\t\tums->timeouts++;\n\t\t\t\tif (!bulk_ctxt->bulk_out_status)\n\t\t\t\t\tums->timeouts += 3;\n\t\t\t}\n\n\t\t\tif (ums->timeouts > 20)\n\t\t\t\traise_exception(ums, UMS_STATE_EXIT);\n\t\t}\n\n\t\tif (bulk_ctxt->bulk_out_status || bulk_ctxt->bulk_out_ignore)\n\t\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\t// Clear request flag to allow a new one to be queued.\n\tums->cbw_req_queued = false;\n\n\t// Is the CBW valid?\n\tbulk_recv_pkt_t *cbw = (bulk_recv_pkt_t *)bulk_ctxt->bulk_out_buf;\n\tif (bulk_ctxt->bulk_out_length_actual != USB_BULK_CB_WRAP_LEN || cbw->Signature != USB_BULK_CB_SIG)\n\t{\n\t\tgfx_printf(\"USB: invalid CBW: len %X sig 0x%X\\n\", bulk_ctxt->bulk_out_length_actual, cbw->Signature);\n\n\t\t/*\n\t\t * The Bulk-only spec says we MUST stall the IN endpoint\n\t\t * (6.6.1), so it's unavoidable.  It also says we must\n\t\t * retain this state until the next reset, but there's\n\t\t * no way to tell the controller driver it should ignore\n\t\t * Clear-Feature(HALT) requests.\n\t\t *\n\t\t * We aren't required to halt the OUT endpoint; instead\n\t\t * we can simply accept and discard any data received\n\t\t * until the next reset.\n\t\t */\n\t\t_wedge_bulk_in_endpoint(ums);\n\t\tbulk_ctxt->bulk_out_ignore = 1;\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\t// Is the CBW meaningful?\n\tif (cbw->Lun >= UMS_MAX_LUN || cbw->Flags & ~USB_BULK_IN_FLAG ||\n\t\t\tcbw->Length == 0 || cbw->Length > SCSI_MAX_CMD_SZ)\n\t{\n\t\tgfx_printf(\"USB: non-meaningful CBW: lun = %X, flags = 0x%X, cmdlen %X\\n\",\n\t\t\tcbw->Lun, cbw->Flags, cbw->Length);\n\n\t\t/* We can do anything we want here, so let's stall the\n\t\t * bulk pipes if we are allowed to. */\n\t\tif (ums->can_stall)\n\t\t{\n\t\t\t_set_ep_stall(bulk_ctxt->bulk_out);\n\t\t\t_set_ep_stall(bulk_ctxt->bulk_in);\n\t\t\tums->set_text(ums->label, \"#FFDD00 Error:# CBW unknown - Stalled both EP!\");\n\t\t}\n\n\t\treturn UMS_RES_INVALID_ARG;\n\t}\n\n\t// Save the command for later.\n\tums->cmnd_size = cbw->Length;\n\tmemcpy(ums->cmnd, cbw->CDB, ums->cmnd_size);\n\n\tif (cbw->Flags & USB_BULK_IN_FLAG)\n\t\tums->data_dir = DATA_DIR_TO_HOST;\n\telse\n\t\tums->data_dir = DATA_DIR_FROM_HOST;\n\n\tums->data_size = cbw->DataTransferLength;\n\n\tif (ums->data_size == 0)\n\t\tums->data_dir = DATA_DIR_NONE;\n\n\tums->lun_idx = cbw->Lun;\n\tums->tag = cbw->Tag;\n\n\tif (!ums->lun.unmounted)\n\t\tums->timeouts = 0;\n\n\treturn UMS_RES_OK;\n}\n\nstatic int _get_next_command(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)\n{\n\tint rc = UMS_RES_OK;\n\n\t/* Wait for the next buffer to become available */\n\t// while (bulk_ctxt->bulk_out_buf_state != BUF_STATE_EMPTY)\n\t// {\n\t// \t//wait irq.\n\t// }\n\n\tbulk_ctxt->bulk_out_length = USB_BULK_CB_WRAP_LEN;\n\n\t// Queue a request to read a Bulk-only CBW.\n\tif (!ums->cbw_req_queued)\n\t\t_transfer_start(ums,  bulk_ctxt, bulk_ctxt->bulk_out, USB_XFER_SYNCED_CMD);\n\telse\n\t\t_transfer_finish(ums, bulk_ctxt, bulk_ctxt->bulk_out, USB_XFER_SYNCED_CMD);\n\n\t/*\n\t * On XUSB do not allow multiple requests for CBW to be done.\n\t * This avoids an issue with some XHCI controllers and OS combos (e.g. ASMedia and Linux/Mac OS)\n\t * which confuse that and concatenate an old CBW request with another write request (SCSI Write)\n\t * and create a babble error (transmit overflow).\n\t */\n\tif (ums->xusb)\n\t\tums->cbw_req_queued = true;\n\n\t/* We will drain the buffer in software, which means we\n\t * can reuse it for the next filling.  No need to advance\n\t * next_buffhd_to_fill. */\n\n\t/* Wait for the CBW to arrive */\n\t// while (bulk_ctxt->bulk_out_buf_state != BUF_STATE_FULL)\n\t// {\n\t// \t//wait irq.\n\t// }\n\n\trc = _received_cbw(ums, bulk_ctxt);\n\tbulk_ctxt->bulk_out_buf_state = BUF_STATE_EMPTY;\n\n\treturn rc;\n}\n\nstatic void _send_status(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)\n{\n\tu8  status = USB_STATUS_PASS;\n\tu32 sd = ums->lun.sense_data;\n\n\tif (ums->phase_error)\n\t{\n\t\tums->set_text(ums->label, \"#FFDD00 Error:# Phase-error!\");\n\t\tstatus = USB_STATUS_PHASE_ERROR;\n\t\tsd = SS_INVALID_COMMAND;\n\t}\n\telse if (sd != SS_NO_SENSE)\n\t{\n\t\tDPRINTF(\"USB: CMD fail\\n\");\n\t\tstatus = USB_STATUS_FAIL;\n\t\tDPRINTF(\"USB:   Sense: SK x%02X, ASC x%02X, ASCQ x%02X; info x%X\\n\",\n\t\t\tSK(sd), ASC(sd), ASCQ(sd), ums->lun.sense_data_info);\n\t}\n\n\t// Store and send the Bulk-only CSW.\n\tbulk_send_pkt_t *csw = (bulk_send_pkt_t *)bulk_ctxt->bulk_in_buf;\n\n\tcsw->Signature = USB_BULK_CS_SIG;\n\tcsw->Tag       = ums->tag;\n\tcsw->Residue   = ums->residue;\n\tcsw->Status    = status;\n\n\tbulk_ctxt->bulk_in_length = USB_BULK_CS_WRAP_LEN;\n\t_transfer_start(ums, bulk_ctxt, bulk_ctxt->bulk_in, USB_XFER_SYNCED_CMD);\n}\n\nstatic void _handle_exception(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)\n{\n\tenum ums_state old_state;\n\n\t// Clear out the controller's fifos.\n\t_flush_endpoint(bulk_ctxt->bulk_in);\n\t_flush_endpoint(bulk_ctxt->bulk_out);\n\n\t/* Reset the I/O buffer states and pointers, the SCSI\n\t * state, and the exception.  Then invoke the handler. */\n\n\tbulk_ctxt->bulk_in_buf_state  = BUF_STATE_EMPTY;\n\tbulk_ctxt->bulk_out_buf_state = BUF_STATE_EMPTY;\n\n\told_state = ums->state;\n\n\tif (old_state != UMS_STATE_ABORT_BULK_OUT)\n\t{\n\t\tums->lun.prevent_medium_removal = 0;\n\t\tums->lun.sense_data             = SS_NO_SENSE;\n\t\tums->lun.unit_attention_data    = SS_NO_SENSE;\n\t\tums->lun.sense_data_info        = 0;\n\t\tums->lun.info_valid             = 0;\n\t}\n\n\tums->state = UMS_STATE_NORMAL;\n\n\t// Carry out any extra actions required for the exception.\n\tswitch (old_state)\n\t{\n\tcase UMS_STATE_NORMAL:\n\t\tbreak;\n\tcase UMS_STATE_ABORT_BULK_OUT:\n\t\t_send_status(ums, bulk_ctxt);\n\t\tbreak;\n\n\tcase UMS_STATE_PROTOCOL_RESET:\n\t\t/* In case we were forced against our will to halt a\n\t\t * bulk endpoint, clear the halt now.  (The SuperH UDC\n\t\t * requires this.) */\n\t\tif (bulk_ctxt->bulk_out_ignore)\n\t\t{\n\t\t\tbulk_ctxt->bulk_out_ignore = 0;\n\t\t\t_clear_ep_stall(bulk_ctxt->bulk_in);\n\t\t}\n\t\tums->lun.unit_attention_data = SS_RESET_OCCURRED;\n\t\tbreak;\n\n\tcase UMS_STATE_EXIT:\n\t\tums->state = UMS_STATE_TERMINATED;\t// Stop the thread.\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n}\n\nstatic inline void _system_maintainance(usbd_gadget_ums_t *ums)\n{\n\tstatic u32 timer_dram = 0;\n\tstatic u32 timer_status_bar = 0;\n\n\tu32 time = get_tmr_ms();\n\n\tif (timer_status_bar < time)\n\t{\n\t\tums->system_maintenance(true);\n\t\ttimer_status_bar = get_tmr_ms() + 30000;\n\t}\n\telse if (timer_dram < time)\n\t{\n\t\tminerva_periodic_training();\n\t\ttimer_dram = get_tmr_ms() + EMC_PERIODIC_TRAIN_MS;\n\t}\n}\n\nint usb_device_gadget_ums(usb_ctxt_t *usbs)\n{\n\tint res = 0;\n\tusbd_gadget_ums_t ums = {0};\n\n\t// Get USB Controller ops.\n\tif (hw_get_chip_id() == GP_HIDREV_MAJOR_T210)\n\t\tusb_device_get_ops(&usb_ops);\n\telse\n\t{\n\t\tums.xusb = true;\n\t\txusb_device_get_ops(&usb_ops);\n\t}\n\n\tusbs->set_text(usbs->label, \"#C7EA46 Status:# Started USB\");\n\n\tif (usb_ops.usb_device_init())\n\t{\n\t\tusb_ops.usbd_end(false, true);\n\t\treturn 1;\n\t}\n\n\tums.state = UMS_STATE_NORMAL;\n\tums.can_stall = 0;\n\n\tums.bulk_ctxt.bulk_in     = USB_EP_BULK_IN;\n\tums.bulk_ctxt.bulk_in_buf = (u8 *)USB_EP_BULK_IN_BUF_ADDR;\n\n\tums.bulk_ctxt.bulk_out     = USB_EP_BULK_OUT;\n\tums.bulk_ctxt.bulk_out_buf = (u8 *)USB_EP_BULK_OUT_BUF_ADDR;\n\n\t// Set LUN parameters.\n\tums.lun.ro          = usbs->ro;\n\tums.lun.type        = usbs->type;\n\tums.lun.partition   = usbs->partition;\n\tums.lun.num_sectors = usbs->sectors;\n\tums.lun.offset      = usbs->offset;\n\tums.lun.removable = 1; // Always removable to force OSes to use prevent media removal.\n\tums.lun.unit_attention_data = SS_RESET_OCCURRED;\n\n\t// Set system functions\n\tums.label = usbs->label;\n\tums.set_text = usbs->set_text;\n\tums.system_maintenance = usbs->system_maintenance;\n\n\tums.set_text(ums.label, \"#C7EA46 Status:# Mounting disk\");\n\n\t// Initialize sdmmc.\n\tif (usbs->type == MMC_SD)\n\t{\n\t\tsd_end();\n\t\tif (sd_mount())\n\t\t{\n\t\t\tums.set_text(ums.label, \"#FFDD00 Failed to init SD!#\");\n\t\t\tres = 1;\n\t\t\tgoto init_fail;\n\t\t}\n\t\tsd_unmount();\n\n\t\tums.lun.sdmmc   = &sd_sdmmc;\n\t\tums.lun.storage = &sd_storage;\n\t}\n\telse\n\t{\n\t\tif (emmc_initialize(false))\n\t\t{\n\t\t\tums.set_text(ums.label, \"#FFDD00 Failed to init eMMC!#\");\n\t\t\tres = 1;\n\t\t\tgoto init_fail;\n\t\t}\n\t\temmc_set_partition(ums.lun.partition - 1);\n\n\t\tums.lun.sdmmc   = &emmc_sdmmc;\n\t\tums.lun.storage = &emmc_storage;\n\t}\n\n\tums.set_text(ums.label, \"#C7EA46 Status:# Waiting for connection\");\n\n\t// Initialize Control Endpoint.\n\tif (usb_ops.usb_device_enumerate(USB_GADGET_UMS))\n\t\tgoto usb_enum_error;\n\n\tums.set_text(ums.label, \"#C7EA46 Status:# Waiting for LUN\");\n\n\tif (usb_ops.usb_device_class_send_max_lun(0)) // One device for now.\n\t\tgoto usb_enum_error;\n\n\tums.set_text(ums.label, \"#C7EA46 Status:# Started UMS\");\n\n\t// If partition sectors are not set get them from hardware.\n\tif (!ums.lun.num_sectors)\n\t{\n\t\tif (usbs->type == MMC_EMMC && (ums.lun.partition - 1)) // eMMC BOOT0/1.\n\t\t\tums.lun.num_sectors = emmc_storage.ext_csd.boot_mult << 8;\n\t\telse\n\t\t\tums.lun.num_sectors = ums.lun.storage->sec_cnt;   // eMMC GPP or SD.\n\t}\n\n\tdo\n\t{\n\t\t// Do DRAM training and update system tasks.\n\t\t_system_maintainance(&ums);\n\n\t\t// Check for force unmount button combo.\n\t\tif (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))\n\t\t{\n\t\t\t// Check if we are allowed to unload the media.\n\t\t\tif (ums.lun.prevent_medium_removal)\n\t\t\t\tums.set_text(ums.label, \"#C7EA46 Status:# Unload attempt prevented\");\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif (ums.state != UMS_STATE_NORMAL)\n\t\t{\n\t\t\t_handle_exception(&ums, &ums.bulk_ctxt);\n\t\t\tcontinue;\n\t\t}\n\n\t\t_handle_ep0_ctrl(&ums);\n\n\t\tif (_get_next_command(&ums, &ums.bulk_ctxt) || (ums.state > UMS_STATE_NORMAL))\n\t\t\tcontinue;\n\n\t\t_handle_ep0_ctrl(&ums);\n\n\t\t_parse_scsi_cmd(&ums, &ums.bulk_ctxt);\n\n\t\tif (ums.state > UMS_STATE_NORMAL)\n\t\t\tcontinue;\n\n\t\t_handle_ep0_ctrl(&ums);\n\n\t\tif (_finish_reply(&ums, &ums.bulk_ctxt) || (ums.state > UMS_STATE_NORMAL))\n\t\t\tcontinue;\n\n\t\t_send_status(&ums, &ums.bulk_ctxt);\n\t} while (ums.state != UMS_STATE_TERMINATED);\n\n\tif (ums.lun.prevent_medium_removal)\n\t\tums.set_text(ums.label, \"#FFDD00 Error:# Disk unsafely ejected\");\n\telse\n\t\tums.set_text(ums.label, \"#C7EA46 Status:# Disk ejected\");\n\tgoto exit;\n\nusb_enum_error:\n\tums.set_text(ums.label, \"#FFDD00 Error:# Timed out or canceled!\");\n\tres = 1;\n\nexit:\n\tif (ums.lun.type == MMC_EMMC)\n\t\temmc_end();\n\ninit_fail:\n\tusb_ops.usbd_end(true, false);\n\n\treturn res;\n}\n"
  },
  {
    "path": "bdk/usb/usb_t210.h",
    "content": "/*\n * Enhanced & eXtensible USB device (EDCI & XDCI) driver for Tegra X1\n *\n * Copyright (c) 2019-2021 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _USB_T210_H_\n#define _USB_T210_H_\n\n#include <utils/types.h>\n\n/* EHCI USB */\n\n/* General USB registers */\n#define USB1_IF_USB_SUSP_CTRL         0x400\n#define  SUSP_CTRL_USB_WAKE_ON_CNNT_EN_DEV   BIT(3)\n#define  SUSP_CTRL_USB_WAKE_ON_DISCON_EN_DEV BIT(4)\n#define  SUSP_CTRL_USB_PHY_CLK_VALID         BIT(7)\n#define  SUSP_CTRL_UTMIP_RESET               BIT(11)\n#define  SUSP_CTRL_UTMIP_PHY_ENB             BIT(12)\n#define  SUSP_CTRL_UTMIP_UTMIP_SUSPL1_SET    BIT(25)\n#define USB1_IF_USB_PHY_VBUS_SENSORS  0x404\n#define USB1_UTMIP_XCVR_CFG0          0x808\n#define USB1_UTMIP_BIAS_CFG0          0x80C\n#define USB1_UTMIP_HSRX_CFG0          0x810\n#define USB1_UTMIP_HSRX_CFG1          0x814\n#define USB1_UTMIP_TX_CFG0            0x820\n#define USB1_UTMIP_MISC_CFG1          0x828\n#define USB1_UTMIP_DEBOUNCE_CFG0      0x82C\n#define USB1_UTMIP_BAT_CHRG_CFG0      0x830\n#define  BAT_CHRG_CFG0_PWRDOWN_CHRG          BIT(0)\n#define  BAT_CHRG_CFG0_OP_SRC_EN             BIT(3)\n#define USB1_UTMIP_SPARE_CFG0         0x834\n#define USB1_UTMIP_XCVR_CFG1          0x838\n#define USB1_UTMIP_BIAS_CFG1          0x83C\n#define USB1_UTMIP_BIAS_CFG2          0x850\n#define USB1_UTMIP_XCVR_CFG2          0x854\n#define USB1_UTMIP_XCVR_CFG3          0x858\n\n/* USB Queue Head Descriptor */\n#define USB2_QH_USB2D_QH_EP_BASE      (USB_BASE + 0x1000)\n#define  USB_QHD_EP_CAP_IOS_ENABLE        BIT(15)\n#define  USB_QHD_EP_CAP_MAX_PKT_LEN_MASK  0x7FF\n#define  USB_QHD_EP_CAP_ZERO_LEN_TERM_DIS BIT(29)\n#define  USB_QHD_EP_CAP_MULTI_NON_ISO     (0 << 30)\n#define  USB_QHD_EP_CAP_MULTI_1           (1 << 30)\n#define  USB_QHD_EP_CAP_MULTI_2           (2 << 30)\n#define  USB_QHD_EP_CAP_MULTI_3           (3 << 30)\n\n#define  USB_QHD_TOKEN_XFER_ERROR         BIT(3)\n#define  USB_QHD_TOKEN_BUFFER_ERROR       BIT(5)\n#define  USB_QHD_TOKEN_HALTED             BIT(6)\n#define  USB_QHD_TOKEN_ACTIVE             BIT(7)\n#define  USB_QHD_TOKEN_MULT_OVERR_MASK    (2 << 10)\n#define  USB_QHD_TOKEN_IRQ_ON_COMPLETE    BIT(15)\n#define  USB_QHD_TOKEN_TOTAL_BYTES_SHIFT  16\n\n/* USB_OTG/USB_1 controllers register bits */\n#define USB2D_PORTSC1_SUSP BIT(7)\n\n#define USB2D_USBCMD_RUN      BIT(0)\n#define USB2D_USBCMD_RESET    BIT(1)\n#define USB2D_USBCMD_ITC_MASK (0xFF << 16)\n\n#define USB2D_USBSTS_UI  BIT(0)\n#define USB2D_USBSTS_UEI BIT(1)\n#define USB2D_USBSTS_PCI BIT(2)\n#define USB2D_USBSTS_FRI BIT(3)\n#define USB2D_USBSTS_SEI BIT(4)\n#define USB2D_USBSTS_AAI BIT(5)\n#define USB2D_USBSTS_URI BIT(6)\n#define USB2D_USBSTS_SRI BIT(7)\n#define USB2D_USBSTS_SLI BIT(8)\n\n#define USB2D_USBMODE_CM_MASK   (3 << 0)\n#define USB2D_USBMODE_CM_IDLE   0\n#define USB2D_USBMODE_CM_RSVD   1\n#define USB2D_USBMODE_CM_DEVICE 2\n#define USB2D_USBMODE_CM_HOST   3\n\n#define USB2D_ENDPT_STATUS_RX_OFFSET BIT(0)\n#define USB2D_ENDPT_STATUS_TX_OFFSET BIT(16)\n\n#define USB2D_ENDPTCTRL_RX_EP_STALL     BIT(0)\n#define USB2D_ENDPTCTRL_RX_EP_TYPE_CTRL (0 << 2)\n#define USB2D_ENDPTCTRL_RX_EP_TYPE_ISO  (1 << 2)\n#define USB2D_ENDPTCTRL_RX_EP_TYPE_BULK (2 << 2)\n#define USB2D_ENDPTCTRL_RX_EP_TYPE_INTR (3 << 2)\n#define USB2D_ENDPTCTRL_RX_EP_TYPE_MASK (3 << 2)\n#define USB2D_ENDPTCTRL_RX_EP_INHIBIT   BIT(5)\n#define USB2D_ENDPTCTRL_RX_EP_RESET     BIT(6)\n#define USB2D_ENDPTCTRL_RX_EP_ENABLE    BIT(7)\n#define USB2D_ENDPTCTRL_TX_EP_STALL     BIT(16)\n#define USB2D_ENDPTCTRL_TX_EP_TYPE_CTRL (0 << 18)\n#define USB2D_ENDPTCTRL_TX_EP_TYPE_ISO  (1 << 18)\n#define USB2D_ENDPTCTRL_TX_EP_TYPE_BULK (2 << 18)\n#define USB2D_ENDPTCTRL_TX_EP_TYPE_INTR (3 << 18)\n#define USB2D_ENDPTCTRL_TX_EP_TYPE_MASK (3 << 18)\n#define USB2D_ENDPTCTRL_TX_EP_INHIBIT   BIT(21)\n#define USB2D_ENDPTCTRL_TX_EP_RESET     BIT(22)\n#define USB2D_ENDPTCTRL_TX_EP_ENABLE    BIT(23)\n\n#define USB2D_HOSTPC1_DEVLC_ASUS      BIT(17)\n#define USB2D_HOSTPC1_DEVLC_PHCD      BIT(22)\n#define USB2D_HOSTPC1_DEVLC_PSPD_MASK (3 << 25)\n\n#define USB2D_OTGSC_USB_ID_PULLUP     BIT(5)\n#define USB2D_OTGSC_USB_IRQ_STS_MASK  (0x7F << 16)\n\n/* USB_OTG/USB_1 controllers registers */\ntypedef struct _t210_usb2d_t\n{\n\tvu32 id;\n\tvu32 unk0;\n\tvu32 hw_host;\n\tvu32 hw_device;\n\tvu32 hw_txbuf;\n\tvu32 hw_rxbuf;\n\tvu32 unk1[26];\n\tvu32 gptimer0ld;\n\tvu32 gptimer0ctrl;\n\tvu32 gptimer1ld;\n\tvu32 gptimer1ctrl;\n\tvu32 unk2[28];\n\tvu16 caplength;\n\tvu16 hciversion;\n\tvu32 hcsparams;\n\tvu32 hccparams;\n\tvu32 unk3[5];\n\tvu32 dciversion;\n\tvu32 dccparams;\n\tvu32 extsts;\n\tvu32 usbextintr;\n\tvu32 usbcmd;\n\tvu32 usbsts;\n\tvu32 usbintr;\n\tvu32 frindex;\n\tvu32 unk4;\n\tvu32 periodiclistbase;\n\tvu32 asynclistaddr;\n\tvu32 asyncttsts;\n\tvu32 burstsize;\n\tvu32 txfilltuning;\n\tvu32 unk6;\n\tvu32 icusb_ctrl;\n\tvu32 ulpi_viewport;\n\tvu32 rsvd0[4];\n\tvu32 portsc1;\n\tvu32 rsvd1[15];\n\tvu32 hostpc1_devlc;\n\tvu32 rsvd2[15];\n\tvu32 otgsc;\n\tvu32 usbmode;\n\tvu32 unk10;\n\tvu32 endptnak;\n\tvu32 endptnak_enable;\n\tvu32 endptsetupstat;\n\tvu32 endptprime;\n\tvu32 endptflush;\n\tvu32 endptstatus;\n\tvu32 endptcomplete;\n\tvu32 endptctrl[16];\n} t210_usb2d_t;\n\n\n/* XHCI USB */\n\n/* XUSB DEV XHCI registers */\n#define XUSB_DEV_XHCI_DB                 0x4\n#define XUSB_DEV_XHCI_ERSTSZ             0x8\n#define XUSB_DEV_XHCI_ERST0BALO          0x10\n#define XUSB_DEV_XHCI_ERST0BAHI          0x14\n#define XUSB_DEV_XHCI_ERST1BALO          0x18\n#define XUSB_DEV_XHCI_ERST1BAHI          0x1C\n#define XUSB_DEV_XHCI_ERDPLO             0x20\n#define  XHCI_ERDPLO_EHB                 BIT(3)\n#define XUSB_DEV_XHCI_ERDPHI             0x24\n#define XUSB_DEV_XHCI_EREPLO             0x28\n#define  XCHI_ECS                        BIT(0)\n#define XUSB_DEV_XHCI_EREPHI             0x2C\n#define XUSB_DEV_XHCI_CTRL               0x30\n#define  XHCI_CTRL_RUN                   BIT(0)\n#define  XHCI_CTRL_LSE                   BIT(1)\n#define  XHCI_CTRL_IE                    BIT(4)\n#define  XHCI_CTRL_ENABLE                BIT(31)\n#define XUSB_DEV_XHCI_ST                 0x34\n#define  XHCI_ST_RC                      BIT(0)\n#define  XHCI_ST_IP                      BIT(4)\n#define XUSB_DEV_XHCI_RT_IMOD            0x38\n#define XUSB_DEV_XHCI_PORTSC             0x3C\n#define  XHCI_PORTSC_CCS                 BIT(0)\n#define  XHCI_PORTSC_PED                 BIT(1)\n#define  XHCI_PORTSC_PR                  BIT(4)\n#define  XHCI_PORTSC_PLS_MASK            (0xF << 5)\n#define   XHCI_PORTSC_PLS_U0             (0 << 5)\n#define   XHCI_PORTSC_PLS_U1             (1 << 5)\n#define   XHCI_PORTSC_PLS_U2             (2 << 5)\n#define   XHCI_PORTSC_PLS_U3             (3 << 5)\n#define   XHCI_PORTSC_PLS_DISABLED       (4 << 5)\n#define   XHCI_PORTSC_PLS_RXDETECT       (5 << 5)\n#define   XHCI_PORTSC_PLS_INACTIVE       (6 << 5)\n#define   XHCI_PORTSC_PLS_POLLING        (7 << 5)\n#define   XHCI_PORTSC_PLS_RECOVERY       (8 << 5)\n#define   XHCI_PORTSC_PLS_HOTRESET       (9 << 5)\n#define   XHCI_PORTSC_PLS_COMPLIANCE     (10 << 5)\n#define   XHCI_PORTSC_PLS_LOOPBACK       (11 << 5)\n#define   XHCI_PORTSC_PLS_RESUME         (15 << 5)\n#define  XHCI_PORTSC_PS                  (0xF << 10)\n#define  XHCI_PORTSC_LWS                 BIT(16)\n#define  XHCI_PORTSC_CSC                 BIT(17)\n#define  XHCI_PORTSC_WRC                 BIT(19)\n#define  XHCI_PORTSC_PRC                 BIT(21)\n#define  XHCI_PORTSC_PLC                 BIT(22)\n#define  XHCI_PORTSC_CEC                 BIT(23)\n#define  XHCI_PORTSC_WPR                 BIT(30)\n#define XUSB_DEV_XHCI_ECPLO              0x40\n#define XUSB_DEV_XHCI_ECPHI              0x44\n#define XUSB_DEV_XHCI_EP_HALT            0x50\n#define  XHCI_EP_HALT_DCI_EP0_IN         BIT(0)\n#define XUSB_DEV_XHCI_EP_PAUSE           0x54\n#define XUSB_DEV_XHCI_EP_RELOAD          0x58\n#define XUSB_DEV_XHCI_EP_STCHG           0x5C\n#define XUSB_DEV_XHCI_PORTHALT           0x6C\n#define XUSB_DEV_XHCI_EP_STOPPED         0x78\n#define  XHCI_PORTHALT_HALT_LTSSM        BIT(0)\n#define  XHCI_PORTHALT_STCHG_REQ         BIT(20)\n#define XUSB_DEV_XHCI_CFG_DEV_FE         0x85C\n#define  XHCI_CFG_DEV_FE_PORTREGSEL_MASK (3 << 0)\n#define  XHCI_CFG_DEV_FE_PORTREGSEL_SS   (1 << 0)\n#define  XHCI_CFG_DEV_FE_PORTREGSEL_HSFS (2 << 0)\n\n/* XUSB DEV PCI registers */\n#define XUSB_CFG_1                 0x4\n#define  CFG_1_IO_SPACE            BIT(0)\n#define  CFG_1_MEMORY_SPACE        BIT(1)\n#define  CFG_1_BUS_MASTER          BIT(2)\n#define XUSB_CFG_4                 0x10\n#define  CFG_4_ADDRESS_TYPE_32_BIT (0 << 1)\n#define  CFG_4_ADDRESS_TYPE_64_BIT (2 << 1)\n\n/* XUSB DEV Device registers */\n#define XUSB_DEV_CONFIGURATION     0x180\n#define  DEV_CONFIGURATION_EN_FPCI BIT(0)\n#define XUSB_DEV_INTR_MASK         0x188\n#define  DEV_INTR_MASK_IP_INT_MASK BIT(16)\n\n/* XUSB Pad Control registers */\n#define XUSB_PADCTL_USB2_PAD_MUX 0x4\n#define  PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_USB2 (0 << 0)\n#define  PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_XUSB (1 << 0)\n#define  PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_MASK (3 << 0)\n#define  PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_USB2      (0 << 18)\n#define  PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB      (1 << 18)\n#define  PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK      (3 << 18)\n#define XUSB_PADCTL_USB2_PORT_CAP 0x8\n#define  PADCTL_USB2_PORT_CAP_PORT_0_CAP_DIS  (0 << 0)\n#define  PADCTL_USB2_PORT_CAP_PORT_0_CAP_HOST (1 << 0)\n#define  PADCTL_USB2_PORT_CAP_PORT_0_CAP_DEV  (2 << 0)\n#define  PADCTL_USB2_PORT_CAP_PORT_0_CAP_OTG  (3 << 0)\n#define  PADCTL_USB2_PORT_CAP_PORT_0_CAP_MASK (3 << 0)\n#define XUSB_PADCTL_SS_PORT_MAP 0x14\n#define  PADCTL_SS_PORT_MAP_PORT0_MASK (0xF << 0)\n#define XUSB_PADCTL_ELPG_PROGRAM_0 0x20\n#define XUSB_PADCTL_ELPG_PROGRAM_1 0x24\n#define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD0_CTL0 0x80\n#define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD0_CTL1 0x84\n#define XUSB_PADCTL_USB2_OTG_PAD0_CTL_0 0x88\n#define XUSB_PADCTL_USB2_OTG_PAD0_CTL_1 0x8C\n#define XUSB_PADCTL_USB2_BIAS_PAD_CTL_0 0x284\n#define XUSB_PADCTL_USB2_BIAS_PAD_CTL_1 0x288\n#define XUSB_PADCTL_USB2_VBUS_ID 0xC60\n#define  PADCTL_USB2_VBUS_ID_VBUS_OVR_EN   (1 << 12)\n#define  PADCTL_USB2_VBUS_ID_VBUS_OVR_MASK (3 << 12)\n#define  PADCTL_USB2_VBUS_ID_VBUS_ON       BIT(14)\n#define  PADCTL_USB2_VBUS_ID_SRC_ID_OVR_EN (1 << 16)\n#define  PADCTL_USB2_VBUS_ID_SRC_MASK      (3 << 16)\n#define  PADCTL_USB2_VBUS_ID_OVR_GND       (0 << 18)\n#define  PADCTL_USB2_VBUS_ID_OVR_C         (1 << 18)\n#define  PADCTL_USB2_VBUS_ID_OVR_B         (2 << 18)\n#define  PADCTL_USB2_VBUS_ID_OVR_A         (4 << 18)\n#define  PADCTL_USB2_VBUS_ID_OVR_FLOAT     (8 << 18)\n#define  PADCTL_USB2_VBUS_ID_OVR_MASK      (0xF << 18)\n\n#endif\n"
  },
  {
    "path": "bdk/usb/usbd.c",
    "content": "/*\n * Enhanced USB Device (EDCI) driver for Tegra X1\n *\n * Copyright (c) 2019-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n#include <stdlib.h>\n\n#include <usb/usbd.h>\n#include <usb/usb_descriptor_types.h>\n#include <usb/usb_t210.h>\n\n#include <gfx_utils.h>\n#include <soc/bpmp.h>\n#include <soc/clock.h>\n#include <soc/fuse.h>\n#include <soc/gpio.h>\n#include <soc/pinmux.h>\n#include <soc/pmc.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n#include <utils/btn.h>\n\n#include <memory_map.h>\n\ntypedef enum\n{\n\tUSB_HW_EP0 = 0,\n\tUSB_HW_EP1 = 1\n} usb_hw_ep_t;\n\ntypedef enum\n{\n\tUSB_EP_STATUS_IDLE      = 0,\n\tUSB_EP_STATUS_ACTIVE    = 1,\n\tUSB_EP_STATUS_ERROR     = 2,\n\tUSB_EP_STATUS_NO_CONFIG = 3,\n\tUSB_EP_STATUS_STALLED   = 4,\n\tUSB_EP_STATUS_DISABLED  = 5\n} usb_ep_status_t;\n\ntypedef enum {\n\tUSB_LOW_SPEED   = 0,\n\tUSB_FULL_SPEED  = 1,\n\tUSB_HIGH_SPEED  = 2,\n\tUSB_SUPER_SPEED = 3,\n} usb_speed_t;\n\ntypedef struct _dTD_t\n{\n\tvu32 next_dTD;\n\tvu32 info;\n\tvu32 pages[5];\n\tvu32 reserved;\n} dTD_t;\n\ntypedef struct _dQH_t\n{\n\tvu32 ep_capabilities;\n\tvu32 curr_dTD_ptr;\n\tvu32 next_dTD_ptr;\n\tvu32 token;\n\tvu32 buffers[5]; // hmmm.\n\tvu32 reserved;\n\tvu32 setup[2];\n\tvu32 gap[4];\n} dQH_t;\n\ntypedef struct _usbd_t\n{\n\tvolatile dTD_t dtds[4 * 4]; // 4 dTD per endpoint.\n\tvolatile dQH_t *qhs;\n\tint ep_configured[4];\n\tint ep_bytes_requested[4];\n} usbd_t;\n\ntypedef struct _usbd_controller_t\n{\n\tu32 port_speed;\n\tt210_usb2d_t *regs;\n\tusb_ctrl_setup_t control_setup;\n\tusb_desc_t *desc;\n\tusb_gadget_type gadget;\n\tu8 config_num;\n\tu8 interface_num;\n\tu8 max_lun;\n\tbool usb_phy_ready;\n\tbool configuration_set;\n\tbool max_lun_set;\n\tbool bulk_reset_req;\n\tu32  intr_idle_rate;\n\tbool intr_idle_req;\n\tbool hid_report_sent;\n\tvoid *hid_rpt_buffer;\n\tu32  hid_rpt_size;\n\tu32 charger_detect;\n} usbd_controller_t;\n\nextern u8  hid_report_descriptor_jc[];\nextern u8  hid_report_descriptor_touch[];\nextern u32 hid_report_descriptor_jc_size;\nextern u32 hid_report_descriptor_touch_size;\n\nextern usb_desc_t usb_gadget_hid_jc_descriptors;\nextern usb_desc_t usb_gadget_hid_touch_descriptors;\nextern usb_desc_t usb_gadget_ums_descriptors;\n\nusbd_t *usbdaemon;\n\nusbd_controller_t *usbd_otg;\nusbd_controller_t usbd_usb_otg_controller_ctxt;\n\nbool usb_init_done = false;\n\nu8 *usb_ep0_ctrl_buf = (u8 *)USB_EP_CONTROL_BUF_ADDR;\n\nstatic int _usbd_reset_usb_otg_phy_device_mode()\n{\n\tusbd_otg->usb_phy_ready = false;\n\n\t// Clear UTMIP reset.\n\tUSB(USB1_IF_USB_SUSP_CTRL) &= ~SUSP_CTRL_UTMIP_RESET;\n\n\t// Wait for PHY clock to get validated.\n\tu32 retries = 100000; // 200ms timeout.\n\twhile (!(USB(USB1_IF_USB_SUSP_CTRL) & SUSP_CTRL_USB_PHY_CLK_VALID))\n\t{\n\t\tretries--;\n\t\tif (!retries)\n\t\t\treturn USB_ERROR_INIT;\n\t\tusleep(1);\n\t}\n\tusbd_otg->usb_phy_ready = true;\n\n\t// Clear all device addresses, enabled setup requests and transmit events.\n\tusbd_otg->regs->periodiclistbase = 0;\n\tusbd_otg->regs->endptsetupstat   = usbd_otg->regs->endptsetupstat;\n\tusbd_otg->regs->endptcomplete    = usbd_otg->regs->endptcomplete;\n\n\t// Stop device controller.\n\tusbd_otg->regs->usbcmd  &= ~USB2D_USBCMD_RUN;\n\n\t// Set controller mode to idle.\n\tusbd_otg->regs->usbmode &= ~USB2D_USBMODE_CM_MASK;\n\n\t// Reset the controller.\n\tusbd_otg->regs->usbcmd |= USB2D_USBCMD_RESET;\n\n\t// Wait for the reset to complete.\n\tretries = 100000; // 200ms timeout.\n\twhile (usbd_otg->regs->usbcmd & USB2D_USBCMD_RESET)\n\t{\n\t\tretries--;\n\t\tif (!retries)\n\t\t\treturn USB_ERROR_INIT;\n\t\tusleep(1);\n\t}\n\n\t// Wait for PHY clock to get validated after reset.\n\tretries = 100000; // 200ms timeout.\n\twhile (!(USB(USB1_IF_USB_SUSP_CTRL) & SUSP_CTRL_USB_PHY_CLK_VALID))\n\t{\n\t\tretries--;\n\t\tif (!retries)\n\t\t\treturn USB_ERROR_INIT;\n\t\tusleep(1);\n\t}\n\n\t// Set controller to Device mode.\n\tusbd_otg->regs->usbmode = (usbd_otg->regs->usbmode & ~USB2D_USBMODE_CM_MASK) | USB2D_USBMODE_CM_DEVICE;\n\n\t// Wait for the selected mode to be enabled.\n\tretries = 100000; // 200ms timeout.\n\twhile ((usbd_otg->regs->usbmode & USB2D_USBMODE_CM_MASK) != USB2D_USBMODE_CM_DEVICE)\n\t{\n\t\tretries--;\n\t\tif (!retries)\n\t\t\treturn USB_ERROR_INIT;\n\t\tusleep(1);\n\t}\n\n\t// Disable all interrupts.\n\tusbd_otg->regs->usbintr = 0;\n\n\t// Set the ID pullup and disable all OTGSC interrupts.\n\tusbd_otg->regs->otgsc  = USB2D_OTGSC_USB_ID_PULLUP;\n\n\t// Clear all relevant interrupt statuses.\n\tusbd_otg->regs->usbsts = USB2D_USBSTS_UI  | USB2D_USBSTS_UEI | USB2D_USBSTS_PCI |\n\t\t\t\t\t\t\t USB2D_USBSTS_FRI | USB2D_USBSTS_SEI | USB2D_USBSTS_AAI |\n\t\t\t\t\t\t\t USB2D_USBSTS_URI | USB2D_USBSTS_SRI | USB2D_USBSTS_SLI;\n\n\t// Disable and clear all OTGSC interrupts.\n\tusbd_otg->regs->otgsc  = USB2D_OTGSC_USB_IRQ_STS_MASK;\n\n\t// Clear EP0, EP1, EP2 setup requests.\n\tusbd_otg->regs->endptsetupstat = 7; //TODO: Shouldn't this be endptsetupstat = endptsetupstat?\n\n\t// Set all interrupts to immediate.\n\tusbd_otg->regs->usbcmd &= ~USB2D_USBCMD_ITC_MASK;\n\n\treturn USB_RES_OK;\n}\n\nstatic void _usb_charger_detect()\n{\n\t// Charger detect init.\n\tusbd_otg->charger_detect = 0;\n\tbool charger_detect_enable = FUSE(FUSE_RESERVED_SW) & 0x10; // Disabled on Switch production.\n\tif (charger_detect_enable)\n\t{\n\t\tusbd_otg->charger_detect |= 1;\n\t\t// Configure detect pin.\n\t\tPINMUX_AUX(PINMUX_AUX_LCD_GPIO1) &= ~(PINMUX_PARKED | PINMUX_TRISTATE | PINMUX_PULL_MASK);\n\t\tgpio_direction_input(GPIO_PORT_V, GPIO_PIN_3);\n\n\t\t// Configure charger pin.\n\t\tPINMUX_AUX(PINMUX_AUX_USB_VBUS_EN1) &= ~(PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_TRISTATE | PINMUX_PULL_MASK);\n\t\tgpio_config(GPIO_PORT_CC, GPIO_PIN_5, GPIO_MODE_GPIO);\n\t\tgpio_output_enable(GPIO_PORT_CC, GPIO_PIN_5, GPIO_OUTPUT_ENABLE);\n\n\t\t// Enable charger.\n\t\tif (gpio_read(GPIO_PORT_V, GPIO_PIN_3))\n\t\t{\n\t\t\tusbd_otg->charger_detect |= 2;\n\t\t\tgpio_write(GPIO_PORT_CC, GPIO_PIN_5, GPIO_HIGH);\n\t\t\tusbd_otg->charger_detect |= 0x100;\n\t\t\tUSB(USB1_UTMIP_BAT_CHRG_CFG0) = BAT_CHRG_CFG0_OP_SRC_EN; // Clears UTMIP_PD_CHRG and enables charger detect.\n\t\t\tusleep(5000);\n\t\t}\n\t}\n}\n\nstatic void _usb_init_phy()\n{\n\t// Configure and enable PLLU.\n\tclock_enable_pllu();\n\n\t// Enable USBD clock.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = BIT(CLK_L_USBD);\n\tusleep(2);\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_USBD);\n\tusleep(2);\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_USBD);\n\tusleep(2);\n\n\t// Clear XUSB_PADCTL reset\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_W_CLR) = BIT(CLK_W_XUSB_PADCTL);\n\n\t// Enable USB PHY and reset for programming.\n\tu32 usb_susp_ctrl = USB(USB1_IF_USB_SUSP_CTRL);\n\tUSB(USB1_IF_USB_SUSP_CTRL) = usb_susp_ctrl | SUSP_CTRL_UTMIP_RESET;\n\tUSB(USB1_IF_USB_SUSP_CTRL) = usb_susp_ctrl | SUSP_CTRL_UTMIP_PHY_ENB | SUSP_CTRL_UTMIP_RESET;\n\n\t// Enable IDDQ control by software and disable UTMIPLL IDDQ.\n\tCLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) = (CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) & 0xFFFFFFFC) | 1;\n\tusleep(10);\n\n\t// Disable crystal clock.\n\tUSB(USB1_UTMIP_MISC_CFG1) &= 0xBFFFFFFF;\n\tCLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) &= 0xBFFFFFFF;\n\n\t// Set B_SESS_VLD.\n\tUSB(USB1_IF_USB_PHY_VBUS_SENSORS) |= 0x1000;\n\tUSB(USB1_IF_USB_PHY_VBUS_SENSORS) |= 0x800;\n\n\t// Set UTMIPLL dividers and config based on OSC and enable it to 960 MHz.\n\tclock_enable_utmipll();\n\n\t// Configure UTMIP Transceiver Cells.\n\tu32 fuse_usb_calib = FUSE(FUSE_USB_CALIB);\n\tUSB(USB1_UTMIP_XCVR_CFG0) = (((USB(USB1_UTMIP_XCVR_CFG0) & 0xFFFFFFF0) | (fuse_usb_calib & 0xF)) & 0xFE3FFFFF) | ((fuse_usb_calib & 0x3F) << 25 >> 29 << 22);\n\tUSB(USB1_UTMIP_XCVR_CFG1) = (USB(USB1_UTMIP_XCVR_CFG1) & 0xFFC3FFFF) | ((fuse_usb_calib << 21) >> 28 << 18);\n\tUSB(USB1_UTMIP_XCVR_CFG3) = (USB(USB1_UTMIP_XCVR_CFG3) & 0xFFFFC1FF) | ((FUSE(FUSE_USB_CALIB_EXT) & 0x1F) << 9);\n\tUSB(USB1_UTMIP_XCVR_CFG0) &= 0xFFDFFFFF;\n\tUSB(USB1_UTMIP_XCVR_CFG2) = (USB(USB1_UTMIP_XCVR_CFG2) & 0xFFFFF1FF) | 0x400;\n\tusleep(1);\n\n\t// Configure misc UTMIP.\n\tUSB(USB1_UTMIP_DEBOUNCE_CFG0) = (USB(USB1_UTMIP_DEBOUNCE_CFG0) & 0xFFFF0000) | 0xBB80;\n\tUSB(USB1_UTMIP_BIAS_CFG1)     = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFFFFC0FF)     | 0x100; // when osc is 38.4KHz\n\n\t//USB(USB1_UTMIP_SPARE_CFG0) &= 0xFFFFFEE7; unpatched0\n\tUSB(USB1_UTMIP_BIAS_CFG2)  |= 2;          //patched0 - UTMIP_HSSQUELCH_LEVEL_NEW: 2.\n\tUSB(USB1_UTMIP_SPARE_CFG0) &= 0xFFFFFE67; //patched0 - FUSE_HS_IREF_CAP_CFG\n\tUSB(USB1_UTMIP_TX_CFG0)    |= 0x80000;\n\n\t//USB(USB1_UTMIP_HSRX_CFG0) = (USB(USB1_UTMIP_HSRX_CFG0) & 0xFFF003FF) | 0x88000 | 0x4000; unpatched1\n\tUSB(USB1_UTMIP_HSRX_CFG0) = (USB(USB1_UTMIP_HSRX_CFG0) & 0xF0F003FF) | 0x88000 | 0x4000; //patched1 - reset UTMIP_PCOUNT_UPDN_DIV: From 1 to 0.\n\tUSB(USB1_UTMIP_BIAS_CFG2) &= 0xFFFFFFF8; //patched1 - UTMIP_HSSQUELCH_LEVEL_NEW: 0\n\n\tUSB(USB1_UTMIP_HSRX_CFG1) = (USB(USB1_UTMIP_HSRX_CFG1) & 0xFFFFFFC1) | 0x12;\n\tUSB(USB1_UTMIP_MISC_CFG1) |= 0x40000000;\n\n\t// Enable crystal clock.\n\tCLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) |= 0x40000000;\n\n\t// Enable USB2 tracking clock.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_Y_SET)            = BIT(CLK_Y_USB2_TRK);\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK) & 0xFFFFFF00) | 6; // Set trank divisor to 4.\n\n\tUSB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFFC03F07) | 0x78000 | 0x50; // Set delays.\n\tUSB(USB1_UTMIP_BIAS_CFG0) &= 0xFFFFFBFF; // Disable Power down bias circuit.\n\tusleep(1);\n\n\t// Force PDTRK input into power up.\n\tUSB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFFFFFFFE) | 2;\n\tusleep(100);\n\n\t// TRK cycle done. Force PDTRK input into power down.\n\tUSB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFF7FFFFF) | 1;\n\tusleep(3);\n\n\t// Force PDTRK input into power up.\n\tUSB(USB1_UTMIP_BIAS_CFG1) = USB(USB1_UTMIP_BIAS_CFG1) & 0xFFFFFFFE;\n\tusleep(100);\n\n\t// TRK cycle done. Force PDTRK input into power down.\n\tUSB(USB1_UTMIP_BIAS_CFG1) = (USB(USB1_UTMIP_BIAS_CFG1) & 0xFF7FFFFF) | 1;\n\n\t// Disable USB2 tracking clock and configure UTMIP misc.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_Y_CLR) = BIT(CLK_Y_USB2_TRK);\n\tCLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) & 0xFEFFFFEA) | 0x2000000 | 0x28 | 2;\n\tusleep(1);\n\n\tUSB(USB1_UTMIP_BIAS_CFG0) &= 0xFF3FF7FF;\n\tusleep(1);\n\n\t// Clear power downs on UTMIP ID and VBUS wake up, PD, PD2, PDZI, PDCHRP, PDDR.\n\tPMC(APBDEV_PMC_USB_AO)    &= 0xFFFFFFF3; // UTMIP ID and VBUS wake up.\n\tusleep(1);\n\tUSB(USB1_UTMIP_XCVR_CFG0) &= 0xFFFFBFFF; // UTMIP_FORCE_PD_POWERDOWN.\n\tusleep(1);\n\tUSB(USB1_UTMIP_XCVR_CFG0) &= 0xFFFEFFFF; // UTMIP_FORCE_PD2_POWERDOWN.\n\tusleep(1);\n\tUSB(USB1_UTMIP_XCVR_CFG0) &= 0xFFFBFFFF; // UTMIP_FORCE_PDZI_POWERDOWN.\n\tusleep(1);\n\tUSB(USB1_UTMIP_XCVR_CFG1) &= 0xFFFFFFFB; // UTMIP_FORCE_PDCHRP_POWERDOWN.\n\tusleep(1);\n\tUSB(USB1_UTMIP_XCVR_CFG1) &= 0xFFFFFFEF; // UTMIP_FORCE_PDDR_POWERDOWN.\n\tusleep(1);\n}\n\nint usb_device_init()\n{\n\tif (usb_init_done)\n\t\treturn USB_RES_OK;\n\n\t// Ease the stress to APB.\n\tbpmp_clk_rate_relaxed(true);\n\n\t// Initialize USB2 controller PHY.\n\t_usb_init_phy();\n\n\t// Restore OC.\n\tbpmp_clk_rate_relaxed(false);\n\n\t// AHB USB performance cfg.\n\tAHB_GIZMO(AHB_GIZMO_AHB_MEM) |= AHB_MEM_DONT_SPLIT_AHB_WR | AHB_MEM_ENB_FAST_REARBITRATE;\n\tAHB_GIZMO(AHB_GIZMO_USB)     |= AHB_GIZMO_IMMEDIATE;\n\tAHB_GIZMO(AHB_ARBITRATION_PRIORITY_CTRL) = PRIORITY_CTRL_WEIGHT(7) | PRIORITY_SELECT_USB;\n\tAHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1)     = MEM_PREFETCH_ENABLE     | MEM_PREFETCH_USB_MST_ID |\n\t\t\t\t\t\t\t\t\t\t\t   MEM_PREFETCH_ADDR_BNDRY(12) | 0x1000; // Addr boundary 64KB, Inactivity 4096 cycles.\n\n\t// Set software and hardware context storage and clear it.\n\tusbdaemon = (usbd_t *)USBD_ADDR; // Depends on USB_TD_BUFFER_PAGE_SIZE aligned address.\n\tusbd_otg  = &usbd_usb_otg_controller_ctxt;\n\tmemset(usbd_otg,  0, sizeof(usbd_controller_t));\n\tmemset(usbdaemon, 0, sizeof(usbd_t));\n\n\tusbd_otg->regs = (t210_usb2d_t *)USB_OTG_BASE;\n\tusbd_otg->usb_phy_ready = false;\n\n\t// Initialize USB PHY on the USB_OTG Controller (#1) in Device mode.\n\tint res = _usbd_reset_usb_otg_phy_device_mode();\n\tusbd_otg->configuration_set = false;\n\n\t_usb_charger_detect();\n\n\tif (!res)\n\t\tusb_init_done = true;\n\n\treturn res;\n}\n\nstatic void _usb_device_power_down()\n{\n\t// Enable PHY low power suspend.\n\tusbd_otg->regs->hostpc1_devlc |= USB2D_HOSTPC1_DEVLC_PHCD;\n\t// Do not use any controller regs after the above!\n\t// A reset or clear of the PHCD suspend bit must happen.\n\n\t// Power down OTG and Bias circuits.\n\tUSB(USB1_UTMIP_BIAS_CFG0) |= BIT(11) | BIT(10); // UTMIP_OTGPD, UTMIP_BIASPD.\n\n\t// Power down ID detectors.\n\tUSB(USB1_UTMIP_BIAS_CFG0) |= BIT(23) | BIT(22); // UTMIP_IDPD_SEL, UTMIP_IDPD_VAL.\n\n\tif (usbd_otg->charger_detect)\n\t{\n\t\tUSB(USB1_UTMIP_BAT_CHRG_CFG0) = 1;  //UTMIP_PD_CHRG\n\t\tusbd_otg->charger_detect = 0;\n\t}\n\n\t// Power down the UTMIP transceivers.\n\t// UTMIP_FORCE_PDZI_POWERDOWN, UTMIP_FORCE_PD2_POWERDOWN, UTMIP_FORCE_PD_POWERDOWN.\n\tUSB(USB1_UTMIP_XCVR_CFG0) |= BIT(18) | BIT(16) |BIT(14);\n\t// UTMIP_FORCE_PDDR_POWERDOWN, UTMIP_FORCE_PDCHRP_POWERDOWN, UTMIP_FORCE_PDDISC_POWERDOWN.\n\tUSB(USB1_UTMIP_XCVR_CFG1) |= BIT(4) | BIT(2) | BIT(0);\n\n\t// Keep UTMIP in reset.\n\tUSB(USB1_IF_USB_SUSP_CTRL) |= SUSP_CTRL_UTMIP_RESET;\n\n\t// Power down PD trunk.\n\tUSB(USB1_UTMIP_BIAS_CFG1) |= BIT(0); //UTMIP_FORCE_PDTRK_POWERDOWN.\n\n\t// Force UTMIP_PLL power down.\n\tCLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) |= BIT(14);           // UTMIP_FORCE_PLL_ENABLE_POWERDOWN.\n\tCLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) |= BIT(12);           // UTMIP_FORCE_PLL_ACTIVE_POWERDOWN.\n\tCLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) |= BIT(4) | BIT(0); // UTMIP_FORCE_PD_SAMP_A/C_POWERDOWN.\n\tCLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) |= BIT(16);           // UTMIP_FORCE_PLLU_POWERDOWN.\n\n\t// Disable crystal clock.\n\tUSB(USB1_UTMIP_MISC_CFG1) &= 0xBFFFFFFF;\n\n\t// Force enable UTMIPLL IDDQ.\n\tCLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) |= 3;\n\n\t// Set XUSB_PADCTL reset\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB_PADCTL);\n\n\t// Disable USBD clock.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = BIT(CLK_L_USBD);\n\n\t// Disable PLLU.\n\tclock_disable_pllu();\n\n\tusb_init_done = false;\n}\n\nstatic void _usbd_disable_ep1()\n{\n\tusbd_otg->regs->endptctrl[1] = 0;\n}\n\nstatic void _usbd_stall_reset_ep1(usb_dir_t direction, usb_ep_cfg_t stall)\n{\n\tstall &= 1;\n\tif (direction == USB_DIR_IN)\n\t{\n\t\tusbd_otg->regs->endptctrl[1] = (usbd_otg->regs->endptctrl[1] & ~USB2D_ENDPTCTRL_TX_EP_STALL) | ((u32)stall << 16);\n\t\tif (!stall)\n\t\t\tusbd_otg->regs->endptctrl[1] |= USB2D_ENDPTCTRL_TX_EP_RESET;\n\t}\n\telse\n\t{\n\t\tusbd_otg->regs->endptctrl[1] = (usbd_otg->regs->endptctrl[1] & ~USB2D_ENDPTCTRL_RX_EP_STALL) | stall;\n\t\tif (!stall)\n\t\t\tusbd_otg->regs->endptctrl[1] |= USB2D_ENDPTCTRL_RX_EP_RESET;\n\t}\n}\n\nvoid usb_device_stall_ep1_bulk_out()\n{\n\t_usbd_stall_reset_ep1(USB_DIR_OUT, USB_EP_CFG_STALL);\n}\n\nvoid usb_device_stall_ep1_bulk_in()\n{\n\t_usbd_stall_reset_ep1(USB_DIR_IN, USB_EP_CFG_STALL);\n}\n\nstatic int _usbd_get_max_pkt_length(int endpoint)\n{\n\tswitch (endpoint)\n\t{\n\tcase USB_EP_CTRL_OUT:\n\tcase USB_EP_CTRL_IN:\n\t\t\treturn 64;\n\tcase USB_EP_BULK_OUT:\n\tcase USB_EP_BULK_IN:\n\t\tif (usbd_otg->port_speed == USB_HIGH_SPEED)\n\t\t\treturn 512;\n\t\telse\n\t\t\treturn 64;\n\tdefault:\n\t\treturn 64;\n\t}\n}\n\nstatic void _usbd_initialize_ep_ctrl(u32 endpoint)\n{\n\tusb_hw_ep_t actual_ep = (endpoint & 2) >> 1;\n\tusb_dir_t direction = endpoint & 1;\n\n\tmemset((void *)&usbdaemon->qhs[endpoint], 0, sizeof(dQH_t));\n\n\tif (!endpoint)\n\t\tusbdaemon->qhs[endpoint].ep_capabilities = USB_QHD_EP_CAP_IOS_ENABLE;\n\n\tusbdaemon->qhs[endpoint].next_dTD_ptr = 1; // TERMINATE_SET\n\n\tu32 max_packet_len = _usbd_get_max_pkt_length(endpoint) & USB_QHD_EP_CAP_MAX_PKT_LEN_MASK;\n\tusbdaemon->qhs[endpoint].ep_capabilities |= max_packet_len << 16;\n\n\tif (direction == USB_DIR_IN)\n\t{\n\t\tu32 endpoint_type = usbd_otg->regs->endptctrl[actual_ep] & ~USB2D_ENDPTCTRL_TX_EP_TYPE_MASK;\n\t\tif (actual_ep)\n\t\t\tendpoint_type |= usbd_otg->gadget ? USB2D_ENDPTCTRL_TX_EP_TYPE_INTR : USB2D_ENDPTCTRL_TX_EP_TYPE_BULK;\n\t\telse\n\t\t\tendpoint_type |= USB2D_ENDPTCTRL_TX_EP_TYPE_CTRL;\n\n\t\tusbd_otg->regs->endptctrl[actual_ep] = endpoint_type;\n\n\t\tusbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_TX_EP_STALL;\n\n\t\tif (actual_ep == USB_HW_EP1)\n\t\t\tusbd_otg->regs->endptctrl[1] |= USB2D_ENDPTCTRL_TX_EP_RESET;\n\n\t\tusbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_TX_EP_ENABLE;\n\t}\n\telse // EP Bulk OUT.\n\t{\n\t\tu32 endpoint_type = usbd_otg->regs->endptctrl[actual_ep] & ~USB2D_ENDPTCTRL_RX_EP_TYPE_MASK;\n\t\tif (actual_ep)\n\t\t\tendpoint_type |= usbd_otg->gadget ? USB2D_ENDPTCTRL_RX_EP_TYPE_INTR : USB2D_ENDPTCTRL_RX_EP_TYPE_BULK;\n\t\telse\n\t\t\tendpoint_type |= USB2D_ENDPTCTRL_RX_EP_TYPE_CTRL;\n\n\t\tusbd_otg->regs->endptctrl[actual_ep]  = endpoint_type;\n\t\tusbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_RX_EP_STALL;\n\n\t\tif (actual_ep == USB_HW_EP1)\n\t\t\tusbd_otg->regs->endptctrl[1] |= USB2D_ENDPTCTRL_RX_EP_RESET;\n\n\t\tusbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_RX_EP_ENABLE;\n\t}\n}\n\nstatic int _usbd_initialize_ep0()\n{\n\tmemset((void *)usbdaemon->qhs,  0, sizeof(dQH_t) * 4); // Clear all used EP queue heads.\n\tmemset((void *)usbdaemon->dtds, 0, sizeof(dTD_t) * 4); // Clear all used EP0 token heads.\n\n\tusbd_otg->regs->asynclistaddr = (u32)usbdaemon->qhs;\n\n\t_usbd_initialize_ep_ctrl(USB_EP_CTRL_OUT);\n\t_usbd_initialize_ep_ctrl(USB_EP_CTRL_IN);\n\n\t// Disable Auto Low Power.\n\tusbd_otg->regs->hostpc1_devlc &= ~USB2D_HOSTPC1_DEVLC_ASUS;\n\n\t// Initiate an attach event.\n\tusbd_otg->regs->usbcmd |= USB2D_USBCMD_RUN;\n\n\tu32 retries = 100000; // 200ms timeout.\n\twhile (!(usbd_otg->regs->usbcmd & USB2D_USBCMD_RUN))\n\t{\n\t\tretries--;\n\t\tif (!retries)\n\t\t\treturn USB_ERROR_TIMEOUT;\n\t\tusleep(1);\n\t}\n\n\treturn USB_RES_OK;\n}\n\n// static void _disable_usb_wdt4()\n// {\n// \tif (TIMER_WDT4_STATUS & 1)// active\n// \t{\n// \t\tTIMER_TMR0_TMR_PTV &= 0x7FFFFFFF; // Disable timer\n// \t\tTIMER_WDT4_UNLOCK_PATTERN = 0xC45A; // Alow writes to disable counter bit.\n// \t\tTIMER_WDT4_COMMAND |= 2; // Disable counter\n// \t\tTIMER_TMR0_TMR_PCR |= 0x40000000;// INTR_CLR\n// \t}\n// }\n\nint usbd_flush_endpoint(u32 endpoint)\n{\n\n\tusb_hw_ep_t actual_ep = (endpoint & 2) >> 1;\n\tusb_dir_t direction   = endpoint & 1;\n\tu32 reg_mask          = endpoint;\n\n\t// Flash all endpoints or 1.\n\tif (endpoint != USB_EP_ALL)\n\t{\n\t\tif (direction == USB_DIR_IN)\n\t\t\treg_mask = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep;\n\t\telse\n\t\t\treg_mask = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep;\n\t}\n\tusbd_otg->regs->endptflush = reg_mask;\n\n\tu32 retries = 100000; // 200ms timeout.\n\twhile (usbd_otg->regs->endptflush & reg_mask)\n\t{\n\t\tretries--;\n\t\tif (!retries)\n\t\t\treturn USB_ERROR_TIMEOUT;\n\t\tusleep(1);\n\t}\n\n\t// Wait for the endpoint to finish all transactions (buffer not ready).\n\tretries = 100000; // 200ms timeout.\n\twhile (usbd_otg->regs->endptstatus & reg_mask)\n\t{\n\t\tretries--;\n\t\tif (!retries)\n\t\t\treturn USB_ERROR_TIMEOUT;\n\t\tusleep(1);\n\t}\n\n\t// Wait for the endpoint to clear the primed status.\n\tretries = 100000; // 200ms timeout.\n\twhile (usbd_otg->regs->endptprime & reg_mask)\n\t{\n\t\tretries--;\n\t\tif (!retries)\n\t\t\treturn USB_ERROR_TIMEOUT;\n\t\tusleep(1);\n\t}\n\n\treturn USB_RES_OK;\n}\n\nstatic void _usb_reset_disable_ep1()\n{\n\tusbd_flush_endpoint(USB_EP_ALL);\n\t_usbd_stall_reset_ep1(USB_DIR_OUT, USB_EP_CFG_RESET); // EP1 Bulk OUT.\n\t_usbd_stall_reset_ep1(USB_DIR_IN, USB_EP_CFG_RESET);  // EP1 Bulk IN.\n\t_usbd_disable_ep1();\n\n\tusbd_otg->config_num        = 0;\n\tusbd_otg->interface_num     = 0;\n\tusbd_otg->configuration_set = false;\n\tusbd_otg->max_lun_set       = false;\n}\n\nvoid usbd_end(bool reset_ep, bool only_controller)\n{\n\tif (reset_ep)\n\t\t_usb_reset_disable_ep1();\n\n\t// Stop device controller.\n\tusbd_otg->regs->usbcmd &= ~USB2D_USBCMD_RUN;\n\n\t// Enable PHY auto low power suspend.\n\tusbd_otg->regs->hostpc1_devlc |= USB2D_HOSTPC1_DEVLC_ASUS;\n\n\tif (!only_controller)\n\t\t_usb_device_power_down();\n}\n\nstatic void _usbd_mark_ep_complete(u32 endpoint)\n{\n\tu32 complete_bit;\n\tusb_hw_ep_t actual_ep = (endpoint & 2) >> 1;\n\tusb_dir_t direction = endpoint & 1;\n\n\tusbd_flush_endpoint(endpoint);\n\n\tmemset((void *)&usbdaemon->dtds[endpoint * 4], 0, sizeof(dTD_t) * 4);\n\tmemset((void *)&usbdaemon->qhs[endpoint],      0, sizeof(dQH_t));\n\n\tusbdaemon->ep_configured[endpoint]      = 0;\n\tusbdaemon->ep_bytes_requested[endpoint] = 0;\n\n\tif (direction == USB_DIR_IN)\n\t\tcomplete_bit = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep;\n\telse\n\t\tcomplete_bit = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep;\n\n\tusbd_otg->regs->endptcomplete |= complete_bit;\n}\n\nstatic usb_ep_status_t _usbd_get_ep_status(usb_ep_t endpoint)\n{\n\tbool status;\n\tu32 reg_val;\n\tu32 reg_mask;\n\tu32 actual_ep = (endpoint & 2) >> 1;\n\tusb_dir_t direction = endpoint & 1;\n\n\tif (direction == USB_DIR_IN)\n\t\treg_mask = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep;\n\telse\n\t\treg_mask = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep;\n\n\tif (actual_ep == USB_HW_EP1)\n\t\treg_val = usbd_otg->regs->endptctrl[1];\n\telse\n\t\treg_val = usbd_otg->regs->endptctrl[0];\n\n\t// Check stalled status.\n\tif (direction == USB_DIR_IN)\n\t\tstatus = reg_val & USB2D_ENDPTCTRL_TX_EP_STALL;\n\telse\n\t\tstatus = reg_val & USB2D_ENDPTCTRL_RX_EP_STALL;\n\n\tif (status)\n\t\treturn USB_EP_STATUS_STALLED;\n\n\t// Check enabled status.\n\tif (direction == USB_DIR_IN)\n\t\tstatus = reg_val & USB2D_ENDPTCTRL_TX_EP_ENABLE;\n\telse\n\t\tstatus = reg_val & USB2D_ENDPTCTRL_RX_EP_ENABLE;\n\n\tif (!status)\n\t\treturn USB_EP_STATUS_DISABLED;\n\n\t// CHeck qHD error status.\n\tu32 token_error_mask = USB_QHD_TOKEN_HALTED | USB_QHD_TOKEN_BUFFER_ERROR | USB_QHD_TOKEN_XFER_ERROR;\n\tif (usbdaemon->qhs[endpoint].token & token_error_mask)\n\t\treturn USB_EP_STATUS_ERROR;\n\n\t// Check if endpoint has a request or a ready buffer.\n\tif ((usbd_otg->regs->endptprime & reg_mask) || (usbd_otg->regs->endptstatus & reg_mask))\n\t\treturn USB_EP_STATUS_ACTIVE; // RX/TX active.\n\n\t// Return idle or not configured status.\n\tif (!usbdaemon->ep_configured[endpoint])\n\t\treturn USB_EP_STATUS_NO_CONFIG;\n\n\treturn USB_EP_STATUS_IDLE;\n}\n\nstatic int _usbd_ep_operation(usb_ep_t endpoint, u8 *buf, u32 len, u32 sync_timeout)\n{\n\tif (!buf)\n\t\tlen = 0;\n\n\tu32 prime_bit;\n\tusb_hw_ep_t actual_ep = (endpoint & 2) >> 1;\n\tusb_dir_t direction = endpoint & 1;\n\tu32 length_left = len;\n\tu32 dtd_ep_idx = endpoint * 4;\n\n\t_usbd_mark_ep_complete(endpoint);\n\n\tif (endpoint == USB_EP_CTRL_OUT)\n\t\tusbdaemon->qhs[endpoint].ep_capabilities = USB_QHD_EP_CAP_IOS_ENABLE;\n\n\tu32 max_packet_len = _usbd_get_max_pkt_length(endpoint) & USB_QHD_EP_CAP_MAX_PKT_LEN_MASK;\n\tusbdaemon->qhs[endpoint].ep_capabilities |= (max_packet_len << 16) | USB_QHD_EP_CAP_ZERO_LEN_TERM_DIS;\n\tusbdaemon->qhs[endpoint].next_dTD_ptr = 0; // Clear terminate bit.\n\t//usbdaemon->qhs[endpoint].ep_capabilities |= USB_QHD_TOKEN_IRQ_ON_COMPLETE;\n\n\tusbdaemon->ep_configured[endpoint] = 1;\n\tusbdaemon->ep_bytes_requested[endpoint] = len;\n\n\t// Configure dTD.\n\tu32 dtd_idx = 0;\n\tdo\n\t{\n\t\tif (dtd_idx)\n\t\t\tusbdaemon->dtds[dtd_ep_idx + dtd_idx - 1].next_dTD = (u32)&usbdaemon->dtds[dtd_ep_idx + dtd_idx];\n\n\t\tu32 dtd_size = MIN(length_left, USB_TD_BUFFER_MAX_SIZE); // 16KB max per dTD.\n\t\tusbdaemon->dtds[dtd_ep_idx + dtd_idx].info = (dtd_size << 16) | USB_QHD_TOKEN_ACTIVE;\n\t\t// usbdaemon->dtds[dtd_ep_idx + dtd_idx].info |= USB_QHD_TOKEN_IRQ_ON_COMPLETE;\n\n\t\t// Set buffers addresses to all page pointers.\n\t\tu32 dt_buffer_offset = dtd_idx * USB_TD_BUFFER_MAX_SIZE;\n\t\tfor (u32 i = 0; i < 4; i++)\n\t\t\tusbdaemon->dtds[dtd_ep_idx + dtd_idx].pages[i] = !buf ? 0 :\n\t\t\t\t(u32)&buf[dt_buffer_offset + (USB_TD_BUFFER_PAGE_SIZE * i)];\n\n\t\t//usbdaemon->dtds[dtd_ep_idx + dtd_idx].pages[5] =\n\t\t//\t(u32)&buf[dt_buffer_offset + (USB_TD_BUFFER_PAGE_SIZE * 4)]; // Last buffer. Unused.\n\n\t\tlength_left -= dtd_size;\n\t\tif (length_left)\n\t\t\tdtd_idx++;\n\t}\n\twhile (length_left);\n\n\t// Last dTD, terminate it.\n\tusbdaemon->dtds[dtd_ep_idx + dtd_idx].next_dTD = 1;\n\n\t// Set first dTD address to queue head next dTD.\n\tusbdaemon->qhs[endpoint].next_dTD_ptr |= (u32)&usbdaemon->dtds[dtd_ep_idx] & 0xFFFFFFE0;\n\n\t// Flush AHB prefetcher.\n\tAHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) &= ~MEM_PREFETCH_ENABLE;\n\tAHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1) |=  MEM_PREFETCH_ENABLE;\n\n\tif (direction == USB_DIR_IN)\n\t\tprime_bit = USB2D_ENDPT_STATUS_TX_OFFSET << actual_ep;\n\telse\n\t\tprime_bit = USB2D_ENDPT_STATUS_RX_OFFSET << actual_ep;\n\n\t// Flush data before priming EP.\n\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_CLEAN_WAY, false);\n\n\t// Prime endpoint.\n\tusbd_otg->regs->endptprime |= prime_bit; // USB2_CONTROLLER_USB2D_ENDPTPRIME.\n\n\tint res = USB_RES_OK;\n\tusb_ep_status_t ep_status;\n\tif (sync_timeout)\n\t{\n\t\tep_status = _usbd_get_ep_status(endpoint);\n\t\tif (ep_status == USB_EP_STATUS_ACTIVE)\n\t\t{\n\t\t\tu32 retries = sync_timeout;\n\t\t\twhile (retries)\n\t\t\t{\n\t\t\t\tep_status = _usbd_get_ep_status(endpoint);\n\t\t\t\tif (ep_status != USB_EP_STATUS_ACTIVE)\n\t\t\t\t{\n\t\t\t\t\tif (ep_status == USB_EP_STATUS_DISABLED)\n\t\t\t\t\t\tres = USB2_ERROR_XFER_EP_DISABLED;\n\t\t\t\t\tgoto out;\n\t\t\t\t}\n\t\t\t\tretries--;\n\t\t\t\tusleep(1);\n\t\t\t}\n\t\t\tres = USB_ERROR_TIMEOUT;\n\t\t}\n\t\telse if (ep_status == USB_EP_STATUS_DISABLED)\n\t\t\tres = USB2_ERROR_XFER_EP_DISABLED;\nout:\n\t\tif (res)\n\t\t\t_usbd_mark_ep_complete(endpoint);\n\t\telse if (_usbd_get_ep_status(endpoint) != USB_EP_STATUS_IDLE)\n\t\t\tres = USB_ERROR_XFER_ERROR;\n\n\t\t// Invalidate data after OP is done.\n\t\tif (direction == USB_DIR_OUT)\n\t\t\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);\n\t}\n\n\treturn res;\n}\n\nstatic int _usbd_ep_ack(usb_ep_t ep)\n{\n\treturn _usbd_ep_operation(ep, NULL, 0, USB_XFER_SYNCED_ENUM);\n}\n\nstatic void _usbd_set_ep0_stall()\n{\n\t// EP Control endpoints must be always stalled together.\n\tusbd_otg->regs->endptctrl[0] = USB2D_ENDPTCTRL_TX_EP_ENABLE | USB2D_ENDPTCTRL_TX_EP_STALL |\n\t\t\t\t\t\t\t\t   USB2D_ENDPTCTRL_RX_EP_ENABLE | USB2D_ENDPTCTRL_RX_EP_STALL;\n}\n\nint usbd_set_ep_stall(u32 endpoint, int ep_stall)\n{\n\tusb_hw_ep_t actual_ep = (endpoint & 2) >> 1;\n\tusb_dir_t direction = endpoint & 1;\n\n\tif (ep_stall)\n\t{\n\t\tif (direction == USB_DIR_IN)\n\t\t\tusbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_TX_EP_STALL; // Stall EP Bulk IN.\n\t\telse\n\t\t\tusbd_otg->regs->endptctrl[actual_ep] |= USB2D_ENDPTCTRL_RX_EP_STALL; // Stall EP Bulk OUT.\n\t}\n\telse\n\t{\n\t\tif (direction == USB_DIR_IN)\n\t\t\tusbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_TX_EP_STALL; // Clear stall EP Bulk IN.\n\t\telse\n\t\t\tusbd_otg->regs->endptctrl[actual_ep] &= ~USB2D_ENDPTCTRL_RX_EP_STALL; // Clear stall EP Bulk OUT.\n\t}\n\n\treturn USB_RES_OK;\n}\n\nstatic void _usbd_handle_get_class_request(bool *transmit_data, u8 *desc, int *size, bool *ep_stall)\n{\n\tu8 _bRequest = usbd_otg->control_setup.bRequest;\n\tu16 _wIndex  = usbd_otg->control_setup.wIndex;\n\tu16 _wValue  = usbd_otg->control_setup.wValue;\n\tu16 _wLength = usbd_otg->control_setup.wLength;\n\n\tbool valid_interface = _wIndex == usbd_otg->interface_num;\n\tbool valid_val = (_bRequest >= USB_REQUEST_BULK_GET_MAX_LUN) ? (!_wValue) : true;\n\n\tif (!valid_interface || !valid_val)\n\t{\n\t\t*ep_stall = true;\n\t\treturn;\n\t}\n\n\tswitch (_bRequest)\n\t{\n\tcase USB_REQUEST_INTR_GET_REPORT:\n\t\tif (usbd_otg->hid_rpt_size != _wLength)\n\t\t\tbreak;\n\n\t\t// _wValue unused as there's only one report type and id.\n\t\t*transmit_data = true;\n\t\t*size = usbd_otg->hid_rpt_size;\n\t\tmemcpy(desc, usbd_otg->hid_rpt_buffer, usbd_otg->hid_rpt_size);\n\t\treturn;\n\n\tcase USB_REQUEST_INTR_SET_IDLE:\n\t\tif (_wLength)\n\t\t\tbreak;\n\n\t\tusbd_otg->intr_idle_rate = (_wValue & 0xFF) * 4 * 1000; // Only one interface so upper byte ignored.\n\t\tusbd_otg->intr_idle_req  = true;\n\t\t_usbd_ep_ack(USB_EP_CTRL_IN);\n\t\treturn; // DELAYED_STATUS;\n\n\tcase USB_REQUEST_BULK_RESET:\n\t\tif (_wLength)\n\t\t\tbreak;\n\n\t\t_usbd_ep_ack(USB_EP_CTRL_IN);\n\t\tusbd_otg->bulk_reset_req = true;\n\t\treturn; // DELAYED_STATUS;\n\n\tcase USB_REQUEST_BULK_GET_MAX_LUN:\n\t\tif (_wLength != 1)\n\t\t\tbreak;\n\n\t\t*transmit_data = true;\n\t\t*size = 1;\n\t\tdesc[0] = usbd_otg->max_lun; // Set 0 LUN for 1 drive supported.\n\t\tusbd_otg->max_lun_set = true;\n\t\treturn;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\t*ep_stall = true;\n}\n\nstatic void _usbd_handle_get_descriptor(bool *transmit_data, void **desc, int *size, bool *ep_stall)\n{\n\tu8 descriptor_type = usbd_otg->control_setup.wValue >> 8;\n\tu8 descriptor_subtype = usbd_otg->control_setup.wValue & 0xFF;\n\n\tswitch (descriptor_type)\n\t{\n\tcase USB_DESCRIPTOR_DEVICE:\n\t\t{\n/*\n\t\tu32 soc_rev = APB_MISC(APB_MISC_GP_HIDREV);\n\t\tusb_device_descriptor.idProduct  = (soc_rev >> 8)  & 0xFF; // chip_id.\n\t\tusb_device_descriptor.idProduct |= ((soc_rev << 4) | (FUSE(FUSE_SKU_INFO) & 0xF)) << 8; // HIDFAM.\n\t\tusb_device_descriptor.bcdDevice  = (soc_rev >> 16) & 0xF; // MINORREV.\n\t\tusb_device_descriptor.bcdDevice |= ((soc_rev >> 4) & 0xF) << 8; // MAJORREV.\n*/\n\t\t*desc = usbd_otg->desc->dev;\n\t\t*size = usbd_otg->desc->dev->bLength;\n\t\t*transmit_data = true;\n\t\treturn;\n\t\t}\n\tcase USB_DESCRIPTOR_CONFIGURATION:\n\t\tif (usbd_otg->gadget == USB_GADGET_UMS)\n\t\t{\n\t\t\tif (usbd_otg->port_speed == USB_HIGH_SPEED) // High speed. 512 bytes.\n\t\t\t{\n\t\t\t\tfor (u32 i = 0; i < usbd_otg->desc->cfg->interface.bNumEndpoints; i++)\n\t\t\t\t\tusbd_otg->desc->cfg->endpoint[i].wMaxPacketSize = 0x200; // No burst.\n\t\t\t}\n\t\t\telse // Full speed. 64 bytes.\n\t\t\t{\n\t\t\t\tfor (u32 i = 0; i < usbd_otg->desc->cfg->interface.bNumEndpoints; i++)\n\t\t\t\t\tusbd_otg->desc->cfg->endpoint[i].wMaxPacketSize = 0x40;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tusb_cfg_hid_descr_t *tmp = (usb_cfg_hid_descr_t *)usbd_otg->desc->cfg;\n\t\t\tif (usbd_otg->port_speed == USB_HIGH_SPEED) // High speed. 512 bytes.\n\t\t\t{\n\t\t\t\tfor (u32 i = 0; i < tmp->interface.bNumEndpoints; i++)\n\t\t\t\t{\n\t\t\t\t\ttmp->endpoint[i].wMaxPacketSize = 0x200;\n\t\t\t\t\ttmp->endpoint[i].bInterval = usbd_otg->gadget == USB_GADGET_HID_GAMEPAD ? 4 : 3; // 8ms : 4ms.\n\t\t\t\t}\n\t\t\t}\n\t\t\telse // Full speed. 64 bytes.\n\t\t\t{\n\t\t\t\tfor (u32 i = 0; i < tmp->interface.bNumEndpoints; i++)\n\t\t\t\t{\n\t\t\t\t\ttmp->endpoint[i].wMaxPacketSize = 0x40;\n\t\t\t\t\ttmp->endpoint[i].bInterval = usbd_otg->gadget == USB_GADGET_HID_GAMEPAD ? 8 : 4; // 8ms : 4ms.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t*desc = usbd_otg->desc->cfg;\n\t\t*size = usbd_otg->desc->cfg->config.wTotalLength;\n\t\t*transmit_data = true;\n\t\treturn;\n\tcase USB_DESCRIPTOR_STRING:\n\t\tswitch (descriptor_subtype)\n\t\t{\n\t\tcase 1:\n\t\t\t*desc = usbd_otg->desc->vendor;\n\t\t\t*size = usbd_otg->desc->vendor[0];\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\t*desc = usbd_otg->desc->product;\n\t\t\t*size = usbd_otg->desc->product[0];\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\t*desc = usbd_otg->desc->serial;\n\t\t\t*size = usbd_otg->desc->serial[0];\n\t\t\tbreak;\n\t\tcase 0xEE:\n\t\t\t*desc = usbd_otg->desc->ms_os;\n\t\t\t*size = usbd_otg->desc->ms_os->bLength;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t*desc = usbd_otg->desc->lang_id;\n\t\t\t*size = 4;\n\t\t\tbreak;\n\t\t}\n\t\t*transmit_data = true;\n\t\treturn;\n\tcase USB_DESCRIPTOR_DEVICE_QUALIFIER:\n\t\tif (!usbd_otg->desc->dev_qual)\n\t\t\tgoto exit;\n\t\tusbd_otg->desc->dev_qual->bNumOtherConfigs = 1;\n\t\t*desc = usbd_otg->desc->dev_qual;\n\t\t*size = usbd_otg->desc->dev_qual->bLength;\n\t\t*transmit_data = true;\n\t\treturn;\n\tcase USB_DESCRIPTOR_OTHER_SPEED_CONFIGURATION:\n\t\tif (!usbd_otg->desc->cfg_other)\n\t\t\tgoto exit;\n\t\tif (usbd_otg->port_speed == USB_HIGH_SPEED)\n\t\t{\n\t\t\tfor (u32 i = 0; i < usbd_otg->desc->cfg_other->interface.bNumEndpoints; i++)\n\t\t\t\tusbd_otg->desc->cfg_other->endpoint[i].wMaxPacketSize = 0x40;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (u32 i = 0; i < usbd_otg->desc->cfg_other->interface.bNumEndpoints; i++)\n\t\t\t\tusbd_otg->desc->cfg_other->endpoint[i].wMaxPacketSize = 0x200;\n\t\t}\n\t\tif ((usbd_otg->charger_detect & 1) && (usbd_otg->charger_detect & 2))\n\t\t\tusbd_otg->desc->cfg_other->config.bMaxPower = 500 / 2;\n\t\t*desc = usbd_otg->desc->cfg_other;\n\t\t*size = usbd_otg->desc->cfg_other->config.wTotalLength;\n\t\t*transmit_data = true;\n\t\treturn;\n\tcase USB_DESCRIPTOR_DEVICE_BINARY_OBJECT:\n\t\t*desc = usbd_otg->desc->dev_bot;\n\t\t*size = usbd_otg->desc->dev_bot->wTotalLength;\n\t\t*transmit_data = true;\n\t\treturn;\n\tdefault:\n\t\t*transmit_data = false;\n\t\t*ep_stall = true;\n\t\treturn;\n\t}\nexit:\n\t*transmit_data = false;\n\t*ep_stall = true;\n\treturn;\n}\n\nstatic int _usbd_handle_set_request(bool *ep_stall)\n{\n\tint res = USB_RES_OK;\n\tu8 bRequest = usbd_otg->control_setup.bRequest;\n\tif (bRequest == USB_REQUEST_SET_ADDRESS)\n\t{\n\t\tres = _usbd_ep_ack(USB_EP_CTRL_IN);\n\n\t\t// Set USB address for device mode.\n\t\tif (!res)\n\t\t\tusbd_otg->regs->periodiclistbase = (usbd_otg->regs->periodiclistbase & 0x1FFFFFF) | ((usbd_otg->control_setup.wValue & 0xFF) << 25);\n\t}\n\telse if (bRequest == USB_REQUEST_SET_CONFIGURATION)\n\t{\n\t\tres = _usbd_ep_ack(USB_EP_CTRL_IN);\n\t\tif (!res)\n\t\t{\n\t\t\tusbd_otg->config_num = usbd_otg->control_setup.wValue;\n\n\t\t\t// Remove configuration.\n\t\t\tif (!usbd_otg->config_num)\n\t\t\t{\n\t\t\t\t//! TODO: Signal that to userspace.\n\t\t\t\t_usb_reset_disable_ep1();\n\t\t\t\treturn res;\n\t\t\t}\n\n\t\t\t// Initialize configuration.\n\t\t\t_usbd_initialize_ep_ctrl(USB_EP_BULK_OUT);\n\t\t\t_usbd_initialize_ep_ctrl(USB_EP_BULK_IN);\n\t\t\tusbd_otg->configuration_set = true;\n\t\t}\n\t}\n\telse\n\t\t*ep_stall = true;\n\n\treturn res;\n}\n\nstatic int _usbd_handle_ep0_control_transfer()\n{\n\tint res = USB_RES_OK;\n\tbool ep_stall = false;\n\tbool transmit_data = false;\n\n\tu8 *desc = (u8 *)USB_DESCRIPTOR_ADDR;\n\tint size = 0;\n\n\tu8  _bmRequestType = usbd_otg->control_setup.bmRequestType;\n\tu8  _bRequest      = usbd_otg->control_setup.bRequest;\n\tu16 _wValue        = usbd_otg->control_setup.wValue;\n\tu16 _wIndex        = usbd_otg->control_setup.wIndex;\n\tu16 _wLength       = usbd_otg->control_setup.wLength;\n\n\t//gfx_printf(\"%02X %02X %04X %04X %04X\\n\", _bmRequestType, _bRequest, _wValue, _wIndex, _wLength);\n\n\tswitch (_bmRequestType)\n\t{\n\tcase (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_DEVICE):    // 0x00.\n\t\tres = _usbd_handle_set_request(&ep_stall);\n\t\tbreak;\n\n\tcase (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_INTERFACE): // 0x01.\n\t\tres = _usbd_ep_ack(USB_EP_CTRL_IN);\n\t\tif (!res)\n\t\t\tusbd_otg->interface_num = _wValue;\n\t\tbreak;\n\n\tcase (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT):  // 0x02.\n\t\tswitch (_bRequest)\n\t\t{\n\t\tcase USB_REQUEST_CLEAR_FEATURE:\n\t\tcase USB_REQUEST_SET_FEATURE:\n\t\t\tif ((_wValue & 0xFF) == USB_FEATURE_ENDPOINT_HALT)\n\t\t\t{\n\t\t\t\tint direction;\n\t\t\t\tswitch (_wIndex) // endpoint\n\t\t\t\t{\n\t\t\t\tcase USB_EP_ADDR_CTRL_OUT:\n\t\t\t\t\tdirection = 2;\n\t\t\t\t\tbreak;\n\t\t\t\tcase USB_EP_ADDR_CTRL_IN:\n\t\t\t\t\tdirection = 3;\n\t\t\t\t\tbreak;\n\t\t\t\tcase USB_EP_ADDR_BULK_OUT:\n\t\t\t\t\tdirection = 0;\n\t\t\t\t\tbreak;\n\t\t\t\tcase USB_EP_ADDR_BULK_IN:\n\t\t\t\t\tdirection = 1;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t_usbd_stall_reset_ep1(3, USB_EP_CFG_STALL);\n\t\t\t\t\tgoto out;\n\t\t\t\t}\n\n\t\t\t\tif (_bRequest == USB_REQUEST_CLEAR_FEATURE)\n\t\t\t\t\t_usbd_stall_reset_ep1(direction, USB_EP_CFG_RESET);\n\t\t\t\telse\n\t\t\t\t\t_usbd_stall_reset_ep1(direction, USB_EP_CFG_STALL);\n\n\t\t\t\tres = _usbd_ep_ack(USB_EP_CTRL_IN);\n\t\t\t}\n\t\t\telse\n\t\t\t\t_usbd_stall_reset_ep1(3, USB_EP_CFG_STALL);\n\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tep_stall = true;\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\n\tcase (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_CLASS    | USB_SETUP_RECIPIENT_INTERFACE): // 0x21.\n\t\tmemset(desc, 0, _wLength);\n\t\t_usbd_handle_get_class_request(&transmit_data, desc, &size, &ep_stall);\n\t\tbreak;\n\n\tcase (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_DEVICE):    // 0x80.\n\t\tswitch (_bRequest)\n\t\t{\n\t\tcase USB_REQUEST_GET_STATUS:\n\t\t\tdesc[0] = USB_STATUS_DEV_SELF_POWERED;\n\t\t\tdesc[1] = 0; // No support for remove wake up.\n\t\t\ttransmit_data = true;\n\t\t\tsize = 2;\n\t\t\tbreak;\n\t\tcase USB_REQUEST_GET_DESCRIPTOR:\n\t\t\t_usbd_handle_get_descriptor(&transmit_data, (void **)&desc, &size, &ep_stall);\n\t\t\tbreak;\n\t\tcase USB_REQUEST_GET_CONFIGURATION:\n\t\t\tdesc = (u8 *)&usbd_otg->config_num;\n\t\t\tsize = _wLength;\n\t\t\ttransmit_data = true;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tep_stall = true;\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\n\tcase (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_INTERFACE): // 0x81.\n\t\tif (_bRequest == USB_REQUEST_GET_INTERFACE)\n\t\t{\n\t\t\tmemset(desc, 0, _wLength);\n\t\t\tdesc[0] = usbd_otg->interface_num;\n\t\t\tsize = _wLength;\n\t\t}\n\t\telse if (_bRequest == USB_REQUEST_GET_STATUS)\n\t\t{\n\t\t\tmemset(desc, 0, _wLength);\n\t\t\tsize = _wLength;\n\t\t}\n\t\telse if (_bRequest == USB_REQUEST_GET_DESCRIPTOR && (_wValue >> 8) == USB_DESCRIPTOR_HID_REPORT && usbd_otg->gadget >= USB_GADGET_HID_GAMEPAD)\n\t\t{\n\t\t\tif (usbd_otg->gadget == USB_GADGET_HID_GAMEPAD)\n\t\t\t{\n\t\t\t\tdesc = (u8 *)&hid_report_descriptor_jc;\n\t\t\t\tsize = hid_report_descriptor_jc_size;\n\t\t\t}\n\t\t\telse // USB_GADGET_HID_TOUCHPAD\n\t\t\t{\n\t\t\t\tdesc = (u8 *)&hid_report_descriptor_touch;\n\t\t\t\tsize = hid_report_descriptor_touch_size;\n\t\t\t}\n\n\t\t\tusbd_otg->hid_report_sent = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tep_stall = true;\n\t\t\tbreak;\n\t\t}\n\n\t\tif (_wLength < size)\n\t\t\tsize = _wLength;\n\t\ttransmit_data = true;\n\t\tbreak;\n\n\tcase (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT):  // 0x82.\n\t\tif (_bRequest == USB_REQUEST_GET_STATUS)\n\t\t{\n\t\t\tint ep_req;\n\t\t\tswitch (_wIndex)\n\t\t\t{\n\t\t\tcase USB_EP_ADDR_CTRL_OUT:\n\t\t\t\tep_req = USB_EP_CTRL_OUT;\n\t\t\t\tbreak;\n\t\t\tcase USB_EP_ADDR_BULK_OUT:\n\t\t\t\tep_req = USB_EP_BULK_OUT;\n\t\t\t\tbreak;\n\t\t\tcase USB_EP_ADDR_CTRL_IN:\n\t\t\t\tep_req = USB_EP_CTRL_IN;\n\t\t\t\tbreak;\n\t\t\tcase USB_EP_ADDR_BULK_IN:\n\t\t\t\tep_req = USB_EP_BULK_IN;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t_usbd_stall_reset_ep1(3, USB_EP_CFG_STALL);\n\t\t\t\tgoto out;\n\t\t\t}\n\n\t\t\tsize = _wLength;\n\t\t\tmemset(desc, 0, size);\n\n\t\t\tif (_usbd_get_ep_status(ep_req) == USB_EP_STATUS_STALLED)\n\t\t\t\tdesc[0] = USB_STATUS_EP_HALTED;\n\t\t\telse\n\t\t\t\tdesc[0] = USB_STATUS_EP_OK;\n\n\t\t\ttransmit_data = true;\n\t\t}\n\t\telse\n\t\t\t_usbd_stall_reset_ep1(3, USB_EP_CFG_STALL);\n\t\tbreak;\n\n\tcase (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_CLASS    | USB_SETUP_RECIPIENT_INTERFACE): // 0xA1.\n\t\tmemset(desc, 0, _wLength);\n\t\t_usbd_handle_get_class_request(&transmit_data, desc, &size, &ep_stall);\n\t\tbreak;\n\n\tcase (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_VENDOR   | USB_SETUP_RECIPIENT_DEVICE):    // 0xC0.\n\tcase (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_VENDOR   | USB_SETUP_RECIPIENT_INTERFACE): // 0xC1.\n\t\tif (_bRequest == USB_REQUEST_GET_MS_DESCRIPTOR)\n\t\t{\n\t\t\tswitch (_wIndex)\n\t\t\t{\n\t\t\tcase USB_DESCRIPTOR_MS_COMPAT_ID:\n\t\t\t\tdesc = (u8 *)usbd_otg->desc->ms_cid;\n\t\t\t\tsize = usbd_otg->desc->ms_cid->dLength;\n\t\t\t\ttransmit_data = true;\n\t\t\t\tbreak;\n\t\t\tcase USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES:\n\t\t\t\tdesc = (u8 *)usbd_otg->desc->mx_ext;\n\t\t\t\tsize = usbd_otg->desc->mx_ext->dLength;\n\t\t\t\ttransmit_data = true;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tep_stall = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tep_stall = true;\n\t\tbreak;\n\n\tdefault:\n\t\tep_stall = true;\n\t\tbreak;\n\t}\n\n\t// Transmit data to HOST if any.\n\tif (transmit_data)\n\t{\n\t\tmemcpy(usb_ep0_ctrl_buf, desc, size);\n\n\t\tif (_wLength < size)\n\t\t\tsize = _wLength;\n\t\tres = _usbd_ep_operation(USB_EP_CTRL_IN, usb_ep0_ctrl_buf, size, USB_XFER_SYNCED_ENUM);\n\t\tif (!res)\n\t\t\tres = _usbd_ep_ack(USB_EP_CTRL_OUT);\n\t}\n\nout:\n\tif (ep_stall)\n\t\t_usbd_set_ep0_stall();\n\n\treturn res;\n}\n\nstatic int _usbd_ep0_initialize()\n{\n\tbool enter = false;\n\tif (usbd_otg->configuration_set)\n\t\tenter = true;\n\telse\n\t{\n\t\tusbdaemon->qhs = (volatile dQH_t *)USB2_QH_USB2D_QH_EP_BASE;\n\n\t\tif (!_usbd_initialize_ep0())\n\t\t\tenter = true;\n\t}\n\n\tif (enter)\n\t{\n\t\tusbd_otg->configuration_set = false;\n\t\tusbd_otg->max_lun_set = false;\n\n\t\t// Timeout if cable or communication isn't started in 1.5 minutes.\n\t\tu32 timer = get_tmr_ms() + 90000;\n\t\twhile (true)\n\t\t{\n\t\t\tu32 usb_status_irqs = usbd_otg->regs->usbsts;\n\n\t\t\t// Clear all interrupt statuses.\n\t\t\tusbd_otg->regs->usbsts = usb_status_irqs;\n\n\t\t\t// Check if a reset was received.\n\t\t\tif (usb_status_irqs & USB2D_USBSTS_URI)\n\t\t\t{\n\t\t\t\t//_disable_usb_wdt4();\n\n\t\t\t\t// Clear all device addresses, enabled setup requests, transmit events and flush all endpoints.\n\t\t\t\tusbd_otg->regs->periodiclistbase = 0;\n\t\t\t\tusbd_otg->regs->endptsetupstat   = usbd_otg->regs->endptsetupstat;\n\t\t\t\tusbd_otg->regs->endptcomplete    = usbd_otg->regs->endptcomplete;\n\t\t\t\tusbd_flush_endpoint(USB_EP_ALL);\n\t\t\t}\n\n\t\t\t// Check if port change happened.\n\t\t\tif (usb_status_irqs & USB2D_USBSTS_PCI)\n\t\t\t\tusbd_otg->port_speed = (usbd_otg->regs->hostpc1_devlc & USB2D_HOSTPC1_DEVLC_PSPD_MASK) >> 25;\n\n\t\t\t// Acknowledge setup request for EP0 and copy its configuration.\n\t\t\tu32 ep0_setup_req = usbd_otg->regs->endptsetupstat;\n\t\t\tif (ep0_setup_req & 1)\n\t\t\t{\n\t\t\t\tusbd_otg->regs->endptsetupstat = ep0_setup_req;\n\t\t\t\tmemcpy(&usbd_otg->control_setup, (void *)usbdaemon->qhs->setup, 8);\n\t\t\t\tif (_usbd_handle_ep0_control_transfer())\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (usbd_otg->configuration_set)\n\t\t\t\treturn USB_RES_OK;\n\n\t\t\tif (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))\n\t\t\t\treturn USB_ERROR_USER_ABORT;\n\t\t}\n\t}\n\n\treturn USB_ERROR_TIMEOUT;\n}\n\nint usb_device_enumerate(usb_gadget_type gadget)\n{\n\tswitch (gadget)\n\t{\n\tcase USB_GADGET_UMS:\n\t\tusbd_otg->desc = &usb_gadget_ums_descriptors;\n\t\tbreak;\n\tcase USB_GADGET_HID_GAMEPAD:\n\t\tusbd_otg->desc = &usb_gadget_hid_jc_descriptors;\n\t\tbreak;\n\tcase USB_GADGET_HID_TOUCHPAD:\n\t\tusbd_otg->desc = &usb_gadget_hid_touch_descriptors;\n\t\tbreak;\n\t}\n\n\tusbd_otg->gadget = gadget;\n\n\treturn _usbd_ep0_initialize();\n}\n\nint usbd_handle_ep0_ctrl_setup(u32 *data)\n{\n\t// Acknowledge setup request for EP0 and copy its configuration.\n\tu32 ep0_setup_req = usbd_otg->regs->endptsetupstat;\n\tif (ep0_setup_req & 1)\n\t{\n\t\tusbd_otg->regs->endptsetupstat = ep0_setup_req;\n\t\tmemcpy(&usbd_otg->control_setup, (void *)usbdaemon->qhs->setup, 8);\n\t\t_usbd_handle_ep0_control_transfer();\n\t\tmemset(usb_ep0_ctrl_buf, 0, USB_TD_BUFFER_PAGE_SIZE);\n\t}\n\n\tif (usbd_otg->intr_idle_req)\n\t{\n\t\tif (data)\n\t\t\t*data = usbd_otg->intr_idle_rate;\n\n\t\tusbd_otg->intr_idle_req = false;\n\t\treturn USB_RES_OK;\n\t}\n\n\t// Only return error if bulk reset was requested.\n\tif (usbd_otg->bulk_reset_req)\n\t{\n\t\tusbd_otg->bulk_reset_req = false;\n\t\treturn USB_RES_BULK_RESET;\n\t}\n\n\treturn USB_RES_OK;\n}\n\nstatic usb_ep_status_t _usbd_get_ep1_status(usb_dir_t dir)\n{\n\tusb_ep_t ep;\n\tif (dir == USB_DIR_OUT)\n\t\tep = USB_EP_BULK_OUT;\n\telse\n\t\tep = USB_EP_BULK_IN;\n\treturn _usbd_get_ep_status(ep);\n}\n\nint usb_device_ep1_out_read(u8 *buf, u32 len, u32 *bytes_read, u32 sync_timeout)\n{\n\tif ((u32)buf % USB_EP_BUFFER_ALIGN)\n\t\treturn USB2_ERROR_XFER_NOT_ALIGNED;\n\n\tif (len > USB_EP_BUFFER_MAX_SIZE)\n\t\tlen = USB_EP_BUFFER_MAX_SIZE;\n\n\tint res = _usbd_ep_operation(USB_EP_BULK_OUT, buf, len, sync_timeout);\n\n\tif (sync_timeout && bytes_read)\n\t\t*bytes_read = res ? 0 : len;\n\n\treturn res;\n}\n\nint usb_device_ep1_out_read_big(u8 *buf, u32 len, u32 *bytes_read)\n{\n\tif ((u32)buf % USB_EP_BUFFER_ALIGN)\n\t\treturn USB2_ERROR_XFER_NOT_ALIGNED;\n\n\tif (len > USB_EP_BULK_OUT_MAX_XFER)\n\t\tlen = USB_EP_BULK_OUT_MAX_XFER;\n\n\tint res;\n\tu32 bytes = 0;\n\t*bytes_read = 0;\n\tu8 *buf_curr = buf;\n\n\twhile (len)\n\t{\n\t\tu32 len_ep = MIN(len, USB_EP_BUFFER_MAX_SIZE);\n\n\t\tres = usb_device_ep1_out_read(buf_curr, len_ep, &bytes, USB_XFER_SYNCED_DATA);\n\t\tif (res)\n\t\t\treturn res;\n\n\t\tlen -= len_ep;\n\t\tbuf_curr += len_ep;\n\t\t*bytes_read = *bytes_read + bytes;\n\t}\n\n\treturn USB_RES_OK;\n}\n\nstatic int _usbd_get_ep1_out_bytes_read()\n{\n\tif (_usbd_get_ep_status(USB_EP_BULK_OUT) != USB_EP_STATUS_IDLE)\n\t\treturn 0;\n\telse\n\t\treturn (usbdaemon->ep_bytes_requested[USB_EP_BULK_OUT] - (usbdaemon->qhs[USB_EP_BULK_OUT].token >> 16));\n}\n\nint usb_device_ep1_out_reading_finish(u32 *pending_bytes, u32 sync_timeout)\n{\n\tusb_ep_status_t ep_status;\n\tdo\n\t{\n\t\tep_status = _usbd_get_ep1_status(USB_DIR_OUT);\n\t\tif ((ep_status == USB_EP_STATUS_IDLE) || (ep_status == USB_EP_STATUS_DISABLED))\n\t\t\tbreak;\n\n\t\tusbd_handle_ep0_ctrl_setup(NULL);\n\t}\n\twhile ((ep_status == USB_EP_STATUS_ACTIVE) || (ep_status == USB_EP_STATUS_STALLED));\n\n\t*pending_bytes = _usbd_get_ep1_out_bytes_read();\n\n\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);\n\n\tif (ep_status == USB_EP_STATUS_IDLE)\n\t\treturn USB_RES_OK;\n\telse if (ep_status == USB_EP_STATUS_DISABLED)\n\t\treturn USB2_ERROR_XFER_EP_DISABLED;\n\telse\n\t\treturn USB_ERROR_XFER_ERROR;\n}\n\nint usb_device_ep1_in_write(u8 *buf, u32 len, u32 *bytes_written, u32 sync_timeout)\n{\n\tif ((u32)buf % USB_EP_BUFFER_ALIGN)\n\t\treturn USB2_ERROR_XFER_NOT_ALIGNED;\n\n\tif (len > USB_EP_BUFFER_MAX_SIZE)\n\t\tlen = USB_EP_BUFFER_MAX_SIZE;\n\n\tint res = _usbd_ep_operation(USB_EP_BULK_IN, buf, len, sync_timeout);\n\n\tif (sync_timeout && bytes_written)\n\t\t*bytes_written = res ? 0 : len;\n\n\treturn res;\n}\n\nstatic int _usbd_get_ep1_in_bytes_written()\n{\n\tif (_usbd_get_ep_status(USB_EP_BULK_IN) != USB_EP_STATUS_IDLE)\n\t\treturn 0;\n\telse\n\t\treturn (usbdaemon->ep_bytes_requested[USB_EP_BULK_IN] - (usbdaemon->qhs[USB_EP_BULK_IN].token >> 16));\n}\n\nint usb_device_ep1_in_writing_finish(u32 *pending_bytes, u32 sync_timeout)\n{\n\tusb_ep_status_t ep_status;\n\tdo\n\t{\n\t\tep_status = _usbd_get_ep1_status(USB_DIR_IN);\n\t\tif ((ep_status == USB_EP_STATUS_IDLE) || (ep_status == USB_EP_STATUS_DISABLED))\n\t\t\tbreak;\n\n\t\tusbd_handle_ep0_ctrl_setup(NULL);\n\t}\n\twhile ((ep_status == USB_EP_STATUS_ACTIVE) || (ep_status == USB_EP_STATUS_STALLED));\n\n\t*pending_bytes = _usbd_get_ep1_in_bytes_written();\n\n\tif (ep_status == USB_EP_STATUS_IDLE)\n\t\treturn USB_RES_OK;\n\telse if (ep_status == USB_EP_STATUS_DISABLED)\n\t\treturn USB2_ERROR_XFER_EP_DISABLED;\n\n\tusb_device_stall_ep1_bulk_out();\n\treturn USB_ERROR_XFER_ERROR;\n}\n\nbool usb_device_get_suspended()\n{\n\tbool suspended = (usbd_otg->regs->portsc1 & USB2D_PORTSC1_SUSP) == USB2D_PORTSC1_SUSP;\n\treturn suspended;\n}\n\nbool usb_device_get_port_in_sleep()\n{\n\t// Windows heuristic: Forces port into suspend, sleep and J-State.\n\treturn (usbd_otg->regs->portsc1) == 0x885;\n}\n\nint usb_device_class_send_max_lun(u8 max_lun)\n{\n\t// Timeout if get MAX_LUN request doesn't happen in 10s.\n\tu32 timer = get_tmr_ms() + 10000;\n\n\tusbd_otg->max_lun = max_lun;\n\n\twhile (!usbd_otg->max_lun_set)\n\t{\n\t\tusbd_handle_ep0_ctrl_setup(NULL);\n\t\tif (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))\n\t\t\treturn USB_ERROR_USER_ABORT;\n\t}\n\n\treturn USB_RES_OK;\n}\n\nint usb_device_class_send_hid_report(void *rpt_buffer, u32 rpt_size)\n{\n\t// Set buffers.\n\tusbd_otg->hid_rpt_buffer = rpt_buffer;\n\tusbd_otg->hid_rpt_size   = rpt_size;\n\n\t// Timeout if get GET_HID_REPORT request doesn't happen in 10s.\n\tu32 timer = get_tmr_ms() + 10000;\n\n\t// Wait for request and transfer start.\n\twhile (!usbd_otg->hid_report_sent)\n\t{\n\t\tusbd_handle_ep0_ctrl_setup(NULL);\n\t\tif (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))\n\t\t\treturn USB_ERROR_USER_ABORT;\n\t}\n\n\treturn USB_RES_OK;\n}\n\nvoid usb_device_get_ops(usb_ops_t *ops)\n{\n\tops->usbd_flush_endpoint               = usbd_flush_endpoint;\n\tops->usbd_set_ep_stall                 = usbd_set_ep_stall;\n\tops->usbd_handle_ep0_ctrl_setup        = usbd_handle_ep0_ctrl_setup;\n\tops->usbd_end                          = usbd_end;\n\tops->usb_device_init                   = usb_device_init;\n\tops->usb_device_enumerate              = usb_device_enumerate;\n\tops->usb_device_class_send_max_lun     = usb_device_class_send_max_lun;\n\tops->usb_device_class_send_hid_report  = usb_device_class_send_hid_report;\n\tops->usb_device_get_suspended          = usb_device_get_suspended;\n\tops->usb_device_get_port_in_sleep      = usb_device_get_port_in_sleep;\n\n\tops->usb_device_ep1_out_read           = usb_device_ep1_out_read;\n\tops->usb_device_ep1_out_read_big       = usb_device_ep1_out_read_big;\n\tops->usb_device_ep1_out_reading_finish = usb_device_ep1_out_reading_finish;\n\tops->usb_device_ep1_in_write           = usb_device_ep1_in_write;\n\tops->usb_device_ep1_in_writing_finish  = usb_device_ep1_in_writing_finish;\n}\n\n"
  },
  {
    "path": "bdk/usb/usbd.h",
    "content": "/*\n * Enhanced & eXtensible USB Device (EDCI & XDCI) driver for Tegra X1\n *\n * Copyright (c) 2019-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _USB_H_\n#define _USB_H_\n\n#include <utils/types.h>\n\n#define USB_TD_BUFFER_PAGE_SIZE 0x1000\n#define USB_TD_BUFFER_MAX_SIZE  (USB_TD_BUFFER_PAGE_SIZE * 4)\n//#define USB_HW_BUFFER_5_PAGES 0x5000\n#define USB_EP_BUFFER_1_TD      (USB_TD_BUFFER_MAX_SIZE)\n#define USB_EP_BUFFER_2_TD      (USB_TD_BUFFER_MAX_SIZE * 2)\n#define USB_EP_BUFFER_4_TD      (USB_TD_BUFFER_MAX_SIZE * 4)\n#define USB_EP_BUFFER_MAX_SIZE  (USB_EP_BUFFER_4_TD)\n#define USB_EP_BUFFER_ALIGN     (USB_TD_BUFFER_PAGE_SIZE)\n\n#define USB_XFER_START        0\n#define USB_XFER_SYNCED_ENUM  1000000 // ~2s.\n#define USB_XFER_SYNCED_CMD   1000000 // ~2s.\n#define USB_XFER_SYNCED_DATA  2000000 // ~4s.\n#define USB_XFER_SYNCED_CLASS 5000000 // ~10s.\n#define USB_XFER_SYNCED       -1      // Max.\n\ntypedef enum _usb_hid_type\n{\n\tUSB_HID_GAMEPAD,\n\tUSB_HID_TOUCHPAD\n} usb_hid_type;\n\ntypedef enum _usb_gadget_type\n{\n\tUSB_GADGET_UMS          = 0,\n\tUSB_GADGET_HID_GAMEPAD  = 1,\n\tUSB_GADGET_HID_TOUCHPAD = 2,\n} usb_gadget_type;\n\ntypedef enum {\n\tUSB_DIR_OUT = 0,\n\tUSB_DIR_IN  = 1,\n} usb_dir_t;\n\ntypedef enum\n{\n\tXUSB_EP_CTRL_IN  = 0, // EP0.\n\tXUSB_EP_CTRL_OUT = 1, // EP0.\n\n\tUSB_EP_CTRL_OUT = 0,  // EP0.\n\tUSB_EP_CTRL_IN  = 1,  // EP0.\n\n\tUSB_EP_BULK_OUT = 2,  // EP1.\n\tUSB_EP_BULK_IN  = 3,  // EP1.\n\tUSB_EP_ALL      = 0xFFFFFFFF\n} usb_ep_t;\n\ntypedef enum\n{\n\tUSB_EP_ADDR_CTRL_OUT = 0x00,\n\tUSB_EP_ADDR_CTRL_IN  = 0x80,\n\tUSB_EP_ADDR_BULK_OUT = 0x01,\n\tUSB_EP_ADDR_BULK_IN  = 0x81,\n} usb_ep_addr_t;\n\ntypedef enum\n{\n\tUSB_EP_CFG_CLEAR = 0,\n\tUSB_EP_CFG_RESET = 0,\n\tUSB_EP_CFG_STALL = 1\n} usb_ep_cfg_t;\n\ntypedef enum {\n\tUSB_STATUS_EP_OK            = 0,\n\tUSB_STATUS_EP_HALTED        = 1,\n\n\tUSB_STATUS_DEV_SELF_POWERED = 1,\n\tUSB_STATUS_DEV_REMOTE_WAKE  = 2,\n} usb_set_clear_feature_req_t;\n\ntypedef enum {\n\tUSB_SETUP_RECIPIENT_DEVICE    = 0,\n\tUSB_SETUP_RECIPIENT_INTERFACE = 1,\n\tUSB_SETUP_RECIPIENT_ENDPOINT  = 2,\n\tUSB_SETUP_RECIPIENT_OTHER     = 3,\n\n\tUSB_SETUP_TYPE_STANDARD       = 0x00,\n\tUSB_SETUP_TYPE_CLASS          = 0x20,\n\tUSB_SETUP_TYPE_VENDOR         = 0x40,\n\tUSB_SETUP_TYPE_RESERVED       = 0x60,\n\n\tUSB_SETUP_HOST_TO_DEVICE      = 0x00,\n\tUSB_SETUP_DEVICE_TO_HOST      = 0x80,\n} usb_setup_req_type_t;\n\ntypedef enum {\n\tUSB_REQUEST_GET_STATUS        = 0,\n\tUSB_REQUEST_CLEAR_FEATURE     = 1,\n\tUSB_REQUEST_SET_FEATURE       = 3,\n\tUSB_REQUEST_SET_ADDRESS       = 5,\n\tUSB_REQUEST_GET_DESCRIPTOR    = 6,\n\tUSB_REQUEST_SET_DESCRIPTOR    = 7,\n\tUSB_REQUEST_GET_CONFIGURATION = 8,\n\tUSB_REQUEST_SET_CONFIGURATION = 9,\n\tUSB_REQUEST_GET_INTERFACE     = 10,\n\tUSB_REQUEST_SET_INTERFACE     = 11,\n\tUSB_REQUEST_SYNCH_FRAME       = 12,\n\tUSB_REQUEST_SET_SEL           = 13,\n\n\tUSB_REQUEST_GET_MS_DESCRIPTOR = 0x99,\n\n\tUSB_REQUEST_INTR_GET_REPORT   = 1,\n\tUSB_REQUEST_INTR_SET_IDLE     = 10,\n\n\tUSB_REQUEST_BULK_GET_MAX_LUN  = 0xFE,\n\tUSB_REQUEST_BULK_RESET        = 0xFF\n} usb_standard_req_t;\n\ntypedef enum {\n\tUSB_FEATURE_ENDPOINT_HALT        = 0,\n\tUSB_FEATURE_DEVICE_REMOTE_WAKEUP = 1,\n\tUSB_FEATURE_TEST_MODE            = 2,\n} usb_get_status_req_t;\n\ntypedef enum _usb_error_t\n{\n\tUSB_RES_OK           = 0,\n\tUSB_RES_BULK_RESET   = 1,\n\n\tUSB_ERROR_USER_ABORT = 2,\n\tUSB_ERROR_TIMEOUT    = 3,\n\tUSB_ERROR_INIT       = 4,\n\tUSB_ERROR_XFER_ERROR = 5,\n\n\tUSB2_ERROR_XFER_EP_DISABLED     = 28,\n\tUSB2_ERROR_XFER_NOT_ALIGNED     = 29,\n\n\tXUSB_ERROR_INVALID_EP           = USB_ERROR_XFER_ERROR,        // From 2.\n\tXUSB_ERROR_XFER_BULK_IN_RESIDUE = 7,\n\tXUSB_ERROR_INVALID_CYCLE        = USB2_ERROR_XFER_EP_DISABLED, // From 8.\n\tXUSB_ERROR_BABBLE_DETECTED      = 50,\n\tXUSB_ERROR_SEQ_NUM              = 51,\n\tXUSB_ERROR_XFER_DIR             = 52,\n\tXUSB_ERROR_PORT_CFG             = 54\n} usb_error_t;\n\ntypedef struct _usb_ctrl_setup_t\n{\n\tu8 bmRequestType;\n\tu8 bRequest;\n\tu16 wValue;\n\tu16 wIndex;\n\tu16 wLength;\n} usb_ctrl_setup_t;\n\ntypedef struct _usb_ops_t\n{\n\tint  (*usbd_flush_endpoint)(u32);\n\tint  (*usbd_set_ep_stall)(u32, int);\n\tint  (*usbd_handle_ep0_ctrl_setup)(u32 *);\n\tvoid (*usbd_end)(bool, bool);\n\tint  (*usb_device_init)();\n\tint  (*usb_device_enumerate)(usb_gadget_type);\n\n\tint  (*usb_device_class_send_max_lun)(u8);\n\tint  (*usb_device_class_send_hid_report)(void *, u32);\n\n\tint  (*usb_device_ep1_out_read)(u8 *, u32, u32 *, u32);\n\tint  (*usb_device_ep1_out_read_big)(u8 *, u32, u32 *);\n\tint  (*usb_device_ep1_out_reading_finish)(u32 *, u32);\n\tint  (*usb_device_ep1_in_write)(u8 *, u32, u32 *, u32);\n\tint  (*usb_device_ep1_in_writing_finish)(u32 *, u32);\n\tbool (*usb_device_get_suspended)();\n\tbool (*usb_device_get_port_in_sleep)();\n} usb_ops_t;\n\ntypedef struct _usb_ctxt_t\n{\n\tu32 type;\n\n\t// UMS.\n\tu32 partition;\n\tu32 offset;\n\tu32 sectors;\n\tu32 ro;\n\n\t// HID.\n\tu32 idle;\n\n\t// System.\n\tvoid (*system_maintenance)(bool);\n\tvoid *label;\n\tvoid (*set_text)(void *, const char *);\n} usb_ctxt_t;\n\nvoid usb_device_get_ops(usb_ops_t *ops);\nvoid xusb_device_get_ops(usb_ops_t *ops);\n\nint  usb_device_gadget_ums(usb_ctxt_t *usbs);\nint  usb_device_gadget_hid(usb_ctxt_t *usbs);\n\n#endif\n"
  },
  {
    "path": "bdk/usb/xusbd.c",
    "content": "/*\n * eXtensible USB Device driver (XDCI) for Tegra X1\n *\n * Copyright (c) 2020-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <usb/usbd.h>\n#include <usb/usb_descriptor_types.h>\n#include <usb/usb_t210.h>\n\n#include <gfx_utils.h>\n#include <mem/mc.h>\n#include <soc/bpmp.h>\n#include <soc/clock.h>\n#include <soc/fuse.h>\n#include <soc/pmc.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n#include <utils/btn.h>\n\n#include <memory_map.h>\n\n#define XUSB_TRB_SLOTS 16 //! TODO: Consider upping it.\n#define XUSB_LINK_TRB_IDX (XUSB_TRB_SLOTS - 1)\n#define XUSB_LAST_TRB_IDX (XUSB_TRB_SLOTS - 1)\n\n#define EP_DONT_RING     0\n#define EP_RING_DOORBELL 1\n\ntypedef enum {\n\tXUSB_FULL_SPEED  = 1,\n\tXUSB_HIGH_SPEED  = 3,\n\tXUSB_SUPER_SPEED = 4\n} xusb_speed_t;\n\ntypedef enum {\n\tEP_DISABLED = 0,\n\tEP_RUNNING  = 1,\n\tEP_HALTED   = 2,\n\tEP_STOPPED  = 3,\n\tEP_ERROR    = 4\n} xusb_ep_status_t;\n\ntypedef enum {\n\tEP_TYPE_ISOC_OUT = 1,\n\tEP_TYPE_BULK_OUT = 2,\n\tEP_TYPE_INTR_OUT = 3,\n\tEP_TYPE_CNTRL    = 4,\n\tEP_TYPE_ISOC_IN  = 5,\n\tEP_TYPE_BULK_IN  = 6,\n\tEP_TYPE_INTR_IN  = 7\n} xusb_ep_type_t;\n\ntypedef enum {\n\tXUSB_DEFAULT                 = 0,\n\tXUSB_ADDRESSED_STS_WAIT      = 1,\n\tXUSB_ADDRESSED               = 2,\n\tXUSB_CONFIGURED_STS_WAIT     = 3,\n\tXUSB_CONFIGURED              = 4,\n\n\tXUSB_LUN_CONFIGURED_STS_WAIT = 5,\n\tXUSB_LUN_CONFIGURED          = 6,\n\tXUSB_HID_CONFIGURED_STS_WAIT = 7,\n\tXUSB_HID_CONFIGURED          = 8,\n\n\t// XUSB_CONNECTED           = ,\n\t// XUSB_DISCONNECTED        = ,\n\t// XUSB_RESET               = ,\n\t// XUSB_SUSPENDED           = ,\n} xusb_dev_state_t;\n\ntypedef enum {\n\tXUSB_TRB_NONE        = 0,\n\tXUSB_TRB_NORMAL      = 1,\n\tXUSB_TRB_DATA        = 3,\n\tXUSB_TRB_STATUS      = 4,\n\tXUSB_TRB_LINK        = 6,\n\tXUSB_TRB_TRANSFER    = 32,\n\tXUSB_TRB_PORT_CHANGE = 34,\n\tXUSB_TRB_SETUP       = 63,\n} xusb_trb_type_t;\n\ntypedef enum {\n\tXUSB_COMP_INVALID                   = 0,\n\tXUSB_COMP_SUCCESS                   = 1,\n\tXUSB_COMP_DATA_BUFFER_ERROR         = 2,\n\tXUSB_COMP_BABBLE_DETECTED_ERROR     = 3,\n\tXUSB_COMP_USB_TRANSACTION_ERROR     = 4,\n\tXUSB_COMP_TRB_ERROR                 = 5,\n\tXUSB_COMP_STALL_ERROR               = 6,\n\tXUSB_COMP_RESOURCE_ERROR            = 7,\n\tXUSB_COMP_BANDWIDTH_ERROR           = 8,\n\tXUSB_COMP_NO_SLOTS_AVAILABLE_ERROR  = 9,\n\tXUSB_COMP_INVALID_STREAM_TYPE_ERROR = 10,\n\tXUSB_COMP_SLOT_NOT_ENABLED_ERROR    = 11,\n\tXUSB_COMP_EP_DISABLED_ERROR         = 12,\n\tXUSB_COMP_SHORT_PKT                 = 13,\n\tXUSB_COMP_RING_UNDERRUN             = 14,\n\tXUSB_COMP_RING_OVERRUN              = 15,\n\tXUSB_COMP_VF_EVENT_RING_FULL_ERROR  = 16,\n\tXUSB_COMP_PARAMETER_ERROR           = 17,\n\tXUSB_COMP_BANDWIDTH_OVERRUN_ERROR   = 18,\n\tXUSB_COMP_CONTEXT_STATE_ERROR       = 19,\n\tXUSB_COMP_NO_PING_RESPONSE_ERROR    = 20,\n\tXUSB_COMP_EVENT_RING_FULL_ERROR     = 21,\n\tXUSB_COMP_INCOMPATIBLE_DEVICE_ERROR = 22,\n\tXUSB_COMP_MISSED_SERVICE_ERROR      = 23,\n\tXUSB_COMP_COMMAND_RING_STOPPED      = 24,\n\tXUSB_COMP_COMMAND_ABORTED           = 25,\n\tXUSB_COMP_STOPPED                   = 26,\n\tXUSB_COMP_STOPPED_LENGTH_INVALID    = 27,\n\tXUSB_COMP_STOPPED_SHORT_PACKET      = 28,\n\tXUSB_COMP_EXIT_LATENCY_LARGE_ERROR  = 29,\n\tXUSB_COMP_ISOCH_BUFFER_OVERRUN      = 31,\n\tXUSB_COMP_EVENT_LOST_ERROR          = 32,\n\tXUSB_COMP_UNDEFINED_ERROR           = 33,\n\tXUSB_COMP_INVALID_STREAM_ID_ERROR   = 34,\n\tXUSB_COMP_SECONDARY_BANDWIDTH_ERROR = 35,\n\tXUSB_COMP_SPLIT_TRANSACTION_ERROR   = 36,\n\n\tXUSB_COMP_CODE_STREAM_NUMP_ERROR    = 219,\n\tXUSB_COMP_PRIME_PIPE_RECEIVED       = 220,\n\tXUSB_COMP_HOST_REJECTED             = 221,\n\tXUSB_COMP_CTRL_DIR_ERROR            = 222,\n\tXUSB_COMP_CTRL_SEQ_NUM_ERROR        = 223\n} xusb_comp_code_t;\n\ntypedef struct _event_trb_t\n{\n\tu32 rsvd0;\n\tu32 rsvd1;\n\n\tu32 rsvd2:24;\n\tu32 comp_code:8;\n\n\tu32 cycle:1;\n\tu32 rsvd3:9;\n\tu32 trb_type:6;\n\tu32 ep_id:5;\n\tu32 rsvd4:11;\n} event_trb_t;\n\ntypedef struct _transfer_event_trb_t {\n\tu32 trb_pointer_lo;\n\tu32 trb_pointer_hi;\n\n\tu32 trb_tx_len:24;\n\tu32 comp_code:8;\n\n\tu32 cycle:1;\n\tu32 rsvddw3_0:1;\n\tu32 event_data:1;\n\tu32 rsvddw3_1:7;\n\tu32 trb_type:6;\n\tu32 ep_id:5;\n\tu32 rsvddw3_2:11;\n} transfer_event_trb_t;\n\ntypedef struct _setup_event_trb_t\n{\n\tusb_ctrl_setup_t ctrl_setup_data;\n\n\tu32 ctrl_seq_num:16;\n\tu32 rsvddw2_0:8;\n\tu32 comp_code:8;\n\n\tu32 cycle:1;\n\tu32 rsvddw3_0:9;\n\tu32 trb_type:6;\n\tu32 ep_id:5;\n\tu32 rsvddw3_1:11;\n} setup_event_trb_t;\n\ntypedef struct _status_trb_t\n{\n\tu32 rsvd0;\n\tu32 rsvd1;\n\n\tu32 rsvd2:22;\n\tu32 interrupt_target:10;\n\n\tu32 cycle:1;\n\tu32 ent:1;\n\tu32 rsvd3_0:2;\n\tu32 chain:1;\n\tu32 ioc:1;\n\tu32 rsvd3_1:4;\n\tu32 trb_type:6;\n\tu32 dir:1;\n\tu32 rsvd3_2:15;\n} status_trb_t;\n\ntypedef struct _normal_trb_t\n{\n\tu32 databufptr_lo;\n\tu32 databufptr_hi;\n\n\tu32 trb_tx_len:17;\n\tu32 td_size:5;\n\tu32 interrupt_target:10;\n\n\tu32 cycle:1;\n\tu32 ent:1;\n\tu32 isp:1;\n\tu32 no_snoop:1;\n\tu32 chain:1;\n\tu32 ioc:1;\n\tu32 idt:1;\n\tu32 rsvd0_0:2;\n\tu32 bei:1;\n\tu32 trb_type:6;\n\tu32 rsvd0_1:16;\n} normal_trb_t;\n\ntypedef struct _data_trb_t\n{\n\tu32 databufptr_lo;\n\tu32 databufptr_hi;\n\n\tu32 trb_tx_len:17;\n\tu32 td_size:5;\n\tu32 interrupt_target:10;\n\n\tu32 cycle:1;\n\tu32 ent:1;\n\tu32 isp:1;\n\tu32 no_snoop:1;\n\tu32 chain:1;\n\tu32 ioc:1;\n\tu32 rsvd0_0:4;\n\tu32 trb_type:6;\n\tu32 dir:1;\n\tu32 rsvd0_1:15;\n} data_trb_t;\n\ntypedef struct _link_trb_t\n{\n\tu32 rsvd0_0:4;\n\tu32 ring_seg_ptrlo:28;\n\n\tu32 ring_seg_ptrhi;\n\n\tu32 rsvd1_0:22;\n\tu32 interrupt_target:10;\n\n\tu32 cycle:1;\n\tu32 toggle_cycle:1;\n\tu32 rsvd3_0:2;\n\tu32 chain:1;\n\tu32 ioc:1;\n\tu32 rsvd3_1:4;\n\tu32 trb_type:6;\n\tu32 rsvd3_2:16;\n} link_trb_t;\n\ntypedef struct _xusb_ep_ctx_t\n{\n\t// Common context.\n\tu32 ep_state:3;\n\tu32 rsvddW0_0:5;\n\tu32 mult:2;\n\tu32 max_pstreams:5;\n\tu32 lsa:1;\n\tu32 interval:8;\n\tu32 rsvddW0_1:8;\n\n\tu32 rsvddw1_0:1;\n\tu32 cerr:2;\n\tu32 ep_type:3;\n\tu32 rsvddw1_1:1;\n\tu32 hid:1;\n\tu32 max_burst_size:8;\n\tu32 max_packet_size:16;\n\n\tu32 dcs:1;\n\tu32 rsvddw2_0:3;\n\tu32 trd_dequeueptr_lo:28;\n\n\tu32 trd_dequeueptr_hi;\n\n\tu32 avg_trb_len:16;\n\tu32 max_esit_payload:16;\n\n\t// Nvidia context.\n\tu32 event_data_txlen_acc;\n\n\tu32 cprog:8;\n\tu32 sbyte:7;\n\tu32 tp:2;\n\tu32 rec:1;\n\tu32 cec:2;\n\tu32 ced:1;\n\tu32 hsp1:1;\n\tu32 rty1:1;\n\tu32 std:1;\n\tu32 status:8;\n\n\tu32 data_offset;\n\n\tu32 scratch_pad0;\n\n\tu32 scratch_pad1;\n\n\tu32 cping:8;\n\tu32 sping:8;\n\tu32 toggle_cycle:2;\n\tu32 no_snoop:1;\n\tu32 ro:1;\n\tu32 tlm:1;\n\tu32 dlm:1;\n\tu32 hsp2:1;\n\tu32 rty2:1;\n\tu32 stop_rec_req:8;\n\n\tu32 device_addr:8;\n\tu32 hub_addr:8;\n\tu32 root_port_num:8;\n\tu32 slot_id:8;\n\n\tu32 routing_string:20;\n\tu32 speed:4;\n\tu32 lpu:1;\n\tu32 mtt:1;\n\tu32 hub:1;\n\tu32 dci:5;\n\n\tu32 tthub_slot_id:8;\n\tu32 ttport_num:8;\n\tu32 ssf:4;\n\tu32 sps:2;\n\tu32 interrupt_target:10;\n\n\tu32 frz:1;\n\tu32 end:1;\n\tu32 elm:1;\n\tu32 mrx:1;\n\tu32 ep_linklo:28;\n\n\tu32 ep_linkhi;\n} xusb_ep_ctx_t;\n\ntypedef struct _xusbd_controller_t\n{\n\tdata_trb_t *cntrl_epenqueue_ptr;\n\tdata_trb_t *cntrl_epdequeue_ptr;\n\tu32 cntrl_producer_cycle;\n\tdata_trb_t *bulkout_epenqueue_ptr;\n\tdata_trb_t *bulkout_epdequeue_ptr;\n\tu32 bulkout_producer_cycle;\n\tdata_trb_t *bulkin_epenqueue_ptr;\n\tdata_trb_t *bulkin_epdequeue_ptr;\n\tu32 bulkin_producer_cycle;\n\tevent_trb_t *event_enqueue_ptr;\n\tevent_trb_t *event_dequeue_ptr;\n\tu32 event_ccs;\n\tu32 device_state;\n\tu32 tx_bytes[2];\n\tu32 tx_count[2];\n\tu32 ctrl_seq_num;\n\tu32 config_num;\n\tu32 interface_num;\n\tu32 wait_for_event_trb;\n\tu32 port_speed;\n\n\tusb_desc_t *desc;\n\tusb_gadget_type gadget;\n\n\tu8 max_lun;\n\tbool max_lun_set;\n\tvoid *hid_rpt_buffer;\n\tu32  hid_rpt_size;\n\tu32  intr_idle_rate;\n\tbool intr_idle_req;\n\tbool bulk_reset_req;\n} xusbd_controller_t;\n\nextern u32 hid_report_descriptor_jc_size;\nextern u32 hid_report_descriptor_touch_size;\nextern u8 hid_report_descriptor_jc[];\nextern u8 hid_report_descriptor_touch[];\nextern usb_desc_t usb_gadget_hid_jc_descriptors;\nextern usb_desc_t usb_gadget_hid_touch_descriptors;\nextern usb_desc_t usb_gadget_ums_descriptors;\n\n// All rings and EP context must be aligned to 0x10.\ntypedef struct _xusbd_event_queues_t\n{\n\tevent_trb_t xusb_event_ring_seg0[XUSB_TRB_SLOTS];\n\tevent_trb_t xusb_event_ring_seg1[XUSB_TRB_SLOTS];\n\tdata_trb_t  xusb_cntrl_event_queue[XUSB_TRB_SLOTS];\n\tdata_trb_t  xusb_bulkin_event_queue[XUSB_TRB_SLOTS];\n\tdata_trb_t  xusb_bulkout_event_queue[XUSB_TRB_SLOTS];\n\tvolatile xusb_ep_ctx_t xusb_ep_ctxt[4];\n} xusbd_event_queues_t;\n\n// Set event queues context to a 0x10 aligned address.\nxusbd_event_queues_t *xusb_evtq = (xusbd_event_queues_t *)XUSB_RING_ADDR;\n\nxusbd_controller_t *usbd_xotg;\nxusbd_controller_t usbd_xotg_controller_ctxt;\n\nstatic int _xusb_xhci_mask_wait(u32 reg, u32 mask, u32 val, u32 retries)\n{\n\tdo\n\t{\n\t\tif ((XUSB_DEV_XHCI(reg) & mask) == val)\n\t\t\treturn USB_RES_OK;\n\t\tusleep(1);\n\t\t--retries;\n\t}\n\twhile (retries);\n\n\treturn USB_ERROR_TIMEOUT;\n}\n\n// Event rings aligned to 0x10\nstatic void _xusbd_ep_init_event_ring()\n{\n\tmemset(xusb_evtq->xusb_event_ring_seg0, 0, sizeof(xusb_evtq->xusb_event_ring_seg0));\n\tmemset(xusb_evtq->xusb_event_ring_seg1, 0, sizeof(xusb_evtq->xusb_event_ring_seg1));\n\n\t//! TODO USB3: enable pcie regulators.\n\n\t// Set Event Ring Segment 0 Base Address.\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_ERST0BALO) = (u32)xusb_evtq->xusb_event_ring_seg0;\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_ERST0BAHI) = 0;\n\n\t// Set Event Ring Segment 1 Base Address.\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_ERST1BALO) = (u32)xusb_evtq->xusb_event_ring_seg1;\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_ERST1BAHI) = 0;\n\n\t// Set Event Ring Segment sizes.\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_ERSTSZ) = (XUSB_TRB_SLOTS << 16) | XUSB_TRB_SLOTS;\n\n\t// Set Enqueue and Dequeue pointers.\n\tusbd_xotg->event_enqueue_ptr = xusb_evtq->xusb_event_ring_seg0;\n\tusbd_xotg->event_dequeue_ptr = xusb_evtq->xusb_event_ring_seg0;\n\tusbd_xotg->event_ccs = 1;\n\n\t// Event Ring Enqueue Pointer.\n\tu32 evt_ring_addr = (u32)xusb_evtq->xusb_event_ring_seg0 & 0xFFFFFFF0;\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_EREPLO) = (XUSB_DEV_XHCI(XUSB_DEV_XHCI_EREPLO) & 0xE) | evt_ring_addr | XCHI_ECS;\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_EREPHI) = 0;\n\n\t// Set Event Ring Dequeue Pointer.\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_ERDPLO) = (XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERDPLO) & 0xF) | evt_ring_addr;\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_ERDPHI) = 0;\n}\n\nstatic void _xusb_ep_set_type_and_metrics(u32 ep_idx, volatile xusb_ep_ctx_t *ep_ctxt)\n{\n\tusb_ep_descr_t *ep_desc = NULL;\n\tusb_ep_descr_t *endpoints = usbd_xotg->desc->cfg->endpoint;\n\n\tswitch (ep_idx)\n\t{\n\tcase XUSB_EP_CTRL_IN:\n\t\t// Set EP type.\n\t\tep_ctxt->ep_type = EP_TYPE_CNTRL;\n\n\t\t// Set max packet size based on port speed.\n\t\tep_ctxt->avg_trb_len = 8;\n\t\tep_ctxt->max_packet_size = 64; //! TODO USB3: max_packet_size = 512.\n\t\tbreak;\n\n\tcase USB_EP_BULK_OUT:\n\t\t// Set default EP type.\n\t\tep_ctxt->ep_type = EP_TYPE_BULK_OUT;\n\n\t\t// Check configuration descriptor.\n\t\tif (usbd_xotg->desc->cfg->interface.bInterfaceClass == 0x3) // HID Class.\n\t\t\tendpoints = (usb_ep_descr_t *)((void *)endpoints + sizeof(usb_hid_descr_t));\n\n\t\tfor (u32 i = 0; i < usbd_xotg->desc->cfg->interface.bNumEndpoints; i++)\n\t\t\tif (endpoints[i].bEndpointAddress == USB_EP_ADDR_BULK_OUT)\n\t\t\t{\n\t\t\t\tep_desc = &endpoints[i];\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t// Set actual EP type.\n\t\tif (ep_desc)\n\t\t{\n\t\t\tswitch (ep_desc->bmAttributes)\n\t\t\t{\n\t\t\tcase USB_EP_TYPE_ISO:\n\t\t\t\tep_ctxt->ep_type = EP_TYPE_ISOC_OUT;\n\t\t\t\tbreak;\n\t\t\tcase USB_EP_TYPE_BULK:\n\t\t\t\tep_ctxt->ep_type = EP_TYPE_BULK_OUT;\n\t\t\t\tbreak;\n\t\t\tcase USB_EP_TYPE_INTR:\n\t\t\t\tep_ctxt->ep_type = EP_TYPE_INTR_OUT;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Set average TRB length.\n\t\t//TODO: Use ep type instead (we don't expect to calculate avg per gadget)?\n\t\tswitch (usbd_xotg->gadget)\n\t\t{\n\t\tcase USB_GADGET_UMS:\n\t\t\tep_ctxt->avg_trb_len = 3072;\n\t\t\tbreak;\n\t\tcase USB_GADGET_HID_GAMEPAD:\n\t\tcase USB_GADGET_HID_TOUCHPAD:\n\t\t\tep_ctxt->avg_trb_len = 1024;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tswitch (usbd_xotg->port_speed)\n\t\t\t{\n\t\t\tcase XUSB_SUPER_SPEED:\n\t\t\t\tep_ctxt->avg_trb_len = 1024;\n\t\t\t\tbreak;\n\t\t\tcase XUSB_HIGH_SPEED:\n\t\t\tcase XUSB_FULL_SPEED:\n\t\t\t\tep_ctxt->avg_trb_len = 512;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// Set max burst rate.\n\t\tep_ctxt->max_burst_size = (ep_desc->wMaxPacketSize >> 11) & 3;\n\n\t\t// Set max packet size based on port speed.\n\t\tif (usbd_xotg->port_speed == XUSB_SUPER_SPEED)\n\t\t{\n\t\t\tep_ctxt->max_packet_size = 1024;\n\n\t\t\t//! TODO USB3:\n\t\t\t// If ISO or INTR EP, set Max Esit Payload size.\n\t\t\t//\tep_ctxt->max_burst_size = bMaxBurst;\n\t\t\t//if (ep_ctxt->ep_type == EP_TYPE_INTR_OUT || ep_ctxt->ep_type == EP_TYPE_ISOC_OUT)\n\t\t\t//\tep_ctxt->max_esit_payload = ep_ctxt->max_packet_size * (ep_ctxt->max_burst_size + 1);\n\t\t}\n\t\telse if (usbd_xotg->port_speed == XUSB_HIGH_SPEED)\n\t\t{\n\t\t\tep_ctxt->max_packet_size = 512;\n\n\t\t\t// If ISO or INTR EP, set Max Esit Payload size.\n\t\t\tif (ep_ctxt->ep_type == EP_TYPE_INTR_OUT || ep_ctxt->ep_type == EP_TYPE_ISOC_OUT)\n\t\t\t\tep_ctxt->max_esit_payload = ep_ctxt->max_packet_size * (ep_ctxt->max_burst_size + 1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tep_ctxt->max_packet_size = 64;\n\n\t\t\t// If ISO or INTR EP, set Max Esit Payload size.\n\t\t\tif (ep_ctxt->ep_type == EP_TYPE_INTR_OUT || ep_ctxt->ep_type == EP_TYPE_ISOC_OUT)\n\t\t\t\tep_ctxt->max_esit_payload = ep_ctxt->max_packet_size;\n\t\t}\n\t\tbreak;\n\n\tcase USB_EP_BULK_IN:\n\t\t// Set default EP type.\n\t\tep_ctxt->ep_type = EP_TYPE_BULK_IN;\n\n\t\t// Check configuration descriptor.\n\t\tif (usbd_xotg->desc->cfg->interface.bInterfaceClass == 0x3) // HID Class.\n\t\t\tendpoints = (usb_ep_descr_t *)((void *)endpoints + sizeof(usb_hid_descr_t));\n\n\t\tfor (u32 i = 0; i < usbd_xotg->desc->cfg->interface.bNumEndpoints; i++)\n\t\t\tif (endpoints[i].bEndpointAddress == USB_EP_ADDR_BULK_IN)\n\t\t\t{\n\t\t\t\tep_desc = &endpoints[i];\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t// Set actual EP type.\n\t\tif (ep_desc)\n\t\t{\n\t\t\tswitch (ep_desc->bmAttributes)\n\t\t\t{\n\t\t\tcase USB_EP_TYPE_ISO:\n\t\t\t\tep_ctxt->ep_type = EP_TYPE_ISOC_IN;\n\t\t\t\tbreak;\n\t\t\tcase USB_EP_TYPE_BULK:\n\t\t\t\tep_ctxt->ep_type = EP_TYPE_BULK_IN;\n\t\t\t\tbreak;\n\t\t\tcase USB_EP_TYPE_INTR:\n\t\t\t\tep_ctxt->ep_type = EP_TYPE_INTR_IN;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Set average TRB length.\n\t\t//TODO: Use ep type instead (we don't expect to calculate avg per gadget)?\n\t\tswitch (usbd_xotg->gadget)\n\t\t{\n\t\tcase USB_GADGET_UMS:\n\t\t\tep_ctxt->avg_trb_len = 3072;\n\t\t\tbreak;\n\t\tcase USB_GADGET_HID_GAMEPAD:\n\t\tcase USB_GADGET_HID_TOUCHPAD:\n\t\t\tep_ctxt->avg_trb_len = 16; // Normal interrupt avg is 1024KB.\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tswitch (usbd_xotg->port_speed)\n\t\t\t{\n\t\t\tcase XUSB_SUPER_SPEED:\n\t\t\t\tep_ctxt->avg_trb_len = 1024;\n\t\t\t\tbreak;\n\t\t\tcase XUSB_HIGH_SPEED:\n\t\t\tcase XUSB_FULL_SPEED:\n\t\t\t\tep_ctxt->avg_trb_len = 512;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// Set max burst rate.\n\t\tep_ctxt->max_burst_size = (ep_desc->wMaxPacketSize >> 11) & 3;\n\n\t\t// Set max packet size based on port speed.\n\t\tif (usbd_xotg->port_speed == XUSB_SUPER_SPEED)\n\t\t{\n\t\t\tep_ctxt->max_packet_size = 1024;\n\n\t\t\t//! TODO USB3:\n\t\t\t// If ISO or INTR EP, set Max Esit Payload size.\n\t\t\t//\tep_ctxt->max_burst_size = bMaxBurst;\n\t\t\t//if (ep_ctxt->ep_type == EP_TYPE_INTR_IN || ep_ctxt->ep_type == EP_TYPE_ISOC_IN)\n\t\t\t//\tep_ctxt->max_esit_payload = ep_ctxt->max_packet_size * (ep_ctxt->max_burst_size + 1);\n\t\t}\n\t\telse if (usbd_xotg->port_speed == XUSB_HIGH_SPEED)\n\t\t{\n\t\t\tep_ctxt->max_packet_size = 512;\n\n\t\t\t// If ISO or INTR EP, set Max Esit Payload size.\n\t\t\tif (ep_ctxt->ep_type == EP_TYPE_INTR_IN || ep_ctxt->ep_type == EP_TYPE_ISOC_IN)\n\t\t\t\tep_ctxt->max_esit_payload = ep_ctxt->max_packet_size * (ep_ctxt->max_burst_size + 1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tep_ctxt->max_packet_size = 64;\n\n\t\t\t// If ISO or INTR EP, set Max Esit Payload size.\n\t\t\tif (ep_ctxt->ep_type == EP_TYPE_INTR_IN || ep_ctxt->ep_type == EP_TYPE_ISOC_IN)\n\t\t\t\tep_ctxt->max_esit_payload = ep_ctxt->max_packet_size;\n\t\t}\n\t\tbreak;\n\t}\n}\n\nstatic int _xusb_ep_init_context(u32 ep_idx)\n{\n\tlink_trb_t *link_trb;\n\n\tif (ep_idx > USB_EP_BULK_IN)\n\t\treturn USB_ERROR_INIT;\n\n\tif (ep_idx == XUSB_EP_CTRL_OUT)\n\t\tep_idx = XUSB_EP_CTRL_IN;\n\n\tvolatile xusb_ep_ctx_t *ep_ctxt = &xusb_evtq->xusb_ep_ctxt[ep_idx];\n\tmemset((void *)ep_ctxt, 0, sizeof(xusb_ep_ctx_t));\n\n\tep_ctxt->ep_state = EP_RUNNING;\n\tep_ctxt->dcs = 1;\n\tep_ctxt->cec = 3;\n\tep_ctxt->cerr = 3;\n\tep_ctxt->max_burst_size = 0;\n\n\tswitch (ep_idx)\n\t{\n\tcase XUSB_EP_CTRL_IN:\n\t\tusbd_xotg->cntrl_producer_cycle = 1;\n\t\tusbd_xotg->cntrl_epenqueue_ptr  = xusb_evtq->xusb_cntrl_event_queue;\n\t\tusbd_xotg->cntrl_epdequeue_ptr  = xusb_evtq->xusb_cntrl_event_queue;\n\n\t\t_xusb_ep_set_type_and_metrics(ep_idx, ep_ctxt);\n\n\t\tep_ctxt->trd_dequeueptr_lo = (u32)xusb_evtq->xusb_cntrl_event_queue >> 4;\n\t\tep_ctxt->trd_dequeueptr_hi = 0;\n\n\t\tlink_trb = (link_trb_t *)&xusb_evtq->xusb_cntrl_event_queue[XUSB_LINK_TRB_IDX];\n\t\tlink_trb->toggle_cycle   = 1;\n\t\tlink_trb->ring_seg_ptrlo = (u32)xusb_evtq->xusb_cntrl_event_queue >> 4;\n\t\tlink_trb->ring_seg_ptrhi = 0;\n\t\tlink_trb->trb_type       = XUSB_TRB_LINK;\n\t\tbreak;\n\n\tcase USB_EP_BULK_OUT:\n\t\tusbd_xotg->bulkout_producer_cycle = 1;\n\t\tusbd_xotg->bulkout_epenqueue_ptr  = xusb_evtq->xusb_bulkout_event_queue;\n\t\tusbd_xotg->bulkout_epdequeue_ptr  = xusb_evtq->xusb_bulkout_event_queue;\n\n\t\t_xusb_ep_set_type_and_metrics(ep_idx, ep_ctxt);\n\n\t\tep_ctxt->trd_dequeueptr_lo = (u32)xusb_evtq->xusb_bulkout_event_queue >> 4;\n\t\tep_ctxt->trd_dequeueptr_hi = 0;\n\n\t\tlink_trb = (link_trb_t *)&xusb_evtq->xusb_bulkout_event_queue[XUSB_LINK_TRB_IDX];\n\t\tlink_trb->toggle_cycle   = 1;\n\t\tlink_trb->ring_seg_ptrlo = (u32)xusb_evtq->xusb_bulkout_event_queue >> 4;\n\t\tlink_trb->ring_seg_ptrhi = 0;\n\t\tlink_trb->trb_type       = XUSB_TRB_LINK;\n\t\tbreak;\n\n\tcase USB_EP_BULK_IN:\n\t\tusbd_xotg->bulkin_producer_cycle = 1;\n\t\tusbd_xotg->bulkin_epenqueue_ptr  = xusb_evtq->xusb_bulkin_event_queue;\n\t\tusbd_xotg->bulkin_epdequeue_ptr  = xusb_evtq->xusb_bulkin_event_queue;\n\n\t\t_xusb_ep_set_type_and_metrics(ep_idx, ep_ctxt);\n\n\t\tep_ctxt->trd_dequeueptr_lo = (u32)xusb_evtq->xusb_bulkin_event_queue >> 4;\n\t\tep_ctxt->trd_dequeueptr_hi = 0;\n\n\t\tlink_trb = (link_trb_t *)&xusb_evtq->xusb_bulkin_event_queue[XUSB_LINK_TRB_IDX];\n\t\tlink_trb->toggle_cycle   = 1;\n\t\tlink_trb->ring_seg_ptrlo = (u32)xusb_evtq->xusb_bulkin_event_queue >> 4;\n\t\tlink_trb->ring_seg_ptrhi = 0;\n\t\tlink_trb->trb_type       = XUSB_TRB_LINK;\n\t\tbreak;\n\t}\n\n\treturn USB_RES_OK;\n}\n\nstatic int _xusbd_ep_initialize(u32 ep_idx)\n{\n\tswitch (ep_idx)\n\t{\n\tcase XUSB_EP_CTRL_IN:\n\tcase XUSB_EP_CTRL_OUT:\n\t\treturn _xusb_ep_init_context(XUSB_EP_CTRL_IN);\n\tcase USB_EP_BULK_OUT:\n\tcase USB_EP_BULK_IN:\n\t\t_xusb_ep_init_context(ep_idx);\n\t\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_RELOAD) = BIT(ep_idx);\n\t\tint res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_RELOAD, BIT(ep_idx), 0, 1000);\n\t\tif (!res)\n\t\t{\n\t\t\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_PAUSE) &= ~BIT(ep_idx);\n\t\t\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT)  &= ~BIT(ep_idx);\n\t\t}\n\t\treturn res;\n\tdefault:\n\t\treturn USB_ERROR_INIT;\n\t}\n}\n\nstatic void _xusbd_ep1_disable(u32 ep_idx)\n{\n\tvolatile xusb_ep_ctx_t *ep_ctxt = &xusb_evtq->xusb_ep_ctxt[ep_idx];\n\tu32 ep_mask = BIT(ep_idx);\n\n\tswitch (ep_idx)\n\t{\n\tcase USB_EP_BULK_OUT:\n\tcase USB_EP_BULK_IN:\n\t\t// Skip if already disabled.\n\t\tif (!ep_ctxt->ep_state)\n\t\t\treturn;\n\n\t\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) |= ep_mask;\n\n\t\t// Set EP state to disabled.\n\t\tep_ctxt->ep_state = EP_DISABLED;\n\n\t\t// Wait for EP status to change.\n\t\t_xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_STCHG, ep_mask, ep_mask, 1000);\n\n\t\t// Clear status change.\n\t\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_STCHG) = ep_mask;\n\t\tbreak;\n\t}\n}\n\nstatic void _xusb_disable_ep1()\n{\n\t_xusbd_ep1_disable(USB_EP_BULK_OUT);\n\t_xusbd_ep1_disable(USB_EP_BULK_IN);\n\n\t// Device mode stop.\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) &= ~XHCI_CTRL_RUN;\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_ST)   |=  XHCI_ST_RC;\n\n\tusbd_xotg->config_num = 0;\n\tusbd_xotg->interface_num = 0;\n\tusbd_xotg->max_lun_set = false;\n\tusbd_xotg->device_state = XUSB_DEFAULT;\n}\n\nstatic void _xusb_init_phy()\n{\n\t// Configure and enable PLLU.\n\tclock_enable_pllu();\n\n\t// Enable IDDQ control by software and disable UTMIPLL IDDQ.\n\tCLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) = (CLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) & 0xFFFFFFFC) | 1;\n\n\t// Set UTMIPLL dividers and config based on OSC and enable it to 960 MHz.\n\tclock_enable_utmipll();\n\n\t// Set UTMIP misc config.\n\tCLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) = (CLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) & 0xFEFFFFE8) | 0x2000008 | 0x20 | 2;\n\tusleep(2);\n\n\t// Set OTG PAD0 calibration.\n\tu32 fuse_usb_calib = FUSE(FUSE_USB_CALIB);\n\t// Set HS_CURR_LEVEL.\n\tXUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_0) = (XUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_0) & 0xFFFFFFC0) | (fuse_usb_calib & 0x3F);\n\t// Set TERM_RANGE_ADJ and RPD_CTRL.\n\tXUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_1) = (XUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_1) & 0x83FFFF87) | ((fuse_usb_calib & 0x780) >> 4) | ((u32)(FUSE(FUSE_USB_CALIB_EXT) << 27) >> 1);\n\n\t// Set VREG_LEV to 1.\n\tXUSB_PADCTL(XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD0_CTL1) = (XUSB_PADCTL(XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD0_CTL1) & 0xFFFFFE3F) | 0x80;\n\n\t// Disable power down on usb2 ports pads.\n\tXUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_0) &= 0xDBFFFFFF; // Clear pad power down.\n\tXUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_1) &= 0xFFFFFFFB; // Clear pad dr power down.\n\tXUSB_PADCTL(XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD0_CTL0) &= 0xFFFFFFFE; // Clear charging power down.\n\tXUSB_PADCTL(XUSB_PADCTL_USB2_BIAS_PAD_CTL_0) &= 0xFFFFF7FF; // Clear bias power down.\n\t(void)XUSB_PADCTL(XUSB_PADCTL_USB2_OTG_PAD0_CTL_1);         // Commit write.\n\n\t// Enable USB2 tracking clock.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_Y_SET)            = BIT(CLK_Y_USB2_TRK);\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK) & 0xFFFFFF00) | 6; // Set trank divisor to 4.\n\n\t// Set tracking parameters and trigger it.\n\tXUSB_PADCTL(XUSB_PADCTL_USB2_BIAS_PAD_CTL_1) = 0x451E000;\n\tXUSB_PADCTL(XUSB_PADCTL_USB2_BIAS_PAD_CTL_1) =  0x51E000;\n\tusleep(100);\n\n\t// TRK cycle done. Force PDTRK input into power down.\n\tXUSB_PADCTL(XUSB_PADCTL_USB2_BIAS_PAD_CTL_1) = 0x451E000;\n\tusleep(3);\n\n\t// Re-trigger it.\n\tXUSB_PADCTL(XUSB_PADCTL_USB2_BIAS_PAD_CTL_1) = 0x51E000;\n\tusleep(100);\n\n\t// TRK cycle done. Force PDTRK input into power down.\n\tXUSB_PADCTL(XUSB_PADCTL_USB2_BIAS_PAD_CTL_1) |= 0x4000000;\n\n\t// Disable USB2 tracking clock.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_Y_CLR) = BIT(CLK_Y_USB2_TRK);\n\n\t// Wait for XUSB PHY to stabilize.\n\tusleep(30);\n}\n\nstatic void _xusbd_init_device_clocks()\n{\n\t// Disable reset to PLLU_OUT1\n\tCLOCK(CLK_RST_CONTROLLER_PLLU_OUTA) |= 1;\n\tusleep(2);\n\n\t// Enable XUSB device clock.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_SET) = BIT(CLK_U_XUSB_DEV);\n\n\t// Set XUSB device core clock source to PLLP for a 102MHz result.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_CORE_DEV) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_CORE_DEV) & 0x1FFFFF00) | (1 << 29) | 6;\n\tusleep(2);\n\n\t// Set XUSB Full-Speed logic clock source to FO 48MHz.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_FS) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_FS) & 0x1FFFFFFF) | (2 << 29);\n\n\t// Enable XUSB Super-Speed logic clock.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = BIT(CLK_W_XUSB_SS);\n\n\t// Set XUSB Super-Speed logic clock source to HSIC 480MHz for 120MHz result and source FS logic clock from Super-Speed.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_SS) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_SS) & 0x1FFFFF00) | (3 << 29) | 6;\n\n\t// Clear reset to XUSB device and Super-Speed logic.\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_W_CLR) = BIT(CLK_W_XUSB_SS);\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_U_CLR) = BIT(CLK_U_XUSB_DEV);\n\tusleep(2);\n}\n\nint xusb_device_init()\n{\n\t// Ease the stress to APB.\n\tbpmp_clk_rate_relaxed(true);\n\n\t// Disable USB2 device controller clocks.\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_USBD);\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = BIT(CLK_L_USBD);\n\n\t// Enable XUSB clock and clear Reset to XUSB Pad Control.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = BIT(CLK_W_XUSB);\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB);\n\tusleep(2);\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_W_CLR) = BIT(CLK_W_XUSB);\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_W_CLR) = BIT(CLK_W_XUSB_PADCTL);\n\tusleep(2);\n\n\t// USB2 Pads to XUSB.\n\tXUSB_PADCTL(XUSB_PADCTL_USB2_PAD_MUX) =\n\t\t(XUSB_PADCTL(XUSB_PADCTL_USB2_PAD_MUX) & ~(PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK | PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_MASK)) |\n\t\tPADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB | PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_XUSB;\n\n\t// Initialize XUSB controller PHY.\n\t_xusb_init_phy();\n\n\t// Set USB2.0 Port 0 to device mode.\n\tXUSB_PADCTL(XUSB_PADCTL_USB2_PORT_CAP) = (XUSB_PADCTL(XUSB_PADCTL_USB2_PORT_CAP) & ~PADCTL_USB2_PORT_CAP_PORT_0_CAP_MASK) | PADCTL_USB2_PORT_CAP_PORT_0_CAP_DEV;\n\n\t//! TODO USB3\n\t// // Set USB3.0 Port 0 cap to device.\n\t// XUSB_PADCTL(XUSB_PADCTL_SS_PORT_CAP) = (XUSB_PADCTL(XUSB_PADCTL_SS_PORT_CAP) & ~PADCTL_SS_PORT_CAP_0_PORT1_CAP_MASK) | PADCTL_SS_PORT_CAP_0_PORT1_CAP_DEVICE_ONLY;\n\n\t// Set Super Speed Port 0 to USB2 Port 0.\n\tXUSB_PADCTL(XUSB_PADCTL_SS_PORT_MAP) &= ~PADCTL_SS_PORT_MAP_PORT0_MASK; // 0: USB2_PORT0\n\n\t// Power Up ID Wake up and Vbus Wake Up for UTMIP\n\tPMC(APBDEV_PMC_USB_AO) &= 0xFFFFFFF3;\n\tusleep(1);\n\n\t// Initialize device clocks.\n\t_xusbd_init_device_clocks();\n\n\t// Restore OC.\n\tbpmp_clk_rate_relaxed(false);\n\n\t// Enable AHB redirect for access to IRAM for Event/EP ring buffers.\n\tmc_enable_ahb_redirect(1);\n\n\t // Enable XUSB device IPFS.\n\tXUSB_DEV_DEV(XUSB_DEV_CONFIGURATION) |= DEV_CONFIGURATION_EN_FPCI;\n\n\t// Configure PCI and BAR0 address space.\n\tXUSB_DEV_PCI(XUSB_CFG_1) |= CFG_1_BUS_MASTER | CFG_1_MEMORY_SPACE | CFG_1_IO_SPACE;\n\tusleep(1);\n\tXUSB_DEV_PCI(XUSB_CFG_4) = XUSB_DEV_BASE | CFG_4_ADDRESS_TYPE_32_BIT;\n\n\t// Mask SATA interrupt to MCORE.\n\tXUSB_DEV_DEV(XUSB_DEV_INTR_MASK) |= DEV_INTR_MASK_IP_INT_MASK;\n\n\t// AHB USB performance cfg.\n\tAHB_GIZMO(AHB_GIZMO_AHB_MEM) |= AHB_MEM_DONT_SPLIT_AHB_WR | AHB_MEM_ENB_FAST_REARBITRATE;\n\tAHB_GIZMO(AHB_GIZMO_USB3)    |= AHB_GIZMO_IMMEDIATE;\n\tAHB_GIZMO(AHB_ARBITRATION_PRIORITY_CTRL) = PRIORITY_CTRL_WEIGHT(7)     | PRIORITY_SELECT_USB3;\n\tAHB_GIZMO(AHB_AHB_MEM_PREFETCH_CFG1)     = MEM_PREFETCH_ENABLE         | MEM_PREFETCH_USB3_MST_ID |\n\t\t\t\t\t\t\t\t\t\t\t   MEM_PREFETCH_ADDR_BNDRY(12) | 0x1000; // Addr boundary 64KB, Inactivity 4096 cycles.\n\n\t// Initialize context.\n\tusbd_xotg = &usbd_xotg_controller_ctxt;\n\tmemset(usbd_xotg,  0, sizeof(xusbd_controller_t));\n\n\t// Initialize event and EP rings.\n\t_xusbd_ep_init_event_ring();\n\tmemset(xusb_evtq->xusb_cntrl_event_queue,   0, sizeof(xusb_evtq->xusb_cntrl_event_queue));\n\tmemset(xusb_evtq->xusb_bulkin_event_queue,  0, sizeof(xusb_evtq->xusb_bulkin_event_queue));\n\tmemset(xusb_evtq->xusb_bulkout_event_queue, 0, sizeof(xusb_evtq->xusb_bulkout_event_queue));\n\n\t// Initialize Control EP.\n\tint res = _xusbd_ep_initialize(XUSB_EP_CTRL_IN);\n\tif (res)\n\t\treturn USB_ERROR_INIT;\n\n\t// Enable events and interrupts.\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) |= XHCI_CTRL_IE | XHCI_CTRL_LSE;\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_ECPLO) = (u32)xusb_evtq->xusb_ep_ctxt & 0xFFFFFFF0;\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_ECPHI) = 0;\n\n\t//! TODO USB3:\n\t// XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) |= DEV_XHCI_PORTHALT_STCHG_INTR_EN;\n\n\treturn USB_RES_OK;\n}\n\n//! TODO: Power down more stuff.\nstatic void _xusb_device_power_down()\n{\n\t// Disable clock for XUSB Super-Speed and set source to CLK_M.\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB_SS);\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_SS) &= 0x1FFFFF00;\n\tusleep(2);\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = BIT(CLK_W_XUSB_SS);\n\n\t// Put XUSB device into reset.\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = BIT(CLK_U_XUSB_DEV);\n\tusleep(2);\n\n\t// Reset Full-Speed clock source to CLK_M and div1.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_FS) = 0;\n\tusleep(2);\n\n\t// Disable XUSB device clock.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = BIT(CLK_U_XUSB_DEV);\n\n\t// Force UTMIP_PLL power down.\n\tCLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG1) &= (~BIT(15));\n\tCLOCK(CLK_RST_CONTROLLER_UTMIP_PLL_CFG2) |= BIT(4) | BIT(0); // UTMIP_FORCE_PD_SAMP_A/C_POWERDOWN.\n\n\t// Force enable UTMIPLL IDDQ.\n\tCLOCK(CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0) |= 3;\n\n\t// Disable PLLU.\n\tclock_disable_pllu();\n\n\t// Set XUSB_PADCTL clock reset.\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB_PADCTL);\n\n\t// Disable XUSB clock.\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_W_SET) = BIT(CLK_W_XUSB);\n\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = BIT(CLK_W_XUSB);\n}\n\nstatic int _xusb_queue_trb(u32 ep_idx, const void *trb, bool ring_doorbell)\n{\n\tint res = USB_RES_OK;\n\tdata_trb_t *next_trb;\n\tlink_trb_t *link_trb;\n\n\t// Copy TRB and advance Enqueue list.\n\tswitch (ep_idx)\n\t{\n\tcase XUSB_EP_CTRL_IN:\n\t\tmemcpy(usbd_xotg->cntrl_epenqueue_ptr, trb, sizeof(data_trb_t));\n\n\t\t// Advance queue and if Link TRB set index to 0 and toggle cycle bit.\n\t\tnext_trb = &usbd_xotg->cntrl_epenqueue_ptr[1];\n\t\tif (next_trb->trb_type == XUSB_TRB_LINK)\n\t\t{\n\t\t\tlink_trb = (link_trb_t *)next_trb;\n\t\t\tlink_trb->cycle = usbd_xotg->cntrl_producer_cycle & 1;\n\t\t\tlink_trb->toggle_cycle = 1;\n\n\t\t\tnext_trb = (data_trb_t *)(link_trb->ring_seg_ptrlo << 4);\n\n\t\t\tusbd_xotg->cntrl_producer_cycle ^= 1;\n\t\t}\n\t\tusbd_xotg->cntrl_epenqueue_ptr = next_trb;\n\t\tbreak;\n\n\tcase USB_EP_BULK_OUT:\n\t\tmemcpy(usbd_xotg->bulkout_epenqueue_ptr, trb, sizeof(data_trb_t));\n\n\t\t// Advance queue and if Link TRB set index to 0 and toggle cycle bit.\n\t\tnext_trb = &usbd_xotg->bulkout_epenqueue_ptr[1];\n\t\tif (next_trb->trb_type == XUSB_TRB_LINK)\n\t\t{\n\t\t\tlink_trb = (link_trb_t *)next_trb;\n\t\t\tlink_trb->cycle = usbd_xotg->bulkout_producer_cycle & 1;\n\t\t\tlink_trb->toggle_cycle = 1;\n\n\t\t\tnext_trb = (data_trb_t *)(link_trb->ring_seg_ptrlo << 4);\n\n\t\t\tusbd_xotg->bulkout_producer_cycle ^= 1;\n\t\t}\n\t\tusbd_xotg->bulkout_epenqueue_ptr = next_trb;\n\t\tbreak;\n\n\tcase USB_EP_BULK_IN:\n\t\tmemcpy(usbd_xotg->bulkin_epenqueue_ptr, trb, sizeof(data_trb_t));\n\n\t\t// Advance queue and if Link TRB set index to 0 and toggle cycle bit.\n\t\tnext_trb = &usbd_xotg->bulkin_epenqueue_ptr[1];\n\t\tif (next_trb->trb_type == XUSB_TRB_LINK)\n\t\t{\n\t\t\tlink_trb = (link_trb_t *)next_trb;\n\t\t\tlink_trb->cycle = usbd_xotg->bulkin_producer_cycle & 1;\n\t\t\tlink_trb->toggle_cycle = 1;\n\n\t\t\tnext_trb = (data_trb_t *)(link_trb->ring_seg_ptrlo << 4);\n\n\t\t\tusbd_xotg->bulkin_producer_cycle ^= 1;\n\t\t}\n\t\tusbd_xotg->bulkin_epenqueue_ptr = next_trb;\n\t\tbreak;\n\n\tcase XUSB_EP_CTRL_OUT:\n\tdefault:\n\t\tres = XUSB_ERROR_INVALID_EP;\n\t\tbreak;\n\t}\n\n\t// Ring doorbell.\n\tif (ring_doorbell)\n\t{\n\t\t// Flush data before transfer.\n\t\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_CLEAN_WAY, false);\n\n\t\tu32 target_id = (ep_idx << 8) & 0xFFFF;\n\t\tif (ep_idx == XUSB_EP_CTRL_IN)\n\t\t\ttarget_id |= usbd_xotg->ctrl_seq_num << 16;\n\n\t\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_DB) = target_id;\n\t}\n\n\treturn res;\n}\n\nstatic void _xusb_create_status_trb(status_trb_t *trb, usb_dir_t direction)\n{\n\ttrb->cycle    = usbd_xotg->cntrl_producer_cycle & 1;\n\ttrb->ioc      = 1; // Enable interrupt on completion.\n\ttrb->trb_type = XUSB_TRB_STATUS;\n\ttrb->dir      = direction;\n}\n\nstatic void _xusb_create_normal_trb(normal_trb_t *trb, u8 *buf, u32 len, usb_dir_t direction)\n{\n\tu8 producer_cycle;\n\n\ttrb->databufptr_lo = (u32)buf;\n\ttrb->databufptr_hi = 0;\n\n\ttrb->trb_tx_len = len;\n\n\t// Single TRB transfer.\n\ttrb->td_size = 0;\n\ttrb->chain   = 0;\n\n\tif (direction == USB_DIR_IN)\n\t\tproducer_cycle = usbd_xotg->bulkin_producer_cycle & 1;\n\telse\n\t\tproducer_cycle = usbd_xotg->bulkout_producer_cycle & 1;\n\n\ttrb->cycle    = producer_cycle;\n\ttrb->isp      = 1; // Enable interrupt on short packet.\n\ttrb->ioc      = 1; // Enable interrupt on completion.\n\ttrb->trb_type = XUSB_TRB_NORMAL;\n}\n\nstatic void _xusb_create_data_trb(data_trb_t *trb, u8 *buf, u32 len, usb_dir_t direction)\n{\n\ttrb->databufptr_lo = (u32)buf;\n\ttrb->databufptr_hi = 0;\n\n\ttrb->trb_tx_len = len;\n\n\t// Single TRB transfer.\n\ttrb->td_size = 0;\n\ttrb->chain   = 0;\n\n\ttrb->cycle    = usbd_xotg->cntrl_producer_cycle & 1;\n\ttrb->isp      = 1; // Enable interrupt on short packet.\n\ttrb->ioc      = 1; // Enable interrupt on completion.\n\ttrb->trb_type = XUSB_TRB_DATA;\n\ttrb->dir      = direction;\n}\n\nstatic int _xusb_issue_status_trb(usb_dir_t direction)\n{\n\tint res = USB_RES_OK;\n\tstatus_trb_t trb = {0};\n\n\tif (usbd_xotg->cntrl_epenqueue_ptr == usbd_xotg->cntrl_epdequeue_ptr || direction == USB_DIR_OUT)\n\t{\n\t\t_xusb_create_status_trb(&trb, direction);\n\n\t\tres = _xusb_queue_trb(XUSB_EP_CTRL_IN, &trb, EP_RING_DOORBELL);\n\t\tusbd_xotg->wait_for_event_trb = XUSB_TRB_STATUS;\n\t}\n\n\treturn res;\n}\n\nstatic int _xusb_issue_normal_trb(u8 *buf, u32 len, usb_dir_t direction)\n{\n\tnormal_trb_t trb = {0};\n\n\t_xusb_create_normal_trb(&trb, buf, len, direction);\n\tu32 ep_idx = USB_EP_BULK_IN;\n\tif (direction == USB_DIR_OUT)\n\t\tep_idx = USB_EP_BULK_OUT;\n\n\tint res = _xusb_queue_trb(ep_idx, &trb, EP_RING_DOORBELL);\n\tif (!res)\n\t\tusbd_xotg->wait_for_event_trb = XUSB_TRB_NORMAL;\n\n\treturn res;\n}\n\nstatic int _xusb_issue_data_trb(u8 *buf, u32 len, usb_dir_t direction)\n{\n\tdata_trb_t trb = {0};\n\n\tint res = USB_RES_OK;\n\tif (usbd_xotg->cntrl_epenqueue_ptr == usbd_xotg->cntrl_epdequeue_ptr)\n\t{\n\t\t_xusb_create_data_trb(&trb, buf, len, direction);\n\n\t\tres = _xusb_queue_trb(XUSB_EP_CTRL_IN, &trb, EP_RING_DOORBELL);\n\t\tif (!res)\n\t\t\tusbd_xotg->wait_for_event_trb = XUSB_TRB_DATA;\n\t}\n\treturn res;\n}\n\nint xusb_set_ep_stall(u32 endpoint, int ep_stall)\n{\n\tu32 ep_mask = BIT(endpoint);\n\tif (ep_stall)\n\t\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) |= ep_mask;\n\telse\n\t\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) &= ~ep_mask;\n\n\t// Wait for EP status to change.\n\tint res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_STCHG, ep_mask, ep_mask, 1000);\n\tif (res)\n\t\treturn res;\n\n\t// Clear status change.\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_STCHG) = ep_mask;\n\n\treturn USB_RES_OK;\n}\n\nstatic int _xusb_wait_ep_stopped(u32 endpoint)\n{\n\tu32 ep_mask = BIT(endpoint);\n\n\t// Wait for EP status to change.\n\t_xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_STOPPED, ep_mask, ep_mask, 1000);\n\n\t// Clear status change.\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_STOPPED) = ep_mask;\n\n\treturn USB_RES_OK;\n}\n\nstatic int _xusb_handle_transfer_event(const transfer_event_trb_t *trb)\n{\n\t// Advance dequeue list.\n\tdata_trb_t *next_trb;\n\tswitch (trb->ep_id)\n\t{\n\tcase XUSB_EP_CTRL_IN:\n\t\tnext_trb = &usbd_xotg->cntrl_epdequeue_ptr[1];\n\t\tif (next_trb->trb_type == XUSB_TRB_LINK)\n\t\t\tnext_trb = (data_trb_t *)(next_trb->databufptr_lo & 0xFFFFFFF0);\n\t\tusbd_xotg->cntrl_epdequeue_ptr = next_trb;\n\t\tbreak;\n\tcase USB_EP_BULK_OUT:\n\t\tnext_trb = &usbd_xotg->bulkout_epdequeue_ptr[1];\n\t\tif (next_trb->trb_type == XUSB_TRB_LINK)\n\t\t\tnext_trb = (data_trb_t *)(next_trb->databufptr_lo & 0xFFFFFFF0);\n\t\tusbd_xotg->bulkout_epdequeue_ptr = next_trb;\n\t\tbreak;\n\tcase USB_EP_BULK_IN:\n\t\tnext_trb = &usbd_xotg->bulkin_epdequeue_ptr[1];\n\t\tif (next_trb->trb_type == XUSB_TRB_LINK)\n\t\t\tnext_trb = (data_trb_t *)(next_trb->databufptr_lo & 0xFFFFFFF0);\n\t\tusbd_xotg->bulkin_epdequeue_ptr = next_trb;\n\t\tbreak;\n\tdefault:\n\t\t// Should never happen.\n\t\tbreak;\n\t}\n\n\t// Handle completion code.\n\tswitch (trb->comp_code)\n\t{\n\tcase XUSB_COMP_SUCCESS:\n\tcase XUSB_COMP_SHORT_PKT:\n\t\tswitch (trb->ep_id)\n\t\t{\n\t\tcase XUSB_EP_CTRL_IN:\n\t\t\tif (usbd_xotg->wait_for_event_trb == XUSB_TRB_DATA)\n\t\t\t\treturn _xusb_issue_status_trb(USB_DIR_OUT);\n\t\t\telse if (usbd_xotg->wait_for_event_trb == XUSB_TRB_STATUS)\n\t\t\t{\n\t\t\t\tswitch (usbd_xotg->device_state)\n\t\t\t\t{\n\t\t\t\tcase XUSB_ADDRESSED_STS_WAIT:\n\t\t\t\t\tusbd_xotg->device_state = XUSB_ADDRESSED;\n\t\t\t\t\tbreak;\n\t\t\t\tcase XUSB_CONFIGURED_STS_WAIT:\n\t\t\t\t\tusbd_xotg->device_state = XUSB_CONFIGURED;\n\t\t\t\t\tbreak;\n\t\t\t\tcase XUSB_LUN_CONFIGURED_STS_WAIT:\n\t\t\t\t\tusbd_xotg->device_state = XUSB_LUN_CONFIGURED;\n\t\t\t\t\tbreak;\n\t\t\t\tcase XUSB_HID_CONFIGURED_STS_WAIT:\n\t\t\t\t\tusbd_xotg->device_state = XUSB_HID_CONFIGURED;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase USB_EP_BULK_IN:\n\t\t\tusbd_xotg->tx_bytes[USB_DIR_IN] -= trb->trb_tx_len;\n\t\t\tif (usbd_xotg->tx_count[USB_DIR_IN])\n\t\t\t\tusbd_xotg->tx_count[USB_DIR_IN]--;\n\n\t\t\t// If bytes remaining for a Bulk IN transfer, return error.\n\t\t\tif (trb->trb_tx_len)\n\t\t\t\treturn XUSB_ERROR_XFER_BULK_IN_RESIDUE;\n\t\t\tbreak;\n\n\t\tcase USB_EP_BULK_OUT:\n\t\t\t// If short packet and Bulk OUT, it's not an error because we prime EP for 4KB.\n\t\t\tusbd_xotg->tx_bytes[USB_DIR_OUT] -= trb->trb_tx_len;\n\t\t\tif (usbd_xotg->tx_count[USB_DIR_OUT])\n\t\t\t\tusbd_xotg->tx_count[USB_DIR_OUT]--;\n\t\t\tbreak;\n\t\t}\n\t\treturn USB_RES_OK;\n/*\n\tcase XUSB_COMP_USB_TRANSACTION_ERROR:\n\tcase XUSB_COMP_TRB_ERROR:\n\tcase XUSB_COMP_RING_UNDERRUN:\n\tcase XUSB_COMP_RING_OVERRUN:\n\tcase XUSB_COMP_CTRL_DIR_ERROR: // Redefined.\n\t\txusb_set_ep_stall(trb->ep_id, USB_EP_CFG_STALL);\n\t\treturn USB_RES_OK;\n*/\n\tcase XUSB_COMP_BABBLE_DETECTED_ERROR:\n\t\t_xusb_wait_ep_stopped(trb->ep_id);\n\t\txusb_set_ep_stall(trb->ep_id, USB_EP_CFG_STALL);\n\t\treturn XUSB_ERROR_BABBLE_DETECTED;\n\n\tcase XUSB_COMP_CTRL_DIR_ERROR:\n\t\treturn XUSB_ERROR_XFER_DIR;\n\n\tcase XUSB_COMP_CTRL_SEQ_NUM_ERROR:\n\t\treturn XUSB_ERROR_SEQ_NUM; //! TODO: Can mean a new setup packet was received.\n\n\tdefault: // Every other completion code.\n\t\treturn USB_ERROR_XFER_ERROR;\n\t}\n}\n\n/*\n * Other XUSB impl:\n * CBT: PR,  PRC,      WPR,       WRC, CSC, REQ, PLC, CEC.\n * LNX: REQ, PRC PR,   PRC & !PR, WRC, CSC, PLC, CEC.\n * BRO: CSC, PR | PRC, WPR | WRC, REQ, PLC, CEC.\n */\n\nstatic int _xusb_handle_port_change()\n{\n\tu32 status = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC);\n\tu32 halt = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT);\n\tu32 clear_mask = XHCI_PORTSC_CEC | XHCI_PORTSC_PLC | XHCI_PORTSC_PRC | XHCI_PORTSC_WRC | XHCI_PORTSC_CSC;\n\n\t// Port reset (PR).\n\tif (status & XHCI_PORTSC_PR)\n\t{\n\t\t//! TODO:\n\t\t// XHCI_PORTSC_PR: device_state = XUSB_RESET\n\n\t\t//_disable_usb_wdt4();\n\t}\n\n\t// Port Reset Change (PRC).\n\tif (status & XHCI_PORTSC_PRC)\n\t{\n\t\t// Clear PRC bit.\n\t\tstatus &= ~clear_mask;\n\t\tstatus |= XHCI_PORTSC_PRC;\n\t\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status;\n\t}\n\n\t// Warm Port Reset (WPR).\n\tif (status & XHCI_PORTSC_WPR)\n\t{\n\t\t//_disable_usb_wdt4();\n\n\t\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) &= ~XHCI_PORTHALT_HALT_LTSSM;\n\t\t(void)XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT);\n\n\t\t//! TODO: XHCI_PORTSC_WPR: device_state = XUSB_RESET\n\t}\n\n\t// Warm Port Reset Change (WRC).\n\tif (status & XHCI_PORTSC_WRC)\n\t{\n\t\t// Clear WRC bit.\n\t\tstatus &= ~clear_mask;\n\t\tstatus |= XHCI_PORTSC_WRC;\n\t\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status;\n\t}\n\n\t// Reread port status to handle more changes.\n\tstatus = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC);\n\n\t// Connect Status Change (CSC).\n\tif (status & XHCI_PORTSC_CSC)\n\t{\n\t\t//! TODO: Check CCS.\n\t\t// CCS check seems to be\n\t\t// XHCI_PORTSC_CCS 1: device_state = XUSB_CONNECTED\n\t\t// XHCI_PORTSC_CCS 0: device_state = XUSB_DISCONNECTED\n\t\t// Always do XHCI_PORTSC_CSC bit clear.\n\n\t\t// Set port speed.\n\t\tusbd_xotg->port_speed = (status & XHCI_PORTSC_PS) >> 10;\n\n\t\t// In case host does not support Super Speed, revert the control EP packet size.\n\t\tif (usbd_xotg->port_speed != XUSB_SUPER_SPEED)\n\t\t{\n\t\t\tvolatile xusb_ep_ctx_t *ep_ctxt = &xusb_evtq->xusb_ep_ctxt[XUSB_EP_CTRL_IN];\n\t\t\tep_ctxt->avg_trb_len = 8;\n\t\t\tep_ctxt->max_packet_size = 64;\n\t\t\t//! TODO: If super speed is supported, ep context reload, unpause and unhalt must happen.\n\t\t}\n\n\t\t// Clear CSC bit.\n\t\tstatus &= ~clear_mask;\n\t\tstatus |= XHCI_PORTSC_CSC;\n\t\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status;\n\t}\n\n\t// Handle Config Request (STCHG_REQ).\n\tif (halt & XHCI_PORTHALT_STCHG_REQ)\n\t{\n\t\t// Clear Link Training Status and pending request/reject.\n\t\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) &= ~XHCI_PORTHALT_HALT_LTSSM;\n\t\t(void)XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT);\n\t}\n\n\t// Reread port status to handle more changes.\n\tstatus = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC);\n\n\t// Port link state change (PLC).\n\tif (status & XHCI_PORTSC_PLC)\n\t{\n\t\t// check XHCI_PORTSC_PLS_MASK\n\t\t// if XHCI_PORTSC_PLS_U3\n\t\t//  device_state = XUSB_SUSPENDED\n\t\t// else if XHCI_PORTSC_PLS_U0 and XUSB_SUSPENDED\n\t\t//  val = XUSB_DEV_XHCI_EP_PAUSE\n\t\t//  XUSB_DEV_XHCI_EP_PAUSE = 0\n\t\t//  XUSB_DEV_XHCI_EP_STCHG = val;\n\n\t\t// Clear PLC bit.\n\t\tstatus &= ~clear_mask;\n\t\tstatus |= XHCI_PORTSC_PLC;\n\t\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status;\n\t}\n\n\t// Port configuration link error (CEC).\n\tif (status & XHCI_PORTSC_CEC)\n\t{\n\t\tstatus = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC);\n\t\tstatus &= ~clear_mask;\n\t\tstatus |= XHCI_PORTSC_CEC;\n\t\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) = status;\n\n\t\treturn XUSB_ERROR_PORT_CFG;\n\t}\n\n\treturn USB_RES_OK;\n}\n\nstatic int _xusb_handle_get_ep_status(u32 ep_idx)\n{\n\tu32 ep_mask = BIT(ep_idx);\n\tstatic u8 xusb_ep_status_descriptor[2] = {0};\n\n\txusb_ep_status_descriptor[0] = (XUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) & ep_mask) ? USB_STATUS_EP_HALTED : USB_STATUS_EP_OK;\n\n\treturn _xusb_issue_data_trb(xusb_ep_status_descriptor, 2, USB_DIR_IN);\n}\n\nstatic int _xusb_handle_get_class_request(const usb_ctrl_setup_t *ctrl_setup)\n{\n\tu8 _bRequest = ctrl_setup->bRequest;\n\tu16 _wIndex  = ctrl_setup->wIndex;\n\tu16 _wValue  = ctrl_setup->wValue;\n\tu16 _wLength = ctrl_setup->wLength;\n\n\tbool valid_interface = _wIndex == usbd_xotg->interface_num;\n\tbool valid_val = (_bRequest >= USB_REQUEST_BULK_GET_MAX_LUN) ? (!_wValue) : true;\n\n\tif (!valid_interface || !valid_val)\n\t\tgoto stall;\n\n\tswitch (_bRequest)\n\t{\n\tcase USB_REQUEST_INTR_GET_REPORT:\n\t\tif (usbd_xotg->hid_rpt_size != _wLength)\n\t\t\tgoto stall;\n\n\t\t// _wValue unused as there's only one report type and id.\n\t\treturn _xusb_issue_data_trb(usbd_xotg->hid_rpt_buffer, usbd_xotg->hid_rpt_size, USB_DIR_IN);\n\n\tcase USB_REQUEST_INTR_SET_IDLE:\n\t\tif (_wLength)\n\t\t\tgoto stall;\n\n\t\tusbd_xotg->intr_idle_rate = (_wValue & 0xFF) * 4 * 1000; // Only one interface so upper byte ignored.\n\t\tusbd_xotg->intr_idle_req  = true;\n\t\treturn _xusb_issue_status_trb(USB_DIR_IN); // DELAYED_STATUS;\n\n\tcase USB_REQUEST_BULK_RESET:\n\t\tif (_wLength)\n\t\t\tgoto stall;\n\n\t\tusbd_xotg->bulk_reset_req = true;\n\t\treturn _xusb_issue_status_trb(USB_DIR_IN); // DELAYED_STATUS;\n\n\tcase USB_REQUEST_BULK_GET_MAX_LUN:\n\t\tif (_wLength != 1 || !usbd_xotg->max_lun_set)\n\t\t\tgoto stall;\n\n\t\tusbd_xotg->device_state = XUSB_LUN_CONFIGURED_STS_WAIT;\n\t\treturn _xusb_issue_data_trb(&usbd_xotg->max_lun, 1, USB_DIR_IN);\n\t}\n\nstall:\n\txusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL);\n\treturn USB_RES_OK;\n}\n\nstatic int _xusb_handle_get_descriptor(const usb_ctrl_setup_t *ctrl_setup)\n{\n\tu32 size;\n\tvoid *desc;\n\n\tu32 wLength = ctrl_setup->wLength;\n\n\tu8 descriptor_type = ctrl_setup->wValue >> 8;\n\tu8 descriptor_subtype = ctrl_setup->wValue & 0xFF;\n\n\tswitch (descriptor_type)\n\t{\n\tcase USB_DESCRIPTOR_DEVICE:\n\t\t//! TODO USB3: Provide a super speed descriptor.\n/*\n\t\tu32 soc_rev = APB_MISC(APB_MISC_GP_HIDREV);\n\t\tusb_device_descriptor.idProduct  = (soc_rev >> 8)  & 0xFF; // chip_id.\n\t\tusb_device_descriptor.idProduct |= ((soc_rev << 4) | (FUSE(FUSE_SKU_INFO) & 0xF)) << 8; // HIDFAM.\n\t\tusb_device_descriptor.bcdDevice  = (soc_rev >> 16) & 0xF; // MINORREV.\n\t\tusb_device_descriptor.bcdDevice |= ((soc_rev >> 4) & 0xF) << 8; // MAJORREV.\n*/\n\t\tdesc = usbd_xotg->desc->dev;\n\t\tsize = usbd_xotg->desc->dev->bLength;\n\t\tbreak;\n\tcase USB_DESCRIPTOR_CONFIGURATION:\n\t\t//! TODO USB3: Provide a super speed descriptor.\n\t\tif (usbd_xotg->gadget == USB_GADGET_UMS)\n\t\t{\n\t\t\tif (usbd_xotg->port_speed == XUSB_HIGH_SPEED) // High speed. 512 bytes.\n\t\t\t{\n\t\t\t\tfor (u32 i = 0; i < usbd_xotg->desc->cfg->interface.bNumEndpoints; i++)\n\t\t\t\t\tusbd_xotg->desc->cfg->endpoint[i].wMaxPacketSize = 0x200; // No burst.\n\t\t\t}\n\t\t\telse // Full speed. 64 bytes.\n\t\t\t{\n\t\t\t\tfor (u32 i = 0; i < usbd_xotg->desc->cfg->interface.bNumEndpoints; i++)\n\t\t\t\t\tusbd_xotg->desc->cfg->endpoint[i].wMaxPacketSize = 0x40;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tusb_cfg_hid_descr_t *tmp = (usb_cfg_hid_descr_t *)usbd_xotg->desc->cfg;\n\t\t\tif (usbd_xotg->port_speed == XUSB_HIGH_SPEED) // High speed. 512 bytes.\n\t\t\t{\n\t\t\t\tfor (u32 i = 0; i < tmp->interface.bNumEndpoints; i++)\n\t\t\t\t{\n\t\t\t\t\ttmp->endpoint[i].wMaxPacketSize = 0x200;\n\t\t\t\t\ttmp->endpoint[i].bInterval = usbd_xotg->gadget == USB_GADGET_HID_GAMEPAD ? 4 : 3; // 8ms : 4ms.\n\t\t\t\t}\n\t\t\t}\n\t\t\telse // Full speed. 64 bytes.\n\t\t\t{\n\t\t\t\tfor (u32 i = 0; i < tmp->interface.bNumEndpoints; i++)\n\t\t\t\t{\n\t\t\t\t\ttmp->endpoint[i].wMaxPacketSize = 0x40;\n\t\t\t\t\ttmp->endpoint[i].bInterval = usbd_xotg->gadget == USB_GADGET_HID_GAMEPAD ? 8 : 4; // 8ms : 4ms.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdesc = usbd_xotg->desc->cfg;\n\t\tsize = usbd_xotg->desc->cfg->config.wTotalLength;\n\t\tbreak;\n\tcase USB_DESCRIPTOR_STRING:\n\t\tswitch (descriptor_subtype)\n\t\t{\n\t\tcase 1:\n\t\t\tdesc = usbd_xotg->desc->vendor;\n\t\t\tsize = usbd_xotg->desc->vendor[0];\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tdesc = usbd_xotg->desc->product;\n\t\t\tsize = usbd_xotg->desc->product[0];\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tdesc = usbd_xotg->desc->serial;\n\t\t\tsize = usbd_xotg->desc->serial[0];\n\t\t\tbreak;\n\t\tcase 0xEE:\n\t\t\tdesc = usbd_xotg->desc->ms_os;\n\t\t\tsize = usbd_xotg->desc->ms_os->bLength;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tdesc = usbd_xotg->desc->lang_id;\n\t\t\tsize = 4;\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase USB_DESCRIPTOR_DEVICE_QUALIFIER:\n\t\tif (!usbd_xotg->desc->dev_qual)\n\t\t{\n\t\t\txusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL);\n\t\t\treturn USB_RES_OK;\n\t\t}\n\t\tusbd_xotg->desc->dev_qual->bNumOtherConfigs = 0;\n\t\tdesc = usbd_xotg->desc->dev_qual;\n\t\tsize = usbd_xotg->desc->dev_qual->bLength;\n\t\tbreak;\n\tcase USB_DESCRIPTOR_OTHER_SPEED_CONFIGURATION:\n\t\tif (!usbd_xotg->desc->cfg_other)\n\t\t{\n\t\t\txusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL);\n\t\t\treturn USB_RES_OK;\n\t\t}\n\t\tif (usbd_xotg->port_speed == XUSB_HIGH_SPEED)\n\t\t{\n\t\t\tfor (u32 i = 0; i < usbd_xotg->desc->cfg_other->interface.bNumEndpoints; i++)\n\t\t\t\tusbd_xotg->desc->cfg_other->endpoint[i].wMaxPacketSize = 0x40;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (u32 i = 0; i < usbd_xotg->desc->cfg_other->interface.bNumEndpoints; i++)\n\t\t\t\tusbd_xotg->desc->cfg_other->endpoint[i].wMaxPacketSize = 0x200;\n\t\t}\n\t\tdesc = usbd_xotg->desc->cfg_other;\n\t\tsize = usbd_xotg->desc->cfg_other->config.wTotalLength;\n\t\tbreak;\n\tcase USB_DESCRIPTOR_DEVICE_BINARY_OBJECT:\n\t\tdesc = usbd_xotg->desc->dev_bot;\n\t\tsize = usbd_xotg->desc->dev_bot->wTotalLength;\n\t\tbreak;\n\tdefault:\n\t\txusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL);\n\t\treturn USB_RES_OK;\n\t}\n\n\tif (wLength < size)\n\t\tsize = wLength;\n\n\treturn _xusb_issue_data_trb(desc, size, USB_DIR_IN);\n}\n\nstatic void _xusb_handle_set_request_dev_address(const usb_ctrl_setup_t *ctrl_setup)\n{\n\tu32 addr = ctrl_setup->wValue & 0xFF;\n\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) = (XUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) & 0x80FFFFFF) | (addr << 24);\n\txusb_evtq->xusb_ep_ctxt[XUSB_EP_CTRL_IN].device_addr = addr;\n\n\t_xusb_issue_status_trb(USB_DIR_IN);\n\n\tusbd_xotg->device_state = XUSB_ADDRESSED_STS_WAIT;\n}\n\nstatic void _xusb_handle_set_request_configuration(const usb_ctrl_setup_t *ctrl_setup)\n{\n\tusbd_xotg->config_num = ctrl_setup->wValue;\n\n\t// Remove configuration.\n\tif (!usbd_xotg->config_num)\n\t{\n\t\t//! TODO: Signal that to userspace.\n\t\t_xusb_disable_ep1();\n\n\t\t_xusb_issue_status_trb(USB_DIR_IN);\n\n\t\treturn;\n\t}\n\n\t// Initialize BULK EPs.\n\t_xusbd_ep_initialize(USB_EP_BULK_OUT);\n\t_xusbd_ep_initialize(USB_EP_BULK_IN);\n\n\t// Device mode start.\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) |= XHCI_CTRL_RUN;\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_ST)   |= XHCI_ST_RC;\n\n\t_xusb_issue_status_trb(USB_DIR_IN);\n\tusbd_xotg->device_state = XUSB_CONFIGURED_STS_WAIT;\n}\n\nstatic int _xusbd_handle_ep0_control_transfer(usb_ctrl_setup_t *ctrl_setup)\n{\n\tu32 size;\n\tu8 *desc;\n\tbool ep_stall = false;\n\tbool transmit_data = false;\n\n\tu8  _bmRequestType = ctrl_setup->bmRequestType;\n\tu8  _bRequest      = ctrl_setup->bRequest;\n\tu16 _wValue        = ctrl_setup->wValue;\n\tu16 _wIndex        = ctrl_setup->wIndex;\n\tu16 _wLength       = ctrl_setup->wLength;\n\n\tstatic u8 xusb_dev_status_descriptor[2] = {USB_STATUS_DEV_SELF_POWERED, 0};\n\tstatic u8 xusb_interface_descriptor[4] = {0};\n\tstatic u8 xusb_configuration_descriptor[2] = {0};\n\tstatic u8 xusb_status_descriptor[2] = {0};\n\n\t//gfx_printf(\"ctrl: %02X %02X %04X %04X %04X\\n\", _bmRequestType, _bRequest, _wValue, _wIndex, _wLength);\n\n\t// Unhalt EP0 IN.\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_EP_HALT) &= ~XHCI_EP_HALT_DCI_EP0_IN;\n\tu32 res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_EP_HALT, XHCI_EP_HALT_DCI_EP0_IN, 0, 1000);\n\tif (res)\n\t\treturn res;\n\n\tswitch (_bmRequestType)\n\t{\n\tcase (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_DEVICE):    // 0x00.\n\t\tif (_bRequest == USB_REQUEST_SET_ADDRESS)\n\t\t\t_xusb_handle_set_request_dev_address(ctrl_setup);\n\t\telse if (_bRequest == USB_REQUEST_SET_CONFIGURATION)\n\t\t\t_xusb_handle_set_request_configuration(ctrl_setup);\n\t\treturn USB_RES_OK; // What about others.\n\n\tcase (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_INTERFACE): // 0x01.\n\t\tusbd_xotg->interface_num = _wValue;\n\t\treturn _xusb_issue_status_trb(USB_DIR_IN);\n\n\tcase (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT):  // 0x02.\n\t\tif ((_wValue & 0xFF) == USB_FEATURE_ENDPOINT_HALT)\n\t\t{\n\t\t\tif (_bRequest == USB_REQUEST_CLEAR_FEATURE || _bRequest == USB_REQUEST_SET_FEATURE)\n\t\t\t{\n\t\t\t\tu32 ep = 0;\n\t\t\t\tswitch (_wIndex) // endpoint\n\t\t\t\t{\n\t\t\t\tcase USB_EP_ADDR_CTRL_OUT:\n\t\t\t\t\tep = XUSB_EP_CTRL_OUT;\n\t\t\t\t\tbreak;\n\t\t\t\tcase USB_EP_ADDR_CTRL_IN:\n\t\t\t\t\tep = XUSB_EP_CTRL_IN;\n\t\t\t\t\tbreak;\n\t\t\t\tcase USB_EP_ADDR_BULK_OUT:\n\t\t\t\t\tep = USB_EP_BULK_OUT;\n\t\t\t\t\tbreak;\n\t\t\t\tcase USB_EP_ADDR_BULK_IN:\n\t\t\t\t\tep = USB_EP_BULK_IN;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\txusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL);\n\t\t\t\t\treturn USB_RES_OK;\n\t\t\t\t}\n\n\t\t\t\tif (_bRequest == USB_REQUEST_CLEAR_FEATURE)\n\t\t\t\t\txusb_set_ep_stall(ep, USB_EP_CFG_CLEAR);\n\t\t\t\telse if (_bRequest == USB_REQUEST_SET_FEATURE)\n\t\t\t\t\txusb_set_ep_stall(ep, USB_EP_CFG_STALL);\n\n\t\t\t\treturn _xusb_issue_status_trb(USB_DIR_IN);\n\t\t\t}\n\t\t}\n\t\tep_stall = true;\n\t\tbreak;\n\n\tcase (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_CLASS    | USB_SETUP_RECIPIENT_INTERFACE): // 0x21.\n\t\treturn _xusb_handle_get_class_request(ctrl_setup);\n\n\tcase (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_DEVICE):    // 0x80.\n\t\tswitch (_bRequest)\n\t\t{\n\t\tcase USB_REQUEST_GET_STATUS:\n\t\t\tdesc = xusb_dev_status_descriptor;\n\t\t\tsize = sizeof(xusb_dev_status_descriptor);\n\t\t\ttransmit_data = true;\n\t\t\tbreak;\n\t\tcase USB_REQUEST_GET_DESCRIPTOR:\n\t\t\treturn _xusb_handle_get_descriptor(ctrl_setup);\n\t\tcase USB_REQUEST_GET_CONFIGURATION:\n\t\t\txusb_configuration_descriptor[0] = usbd_xotg->config_num;\n\t\t\tdesc = xusb_configuration_descriptor;\n\t\t\tsize = sizeof(xusb_configuration_descriptor);\n\t\t\ttransmit_data = true;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tep_stall = true;\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\n\tcase (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_INTERFACE): // 0x81.\n\t\tif (_bRequest == USB_REQUEST_GET_INTERFACE)\n\t\t{\n\t\t\tdesc = xusb_interface_descriptor;\n\t\t\tsize = sizeof(xusb_interface_descriptor);\n\t\t\txusb_interface_descriptor[0] = usbd_xotg->interface_num;\n\t\t\ttransmit_data = true;\n\t\t}\n\t\telse if (_bRequest == USB_REQUEST_GET_STATUS)\n\t\t{\n\t\t\tdesc = xusb_status_descriptor;\n\t\t\tsize = sizeof(xusb_status_descriptor);\n\t\t\ttransmit_data = true;\n\t\t}\n\t\telse if (_bRequest == USB_REQUEST_GET_DESCRIPTOR && (_wValue >> 8) == USB_DESCRIPTOR_HID_REPORT && usbd_xotg->gadget >= USB_GADGET_HID_GAMEPAD)\n\t\t{\n\t\t\tif (usbd_xotg->gadget == USB_GADGET_HID_GAMEPAD)\n\t\t\t{\n\t\t\t\tdesc = (u8 *)&hid_report_descriptor_jc;\n\t\t\t\tsize = hid_report_descriptor_jc_size;\n\t\t\t}\n\t\t\telse // USB_GADGET_HID_TOUCHPAD\n\t\t\t{\n\t\t\t\tdesc = (u8 *)&hid_report_descriptor_touch;\n\t\t\t\tsize = hid_report_descriptor_touch_size;\n\t\t\t}\n\t\t\ttransmit_data = true;\n\t\t\tusbd_xotg->device_state = XUSB_HID_CONFIGURED_STS_WAIT;\n\t\t}\n\t\telse\n\t\t\tep_stall = true;\n\t\tbreak;\n\n\tcase (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT):  // 0x82.\n\t\tif (_bRequest == USB_REQUEST_GET_STATUS)\n\t\t{\n\t\t\tu32 ep = 0;\n\t\t\tswitch (_wIndex) // endpoint\n\t\t\t{\n\t\t\tcase USB_EP_ADDR_CTRL_OUT:\n\t\t\t\tep = XUSB_EP_CTRL_OUT;\n\t\t\t\tbreak;\n\t\t\tcase USB_EP_ADDR_CTRL_IN:\n\t\t\t\tep = XUSB_EP_CTRL_IN;\n\t\t\t\tbreak;\n\t\t\tcase USB_EP_ADDR_BULK_OUT:\n\t\t\t\tep = USB_EP_BULK_OUT;\n\t\t\t\tbreak;\n\t\t\tcase USB_EP_ADDR_BULK_IN:\n\t\t\t\tep = USB_EP_BULK_IN;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\txusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL);\n\t\t\t\treturn USB_RES_OK;\n\t\t\t}\n\t\t\treturn _xusb_handle_get_ep_status(ep);\n\t\t}\n\n\t\tep_stall = true;\n\t\tbreak;\n\n\tcase (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_CLASS    | USB_SETUP_RECIPIENT_INTERFACE): // 0xA1.\n\t\treturn _xusb_handle_get_class_request(ctrl_setup);\n\n\tcase (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_VENDOR   | USB_SETUP_RECIPIENT_DEVICE):    // 0xC0.\n\tcase (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_VENDOR   | USB_SETUP_RECIPIENT_INTERFACE): // 0xC1.\n\t\tif (_bRequest == USB_REQUEST_GET_MS_DESCRIPTOR)\n\t\t{\n\t\t\tswitch (_wIndex)\n\t\t\t{\n\t\t\tcase USB_DESCRIPTOR_MS_COMPAT_ID:\n\t\t\t\tdesc = (u8 *)usbd_xotg->desc->ms_cid;\n\t\t\t\tsize = usbd_xotg->desc->ms_cid->dLength;\n\t\t\t\ttransmit_data = true;\n\t\t\t\tbreak;\n\t\t\tcase USB_DESCRIPTOR_MS_EXTENDED_PROPERTIES:\n\t\t\t\tdesc = (u8 *)usbd_xotg->desc->mx_ext;\n\t\t\t\tsize = usbd_xotg->desc->mx_ext->dLength;\n\t\t\t\ttransmit_data = true;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tep_stall = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tep_stall = true;\n\t\tbreak;\n\n\tdefault:\n\t\tep_stall = true;\n\t\tbreak;\n\t}\n\n\tif (transmit_data)\n\t{\n\t\tmemcpy((u8 *)USB_EP_CONTROL_BUF_ADDR, desc, size);\n\t\tif (_wLength < size)\n\t\t\t\tsize = _wLength;\n\t\treturn _xusb_issue_data_trb((u8 *)USB_EP_CONTROL_BUF_ADDR, size, USB_DIR_IN);\n\t}\n\n\tif (ep_stall)\n\t\txusb_set_ep_stall(XUSB_EP_CTRL_IN, USB_EP_CFG_STALL);\n\n\treturn USB_RES_OK;\n}\n\nstatic int _xusb_ep_operation(u32 tries)\n{\n\tusb_ctrl_setup_t setup_event;\n\tvolatile event_trb_t *event_trb;\n\tsetup_event_trb_t *setup_event_trb;\n\n\t// Wait for an interrupt event.\n\tint res = _xusb_xhci_mask_wait(XUSB_DEV_XHCI_ST, XHCI_ST_IP, XHCI_ST_IP, tries);\n\tif (res)\n\t\treturn res;\n\n\t// Clear interrupt status.\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_ST) |= XHCI_ST_IP;\n\n\tusbd_xotg->event_enqueue_ptr = (event_trb_t *)(XUSB_DEV_XHCI(XUSB_DEV_XHCI_EREPLO) & 0xFFFFFFF0);\n\tevent_trb = usbd_xotg->event_dequeue_ptr;\n\n\t// Check if cycle matches.\n\tif ((event_trb->cycle & 1) != usbd_xotg->event_ccs)\n\t\treturn XUSB_ERROR_INVALID_CYCLE;\n\n\twhile ((event_trb->cycle & 1) == usbd_xotg->event_ccs)\n\t{\n\t\tswitch (event_trb->trb_type)\n\t\t{\n\t\tcase XUSB_TRB_TRANSFER:\n\t\t\tres = _xusb_handle_transfer_event((transfer_event_trb_t *)event_trb);\n\t\t\tbreak;\n\t\tcase XUSB_TRB_PORT_CHANGE:\n\t\t\tres = _xusb_handle_port_change();\n\t\t\tbreak;\n\t\tcase XUSB_TRB_SETUP:\n\t\t\tsetup_event_trb = (setup_event_trb_t *)event_trb;\n\t\t\tmemcpy(&setup_event, &setup_event_trb->ctrl_setup_data, sizeof(usb_ctrl_setup_t));\n\t\t\tusbd_xotg->ctrl_seq_num = setup_event_trb->ctrl_seq_num;\n\t\t\tres = _xusbd_handle_ep0_control_transfer(&setup_event);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t// TRB not supported.\n\t\t\tbreak;\n\t\t}\n\n\t\t// Check if last event TRB and reset to first one.\n\t\tif (usbd_xotg->event_dequeue_ptr == &xusb_evtq->xusb_event_ring_seg1[XUSB_LAST_TRB_IDX])\n\t\t{\n\t\t\tusbd_xotg->event_dequeue_ptr = xusb_evtq->xusb_event_ring_seg0;\n\t\t\tusbd_xotg->event_ccs ^= 1;\n\t\t}\n\t\telse // Advance dequeue to next event.\n\t\t\tusbd_xotg->event_dequeue_ptr = &usbd_xotg->event_dequeue_ptr[1];\n\n\t\t// Set next event.\n\t\tevent_trb = usbd_xotg->event_dequeue_ptr;\n\n\t\t// If events exceed the interrupt time, handle them next interrupt.\n\t\tif (usbd_xotg->event_dequeue_ptr == usbd_xotg->event_enqueue_ptr)\n\t\t\tbreak;\n\t}\n\n\t// Clear Event Handler bit if enabled and set Dequeue pointer.\n\tu32 erdp = XUSB_DEV_XHCI(XUSB_DEV_XHCI_ERDPLO) & 0xF;\n\tif (erdp & XHCI_ERDPLO_EHB)\n\t\terdp |= XHCI_ERDPLO_EHB;\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_ERDPLO) = ((u32)usbd_xotg->event_dequeue_ptr & 0xFFFFFFF0) | erdp;\n\n\treturn res;\n}\n\nint xusb_device_enumerate(usb_gadget_type gadget)\n{\n\tswitch (gadget)\n\t{\n\tcase USB_GADGET_UMS:\n\t\tusbd_xotg->desc = &usb_gadget_ums_descriptors;\n\t\tbreak;\n\tcase USB_GADGET_HID_GAMEPAD:\n\t\tusbd_xotg->desc = &usb_gadget_hid_jc_descriptors;\n\t\tbreak;\n\tcase USB_GADGET_HID_TOUCHPAD:\n\t\tusbd_xotg->desc = &usb_gadget_hid_touch_descriptors;\n\t\tbreak;\n\t}\n\n\tusbd_xotg->gadget = gadget;\n\n\t/*\n\t * Set interrupt moderation to 0us.\n\t * This is important because default value creates a 4.62ms latency.\n\t * Effectively hurting transfers by having 15% to 96% performance loss.\n\t */\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_RT_IMOD) = 0;\n\n\t// Disable Wake events.\n\tXUSB_PADCTL(XUSB_PADCTL_ELPG_PROGRAM_0) = 0;\n\tXUSB_PADCTL(XUSB_PADCTL_ELPG_PROGRAM_1) = 0;\n\n\t// Enable overrides for VBUS and ID.\n\tXUSB_PADCTL(XUSB_PADCTL_USB2_VBUS_ID) = (XUSB_PADCTL(XUSB_PADCTL_USB2_VBUS_ID) & ~(PADCTL_USB2_VBUS_ID_VBUS_OVR_MASK | PADCTL_USB2_VBUS_ID_SRC_MASK)) |\n\t\t\t\t\t\t\t\t\t\t\tPADCTL_USB2_VBUS_ID_VBUS_OVR_EN | PADCTL_USB2_VBUS_ID_SRC_ID_OVR_EN;\n\n\t// Clear halt for LTSSM.\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTHALT) &= ~XHCI_PORTHALT_HALT_LTSSM;\n\n\t// Enable device mode.\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) |= XHCI_CTRL_ENABLE;\n\n\t// Override access to High/Full Speed.\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_CFG_DEV_FE) = (XUSB_DEV_XHCI(XUSB_DEV_XHCI_CFG_DEV_FE) & ~XHCI_CFG_DEV_FE_PORTREGSEL_MASK) | XHCI_CFG_DEV_FE_PORTREGSEL_HSFS;\n\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC)     = (XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) & ~XHCI_PORTSC_PLS_MASK) | XHCI_PORTSC_LWS | XHCI_PORTSC_PLS_RXDETECT;\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_CFG_DEV_FE) &= ~XHCI_CFG_DEV_FE_PORTREGSEL_MASK;\n\n\t// Enable VBUS and set ID to Float.\n\tXUSB_PADCTL(XUSB_PADCTL_USB2_VBUS_ID) = (XUSB_PADCTL(XUSB_PADCTL_USB2_VBUS_ID) & ~PADCTL_USB2_VBUS_ID_OVR_MASK) |\n\t\t\t\t\t\t\t\t\t\t\tPADCTL_USB2_VBUS_ID_OVR_FLOAT | PADCTL_USB2_VBUS_ID_VBUS_ON;\n\n\tusbd_xotg->wait_for_event_trb = XUSB_TRB_SETUP;\n\tusbd_xotg->device_state       = XUSB_DEFAULT;\n\n\t// Timeout if cable or communication isn't started in 1.5 minutes.\n\tu32 timer = get_tmr_ms() + 90000;\n\twhile (true)\n\t{\n\t\tint res = _xusb_ep_operation(USB_XFER_SYNCED_ENUM); // 2s timeout.\n\t\tif (res && res != USB_ERROR_TIMEOUT)\n\t\t\treturn res;\n\n\t\tif (usbd_xotg->device_state == XUSB_CONFIGURED)\n\t\t\tbreak;\n\n\t\tif (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))\n\t\t\treturn USB_ERROR_USER_ABORT;\n\t}\n\n\treturn USB_RES_OK;\n}\n\nvoid xusb_end(bool reset_ep, bool only_controller)\n{\n\t// Disable endpoints and stop device mode operation.\n\t_xusb_disable_ep1();\n\n\t// Disable device mode.\n\tXUSB_DEV_XHCI(XUSB_DEV_XHCI_CTRL) = 0;\n\n\t//! TODO: Add only controller support?\n\t_xusb_device_power_down();\n}\n\nint xusb_handle_ep0_ctrl_setup(u32 *data)\n{\n\t/*\n\t * EP0 Control handling is done by normal ep operation in XUSB.\n\t * Here we handle the interface only, except if HID.\n\t */\n\tif (usbd_xotg->gadget >= USB_GADGET_HID_GAMEPAD)\n\t\t_xusb_ep_operation(1);\n\n\tif (usbd_xotg->intr_idle_req)\n\t{\n\t\tif (data)\n\t\t\t*data = usbd_xotg->intr_idle_rate;\n\n\t\tusbd_xotg->intr_idle_req = false;\n\t\treturn USB_RES_OK;\n\t}\n\n\tif (usbd_xotg->bulk_reset_req)\n\t{\n\t\tusbd_xotg->bulk_reset_req = false;\n\t\treturn USB_RES_BULK_RESET;\n\t}\n\n\treturn USB_RES_OK;\n}\n\nint xusb_device_ep1_out_read(u8 *buf, u32 len, u32 *bytes_read, u32 sync_tries)\n{\n\tif (len > USB_EP_BUFFER_MAX_SIZE)\n\t\tlen = USB_EP_BUFFER_MAX_SIZE;\n\n\tint res = USB_RES_OK;\n\tusbd_xotg->tx_count[USB_DIR_OUT] = 0;\n\tusbd_xotg->tx_bytes[USB_DIR_OUT] = len;\n\n\t_xusb_issue_normal_trb(buf, len, USB_DIR_OUT);\n\tusbd_xotg->tx_count[USB_DIR_OUT]++;\n\n\tif (sync_tries)\n\t{\n\t\twhile (!res && usbd_xotg->tx_count[USB_DIR_OUT])\n\t\t\tres = _xusb_ep_operation(sync_tries);\n\n\t\tif (bytes_read)\n\t\t\t*bytes_read = res ? 0 : usbd_xotg->tx_bytes[USB_DIR_OUT];\n\t}\n\n\t// Invalidate data after transfer.\n\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);\n\n\treturn res;\n}\n\nint xusb_device_ep1_out_read_big(u8 *buf, u32 len, u32 *bytes_read)\n{\n\tif (len > USB_EP_BULK_OUT_MAX_XFER)\n\t\tlen = USB_EP_BULK_OUT_MAX_XFER;\n\n\tu32 bytes = 0;\n\t*bytes_read = 0;\n\tu8 *buf_curr = buf;\n\n\twhile (len)\n\t{\n\t\tu32 len_ep = MIN(len, USB_EP_BUFFER_MAX_SIZE);\n\n\t\tint res = xusb_device_ep1_out_read(buf_curr, len_ep, &bytes, USB_XFER_SYNCED_DATA);\n\t\tif (res)\n\t\t\treturn res;\n\n\t\tlen -= len_ep;\n\t\tbuf_curr += len_ep;\n\t\t*bytes_read = *bytes_read + bytes;\n\t}\n\n\treturn USB_RES_OK;\n}\n\nint xusb_device_ep1_out_reading_finish(u32 *pending_bytes, u32 sync_tries)\n{\n\tint res = USB_RES_OK;\n\twhile (!res && usbd_xotg->tx_count[USB_DIR_OUT])\n\t\tres = _xusb_ep_operation(sync_tries); // Infinite retries.\n\n\tif (pending_bytes)\n\t\t*pending_bytes = res ? 0 : usbd_xotg->tx_bytes[USB_DIR_OUT];\n\n\t// Invalidate data after transfer.\n\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);\n\n\treturn res;\n}\n\nint xusb_device_ep1_in_write(u8 *buf, u32 len, u32 *bytes_written, u32 sync_tries)\n{\n\tif (len > USB_EP_BUFFER_MAX_SIZE)\n\t\tlen = USB_EP_BUFFER_MAX_SIZE;\n\n\t// Flush data before transfer.\n\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_CLEAN_WAY, false);\n\n\tint res = USB_RES_OK;\n\tusbd_xotg->tx_count[USB_DIR_IN] = 0;\n\tusbd_xotg->tx_bytes[USB_DIR_IN] = len;\n\n\t_xusb_issue_normal_trb(buf, len, USB_DIR_IN);\n\tusbd_xotg->tx_count[USB_DIR_IN]++;\n\n\tif (sync_tries)\n\t{\n\t\twhile (!res && usbd_xotg->tx_count[USB_DIR_IN])\n\t\t\tres = _xusb_ep_operation(sync_tries);\n\n\t\tif (bytes_written)\n\t\t\t*bytes_written = res ? 0 : usbd_xotg->tx_bytes[USB_DIR_IN];\n\t}\n\telse\n\t{\n\t\tif ((usbd_xotg->port_speed == XUSB_FULL_SPEED  && len == 64)  ||\n\t\t\t(usbd_xotg->port_speed == XUSB_HIGH_SPEED  && len == 512) ||\n\t\t\t(usbd_xotg->port_speed == XUSB_SUPER_SPEED && len == 1024))\n\t\t{\n\t\t\t_xusb_issue_normal_trb(buf, 0, USB_DIR_IN);\n\t\t\tusbd_xotg->tx_count[USB_DIR_IN]++;\n\t\t}\n\t}\n\n\treturn res;\n}\n\nint xusb_device_ep1_in_writing_finish(u32 *pending_bytes, u32 sync_tries)\n{\n\tint res = USB_RES_OK;\n\twhile (!res && usbd_xotg->tx_count[USB_DIR_IN])\n\t\tres = _xusb_ep_operation(sync_tries); // Infinite retries.\n\n\tif (pending_bytes)\n\t\t*pending_bytes = res ? 0 : usbd_xotg->tx_bytes[USB_DIR_IN];\n\n\treturn res;\n}\n\nbool xusb_device_get_port_in_sleep()\n{\n\t// Ejection heuristic.\n\tu32 link_mode = XUSB_DEV_XHCI(XUSB_DEV_XHCI_PORTSC) & XHCI_PORTSC_PLS_MASK;\n\treturn (link_mode == XHCI_PORTSC_PLS_U3);\n}\n\nbool xusb_device_class_send_max_lun(u8 max_lun)\n{\n\t// Timeout if get MAX_LUN request doesn't happen in 10s.\n\tu32 timer = get_tmr_ms() + 10000;\n\n\tusbd_xotg->max_lun     = max_lun;\n\tusbd_xotg->max_lun_set = true;\n\n\t// Wait for request and transfer start.\n\twhile (usbd_xotg->device_state != XUSB_LUN_CONFIGURED)\n\t{\n\t\t_xusb_ep_operation(USB_XFER_SYNCED_CLASS);\n\t\tif (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))\n\t\t\treturn true;\n\t}\n\n\tusbd_xotg->device_state = XUSB_CONFIGURED;\n\n\treturn false;\n}\n\nbool xusb_device_class_send_hid_report(void *rpt_buffer, u32 rpt_size)\n{\n\t// Set buffers.\n\tusbd_xotg->hid_rpt_buffer = rpt_buffer;\n\tusbd_xotg->hid_rpt_size   = rpt_size;\n\n\t// Timeout if get GET_HID_REPORT request doesn't happen in 10s.\n\tu32 timer = get_tmr_ms() + 10000;\n\n\t// Wait for request and transfer start.\n\twhile (usbd_xotg->device_state != XUSB_HID_CONFIGURED)\n\t{\n\t\t_xusb_ep_operation(USB_XFER_SYNCED_CLASS);\n\t\tif (timer < get_tmr_ms() || btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))\n\t\t\treturn true;\n\t}\n\n\tusbd_xotg->device_state = XUSB_CONFIGURED;\n\n\treturn false;\n}\n\nvoid xusb_device_get_ops(usb_ops_t *ops)\n{\n\tops->usbd_flush_endpoint               = NULL;\n\tops->usbd_set_ep_stall                 = xusb_set_ep_stall;\n\tops->usbd_handle_ep0_ctrl_setup        = xusb_handle_ep0_ctrl_setup;\n\tops->usbd_end                          = xusb_end;\n\tops->usb_device_init                   = xusb_device_init;\n\tops->usb_device_enumerate              = xusb_device_enumerate;\n\tops->usb_device_class_send_max_lun     = xusb_device_class_send_max_lun;\n\tops->usb_device_class_send_hid_report  = xusb_device_class_send_hid_report;\n\tops->usb_device_get_suspended          = xusb_device_get_port_in_sleep;\n\tops->usb_device_get_port_in_sleep      = xusb_device_get_port_in_sleep;\n\n\tops->usb_device_ep1_out_read           = xusb_device_ep1_out_read;\n\tops->usb_device_ep1_out_read_big       = xusb_device_ep1_out_read_big;\n\tops->usb_device_ep1_out_reading_finish = xusb_device_ep1_out_reading_finish;\n\tops->usb_device_ep1_in_write           = xusb_device_ep1_in_write;\n\tops->usb_device_ep1_in_writing_finish  = xusb_device_ep1_in_writing_finish;\n}\n"
  },
  {
    "path": "bdk/utils/aarch64_util.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _ARM64_H_\n#define _ARM64_H_\n\n#include <utils/types.h>\n\n#define LSL0 0\n#define LSL16 16\n#define LSL32 32\n\n#define _PAGEOFF(x) ((x) & 0xFFFFF000)\n\n#define _ADRP(r, o) (0x90000000 | ((((o) >> 12) & 0x3) << 29) | ((((o) >> 12) & 0x1FFFFC) << 3) | ((r) & 0x1F))\n#define _BL(a, o) (0x94000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF))\n#define _B(a, o) (0x14000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF))\n#define _MOVKX(r, i, s) (0xF2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F))\n#define _MOVZX(r, i, s) (0xD2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F))\n#define _MOVZW(r, i, s) (0x52800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F))\n#define _NOP() 0xD503201F\n\n#endif\n"
  },
  {
    "path": "bdk/utils/btn.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2022 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include \"btn.h\"\n#include <soc/i2c.h>\n#include <soc/gpio.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n#include <power/max77620.h>\n\nu8 btn_read()\n{\n\tu8 res = 0;\n\tif (!gpio_read(GPIO_PORT_X, GPIO_PIN_7))\n\t\tres |= BTN_VOL_DOWN;\n\tif (!gpio_read(GPIO_PORT_X, GPIO_PIN_6))\n\t\tres |= BTN_VOL_UP;\n\t// HOAG can use the GPIO. Icosa/Iowa/AULA cannot. Traces are there but they miss a resistor.\n\tif (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFSTAT) & MAX77620_ONOFFSTAT_EN0)\n\t\tres |= BTN_POWER;\n\treturn res;\n}\n\nu8 btn_read_vol()\n{\n\tu8 res = 0;\n\tif (!gpio_read(GPIO_PORT_X, GPIO_PIN_7))\n\t\tres |= BTN_VOL_DOWN;\n\tif (!gpio_read(GPIO_PORT_X, GPIO_PIN_6))\n\t\tres |= BTN_VOL_UP;\n\treturn res;\n}\n\nu8 btn_read_home()\n{\n\treturn (!gpio_read(GPIO_PORT_Y, GPIO_PIN_1)) ? BTN_HOME : 0;\n}\n\nu8 btn_wait()\n{\n\tu8 res = 0, btn = btn_read();\n\tbool pwr = false;\n\n\t//Power button down, raise a filter.\n\tif (btn & BTN_POWER)\n\t{\n\t\tpwr = true;\n\t\tbtn &= ~BTN_POWER;\n\t}\n\n\tdo\n\t{\n\t\tres = btn_read();\n\t\t//Power button up, remove filter.\n\t\tif (!(res & BTN_POWER) && pwr)\n\t\t\tpwr = false;\n\t\telse if (pwr) //Power button still down.\n\t\t\tres &= ~BTN_POWER;\n\t} while (btn == res);\n\n\treturn res;\n}\n\nu8 btn_wait_timeout(u32 time_ms, u8 mask)\n{\n\tu32 timeout = get_tmr_ms() + time_ms;\n\tu8 res = btn_read() & mask;\n\n\twhile (get_tmr_ms() < timeout)\n\t{\n\t\tif (res == mask)\n\t\t\tbreak;\n\t\telse\n\t\t\tres = btn_read() & mask;\n\t};\n\n\treturn res;\n}\n\nu8 btn_wait_timeout_single(u32 time_ms, u8 mask)\n{\n\tu8 single_button = mask & BTN_SINGLE;\n\tmask &= ~BTN_SINGLE;\n\n\tu32 timeout = get_tmr_ms() + time_ms;\n\tu8 res = btn_read();\n\n\twhile (get_tmr_ms() < timeout)\n\t{\n\t\tif ((res & mask) == mask)\n\t\t{\n\t\t\tif (single_button && (res & ~mask)) // Undesired button detected.\n\t\t\t\tres = btn_read();\n\t\t\telse\n\t\t\t\treturn (res & mask);\n\t\t}\n\t\telse\n\t\t\tres = btn_read();\n\t};\n\n\t// Timed out.\n\tif (!single_button || !time_ms)\n\t\treturn (res & mask);\n\telse\n\t\treturn 0; // Return no button press if single button requested.\n}\n"
  },
  {
    "path": "bdk/utils/btn.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2022 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _BTN_H_\n#define _BTN_H_\n\n#include <utils/types.h>\n\n#define BTN_POWER    BIT(0)\n#define BTN_VOL_DOWN BIT(1)\n#define BTN_VOL_UP   BIT(2)\n#define BTN_HOME     BIT(3)\n#define BTN_SINGLE   BIT(7)\n\nu8 btn_read();\nu8 btn_read_vol();\nu8 btn_read_home();\nu8 btn_wait();\nu8 btn_wait_timeout(u32 time_ms, u8 mask);\nu8 btn_wait_timeout_single(u32 time_ms, u8 mask);\n\n#endif\n"
  },
  {
    "path": "bdk/utils/dirlist.c",
    "content": "/*\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n#include <stdlib.h>\n\n#include \"dirlist.h\"\n#include <libs/fatfs/ff.h>\n#include <mem/heap.h>\n#include <utils/types.h>\n\ndirlist_t *dirlist(const char *directory, const char *pattern, u32 flags)\n{\n\tint res = 0;\n\tu32 k = 0;\n\tDIR dir;\n\tFILINFO fno;\n\tbool show_hidden = !!(flags & DIR_SHOW_HIDDEN);\n\tbool show_dirs   = !!(flags & DIR_SHOW_DIRS);\n\tbool ascii_order = !!(flags & DIR_ASCII_ORDER);\n\n\tdirlist_t *dir_entries = (dirlist_t *)malloc(sizeof(dirlist_t));\n\n\t// Setup pointer tree.\n\tfor (u32 i = 0; i < DIR_MAX_ENTRIES; i++)\n\t\tdir_entries->name[i] = &dir_entries->data[i * 256];\n\n\tif (!pattern && !f_opendir(&dir, directory))\n\t{\n\t\tfor (;;)\n\t\t{\n\t\t\tres = f_readdir(&dir, &fno);\n\t\t\tif (res || !fno.fname[0])\n\t\t\t\tbreak;\n\n\t\t\tbool curr_parse = show_dirs ? (fno.fattrib & AM_DIR) : !(fno.fattrib & AM_DIR);\n\n\t\t\tif (curr_parse)\n\t\t\t{\n\t\t\t\tif ((fno.fname[0] != '.') && (show_hidden || !(fno.fattrib & AM_HID)))\n\t\t\t\t{\n\t\t\t\t\tstrcpy(&dir_entries->data[k * 256], fno.fname);\n\t\t\t\t\tif (++k >= DIR_MAX_ENTRIES)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tf_closedir(&dir);\n\t}\n\telse if (pattern && !f_findfirst(&dir, &fno, directory, pattern) && fno.fname[0])\n\t{\n\t\tdo\n\t\t{\n\t\t\tif (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (show_hidden || !(fno.fattrib & AM_HID)))\n\t\t\t{\n\t\t\t\tstrcpy(&dir_entries->data[k * 256], fno.fname);\n\t\t\t\tif (++k >= DIR_MAX_ENTRIES)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tres = f_findnext(&dir, &fno);\n\t\t} while (fno.fname[0] && !res);\n\t\tf_closedir(&dir);\n\t}\n\n\tif (!k)\n\t{\n\t\tfree(dir_entries);\n\n\t\treturn NULL;\n\t}\n\n\t// Terminate name list.\n\tdir_entries->name[k] = NULL;\n\n\t// Choose list ordering.\n\tint (*strcmpex)(const char* str1, const char* str2) = ascii_order ? strcmp : strcasecmp;\n\n\t// Reorder ini files Alphabetically.\n\tfor (u32 i = 0; i < k - 1 ; i++)\n\t{\n\t\tfor (u32 j = i + 1; j < k; j++)\n\t\t{\n\t\t\tif (strcmpex(dir_entries->name[i], dir_entries->name[j]) > 0)\n\t\t\t{\n\t\t\t\tchar *tmp = dir_entries->name[i];\n\t\t\t\tdir_entries->name[i] = dir_entries->name[j];\n\t\t\t\tdir_entries->name[j] = tmp;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn dir_entries;\n}\n"
  },
  {
    "path": "bdk/utils/dirlist.h",
    "content": "/*\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <utils/types.h>\n\n#ifndef _DIRLIST_H_\n#define _DIRLIST_H_\n\n#define DIR_MAX_ENTRIES 64\n\n#define DIR_SHOW_HIDDEN BIT(0)\n#define DIR_SHOW_DIRS   BIT(1)\n#define DIR_ASCII_ORDER BIT(2)\n\ntypedef struct _dirlist_t\n{\n\tchar *name[DIR_MAX_ENTRIES];\n\tchar  data[DIR_MAX_ENTRIES * 256];\n} dirlist_t;\n\ndirlist_t *dirlist(const char *directory, const char *pattern, u32 flags);\n\n#endif\n"
  },
  {
    "path": "bdk/utils/ini.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2024 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include \"ini.h\"\n#include <libs/fatfs/ff.h>\n#include <mem/heap.h>\n#include <utils/dirlist.h>\n#include <utils/util.h>\n\nu32 _find_section_name(char *lbuf, u32 lblen, char schar)\n{\n\tu32 i;\n\t// Depends on 'FF_USE_STRFUNC 2' that removes \\r.\n\tfor (i = 0; i < lblen  && lbuf[i] != schar && lbuf[i] != '\\n'; i++)\n\t\t;\n\tlbuf[i] = 0;\n\n\treturn i;\n}\n\nini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type)\n{\n\tif (csec)\n\t\tlist_append(dst, &csec->link);\n\n\t// Calculate total allocation size.\n\tu32 len = name ? strlen(name) + 1 : 0;\n\tchar *buf = zalloc(sizeof(ini_sec_t) + len);\n\n\tcsec = (ini_sec_t *)buf;\n\tcsec->name = strcpy_ns(buf + sizeof(ini_sec_t), name);\n\tcsec->type = type;\n\n\t// Initialize list.\n\tlist_init(&csec->kvs);\n\n\treturn csec;\n}\n\nint ini_parse(link_t *dst, const char *ini_path, bool is_dir)\n{\n\tFIL fp;\n\tu32 lblen;\n\tu32 k = 0;\n\tu32 pathlen = strlen(ini_path);\n\tini_sec_t *csec = NULL;\n\n\tchar *lbuf     = NULL;\n\tdirlist_t *filelist = NULL;\n\tchar *filename = (char *)malloc(256);\n\n\tstrcpy(filename, ini_path);\n\n\t// Get all ini filenames.\n\tif (is_dir)\n\t{\n\t\tfilelist = dirlist(filename, \"*.ini\", DIR_ASCII_ORDER);\n\t\tif (!filelist)\n\t\t{\n\t\t\tfree(filename);\n\t\t\treturn 1;\n\t\t}\n\t\tstrcpy(filename + pathlen, \"/\");\n\t\tpathlen++;\n\t}\n\n\tdo\n\t{\n\t\t// Copy ini filename in path string.\n\t\tif (is_dir)\n\t\t{\n\t\t\tif (filelist->name[k])\n\t\t\t{\n\t\t\t\tstrcpy(filename + pathlen, filelist->name[k]);\n\t\t\t\tk++;\n\t\t\t}\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\n\t\t// Open ini.\n\t\tif (f_open(&fp, filename, FA_READ) != FR_OK)\n\t\t{\n\t\t\tfree(filelist);\n\t\t\tfree(filename);\n\n\t\t\treturn 1;\n\t\t}\n\n\t\tlbuf = malloc(512);\n\n\t\tdo\n\t\t{\n\t\t\t// Fetch one line.\n\t\t\tlbuf[0] = 0;\n\t\t\tf_gets(lbuf, 512, &fp);\n\t\t\tlblen = strlen(lbuf);\n\n\t\t\t// Remove trailing newline. Depends on 'FF_USE_STRFUNC 2' that removes \\r.\n\t\t\tif (lblen && lbuf[lblen - 1] == '\\n')\n\t\t\t\tlbuf[lblen - 1] = 0;\n\n\t\t\tif (lblen > 2 && lbuf[0] == '[') // Create new section.\n\t\t\t{\n\t\t\t\t_find_section_name(lbuf, lblen, ']');\n\n\t\t\t\tcsec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE);\n\t\t\t}\n\t\t\telse if (lblen > 1 && lbuf[0] == '{') // Create new caption. Support empty caption '{}'.\n\t\t\t{\n\t\t\t\t_find_section_name(lbuf, lblen, '}');\n\n\t\t\t\tcsec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION);\n\t\t\t\tcsec->color = 0xFF0AB9E6;\n\t\t\t}\n\t\t\telse if (lblen > 2 && lbuf[0] == '#') // Create comment.\n\t\t\t{\n\t\t\t\tcsec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT);\n\t\t\t}\n\t\t\telse if (lblen < 2) // Create empty line.\n\t\t\t{\n\t\t\t\tcsec = _ini_create_section(dst, csec, NULL, INI_NEWLINE);\n\t\t\t}\n\t\t\telse if (csec && csec->type == INI_CHOICE) // Extract key/value.\n\t\t\t{\n\t\t\t\tu32 i = _find_section_name(lbuf, lblen, '=');\n\n\t\t\t\t// Calculate total allocation size.\n\t\t\t\tu32 klen  = strlen(&lbuf[0]) + 1;\n\t\t\t\tu32 vlen  = strlen(&lbuf[i + 1]) + 1;\n\t\t\t\tchar *buf = zalloc(sizeof(ini_kv_t) + klen + vlen);\n\n\t\t\t\tini_kv_t *kv = (ini_kv_t *)buf;\n\t\t\t\tbuf += sizeof(ini_kv_t);\n\t\t\t\tkv->key = strcpy_ns(buf, &lbuf[0]);\n\t\t\t\tbuf += klen;\n\t\t\t\tkv->val = strcpy_ns(buf, &lbuf[i + 1]);\n\t\t\t\tlist_append(&csec->kvs, &kv->link);\n\t\t\t}\n\t\t} while (!f_eof(&fp));\n\n\t\tfree(lbuf);\n\n\t\tf_close(&fp);\n\n\t\tif (csec)\n\t\t{\n\t\t\tlist_append(dst, &csec->link);\n\t\t\tif (is_dir)\n\t\t\t\tcsec = NULL;\n\t\t}\n\t} while (is_dir);\n\n\tfree(filename);\n\tfree(filelist);\n\n\treturn 0;\n}\n\nchar *ini_check_special_section(ini_sec_t *cfg)\n{\n\tif (cfg == NULL)\n\t\treturn NULL;\n\n\tLIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)\n\t{\n\t\tif (!strcmp(\"l4t\",          kv->key))\n\t\t\treturn ((kv->val[0] == '1') ? (char *)-1 : NULL);\n\t\telse if (!strcmp(\"payload\", kv->key))\n\t\t\treturn kv->val;\n\t}\n\n\treturn NULL;\n}\n\nvoid ini_free(link_t *src)\n{\n\tini_sec_t *prev_sec = NULL;\n\n\t// Parse and free all ini sections.\n\tLIST_FOREACH_ENTRY(ini_sec_t, ini_sec, src, link)\n\t{\n\t\tini_kv_t *prev_kv  = NULL;\n\n\t\t// Free all ini key allocations if they exist.\n\t\tLIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)\n\t\t{\n\t\t\t// Free previous key.\n\t\t\tif (prev_kv)\n\t\t\t\tfree(prev_kv);\n\n\t\t\t// Set next key to free.\n\t\t\tprev_kv = kv;\n\t\t}\n\n\t\t// Free last key.\n\t\tif (prev_kv)\n\t\t\tfree(prev_kv);\n\n\t\t// Free previous section.\n\t\tif (prev_sec)\n\t\t\tfree(prev_sec);\n\n\t\t// Set next section to free.\n\t\tprev_sec = ini_sec;\n\t}\n\n\t// Free last section.\n\tif (prev_sec)\n\t\tfree(prev_sec);\n}\n"
  },
  {
    "path": "bdk/utils/ini.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _INI_H_\n#define _INI_H_\n\n#include <utils/types.h>\n#include <utils/list.h>\n\n#define INI_CHOICE  3\n#define INI_CAPTION 5\n#define INI_CHGLINE 6\n#define INI_NEWLINE 0xFE\n#define INI_COMMENT 0xFF\n\ntypedef struct _ini_kv_t\n{\n\tchar *key;\n\tchar *val;\n\tlink_t link;\n} ini_kv_t;\n\ntypedef struct _ini_sec_t\n{\n\tchar *name;\n\tlink_t kvs;\n\tlink_t link;\n\tu32 type;\n\tu32 color;\n} ini_sec_t;\n\nint   ini_parse(link_t *dst, const char *ini_path, bool is_dir);\nchar *ini_check_special_section(ini_sec_t *cfg);\nvoid  ini_free(link_t *src);\n\n#endif\n\n"
  },
  {
    "path": "bdk/utils/list.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2020 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _LIST_H_\n#define _LIST_H_\n\n#include <utils/types.h>\n\n/*! Initialize list. */\n#define LIST_INIT(name) link_t name = {&name, &name}\n\n/*! Initialize static list. */\n#define LIST_INIT_STATIC(name) static link_t name = {&name, &name}\n\n/*! Iterate over all list links. */\n#define LIST_FOREACH(iter, list) \\\n\tfor (link_t *iter = (list)->next; iter != (list); iter = iter->next)\n\n/*! Iterate over all list links backwards. */\n#define LIST_FOREACH_INVERSE(iter, list) \\\n\tfor (link_t *iter = (list)->prev; iter != (list); iter = iter->prev)\n\n/*! Safely iterate over all list links. */\n#define LIST_FOREACH_SAFE(iter, list) \\\n\tfor (link_t *iter = (list)->next, *safe = iter->next; iter != (list); iter = safe, safe = iter->next)\n\n/*! Iterate over all list members and make sure that the list has at least one entry. */\n#define LIST_FOREACH_ENTRY(etype, iter, list, mn) \\\n\tif ((list)->next != (list)) \\\n\t\tfor (etype *iter = CONTAINER_OF((list)->next, etype, mn); &iter->mn != (list); iter = CONTAINER_OF(iter->mn.next, etype, mn))\n\n/* Iterate over all list members backwards and make sure that the list has at least one entry. */\n#define LIST_FOREACH_ENTRY_INVERSE(type, iter, list, mn) \\\n\tif ((list)->prev != (list)) \\\n\t\tfor (type *iter = CONTAINER_OF((list)->prev, type, mn); &iter->mn != (list); iter = CONTAINER_OF(iter->mn.prev, type, mn))\n\ntypedef struct _link_t\n{\n\tstruct _link_t *prev;\n\tstruct _link_t *next;\n} link_t;\n\nstatic inline void link_init(link_t *l)\n{\n\tl->prev = NULL;\n\tl->next = NULL;\n}\n\nstatic inline int link_used(link_t *l)\n{\n\tif (l->next == NULL)\n\t\treturn 1;\n\treturn 0;\n}\n\nstatic inline void list_init(link_t *lh)\n{\n\tlh->prev = lh;\n\tlh->next = lh;\n}\n\nstatic inline void list_prepend(link_t *lh, link_t *l)\n{\n\tl->next = lh->next;\n\tl->prev = lh;\n\tlh->next->prev = l;\n\tlh->next = l;\n}\n\nstatic inline void list_append(link_t *lh, link_t *l)\n{\n\tl->prev = lh->prev;\n\tl->next = lh;\n\tlh->prev->next = l;\n\tlh->prev = l;\n}\n\nstatic inline void list_remove(link_t *l)\n{\n\tl->next->prev = l->prev;\n\tl->prev->next = l->next;\n\tlink_init(l);\n}\n\nstatic inline int list_empty(link_t *lh)\n{\n\tif (lh->next == lh)\n\t\treturn 1;\n\treturn 0;\n}\n\n#endif\n"
  },
  {
    "path": "bdk/utils/sprintf.c",
    "content": "/*\n* Copyright (c) 2018 naehrwert\n* Copyright (c) 2019-2024 CTCaer\n*\n* This program is free software; you can redistribute it and/or modify it\n* under the terms and conditions of the GNU General Public License,\n* version 2, as published by the Free Software Foundation.\n*\n* This program is distributed in the hope it will be useful, but WITHOUT\n* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n* more details.\n*\n* You should have received a copy of the GNU General Public License\n* along with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n#include <stdarg.h>\n#include <string.h>\n\n#include <utils/types.h>\n\nchar **sout_buf;\n\nstatic void _s_putc(char c)\n{\n\t**sout_buf = c;\n\t*sout_buf += 1;\n}\n\nstatic void _s_putspace(int fcnt)\n{\n\tif (fcnt <= 0)\n\t\treturn;\n\n\tfor (int i = 0; i < fcnt; i++)\n\t\t_s_putc(' ');\n}\n\nstatic void _s_puts(char *s, char fill, int fcnt)\n{\n\tif (fcnt)\n\t{\n\t\tfcnt = fcnt - strlen(s);\n\n\t\t// Left padding. Check if padding is not space based (dot counts as such).\n\t\tif (fill != '.')\n\t\t\t_s_putspace(fcnt);\n\t}\n\n\tfor (; *s; s++)\n\t\t_s_putc(*s);\n\n\t// Right padding. Check if padding is space based (dot counts as such).\n\tif (fill == '.')\n\t\t_s_putspace(fcnt);\n}\n\nstatic void _s_putn(u32 v, int base, char fill, int fcnt)\n{\n\tstatic const char digits[] = \"0123456789ABCDEF\";\n\n\tchar *p;\n\tchar buf[65]; // Number char size + leftover for padding.\n\tint c = fcnt;\n\tbool negative = false;\n\n\tif (base != 10 && base != 16)\n\t\treturn;\n\n\t// Account for negative numbers.\n\tif (base == 10 && v & 0x80000000)\n\t{\n\t\tnegative = true;\n\t\tv = (int)v * -1;\n\t\tc--;\n\t}\n\n\tp = buf + 64;\n\t*p = 0;\n\tdo\n\t{\n\t\tc--;\n\t\t*--p = digits[v % base];\n\t\tv /= base;\n\t} while (v);\n\n\tif (negative)\n\t\t*--p = '-';\n\n\tif (fill != 0)\n\t{\n\t\twhile (c > 0 && p > buf)\n\t\t{\n\t\t\t*--p = fill;\n\t\t\tc--;\n\t\t}\n\t}\n\n\t_s_puts(p, 0, 0);\n}\n\n/*\n * Padding:\n *  Numbers:\n *   %3d:   Fill: ' ', Count: 3.\n *   % 3d:  Fill: ' ', Count: 3.\n *   %.3d:  Fill: '.', Count: 3.\n *   %23d:  Fill: '2', Count: 3.\n *   % 23d: Fill: ' ', Count: 23.\n *   %223d: Fill: '2', Count: 23.\n *\n * Strings, Fill: ' ':\n *  %3s:    Count: 5,   Left.\n *  %23s:   Count: 5,   Left.\n *  %223s:  Count: 25,  Left.\n *  %.3s:   Count: 5,   Right.\n *  %.23s:  Count: 25,  Right.\n *  %.223s: Count: 225, Right.\n */\n\nvoid s_printf(char *out_buf, const char *fmt, ...)\n{\n\tva_list ap;\n\tint fill, fcnt;\n\n\tsout_buf = &out_buf;\n\n\tva_start(ap, fmt);\n\twhile (*fmt)\n\t{\n\t\tif (*fmt == '%')\n\t\t{\n\t\t\tfmt++;\n\t\t\tfill = 0;\n\t\t\tfcnt = 0;\n\n\t\t\t// Check for padding. Number or space based (dot count as space for string).\n\t\t\tif ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ' || *fmt == '.')\n\t\t\t{\n\t\t\t\tfcnt = *fmt; // Padding size or padding type.\n\t\t\t\tfmt++;\n\n\t\t\t\tif (*fmt >= '0' && *fmt <= '9')\n\t\t\t\t{\n\t\t\t\t\t// Padding size exists. Previous char was type.\n\t\t\t\t\tfill = fcnt;\n\t\t\t\t\tfcnt = *fmt - '0';\n\t\t\t\t\tfmt++;\nparse_padding_dec:\n\t\t\t\t\t// Parse padding size extra digits.\n\t\t\t\t\tif (*fmt >= '0' && *fmt <= '9')\n\t\t\t\t\t{\n\t\t\t\t\t\tfcnt = fcnt * 10 + *fmt - '0';\n\t\t\t\t\t\tfmt++;\n\t\t\t\t\t\tgoto parse_padding_dec;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// No padding type, use space. (Max padding size is 9).\n\t\t\t\t\tfill = ' ';\n\t\t\t\t\tfcnt -= '0';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tswitch (*fmt)\n\t\t\t{\n\t\t\tcase 'c':\n\t\t\t\tchar c = va_arg(ap, u32);\n\t\t\t\tif (c != '\\0')\n\t\t\t\t\t_s_putc(c);\n\t\t\t\tbreak;\n\n\t\t\tcase 'd':\n\t\t\t\t_s_putn(va_arg(ap, u32), 10, fill, fcnt);\n\t\t\t\tbreak;\n\n\t\t\tcase 's':\n\t\t\t\t_s_puts(va_arg(ap, char *), fill, fcnt);\n\t\t\t\tbreak;\n\n\t\t\tcase 'p':\n\t\t\tcase 'P':\n\t\t\tcase 'x':\n\t\t\tcase 'X':\n\t\t\t\t_s_putn(va_arg(ap, u32), 16, fill, fcnt);\n\t\t\t\tbreak;\n\n\t\t\tcase '%':\n\t\t\t\t_s_putc('%');\n\t\t\t\tbreak;\n\n\t\t\tcase '\\0':\n\t\t\t\tgoto out;\n\n\t\t\tdefault:\n\t\t\t\t_s_putc('%');\n\t\t\t\t_s_putc(*fmt);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\t_s_putc(*fmt);\n\t\tfmt++;\n\t}\n\nout:\n\t**sout_buf = '\\0';\n\tva_end(ap);\n}\n\nvoid s_vprintf(char *out_buf, const char *fmt, va_list ap)\n{\n\tint fill, fcnt;\n\n\tsout_buf = &out_buf;\n\n\twhile (*fmt)\n\t{\n\t\tif (*fmt == '%')\n\t\t{\n\t\t\tfmt++;\n\t\t\tfill = 0;\n\t\t\tfcnt = 0;\n\n\t\t\t// Check for padding. Number or space based.\n\t\t\tif ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ')\n\t\t\t{\n\t\t\t\tfcnt = *fmt; // Padding size or padding type.\n\t\t\t\tfmt++;\n\n\t\t\t\tif (*fmt >= '0' && *fmt <= '9')\n\t\t\t\t{\n\t\t\t\t\t// Padding size exists. Previous char was type.\n\t\t\t\t\tfill = fcnt;\n\t\t\t\t\tfcnt = *fmt - '0';\n\t\t\t\t\tfmt++;\nparse_padding_dec:\n\t\t\t\t\t// Parse padding size extra digits.\n\t\t\t\t\tif (*fmt >= '0' && *fmt <= '9')\n\t\t\t\t\t{\n\t\t\t\t\t\tfcnt = fcnt * 10 + *fmt - '0';\n\t\t\t\t\t\tfmt++;\n\t\t\t\t\t\tgoto parse_padding_dec;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// No padding type, use space. (Max padding size is 9).\n\t\t\t\t\tfill = ' ';\n\t\t\t\t\tfcnt -= '0';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tswitch (*fmt)\n\t\t\t{\n\t\t\tcase 'c':\n\t\t\t\tchar c = va_arg(ap, u32);\n\t\t\t\tif (c != '\\0')\n\t\t\t\t\t_s_putc(c);\n\t\t\t\tbreak;\n\n\t\t\tcase 'd':\n\t\t\t\t_s_putn(va_arg(ap, u32), 10, fill, fcnt);\n\t\t\t\tbreak;\n\n\t\t\tcase 's':\n\t\t\t\t_s_puts(va_arg(ap, char *), fill, fcnt);\n\t\t\t\tbreak;\n\n\t\t\tcase 'p':\n\t\t\tcase 'P':\n\t\t\tcase 'x':\n\t\t\tcase 'X':\n\t\t\t\t_s_putn(va_arg(ap, u32), 16, fill, fcnt);\n\t\t\t\tbreak;\n\n\t\t\tcase '%':\n\t\t\t\t_s_putc('%');\n\t\t\t\tbreak;\n\n\t\t\tcase '\\0':\n\t\t\t\tgoto out;\n\n\t\t\tdefault:\n\t\t\t\t_s_putc('%');\n\t\t\t\t_s_putc(*fmt);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\t_s_putc(*fmt);\n\t\tfmt++;\n\t}\n\nout:\n\t**sout_buf = '\\0';\n}\n"
  },
  {
    "path": "bdk/utils/sprintf.h",
    "content": "/*\n* Copyright (c) 2019 CTCaer\n*\n* This program is free software; you can redistribute it and/or modify it\n* under the terms and conditions of the GNU General Public License,\n* version 2, as published by the Free Software Foundation.\n*\n* This program is distributed in the hope it will be useful, but WITHOUT\n* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n* more details.\n*\n* You should have received a copy of the GNU General Public License\n* along with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n#ifndef _SPRINTF_H_\n#define _SPRINTF_H_\n\n#include <stdarg.h>\n\n#include <utils/types.h>\n\n/*\n * Padding:\n *  Numbers:\n *   %3d:   Fill: ' ', Count: 3.\n *   % 3d:  Fill: ' ', Count: 3.\n *   %23d:  Fill: '2', Count: 3.\n *   % 23d: Fill: ' ', Count: 23.\n *   %223d: Fill: '2', Count: 23.\n *\n * Strings, Fill: ' ':\n *  %3s:    Count: 5,   Left.\n *  %23s:   Count: 5,   Left.\n *  %223s:  Count: 25,  Left.\n *  %.3s:   Count: 5,   Right.\n *  %.23s:  Count: 25,  Right.\n *  %.223s: Count: 225, Right.\n */\n\nvoid s_printf(char *out_buf, const char *fmt, ...) __attribute__((format(printf, 2, 3)));\nvoid s_vprintf(char *out_buf, const char *fmt, va_list ap);\n\n#endif\n"
  },
  {
    "path": "bdk/utils/tegra_bct.h",
    "content": "/*\n * Copyright (c) 2018-2022 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef TEGRA_BCT_H\n#define TEGRA_BCT_H\n\n#include <utils/types.h>\n\n#include <mem/sdram_param_t210.h>\n#include <mem/sdram_param_t210b01.h>\n\n#define BCT_IRAM_ADDRESS     0x40000100\n#define BCT_IRAM_ADDRESS_B01 0x40000464\n\n#define BCT_BOOT_DEV_NONE  0\n#define BCT_BOOT_DEV_SPI   3\n#define BCT_BOOT_DEV_SDMMC 4\n#define BCT_BOOT_DEV_USB3  9\n#define BCT_BOOT_DEV_UART  11\n\n// ECID is checked for the following.\n#define BCT_SEC_DBG_JTAG  BIT(0)\n#define BCT_SEC_DBG_DEV   BIT(1)\n#define BCT_SEC_DBG_SPNID BIT(2)\n#define BCT_SEC_DBG_SPID  BIT(3)\n#define BCT_SEC_DBG_NID   BIT(4) // ECID not checked for T210B01.\n#define BCT_SEC_DBG_DBG   BIT(5) // ECID not checked for T210B01.\n\n#define BCT_SDMMC_CFG_SDR25_SINGLE_PAGE 0\n#define BCT_SDMMC_CFG_SDR52_MULTI_PAGE  1\n#define BCT_SDMMC_CFG_SDR25_MULTI_PAGE  2\n#define BCT_SDMMC_CFG_DDR52_MULTI_PAGE  3\n#define BCT_SDMMC_CFG_DDR25_MULTI_PAGE  4\n\n#define BCT_SPI_CFG_PIO_X1_20_4MHZ_SREAD 0\n#define BCT_SPI_CFG_PIO_X1_19_2MHZ_SREAD 1\n#define BCT_SPI_CFG_PIO_X4_51_0MHZ_QREAD 2\n\ntypedef struct _bct_bad_blocks_t\n{\n\tu32 used_entries;     // For block table.\n\tu8  virtual_block_size_log2;\n\tu8  block_size_log2;\n\tu8  block_table[512]; // Each bit is a block (4096 blocks).\n\n\tu8  padding[10];\n} bct_bad_blocks_t;\n\ntypedef struct _bct_sdmmc_dev_t210_t\n{\n\tu32 clk_div;\n\tu32 bus_width;\n\tu8  power_class_max;\n\tu8  multi_block_max;\n} bct_sdmmc_dev_t210_t;\n\ntypedef struct _bct_sdmmc_dev_t210b01_t\n{\n\tu8 sdmmc_config;\n\tu8 power_class_max;\n} bct_sdmmc_dev_t210b01_t;\n\ntypedef struct _bct_spi_dev_t210_t\n{\n\tu32 clk_src;\n\tu8  clk_div;\n\tu8  cmd_read_fast;\n\tu8  page_size; // 0: 2KB, 1: 16KB.\n} bct_spi_dev_t210_t;\n\ntypedef struct _bct_spi_dev_t210b01_t\n{\n\tu8 spi_config;\n} bct_spi_dev_t210b01_t;\n\ntypedef struct _bct_usb3_dev_t\n{\n\tu8 clk_div;\n\tu8 root_port;\n\tu8 page_size; // 0: 2KB, 1: 16KB.\n\tu8 oc_pin;\n\tu8 vbus_en;\n} bct_usb3_dev_t;\n\ntypedef union\n{\n\tbct_sdmmc_dev_t210_t sdmmc_params;\n\tbct_spi_dev_t210_t   spi_params;\n\tbct_usb3_dev_t  usb3_params;\n\n\tu8 padding[64];\n} bct_boot_dev_t210_t;\n\ntypedef union\n{\n\tbct_sdmmc_dev_t210b01_t sdmmc_params;\n\tbct_spi_dev_t210b01_t   spi_params;\n\n\tu8 padding[64];\n} bct_boot_dev_t210b01_t;\n\ntypedef struct _bct_bootloader_t210_t\n{\n\tu32 version;\n\tu32 start_block;\n\tu32 start_page;\n\n\tu32 length;     // Should be bl size + 16 and aligned to 16.\n\tu32 load_addr;\n\tu32 entrypoint;\n\tu32 attributes; // ODM.\n\n\tu8  aes_cmac_hash[16];\n\tu8  rsa_pss_signature[256];\n} bct_bootloader_t210_t;\n\ntypedef struct _bct_bootloader_t210b01_t\n{\n\tu32 start_block;\n\tu32 start_page;\n\tu32 version;\n\tu32 padding;\n} bct_bootloader_t210b01_t;\n\ntypedef struct _tegra_bct_t210_t\n{\n\t/* Unsigned section */\n\tbct_bad_blocks_t bad_block_table;\n\n\tu8  rsa_modulus[256];\n\tu8  aes_cmac_hash[16];\n\tu8  rsa_pss_signature[256];\n\n\tu32 secprov_aes_key_num_insecure;\n\tu8  secprov_aes_key[32];\n\n\tu8  customer_data[204];\n\n\t/* Signed section */\n\tu8 random_aes_block[16];\n\n\tu32 ecid[4];\n\n\tu32 data_version; // 0x210001.\n\n\tu32 block_size_log2;\n\tu32 page_size_log2;\n\tu32 partition_size;\n\n\tu32 boot_dev_params_num;\n\tu32 boot_dev_type;\n\tbct_boot_dev_t210_t boot_dev_params;\n\n\tu32 dram_params_num;\n\tsdram_params_t210_t dram_params[4];\n\n\tu32 bootloader_num;\n\tbct_bootloader_t210_t bootLoader[4];\n\tu32 bootloader_failback_en;\n\n\tu32 sec_dbg_ctrl; // Copied to APBDEV_PMC_DEBUG_AUTHENTICATION. ECID checked.\n\n\tu32 secprov_aes_key_num_secure;\n\n\tu8  padding[20];\n} tegra_bct_t210_t;\n\ntypedef struct _tegra_bct_t210b01_t\n{\n\t/* Unsigned section */\n\tu32 rsa_key_size;\n\tu32 padding0[3];\n\tu8  rsa_modulus[256];\n\tu8  rsa_exponent[256];\n\n\tu8  aes_cmac_hash[16];\n\tu8  rsa_pss_signature[256];\n\n\tu8  secprov_aes_key[32];\n\tu32 secprov_aes_key_num_insecure;\n\n\tu8  padding_unsigned[12];\n\n\tu8  customer_data0[208];\n\n\t/* Signed section */\n\tu8  random_aes_block0[16];\n\n\tu32 boot_config0[4]; // Customer controlled features.\n\n\t/// Unused space allocated for customer usage.\n\tu32 customer_data1_signed[16];\n\n\t/* Encrypted section (optionally) */\n\tu8  random_aes_block1[16];\n\n\tu32 ecid[4];\n\n\tu32 data_version; // 0x210001.\n\n\tu32 block_size_log2;\n\tu32 page_size_log2;\n\tu32 partition_size;\n\n\tu32 boot_dev_params_num;\n\tu32 boot_dev_type;\n\tbct_boot_dev_t210b01_t boot_dev_params;\n\n\tu32 dram_params_num;\n\tsdram_params_t210b01_t dram_params[4];\n\n\tu32 bootloader_num;\n\tbct_bootloader_t210b01_t bootLoader[4];\n\n\tu32 sec_dbg_ctrl;      // Copied to APBDEV_PMC_DEBUG_AUTHENTICATION. ECID not checked.\n\tu32 sec_dbg_ctrl_ecid; // Copied to APBDEV_PMC_DEBUG_AUTHENTICATION. ECID checked.\n\n\tu32 boot_config1[4];   // Customer controlled features. bit0 AON TZRAM powergating enable\n\n\tu32 customer_data2_signed[16]; // u32[0]: bl attributes.\n\n\tu32 secprov_aes_key_num_secure;\n\n\tu8 padding_signed[388];\n} tegra_bct_t210b01_t;\n\ntypedef struct _bootLoader_hdr_t210b01_t\n{\n\t/* Unsigned section */\n\tu8  aes_cmac_hash[16];\n\tu8  rsa_pss_signature[256];\n\n\t/* Signed section */\n\tu8  salt[16]; // random_aes_block.\n\tu8  bootLoader_sha256[16];\n\tu32 version;\n\tu32 length;\n\tu32 load_addr;\n\tu32 entrypoint;\n\tu8  padding[16];\n} bootLoader_hdr_t210b01_t;\n\n#endif\n"
  },
  {
    "path": "bdk/utils/tegra_bit.h",
    "content": "/*\n * Copyright (c) 2018-2022 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef TEGRA_BIT_H\n#define TEGRA_BIT_H\n\n#include <utils/types.h>\n\n#define BIT_ADDRESS 0x40000000\n\n#define BIT_BOOT_TYPE_NONE     0\n#define BIT_BOOT_TYPE_COLD     1\n#define BIT_BOOT_TYPE_RCM      2\n#define BIT_BOOT_TYPE_UART     3\n#define BIT_BOOT_TYPE_EXIT_RCM 4\n\n#define BIT_READ_STATUS_NONE             0\n#define BIT_READ_STATUS_SUCCESS          1\n#define BIT_READ_STATUS_VALIDATION_ERROR 2\n#define BIT_READ_STATUS_HW_READ_ERROR    3\n\n#define BIT_USB_CHARGE_DETECT_EN  BIT(0)\n#define BIT_USB_CHARGE_LOW_BATT   BIT(1)\n#define BIT_USB_CHARGE_CONNECTED  BIT(2)\n#define BIT_USB_CHARGE_HI_CURRENT BIT(8)\n\n// From T186 with some additions.\nenum\n{\n\tBIT_FLOW_STATUS_NONE                       = 0,\n\tBIT_FLOW_STATUS_IPATCHUNCORRECTED_ERROR    = 1,\n\tBIT_FLOW_STATUS_IPATCHSUCCESS              = 2,\n\tBIT_FLOW_STATUS_SETUPOSCCLK                = 3,\n\tBIT_FLOW_STATUS_LOWBAT_NOTCHARGED          = 4,\n\tBIT_FLOW_STATUS_LOWBAT_CHARGED             = 5,\n\tBIT_FLOW_STATUS_PLLPENABLED                = 6,\n\tBIT_FLOW_STATUS_MSSINITIALIZED             = 7,\n\tBIT_FLOW_STATUS_FABRICINITIALIZED          = 8,\n\tBIT_FLOW_STATUS_NONSECUREDISPATCHERENTRY   = 9,\n\tBIT_FLOW_STATUS_NONSECUREDISPATCHEREXIT    = 10,\n\tBIT_FLOW_STATUS_FAMODE                     = 11,\n\tBIT_FLOW_STATUS_PREPRODUCTIONMODEUART      = 12,\n\tBIT_FLOW_STATUS_PRODUCTIONMODE             = 13,\n\tBIT_FLOW_STATUS_ODMPRODUCTIONMODE          = 14,\n\tBIT_FLOW_STATUS_DBGRCMMODE                 = 15,\n\tBIT_FLOW_STATUS_RECOVERYMODE               = 16,\n\tBIT_FLOW_STATUS_SECUREDISPATCHERENTRY      = 17,\n\tBIT_FLOW_STATUS_SECUREDISPATCHEREXIT       = 18,\n\tBIT_FLOW_STATUS_RAMDUMPINIT                = 19,\n\tBIT_FLOW_STATUS_RAMDUMPEXIT                = 20,\n\tBIT_FLOW_STATUS_COLDBOOTENTRY              = 21,\n\tBIT_FLOW_STATUS_COLDBOOTEXIT               = 22,\n\tBIT_FLOW_STATUS_CBSETUPBOOTDEVICE          = 23,\n\tBIT_FLOW_STATUS_CBBCTDONE                  = 24,\n\tBIT_FLOW_STATUS_MSSREGIONUNINITIALIZED     = 25,\n\tBIT_FLOW_STATUS_MSSREGIONENABLEINITIALIZED = 26,\n\tBIT_FLOW_STATUS_CBMTSPREBOOTINIT           = 27,\n\tBIT_FLOW_STATUS_CBREINITSUCCESS            = 28,\n\tBIT_FLOW_STATUS_CBSDRAMINITSUCCESS         = 29,\n\tBIT_FLOW_STATUS_CBPAYLOADSUCCESS           = 30,\n\tBIT_FLOW_STATUS_RCMENTRY                   = 31,\n\tBIT_FLOW_STATUS_RCMEXIT                    = 32,\n\tBIT_FLOW_STATUS_SC7ENTRY                   = 33,\n\tBIT_FLOW_STATUS_SC7ACKWAYPOINT             = 34,\n\tBIT_FLOW_STATUS_SC7DBELLERROR              = 35,\n\tBIT_FLOW_STATUS_SC7EXIT                    = 36,\n\tBIT_FLOW_STATUS_SECUREBOOTENTRY            = 37,\n\tBIT_FLOW_STATUS_SECUREBOOTEXIT             = 38,\n\tBIT_FLOW_STATUS_DETECTEDWDTRESET           = 39,\n\tBIT_FLOW_STATUS_DETECTEDAOTAG_SENSORRESET  = 40,\n\tBIT_FLOW_STATUS_DETECTEDVFSENSORRESET      = 41,\n\tBIT_FLOW_STATUS_DETECTEDSWMAINRESET        = 42,\n\tBIT_FLOW_STATUS_DETECTEDHSMRESET           = 43,\n\tBIT_FLOW_STATUS_DETECTEDCSITEDBGRESET      = 44,\n\tBIT_FLOW_STATUS_DETECTEDSC7SPEWDT_0_RESET  = 45,\n\tBIT_FLOW_STATUS_DETECTEDSC7SPEWDT_1_RESET  = 46,\n\tBIT_FLOW_STATUS_DETECTEDSYSRESETN          = 47,\n\tBIT_FLOW_STATUS_CRYPTOINITENTRY            = 48,\n\tBIT_FLOW_STATUS_CRYPTOINITEXIT             = 49,\n\tBIT_FLOW_STATUS_SECUREEXITSTART            = 50\n};\n\ntypedef struct _bit_flow_log_t\n{\n\tu32\tInit_time;\n\tu32\texit_time;\n\tu32\tfunc_id;\n\tu32\tfunc_status;\n} bit_flow_log_t;\n\ntypedef struct _bit_boot_sdmmc_status_t210_t\n{\n\tu8  fuses_bus_width;\n\tu8  fuses_voltage_range;\n\tu8  fuses_boo_mode_disable;\n\tu8  fuses_drd_mode;\n\n\tu32 card_type;\n\tu32 voltage_range;\n\tu8  bus_width;\n\tu8  power_class;\n\tu8  auto_cal_status;\n\tu8  padding;\n\tu32 cid[4];\n\n\tu32 pages_read;\n\tu32 crc_errors;\n\tu8  boot_from_boot_partition;\n\tu8  boot_mode_read_success;\n} bit_boot_sdmmc_status_t210_t;\n\ntypedef struct _bit_boot_sdmmc_status_t210b01_t\n{\n\tu8 clk_src;\n\tu8 clk_div;\n\tu8 clk_en;\n\tu8 clk_rst_status;\n\tu8 clk_div_internal;\n\tu8 data_mode;\n\n\tu8 fuses_bus_width;\n\tu8 fuses_drd_mode;\n\tu8 fuses_config;\n\tu8 fuses_read_mode;\n\n\tu8  card_type;\n\tu32 voltage_range;\n\tu8  bus_width;\n\tu8  power_class;\n\tu8  auto_cal_status;\n\tu32 cid[4];\n\n\tu32 pages_read;\n\tu32 crc_errors;\n\tu8 boot_from_boot_partition;\n\n\tu32 time_init;\n\tu32 time_controller_init;\n\tu32 time_card_enumeration;\n\tu32 time_cmd1_op_cond;\n\tu32 time_cmd2_cid;\n\tu32 time_cmd9_csd;\n\tu32 time_transfer_mode;\n\tu32 time_cmd8_ext_csd;\n\tu32 time_power_class;\n\tu32 time_bus_width_and_partition;\n\tu32 time_read;\n\n\tu32 payload_size;\n} bit_boot_sdmmc_status_t210b01_t;\n\ntypedef struct _bit_boot_spi_status_t210_t\n{\n\tu32 clk_src;\n\tu32 clk_div;\n\tu32 fast_read;\n\n\tu32 pages_read;\n\tu32 last_block_read;\n\tu32 last_page_read;\n\n\tu32 boot_status;\n\tu32 init_status;\n\tu32 read_status;\n\tu32 params_validated;\n} bit_boot_spi_status_t210_t;\n\ntypedef struct _bit_boot_spi_status_t210b01_t\n{\n\tu32 clk_en;\n\tu32 clk_rst_status;\n\tu32 mode;\n\tu32 bus_width;\n\tu32 clk_src;\n\tu32 clk_div;\n\tu32 fast_read;\n\n\tu32 pages_read;\n\tu32 last_block_read;\n\tu32 last_page_read;\n\n\tu32 boot_status;\n\tu32 init_status;\n\tu32 read_status;\n\tu32 params_validated;\n\n\tu32 time_qspi_init;\n\tu32 time_read_time;\n\n\tu32 payload_size;\n} bit_boot_spi_status_t210b01_t;\n\ntypedef struct _bit_boot_usb3_status_t\n{\n\tu8  port;\n\tu8  sense_key;\n\tu8  padding[2];\n\tu32 cur_csw_tag;\n\tu32 curr_cmd_csw_status;\n\tu32 curr_ep_xfer_failed_bytes;\n\tu32 periph_dev_type;\n\tu32 block_num;\n\tu32 last_logical_block_addr;\n\tu32 block_length;\n\tu32 usb3_ctxt;\n\tu32 init_res;\n\tu32 read_page_res;\n\tu32 xusb_driver_status;\n\tu32 dev_status;\n\tu32 ep_status;\n} bit_boot_usb3_status_t;\n\ntypedef union _bit_boot_secondary_dev_status_t210_t\n{\n\tbit_boot_sdmmc_status_t210_t sdmmc_status;\n\tbit_boot_spi_status_t210_t   spi_status;\n\tbit_boot_usb3_status_t       usb3_status;\n\n\tu8 padding[60];\n} bit_boot_secondary_dev_status_t210_t;\n\ntypedef union _bit_boot_secondary_dev_status_t210b01_t\n{\n\tbit_boot_sdmmc_status_t210b01_t sdmmc_status;\n\tbit_boot_spi_status_t210b01_t   spi_status;\n\n\tu8 padding[256];\n} bit_boot_secondary_dev_status_t210b01_t;\n\ntypedef struct _bit_bl_state_t\n{\n\tu32 read_status;\n\n\tu32 first_ecc_block;\n\tu32 first_ecc_page;\n\tu32 first_corrected_ecc_block;\n\tu32 first_corrected_ecc_page;\n\tu8  had_ecc_error;\n\tu8  had_crc_error;\n\tu8  had_corrected_ecc_error;\n\tu8  used_for_ecc_recovery;\n} bit_bl_state_t;\n\ntypedef struct _tegra_bit_t210_t\n{\n\tu32 brom_version;\n\tu32 data_version;\n\tu32 rcm_version;\n\n\tu32 boot_type;\n\n\tu32 primary_dev_type;\n\tu32 secondary_dev_type;\n\n\tu32 boot_time_log_init;\n\tu32 boot_time_log_exit;\n\tu32 bct_read_tick_cnt;\n\tu32 bl_read_tick_cnt;\n\n\tu32 osc_frequency;\n\tu8  dev_initialized;\n\tu8  dram_initialized;\n\n\tu8 force_recovery_bit_cleared; // APBDEV_PMC_SCRATCH0.\n\tu8 failback_bit_cleared;       // APBDEV_PMC_SCRATCH0.\n\tu8 failback_invoked;\n\n\tu8 irom_patch_status; // bit0-3: hamming status, bit7: patches exist.\n\n\tu8  bct_valid;\n\tu8  bct_status[9]; // Each bit is a block (72 blocks).\n\tu32 bct_last_journal_read;\n\tu32 bct_block;\n\tu32 bct_page;\n\tu32 bct_size;\n\tu32 bct_ptr;\n\n\tbit_bl_state_t bl_state[4];\n\n\tbit_boot_secondary_dev_status_t210_t secondary_dev_status;\n\n\tu32 usb_charging_status;\n\n\tu32 safe_start_addr; // Init: 0x400000F4 / UART: 0x40000100 / BL: 0x40002900.\n\n\tu8  padding[12];\n} tegra_bit_t210_t;\n\ntypedef struct _tegra_bit_t210b01_t\n{\n\tu32 brom_version;\n\tu32 data_version;\n\tu32 rcm_version;\n\n\tu32 boot_type;\n\n\tu32 primary_dev_type;\n\tu32 secondary_dev_type;\n\n\tu32 authentication_scheme;\n\tu32 encryption_enabled;\n\n\tu32 brom_flow_tracker;\n\n\tu32 reserved;\n\tu32 boot_time_log_exit;\n\tu32 setup_tick_cnt;\n\tu32 bct_read_tick_cnt;\n\tu32 bl_read_tick_cnt;\n\n\tbit_flow_log_t boot_flow_log[40];\n\n\tu32 osc_frequency;\n\tu8  dev_initialized;\n\tu8  dram_initialized;\n\n\tu8  force_recovery_bit_cleared;\n\tu8  failback_bit_cleared;\n\tu8  failback_invoked;\n\n\tu8  irom_patch_status; // bit0-3: hamming status, bit7: patches exist.\n\n\tu8  bct_size_valid;\n\tu8  bct_size_status[9];\n\tu32 bct_size_last_journal_read;\n\tu32 bct_size_block;\n\tu32 bct_size_page;\n\n\tu8  bct_valid;\n\tu8  bct_status[9];\n\tu8  padding[2];\n\tu32 bct_last_journal_read;\n\tu32 bct_block;\n\tu32 bct_page;\n\tu32 bct_size;\n\tu32 bct_ptr;\n\n\tbit_bl_state_t bl_state[4];\n\n\tbit_boot_secondary_dev_status_t210b01_t secondary_dev_status;\n\n\tu32 usb_charging_status;\n\n\tu8  pmu_boot_sel_read_error;\n\n\tu32 safe_start_addr; // Init: 0x40000464 / UART: 0x40000464 / BL: 0x40002C64.\n} tegra_bit_t210b01_t;\n\n#endif\n"
  },
  {
    "path": "bdk/utils/types.h",
    "content": "/*\n* Copyright (c) 2018 naehrwert\n* Copyright (c) 2018-2025 CTCaer\n*\n* This program is free software; you can redistribute it and/or modify it\n* under the terms and conditions of the GNU General Public License,\n* version 2, as published by the Free Software Foundation.\n*\n* This program is distributed in the hope it will be useful, but WITHOUT\n* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n* more details.\n*\n* You should have received a copy of the GNU General Public License\n* along with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n#ifndef _TYPES_H_\n#define _TYPES_H_\n\n#include <assert.h>\n\n/* Types */\ntypedef signed char s8;\ntypedef short s16;\ntypedef short SHORT;\ntypedef int s32;\ntypedef int INT;\ntypedef int bool;\ntypedef long LONG;\ntypedef long long int s64;\n\ntypedef unsigned char u8;\ntypedef unsigned char BYTE;\ntypedef unsigned short u16;\ntypedef unsigned short WORD;\ntypedef unsigned short WCHAR;\ntypedef unsigned int u32;\ntypedef unsigned int UINT;\ntypedef unsigned long DWORD;\ntypedef unsigned long long QWORD;\ntypedef unsigned long long int u64;\n\ntypedef volatile unsigned char vu8;\ntypedef volatile unsigned short vu16;\ntypedef volatile unsigned int vu32;\n\n#ifdef __aarch64__\ntypedef unsigned long long uptr;\n#else /* __arm__ or __thumb__ */\ntypedef unsigned long uptr;\n#endif\n\n/* Important */\n#define false 0\n#define true  1\n\n#define NULL ((void *)0)\n\n/* Misc */\n#define DISABLE 0\n#define ENABLE  1\n\n/* Sizes */\n#define SZ_1K   0x400\n#define SZ_2K   0x800\n#define SZ_4K   0x1000\n#define SZ_8K   0x2000\n#define SZ_16K  0x4000\n#define SZ_32K  0x8000\n#define SZ_64K  0x10000\n#define SZ_128K 0x20000\n#define SZ_256K 0x40000\n#define SZ_512K 0x80000\n#define SZ_1M   0x100000\n#define SZ_2M   0x200000\n#define SZ_4M   0x400000\n#define SZ_8M   0x800000\n#define SZ_16M  0x1000000\n#define SZ_32M  0x2000000\n#define SZ_64M  0x4000000\n#define SZ_128M 0x8000000\n#define SZ_256M 0x10000000\n#define SZ_512M 0x20000000\n#define SZ_1G   0x40000000\n#define SZ_2G   0x80000000\n#define SZ_PAGE SZ_4K\n\n/* Macros */\n#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))\n#define ALIGN_DOWN(x, a) ((x) & ~((a) - 1))\n#define BIT(n) (1U << (n))\n#define MAX(a, b) ((a) > (b) ? (a) : (b))\n#define MIN(a, b) ((a) < (b) ? (a) : (b))\n\n#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))\n\n#define OFFSET_OF(t, m) ((uptr)&((t *)NULL)->m)\n#define CONTAINER_OF(mp, t, mn) ((t *)((uptr)mp - OFFSET_OF(t, mn)))\n\n#define byte_swap_16(num) ((((num) >> 8) & 0xFF) | (((num) & 0xFF) << 8))\n#define byte_swap_32(num) ((((num) >> 24) &   0xFF) | (((num) & 0xFF00) << 8 ) | \\\n\t\t\t\t\t\t   (((num) >> 8 ) & 0xFF00) | (((num) &   0xFF) << 24))\n\n#define likely(x)   (__builtin_expect((x) != 0, 1))\n#define unlikely(x) (__builtin_expect((x) != 0, 0))\n\n/* Bootloader/Nyx */\n#define BOOT_CFG_AUTOBOOT_EN BIT(0)\n#define BOOT_CFG_FROM_LAUNCH BIT(1)\n#define BOOT_CFG_FROM_ID     BIT(2)\n#define BOOT_CFG_TO_EMUMMC   BIT(3)\n\n#define EXTRA_CFG_KEYS    BIT(0)\n#define EXTRA_CFG_PAYLOAD BIT(1)\n#define EXTRA_CFG_MODULE  BIT(2)\n\n#define EXTRA_CFG_NYX_UMS    BIT(5)\n#define EXTRA_CFG_NYX_RELOAD BIT(6)\n\ntypedef enum _nyx_ums_type\n{\n\tNYX_UMS_SD_CARD = 0,\n\tNYX_UMS_EMMC_BOOT0,\n\tNYX_UMS_EMMC_BOOT1,\n\tNYX_UMS_EMMC_GPP,\n\tNYX_UMS_EMUMMC_BOOT0,\n\tNYX_UMS_EMUMMC_BOOT1,\n\tNYX_UMS_EMUMMC_GPP\n} nyx_ums_type;\n\ntypedef struct __attribute__((__packed__)) _boot_cfg_t\n{\n\tu8 boot_cfg;\n\tu8 autoboot;\n\tu8 autoboot_list;\n\tu8 extra_cfg;\n\tunion\n\t{\n\t\tstruct\n\t\t{\n\t\t\tchar id[8]; // 7 char ASCII null terminated.\n\t\t\tchar emummc_path[0x78]; // emuMMC/XXX, ASCII null terminated.\n\t\t};\n\t\tu8 ums; // nyx_ums_type.\n\t\tu8 xt_str[0x80];\n\t};\n} boot_cfg_t;\n\nstatic_assert(sizeof(boot_cfg_t) == 0x84, \"Boot cfg storage size is wrong!\");\n\n#define RSVD_FLAG_DRAM_8GB BIT(0)\n\ntypedef struct __attribute__((__packed__)) _rsvd_cfg_t\n{\n\tu16 rsvd0;\n\tu8  rsvd_flags;\n\tu8  bclk_t210:4;\n\tu8  bclk_t210b01:4;\n} rsvd_cfg_t;\n\ntypedef struct __attribute__((__packed__)) _ipl_ver_meta_t\n{\n\tu32 magic;\n\tu32 version;\n\trsvd_cfg_t rcfg;\n} ipl_ver_meta_t;\n\ntypedef struct __attribute__((__packed__)) _reloc_meta_t\n{\n\tu32 start;\n\tu32 stack;\n\tu32 end;\n\tu32 ep;\n} reloc_meta_t;\n\n#endif\n"
  },
  {
    "path": "bdk/utils/util.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <mem/heap.h>\n#include <power/max77620.h>\n#include <rtc/max77620-rtc.h>\n#include <soc/bpmp.h>\n#include <soc/hw_init.h>\n#include <soc/i2c.h>\n#include <soc/pmc.h>\n#include <soc/timer.h>\n#include <soc/t210.h>\n#include <storage/sd.h>\n#include <utils/util.h>\n\nu8 bit_count(u32 val)\n{\n\tu8 cnt = 0;\n\tfor (u32 i = 0; i < 32; i++)\n\t{\n\t\tif ((val >> i) & 1)\n\t\t\tcnt++;\n\t}\n\n\treturn cnt;\n}\n\nu32 bit_count_mask(u8 bits)\n{\n\tu32 val = 0;\n\tfor (u32 i = 0; i < bits; i++)\n\t\tval |= 1 << i;\n\n\treturn val;\n}\n\nchar *strcpy_ns(char *dst, char *src)\n{\n\tif (!src || !dst)\n\t\treturn NULL;\n\n\t// Remove starting space.\n\tu32 len = strlen(src);\n\tif (len && src[0] == ' ')\n\t{\n\t\tlen--;\n\t\tsrc++;\n\t}\n\n\tstrcpy(dst, src);\n\n\t// Remove trailing space.\n\tif (len && dst[len - 1] == ' ')\n\t\tdst[len - 1] = 0;\n\n\treturn dst;\n}\n\n// Approximate square root finder for a 64-bit number.\nu64 sqrt64(u64 num)\n{\n\tu64 base = 0;\n\tu64 limit = num;\n\tu64 square_root = 0;\n\n\twhile (base <= limit)\n\t{\n\t\tu64 tmp_sqrt = (base + limit) / 2;\n\n\t\tif (tmp_sqrt * tmp_sqrt == num) {\n\t\t\tsquare_root = tmp_sqrt;\n\t\t\tbreak;\n\t\t}\n\n\t\tif (tmp_sqrt * tmp_sqrt < num)\n\t\t{\n\t\t\tsquare_root = base;\n\t\t\tbase = tmp_sqrt + 1;\n\t\t}\n\t\telse\n\t\t\tlimit = tmp_sqrt - 1;\n\t}\n\n\treturn square_root;\n}\n\n#define\tTULONG_MAX  ((unsigned long)((unsigned long)(~0L)))\n#define\tTLONG_MAX   ((long)(((unsigned long)(~0L)) >> 1))\n#define\tTLONG_MIN   ((long)(~TLONG_MAX))\n#define ISSPACE(ch) ((ch >= '\\t' && ch <= '\\r') || (ch == ' '))\n#define ISDIGIT(ch) ( ch >= '0'  && ch <= '9' )\n#define ISALPHA(ch) ((ch >= 'a'  && ch <= 'z')  || (ch >= 'A' && ch <= 'Z'))\n#define ISUPPER(ch) ( ch >= 'A'  && ch <= 'Z' )\n\n/*\n * Avoid using reentrant newlib version of strol. It's only used for errno.\n *\n * strol/atoi:\n * Copyright (c) 1990 The Regents of the University of California.\n */\nlong strtol(const char *nptr, char **endptr, register int base)\n{\n\tregister const char *s = nptr;\n\tregister unsigned long acc;\n\tregister int c;\n\tregister unsigned long cutoff;\n\tregister int neg = 0, any, cutlim;\n\n\t/*\n\t * Skip white space and pick up leading +/- sign if any.\n\t * If base is 0, allow 0x for hex and 0 for octal, else\n\t * assume decimal; if base is already 16, allow 0x.\n\t */\n\tdo {\n\t\tc = *s++;\n\t} while (ISSPACE(c));\n\tif (c == '-') {\n\t\tneg = 1;\n\t\tc = *s++;\n\t} else if (c == '+')\n\t\tc = *s++;\n\tif ((base == 0 || base == 16) &&\n\t\tc == '0' && (*s == 'x' || *s == 'X')) {\n\t\tc = s[1];\n\t\ts += 2;\n\t\tbase = 16;\n\t}\n\tif (base == 0)\n\t\tbase = c == '0' ? 8 : 10;\n\n\t/*\n\t * Compute the cutoff value between legal numbers and illegal\n\t * numbers.  That is the largest legal value, divided by the\n\t * base.  An input number that is greater than this value, if\n\t * followed by a legal input character, is too big.  One that\n\t * is equal to this value may be valid or not; the limit\n\t * between valid and invalid numbers is then based on the last\n\t * digit.  For instance, if the range for longs is\n\t * [-2147483648..2147483647] and the input base is 10,\n\t * cutoff will be set to 214748364 and cutlim to either\n\t * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated\n\t * a value > 214748364, or equal but the next digit is > 7 (or 8),\n\t * the number is too big, and we will return a range error.\n\t *\n\t * Set any if any `digits' consumed; make it negative to indicate\n\t * overflow.\n\t */\n\tcutoff = neg ? -(unsigned long)TLONG_MIN : (base == 16 ? TULONG_MAX : TLONG_MAX);\n\tcutlim = cutoff % (unsigned long)base;\n\tcutoff /= (unsigned long)base;\n\tfor (acc = 0, any = 0;; c = *s++) {\n\t\tif (ISDIGIT(c))\n\t\t\tc -= '0';\n\t\telse if (ISALPHA(c))\n\t\t\tc -= ISUPPER(c) ? 'A' - 10 : 'a' - 10;\n\t\telse\n\t\t\tbreak;\n\t\tif (c >= base)\n\t\t\tbreak;\n\t\tif (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))\n\t\t\tany = -1;\n\t\telse {\n\t\t\tany = 1;\n\t\t\tacc *= base;\n\t\t\tacc += c;\n\t\t}\n\t}\n\tif (any < 0) {\n\t\tacc = neg ? TLONG_MIN : TLONG_MAX;\n\t} else if (neg)\n\t\tacc = -acc;\n\tif (endptr != 0)\n\t\t*endptr = (char *) (any ? s - 1 : nptr);\n\treturn (acc);\n}\n\nint atoi(const char *nptr)\n{\n  return (int)strtol(nptr, (char **)NULL, 10);\n}\n\nvoid reg_write_array(vu32 *base, const reg_cfg_t *cfg, u32 num_cfg)\n{\n\t// Expected register offset is a u32 array index.\n\tfor (u32 i = 0; i < num_cfg; i++)\n\t\tbase[cfg[i].idx] = cfg[i].val;\n}\n\nu32 crc32_calc(u32 crc, const u8 *buf, u32 len)\n{\n\tconst u8 *p, *q;\n\tstatic u32 *table = NULL;\n\n\t// Calculate CRC table.\n\tif (!table)\n\t{\n\t\ttable = zalloc(256 * sizeof(u32));\n\t\tfor (u32 i = 0; i < 256; i++)\n\t\t{\n\t\t\tu32 rem = i;\n\t\t\tfor (u32 j = 0; j < 8; j++)\n\t\t\t{\n\t\t\t\tif (rem & 1)\n\t\t\t\t{\n\t\t\t\t\trem >>= 1;\n\t\t\t\t\trem ^= 0xedb88320;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\trem >>= 1;\n\t\t\t}\n\t\t\ttable[i] = rem;\n\t\t}\n\t}\n\n\tcrc = ~crc;\n\tq = buf + len;\n\tfor (p = buf; p < q; p++)\n\t{\n\t\tu8 oct = *p;\n\t\tcrc = (crc >> 8) ^ table[(crc & 0xff) ^ oct];\n\t}\n\n\treturn ~crc;\n}\n\nint qsort_compare_int(const void *a, const void *b)\n{\n\treturn (*(int *)a - *(int *)b);\n}\n\nint qsort_compare_char(const void *a, const void *b)\n{\n\treturn strcmp(*(const char **)a, *(const char **)b);\n}\n\nint qsort_compare_char_case(const void *a, const void *b)\n{\n\treturn strcasecmp(*(const char **)a, *(const char **)b);\n}\n\nvoid panic(u32 val)\n{\n\t// Set panic code.\n\tPMC(APBDEV_PMC_SCRATCH200) = val;\n\n\t// Disable SE.\n\t//PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_DISABLE;\n\n\t// Immediately cause a full system reset.\n\twatchdog_start(0, TIMER_PMCRESET_EN);\n\n\twhile (true);\n}\n\nvoid power_set_state(power_state_t state)\n{\n\tu8 reg;\n\n\t// Unmount and power down sd card.\n\tsd_end();\n\n\t// De-initialize and power down various hardware.\n\thw_deinit(false);\n\n\t// Set power state.\n\tswitch (state)\n\t{\n\tcase REBOOT_RCM:\n\t\tPMC(APBDEV_PMC_SCRATCH0) = PMC_SCRATCH0_MODE_RCM; // Enable RCM path.\n\t\tPMC(APBDEV_PMC_CNTRL)   |= PMC_CNTRL_MAIN_RST;    // PMC reset.\n\t\tbreak;\n\n\tcase REBOOT_BYPASS_FUSES:\n\t\tpanic(PMC_NX_PANIC_BYPASS_FUSES); // Bypass fuse programming in package1.\n\t\tbreak;\n\n\tcase POWER_OFF:\n\t\t// Initiate power down sequence and do not generate a reset (regulators retain state after POR).\n\t\ti2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF);\n\t\tbreak;\n\n\tcase POWER_OFF_RESET:\n\tcase POWER_OFF_REBOOT:\n\tdefault:\n\t\t// Enable/Disable soft reset wake event.\n\t\treg = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG2);\n\t\tif (state == POWER_OFF_RESET) // Do not wake up after power off.\n\t\t\treg &= ~(MAX77620_ONOFFCNFG2_SFT_RST_WK | MAX77620_ONOFFCNFG2_WK_ALARM1 | MAX77620_ONOFFCNFG2_WK_ALARM2);\n\t\telse // POWER_OFF_REBOOT. Wake up after power off.\n\t\t\treg |= MAX77620_ONOFFCNFG2_SFT_RST_WK;\n\t\ti2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG2, reg);\n\n\t\t// Initiate power down sequence and generate a reset (regulators' state resets after POR).\n\t\ti2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_SFT_RST);\n\t\tbreak;\n\t}\n\n\twhile (true)\n\t\tbpmp_halt();\n}\n\nvoid power_set_state_ex(void *param)\n{\n\tpower_state_t *state = (power_state_t *)param;\n\tpower_set_state(*state);\n}\n"
  },
  {
    "path": "bdk/utils/util.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _UTIL_H_\n#define _UTIL_H_\n\n#include <utils/types.h>\n#include <mem/minerva.h>\n\ntypedef enum\n{\n\tREBOOT_RCM,          // PMC reset. Enter RCM mode.\n\tREBOOT_BYPASS_FUSES, // PMC reset via watchdog. Enter Normal mode. Bypass fuse programming in package1.\n\n\tPOWER_OFF,           // Power off PMIC. Do not reset regulators.\n\tPOWER_OFF_RESET,     // Power off PMIC. Reset regulators.\n\tPOWER_OFF_REBOOT,    // Power off PMIC. Reset regulators. Power on.\n} power_state_t;\n\ntypedef struct _reg_cfg_t\n{\n\tu32 idx;\n\tu32 val;\n} reg_cfg_t;\n\nu8   bit_count(u32 val);\nu32  bit_count_mask(u8 bits);\nchar *strcpy_ns(char *dst, char *src);\nu64  sqrt64(u64 num);\nlong strtol(const char *nptr, char **endptr, register int base);\nint  atoi(const char *nptr);\n\nvoid reg_write_array(vu32 *base, const reg_cfg_t *cfg, u32 num_cfg);\nu32  crc32_calc(u32 crc, const u8 *buf, u32 len);\n\nint qsort_compare_int(const void *a, const void *b);\nint qsort_compare_char(const void *a, const void *b);\nint qsort_compare_char_case(const void *a, const void *b);\n\nvoid panic(u32 val);\nvoid power_set_state(power_state_t state);\nvoid power_set_state_ex(void *param);\n\n\n/*! hekate and Nyx common defines */\n#define NYX_NEW_INFO 0x3058594E\n\ntypedef enum\n{\n\tERR_LIBSYS_LP0 = BIT(0),\n\tERR_SYSOLD_NYX = BIT(1),\n\tERR_LIBSYS_MTC = BIT(2),\n\tERR_SD_BOOT_EN = BIT(3),\n\tERR_PANIC_CODE = BIT(4),\n\tERR_L4T_KERNEL = BIT(24),\n\tERR_EXCEPTION  = BIT(31),\n} hekate_errors_t;\n\ntypedef enum\n{\n\tNYX_CFG_UMS  = BIT(6),\n\n\tNYX_CFG_EXTRA = 0xFF << 24\n} nyx_cfg_t;\n\ntypedef struct _nyx_info_t\n{\n\tu32 magic;\n\tu32 sd_init;\n\tu32 sd_errors[3];\n\tu8  rsvd[0x1000];\n\tu32 panel_id;\n\tu32 errors;\n} nyx_info_t;\n\ntypedef struct _nyx_info_ex_t\n{\n\tu32 magic;\n\tu32 rsvd_flags;\n} nyx_info_ex_t;\n\ntypedef struct _nyx_storage_t\n{\n\tu32 version;\n\tu32 cfg;\n\tu8  rsdv0[0x8000];\n\tu8  hekate[0x30000];\n\tnyx_info_ex_t info_ex;\n\tu8  rsvd1[SZ_8M - sizeof(nyx_info_ex_t) - sizeof(nyx_info_t)];\n\tnyx_info_t info;\n\tminerva_str_t minerva;\n} nyx_storage_t;\n\n#endif\n"
  },
  {
    "path": "bootloader/config.c",
    "content": "/*\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n#include <stdlib.h>\n\n#include <bdk.h>\n\n#include \"config.h\"\n#include <libs/fatfs/ff.h>\n\nvoid set_default_configuration()\n{\n\th_cfg.t210b01 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01;\n\th_cfg.devmode = fuse_read_hw_state();\n\n\th_cfg.autoboot      = 0;\n\th_cfg.autoboot_list = 0;\n\th_cfg.bootwait      = 3;\n\th_cfg.noticker      = 0; //! TODO: Add GUI option.\n\th_cfg.backlight     = 100;\n\th_cfg.autohosoff    = h_cfg.t210b01 ? 1 : 0;\n\th_cfg.autonogc      = 1;\n\th_cfg.updater2p     = 0;\n\th_cfg.bootprotect   = 0;\n\n\th_cfg.errors = 0;\n\th_cfg.eks = NULL;\n\th_cfg.rcm_patched = fuse_check_patched_rcm();\n\th_cfg.emummc_force_disable = false;\n}\n"
  },
  {
    "path": "bootloader/config.h",
    "content": "/*\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _CONFIG_H_\n#define _CONFIG_H_\n\n#include <bdk.h>\n\n#include \"hos/hos.h\"\n\ntypedef struct _hekate_config\n{\n\t// Non-volatile config.\n\tu32 autoboot;\n\tu32 autoboot_list;\n\tu32 bootwait;\n\tu32 noticker;\n\tu32 backlight;\n\tu32 autohosoff;\n\tu32 autonogc;\n\tu32 updater2p;\n\tu32 bootprotect;\n\t// Global temporary config.\n\tbool t210b01;\n\tbool devmode;\n\tbool emummc_force_disable;\n\tbool rcm_patched;\n\tu32  errors;\n\thos_eks_mbr_t *eks;\n} hekate_config;\n\nextern hekate_config h_cfg;\n\nvoid set_default_configuration();\n\n#endif /* _CONFIG_H_ */\n"
  },
  {
    "path": "bootloader/frontend/fe_info.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <bdk.h>\n\n#include \"fe_info.h\"\n#include \"../config.h\"\n#include \"../hos/hos.h\"\n#include \"../hos/pkg1.h\"\n#include <libs/fatfs/ff.h>\n\n#pragma GCC push_options\n#pragma GCC optimize (\"Os\")\n\nvoid print_fuseinfo()\n{\n\tu32 fuse_size = h_cfg.t210b01 ? 0x368 : 0x300;\n\tu32 fuse_address = h_cfg.t210b01 ? 0x7000F898 : 0x7000F900;\n\n\tgfx_clear_partial_grey(0x1B, 0, 1256);\n\tgfx_con_setpos(0, 0);\n\n\tgfx_printf(\"\\nSKU:         %X - \", FUSE(FUSE_SKU_INFO));\n\tswitch (h_cfg.devmode)\n\t{\n\tcase FUSE_NX_HW_STATE_PROD:\n\t\tgfx_printf(\"Retail\\n\");\n\t\tbreak;\n\tcase FUSE_NX_HW_STATE_DEV:\n\t\tgfx_printf(\"Dev\\n\");\n\t\tbreak;\n\t}\n\tgfx_printf(\"Sdram ID:    %d\\n\", fuse_read_dramid(true));\n\tgfx_printf(\"Burnt fuses: %d / 64\\n\", bit_count(fuse_read_odm(7)));\n\tgfx_printf(\"Secure key:  %08X%08X%08X%08X\\n\\n\\n\",\n\t\tbyte_swap_32(FUSE(FUSE_PRIVATE_KEY0)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY1)),\n\t\tbyte_swap_32(FUSE(FUSE_PRIVATE_KEY2)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY3)));\n\n\tgfx_printf(\"%kFuse cache:\\n\\n%k\", TXT_CLR_CYAN_L, TXT_CLR_DEFAULT);\n\tgfx_hexdump(fuse_address, (u8 *)fuse_address, fuse_size);\n\n\tbtn_wait();\n}\n\nvoid print_mmc_info()\n{\n\tgfx_clear_partial_grey(0x1B, 0, 1256);\n\tgfx_con_setpos(0, 0);\n\n\tstatic const u32 SECTORS_TO_MIB_COEFF = 11;\n\n\tif (emmc_initialize(false))\n\t{\n\t\tEPRINTF(\"Failed to init eMMC.\");\n\t\tgoto out;\n\t}\n\telse\n\t{\n\t\tu16 card_type;\n\t\tu32 speed = 0;\n\n\t\tgfx_printf(\"%kCID:%k\\n\", TXT_CLR_CYAN_L, TXT_CLR_DEFAULT);\n\t\tswitch (emmc_storage.csd.mmca_vsn)\n\t\t{\n\t\tcase 2: /* MMC v2.0 - v2.2 */\n\t\tcase 3: /* MMC v3.1 - v3.3 */\n\t\tcase 4: /* MMC v4 */\n\t\t\tgfx_printf(\n\t\t\t\t\" Vendor ID:  %X\\n\"\n\t\t\t\t\" OEM ID:     %02X\\n\"\n\t\t\t\t\" Model:      %c%c%c%c%c%c\\n\"\n\t\t\t\t\" Prd Rev:    %X\\n\"\n\t\t\t\t\" S/N:        %04X\\n\"\n\t\t\t\t\" Month/Year: %02d/%04d\\n\\n\",\n\t\t\t\temmc_storage.cid.manfid, emmc_storage.cid.oemid,\n\t\t\t\temmc_storage.cid.prod_name[0], emmc_storage.cid.prod_name[1], emmc_storage.cid.prod_name[2],\n\t\t\t\temmc_storage.cid.prod_name[3], emmc_storage.cid.prod_name[4],\temmc_storage.cid.prod_name[5],\n\t\t\t\temmc_storage.cid.prv, emmc_storage.cid.serial, emmc_storage.cid.month, emmc_storage.cid.year);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\n\t\tif (emmc_storage.csd.structure == 0)\n\t\t\tEPRINTF(\"Unknown CSD structure.\");\n\t\telse\n\t\t{\n\t\t\tgfx_printf(\"%kExtended CSD V1.%d:%k\\n\",\n\t\t\t\tTXT_CLR_CYAN_L, emmc_storage.ext_csd.ext_struct, TXT_CLR_DEFAULT);\n\t\t\tcard_type = emmc_storage.ext_csd.card_type;\n\t\t\tchar card_type_support[96];\n\t\t\tcard_type_support[0] = 0;\n\t\t\tif (card_type & EXT_CSD_CARD_TYPE_HS_26)\n\t\t\t{\n\t\t\t\tstrcat(card_type_support, \"HS26\");\n\t\t\t\tspeed = (26 << 16) | 26;\n\t\t\t}\n\t\t\tif (card_type & EXT_CSD_CARD_TYPE_HS_52)\n\t\t\t{\n\t\t\t\tstrcat(card_type_support, \", HS52\");\n\t\t\t\tspeed = (52 << 16) | 52;\n\t\t\t}\n\t\t\tif (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)\n\t\t\t{\n\t\t\t\tstrcat(card_type_support, \", DDR52_1.8V\");\n\t\t\t\tspeed = (52 << 16) | 104;\n\t\t\t}\n\t\t\tif (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)\n\t\t\t{\n\t\t\t\tstrcat(card_type_support, \", HS200_1.8V\");\n\t\t\t\tspeed = (200 << 16) | 200;\n\t\t\t}\n\t\t\tif (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)\n\t\t\t{\n\t\t\t\tstrcat(card_type_support, \", HS400_1.8V\");\n\t\t\t\tspeed = (200 << 16) | 400;\n\t\t\t}\n\n\t\t\tgfx_printf(\n\t\t\t\t\" Spec Version:  %02X\\n\"\n\t\t\t\t\" Extended Rev:  1.%d\\n\"\n\t\t\t\t\" Dev Version:   %d\\n\"\n\t\t\t\t\" Cmd Classes:   %02X\\n\"\n\t\t\t\t\" Capacity:      %s\\n\"\n\t\t\t\t\" Max Rate:      %d MB/s (%d MHz)\\n\"\n\t\t\t\t\" Current Rate:  %d MB/s\\n\"\n\t\t\t\t\" Type Support:  \",\n\t\t\t\temmc_storage.csd.mmca_vsn, emmc_storage.ext_csd.rev, emmc_storage.ext_csd.dev_version, emmc_storage.csd.cmdclass,\n\t\t\t\temmc_storage.csd.capacity == (4096 * EMMC_BLOCKSIZE) ? \"High\" : \"Low\", speed & 0xFFFF, (speed >> 16) & 0xFFFF,\n\t\t\t\temmc_storage.csd.busspeed);\n\t\t\tgfx_con.fntsz = 8;\n\t\t\tgfx_printf(\"%s\", card_type_support);\n\t\t\tgfx_con.fntsz = 16;\n\t\t\tgfx_printf(\"\\n\\n\", card_type_support);\n\n\t\t\tu32 boot_size = emmc_storage.ext_csd.boot_mult << 17;\n\t\t\tu32 rpmb_size = emmc_storage.ext_csd.rpmb_mult << 17;\n\t\t\tgfx_printf(\"%keMMC Partitions:%k\\n\", TXT_CLR_CYAN_L, TXT_CLR_DEFAULT);\n\t\t\tgfx_printf(\" 1: %kBOOT0      %k\\n    Size: %5d KiB (LBA Sectors: 0x%07X)\\n\", TXT_CLR_GREENISH, TXT_CLR_DEFAULT,\n\t\t\t\tboot_size / 1024, boot_size / EMMC_BLOCKSIZE);\n\t\t\tgfx_put_small_sep();\n\t\t\tgfx_printf(\" 2: %kBOOT1      %k\\n    Size: %5d KiB (LBA Sectors: 0x%07X)\\n\", TXT_CLR_GREENISH, TXT_CLR_DEFAULT,\n\t\t\t\tboot_size / 1024, boot_size / EMMC_BLOCKSIZE);\n\t\t\tgfx_put_small_sep();\n\t\t\tgfx_printf(\" 3: %kRPMB       %k\\n    Size: %5d KiB (LBA Sectors: 0x%07X)\\n\", TXT_CLR_GREENISH, TXT_CLR_DEFAULT,\n\t\t\t\trpmb_size / 1024, rpmb_size / EMMC_BLOCKSIZE);\n\t\t\tgfx_put_small_sep();\n\t\t\tgfx_printf(\" 0: %kGPP (USER) %k\\n    Size: %5d MiB (LBA Sectors: 0x%07X)\\n\\n\", TXT_CLR_GREENISH, TXT_CLR_DEFAULT,\n\t\t\t\temmc_storage.sec_cnt >> SECTORS_TO_MIB_COEFF, emmc_storage.sec_cnt);\n\t\t\tgfx_put_small_sep();\n\t\t\tgfx_printf(\"%kGPP (eMMC USER) partition table:%k\\n\", TXT_CLR_CYAN_L, TXT_CLR_DEFAULT);\n\n\t\t\temmc_set_partition(EMMC_GPP);\n\t\t\tLIST_INIT(gpt);\n\t\t\temmc_gpt_parse(&gpt);\n\t\t\tint gpp_idx = 0;\n\t\t\tLIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)\n\t\t\t{\n\t\t\t\tgfx_printf(\" %02d: %k%s%k\\n     Size: % 5d MiB (LBA Sectors 0x%07X)\\n     LBA Range: %08X-%08X\\n\",\n\t\t\t\t\tgpp_idx++, TXT_CLR_GREENISH, part->name, TXT_CLR_DEFAULT, (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF,\n\t\t\t\t\tpart->lba_end - part->lba_start + 1, part->lba_start, part->lba_end);\n\t\t\t\tgfx_put_small_sep();\n\t\t\t}\n\t\t\temmc_gpt_free(&gpt);\n\t\t}\n\t}\n\nout:\n\temmc_end();\n\n\tbtn_wait();\n}\n\nvoid print_sdcard_info()\n{\n\tstatic const u32 SECTORS_TO_MIB_COEFF = 11;\n\n\tgfx_clear_partial_grey(0x1B, 0, 1256);\n\tgfx_con_setpos(0, 0);\n\n\tif (!sd_initialize(false))\n\t{\n\t\tgfx_printf(\"%kCard IDentification:%k\\n\", TXT_CLR_CYAN_L, TXT_CLR_DEFAULT);\n\t\tgfx_printf(\n\t\t\t\" Vendor ID:  %02x\\n\"\n\t\t\t\" OEM ID:     %c%c\\n\"\n\t\t\t\" Model:      %c%c%c%c%c\\n\"\n\t\t\t\" HW rev:     %X\\n\"\n\t\t\t\" FW rev:     %X\\n\"\n\t\t\t\" S/N:        %08x\\n\"\n\t\t\t\" Month/Year: %02d/%04d\\n\\n\",\n\t\t\tsd_storage.cid.manfid, (sd_storage.cid.oemid >> 8) & 0xFF, sd_storage.cid.oemid & 0xFF,\n\t\t\tsd_storage.cid.prod_name[0], sd_storage.cid.prod_name[1], sd_storage.cid.prod_name[2],\n\t\t\tsd_storage.cid.prod_name[3], sd_storage.cid.prod_name[4],\n\t\t\tsd_storage.cid.hwrev, sd_storage.cid.fwrev, sd_storage.cid.serial,\n\t\t\tsd_storage.cid.month, sd_storage.cid.year);\n\n\t\tu16 *sd_errors = sd_get_error_count();\n\t\tgfx_printf(\"%kCard-Specific Data V%d.0:%k\\n\", TXT_CLR_CYAN_L, sd_storage.csd.structure + 1, TXT_CLR_DEFAULT);\n\t\tgfx_printf(\n\t\t\t\" Cmd Classes:    %02X\\n\"\n\t\t\t\" Capacity:       %d MiB\\n\"\n\t\t\t\" Bus Width:      %d\\n\"\n\t\t\t\" Current Rate:   %d MB/s (%d MHz)\\n\"\n\t\t\t\" Speed Class:    %d\\n\"\n\t\t\t\" UHS Grade:      U%d\\n\"\n\t\t\t\" Video Class:    V%d\\n\"\n\t\t\t\" App perf class: A%d\\n\"\n\t\t\t\" Write Protect:  %d\\n\"\n\t\t\t\" SDMMC Errors:   %d %d %d\\n\\n\",\n\t\t\tsd_storage.csd.cmdclass, sd_storage.sec_cnt >> 11,\n\t\t\tsd_storage.ssr.bus_width, sd_storage.csd.busspeed, sd_storage.csd.busspeed * 2,\n\t\t\tsd_storage.ssr.speed_class, sd_storage.ssr.uhs_grade, sd_storage.ssr.video_class,\n\t\t\tsd_storage.ssr.app_class, sd_storage.csd.write_protect,\n\t\t\tsd_errors[0], sd_errors[1], sd_errors[2]); // SD_ERROR_INIT_FAIL, SD_ERROR_RW_FAIL, SD_ERROR_RW_RETRY.\n\n\t\tint res = f_mount(&sd_fs, \"\", 1);\n\t\tif (!res)\n\t\t{\n\t\t\tgfx_puts(\"Acquiring FAT volume info...\\n\\n\");\n\t\t\tgfx_printf(\"%kFound %s volume:%k\\n Free:    %d MiB\\n Cluster: %d KiB\\n\",\n\t\t\t\t\tTXT_CLR_CYAN_L, sd_fs.fs_type == FS_EXFAT ? \"exFAT\" : \"FAT32\", TXT_CLR_DEFAULT,\n\t\t\t\t\tsd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF, (sd_fs.csize > 1) ? (sd_fs.csize >> 1) : 512);\n\t\t\tf_unmount(\"\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEPRINTFARGS(\"Failed to mount SD card (FatFS Error %d).\\n\"\n\t\t\t\t\"Make sure that a FAT partition exists..\", res);\n\t\t}\n\n\t\tsd_end();\n\t}\n\telse\n\t{\n\t\tEPRINTF(\"Failed to init SD card.\");\n\t\tif (!sdmmc_get_sd_inserted())\n\t\t\tEPRINTF(\"Make sure that it is inserted.\");\n\t\telse\n\t\t\tEPRINTF(\"SD Card Reader is not properly seated!\");\n\t\tsd_end();\n\t}\n\n\tbtn_wait();\n}\n\nvoid print_fuel_gauge_info()\n{\n\tint value = 0;\n\n\tgfx_printf(\"%kFuel Gauge Info:\\n%k\", TXT_CLR_CYAN_L, TXT_CLR_DEFAULT);\n\n\tmax17050_get_property(MAX17050_RepSOC, &value);\n\tgfx_printf(\"Capacity now:           %3d%\\n\", value >> 8);\n\n\tmax17050_get_property(MAX17050_RepCap, &value);\n\tgfx_printf(\"Capacity now:           %4d mAh\\n\", value);\n\n\tmax17050_get_property(MAX17050_FullCAP, &value);\n\tgfx_printf(\"Capacity full:          %4d mAh\\n\", value);\n\n\tmax17050_get_property(MAX17050_DesignCap, &value);\n\tgfx_printf(\"Capacity (design):      %4d mAh\\n\", value);\n\n\tmax17050_get_property(MAX17050_Current, &value);\n\tgfx_printf(\"Current now:            %d mA\\n\", value / 1000);\n\n\tmax17050_get_property(MAX17050_AvgCurrent, &value);\n\tgfx_printf(\"Current average:        %d mA\\n\", value / 1000);\n\n\tmax17050_get_property(MAX17050_VCELL, &value);\n\tgfx_printf(\"Voltage now:            %4d mV\\n\", value);\n\n\tmax17050_get_property(MAX17050_OCVInternal, &value);\n\tgfx_printf(\"Voltage open-circuit:   %4d mV\\n\", value);\n\n\tmax17050_get_property(MAX17050_MinVolt, &value);\n\tgfx_printf(\"Min voltage reached:    %4d mV\\n\", value);\n\n\tmax17050_get_property(MAX17050_MaxVolt, &value);\n\tgfx_printf(\"Max voltage reached:    %4d mV\\n\", value);\n\n\tmax17050_get_property(MAX17050_V_empty, &value);\n\tgfx_printf(\"Empty voltage (design): %4d mV\\n\", value);\n\n\tmax17050_get_property(MAX17050_TEMP, &value);\n\tgfx_printf(\"Battery temperature:    %d.%d oC\\n\", value / 10,\n\t\t\t   (value >= 0 ? value : (~value)) % 10);\n}\n\nvoid print_battery_charger_info()\n{\n\tint value = 0;\n\n\tgfx_printf(\"%k\\n\\nBattery Charger Info:\\n%k\", TXT_CLR_CYAN_L, TXT_CLR_DEFAULT);\n\n\tbq24193_get_property(BQ24193_InputCurrentLimit, &value);\n\tgfx_printf(\"Input current limit:  %4d mA\\n\", value);\n\n\tbq24193_get_property(BQ24193_SystemMinimumVoltage, &value);\n\tgfx_printf(\"System voltage limit: %4d mV\\n\", value);\n\n\tbq24193_get_property(BQ24193_FastChargeCurrentLimit, &value);\n\tgfx_printf(\"Charge current limit: %4d mA\\n\", value);\n\n\tbq24193_get_property(BQ24193_ChargeVoltageLimit, &value);\n\tgfx_printf(\"Charge voltage limit: %4d mV\\n\", value);\n\n\tbq24193_get_property(BQ24193_ChargeStatus, &value);\n\tgfx_printf(\"Charge status:        \");\n\tswitch (value)\n\t{\n\tcase 0:\n\t\tgfx_printf(\"Not charging\\n\");\n\t\tbreak;\n\tcase 1:\n\t\tgfx_printf(\"Pre-charging\\n\");\n\t\tbreak;\n\tcase 2:\n\t\tgfx_printf(\"Fast charging\\n\");\n\t\tbreak;\n\tcase 3:\n\t\tgfx_printf(\"Charge terminated\\n\");\n\t\tbreak;\n\tdefault:\n\t\tgfx_printf(\"Unknown (%d)\\n\", value);\n\t\tbreak;\n\t}\n\tbq24193_get_property(BQ24193_TempStatus, &value);\n\tgfx_printf(\"Temperature status:   \");\n\tswitch (value)\n\t{\n\tcase 0:\n\t\tgfx_printf(\"Normal\\n\");\n\t\tbreak;\n\tcase 2:\n\t\tgfx_printf(\"Warm\\n\");\n\t\tbreak;\n\tcase 3:\n\t\tgfx_printf(\"Cool\\n\");\n\t\tbreak;\n\tcase 5:\n\t\tgfx_printf(\"Cold\\n\");\n\t\tbreak;\n\tcase 6:\n\t\tgfx_printf(\"Hot\\n\");\n\t\tbreak;\n\tdefault:\n\t\tgfx_printf(\"Unknown (%d)\\n\", value);\n\t\tbreak;\n\t}\n}\n\nvoid print_battery_info()\n{\n\tgfx_clear_partial_grey(0x1B, 0, 1256);\n\tgfx_con_setpos(0, 0);\n\n\tprint_fuel_gauge_info();\n\n\tprint_battery_charger_info();\n\n\tu8 *buf = (u8 *)malloc(0x100 * 2);\n\n\tgfx_printf(\"%k\\n\\nBattery Fuel Gauge Registers:\\n%k\", TXT_CLR_CYAN_L, TXT_CLR_DEFAULT);\n\n\tfor (int i = 0; i < 0x200; i += 2)\n\t{\n\t\ti2c_recv_buf_small(buf + i, 2, I2C_1, MAXIM17050_I2C_ADDR, i >> 1);\n\t\tusleep(2500);\n\t}\n\n\tgfx_hexdump(0, (u8 *)buf, 0x200);\n\n\tbtn_wait();\n}\n\n#pragma GCC pop_options\n"
  },
  {
    "path": "bootloader/frontend/fe_info.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2022 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _FE_INFO_H_\n#define _FE_INFO_H_\n\nvoid print_fuseinfo();\nvoid print_mmc_info();\nvoid print_sdcard_info();\nvoid print_fuel_gauge_info();\nvoid print_battery_charger_info();\nvoid print_battery_info();\n\n#endif\n"
  },
  {
    "path": "bootloader/frontend/fe_tools.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2024 CTCaer\n * Copyright (c) 2018 Reisyukaku\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n#include <stdlib.h>\n\n#include <bdk.h>\n\n#include \"fe_tools.h\"\n#include \"../config.h\"\n#include \"../gfx/tui.h\"\n#include <libs/fatfs/ff.h>\n\nextern boot_cfg_t b_cfg;\n\n#pragma GCC push_options\n#pragma GCC optimize (\"Os\")\n\nstatic void _toggle_autorcm(bool enable)\n{\n\tgfx_clear_partial_grey(0x1B, 0, 1256);\n\tgfx_con_setpos(0, 0);\n\n\tint i, sect = 0;\n\tu8 corr_mod0, mod1;\n\tu8 *tempbuf = (u8 *)malloc(0x200);\n\n\t// Get the correct RSA modulus byte masks.\n\tnx_emmc_get_autorcm_masks(&corr_mod0, &mod1);\n\n\t// Iterate BCTs.\n\tfor (i = 0; i < 4; i++)\n\t{\n\t\tsect = (0x200 + (0x4000 * i)) / EMMC_BLOCKSIZE;\n\t\tsdmmc_storage_read(&emmc_storage, sect, 1, tempbuf);\n\n\t\t// Check if 2nd byte of modulus is correct.\n\t\tif (tempbuf[0x11] != mod1)\n\t\t\tcontinue;\n\n\t\tif (enable)\n\t\t\ttempbuf[0x10] = 0;\n\t\telse\n\t\t\ttempbuf[0x10] = corr_mod0;\n\t\tsdmmc_storage_write(&emmc_storage, sect, 1, tempbuf);\n\t}\n\n\tfree(tempbuf);\n\n\tif (enable)\n\t\tgfx_printf(\"%kAutoRCM mode enabled!%k\",  TXT_CLR_ORANGE, TXT_CLR_DEFAULT);\n\telse\n\t\tgfx_printf(\"%kAutoRCM mode disabled!%k\", TXT_CLR_GREENISH, TXT_CLR_DEFAULT);\n\tgfx_printf(\"\\n\\nPress any key...\\n\");\n\n\tbtn_wait();\n}\n\nstatic void _enable_autorcm()  { _toggle_autorcm(true); }\nstatic void _disable_autorcm() { _toggle_autorcm(false); }\n\nbool tools_autorcm_enabled()\n{\n\tu8 mod0, mod1;\n\tu8 *tempbuf = (u8 *)malloc(0x200);\n\n\t// Get the correct RSA modulus byte masks.\n\tnx_emmc_get_autorcm_masks(&mod0, &mod1);\n\n\t// Get 1st RSA modulus.\n\temmc_set_partition(EMMC_BOOT0);\n\tsdmmc_storage_read(&emmc_storage, 0x200 / EMMC_BLOCKSIZE, 1, tempbuf);\n\n\t// Check if 2nd byte of modulus is correct.\n\tbool enabled = false;\n\tif (tempbuf[0x11] == mod1)\n\t\tif (tempbuf[0x10] != mod0)\n\t\t\tenabled = true;\n\n\tfree(tempbuf);\n\n\treturn enabled;\n}\n\nvoid menu_autorcm()\n{\n\tgfx_clear_grey(0x1B);\n\tgfx_con_setpos(0, 0);\n\n\tif (h_cfg.rcm_patched)\n\t{\n\t\tWPRINTF(\"This device is RCM patched and the\\nfunction is disabled to avoid BRICKS!\\n\");\n\t\tbtn_wait();\n\n\t\treturn;\n\t}\n\n\tif (emmc_initialize(false))\n\t{\n\t\tEPRINTF(\"Failed to init eMMC.\");\n\t\tbtn_wait();\n\n\t\treturn;\n\t}\n\n\t// Do a simple check on the main BCT.\n\tbool enabled = tools_autorcm_enabled();\n\n\t// Create AutoRCM menu.\n\tment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);\n\n\tments[0].type = MENT_BACK;\n\tments[0].caption = \"Back\";\n\n\tments[1].type = MENT_CHGLINE;\n\n\tments[2].type = MENT_CAPTION;\n\tments[3].type = MENT_CHGLINE;\n\tif (!enabled)\n\t{\n\t\tments[2].caption = \"Status: Disabled!\";\n\t\tments[2].color   = TXT_CLR_GREENISH;\n\t\tments[4].caption = \"Enable AutoRCM\";\n\t\tments[4].handler = _enable_autorcm;\n\t}\n\telse\n\t{\n\t\tments[2].caption = \"Status: Enabled!\";\n\t\tments[2].color   = TXT_CLR_ORANGE;\n\t\tments[4].caption = \"Disable AutoRCM\";\n\t\tments[4].handler = _disable_autorcm;\n\t}\n\tments[4].type = MENT_HDLR_RE;\n\tments[4].data = NULL;\n\n\tmemset(&ments[5], 0, sizeof(ment_t));\n\tmenu_t menu = {ments, \"This corrupts BOOT0!\", 0, 0};\n\n\ttui_do_menu(&menu);\n\n\temmc_end();\n\n\tfree(ments);\n}\n\n#pragma GCC pop_options\n"
  },
  {
    "path": "bootloader/frontend/fe_tools.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2024 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _FE_TOOLS_H_\n#define _FE_TOOLS_H_\n\nvoid menu_autorcm();\nbool tools_autorcm_enabled();\n\n#endif\n"
  },
  {
    "path": "bootloader/gfx/gfx.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2022 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <stdarg.h>\n#include <string.h>\n#include \"gfx.h\"\n\n// Global gfx console and context.\ngfx_ctxt_t gfx_ctxt;\ngfx_con_t gfx_con;\n\nstatic bool gfx_con_init_done = false;\n\nstatic const u8 _gfx_font[] = {\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( )\n\t0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, // Char 033 (!)\n\t0x00, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, // Char 034 (\")\n\t0x00, 0x66, 0x66, 0xFF, 0x66, 0xFF, 0x66, 0x66, // Char 035 (#)\n\t0x00, 0x18, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x18, // Char 036 ($)\n\t0x00, 0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, // Char 037 (%)\n\t0x00, 0x3C, 0x66, 0x3C, 0x1C, 0xE6, 0x66, 0xFC, // Char 038 (&)\n\t0x00, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, // Char 039 (')\n\t0x00, 0x30, 0x18, 0x0C, 0x0C, 0x18, 0x30, 0x00, // Char 040 (()\n\t0x00, 0x0C, 0x18, 0x30, 0x30, 0x18, 0x0C, 0x00, // Char 041 ())\n\t0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, // Char 042 (*)\n\t0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, // Char 043 (+)\n\t0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0C, 0x00, // Char 044 (,)\n\t0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, // Char 045 (-)\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, // Char 046 (.)\n\t0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, // Char 047 (/)\n\t0x00, 0x3C, 0x66, 0x76, 0x6E, 0x66, 0x3C, 0x00, // Char 048 (0)\n\t0x00, 0x18, 0x1C, 0x18, 0x18, 0x18, 0x7E, 0x00, // Char 049 (1)\n\t0x00, 0x3C, 0x62, 0x30, 0x0C, 0x06, 0x7E, 0x00, // Char 050 (2)\n\t0x00, 0x3C, 0x62, 0x38, 0x60, 0x66, 0x3C, 0x00, // Char 051 (3)\n\t0x00, 0x6C, 0x6C, 0x66, 0xFE, 0x60, 0x60, 0x00, // Char 052 (4)\n\t0x00, 0x7E, 0x06, 0x7E, 0x60, 0x66, 0x3C, 0x00, // Char 053 (5)\n\t0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x3C, 0x00, // Char 054 (6)\n\t0x00, 0x7E, 0x30, 0x30, 0x18, 0x18, 0x18, 0x00, // Char 055 (7)\n\t0x00, 0x3C, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, // Char 056 (8)\n\t0x00, 0x3C, 0x66, 0x7C, 0x60, 0x66, 0x3C, 0x00, // Char 057 (9)\n\t0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, // Char 058 (:)\n\t0x00, 0x00, 0x18, 0x00, 0x18, 0x18, 0x0C, 0x00, // Char 059 (;)\n\t0x00, 0x70, 0x1C, 0x06, 0x06, 0x1C, 0x70, 0x00, // Char 060 (<)\n\t0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, // Char 061 (=)\n\t0x00, 0x0E, 0x38, 0x60, 0x60, 0x38, 0x0E, 0x00, // Char 062 (>)\n\t0x00, 0x3C, 0x66, 0x30, 0x18, 0x00, 0x18, 0x00, // Char 063 (?)\n\t0x00, 0x3C, 0x66, 0x76, 0x76, 0x06, 0x46, 0x3C, // Char 064 (@)\n\t0x00, 0x3C, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // Char 065 (A)\n\t0x00, 0x3E, 0x66, 0x3E, 0x66, 0x66, 0x3E, 0x00, // Char 066 (B)\n\t0x00, 0x3C, 0x66, 0x06, 0x06, 0x66, 0x3C, 0x00, // Char 067 (C)\n\t0x00, 0x1E, 0x36, 0x66, 0x66, 0x36, 0x1E, 0x00, // Char 068 (D)\n\t0x00, 0x7E, 0x06, 0x1E, 0x06, 0x06, 0x7E, 0x00, // Char 069 (E)\n\t0x00, 0x3E, 0x06, 0x1E, 0x06, 0x06, 0x06, 0x00, // Char 070 (F)\n\t0x00, 0x3C, 0x66, 0x06, 0x76, 0x66, 0x3C, 0x00, // Char 071 (G)\n\t0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // Char 072 (H)\n\t0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // Char 073 (I)\n\t0x00, 0x78, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, // Char 074 (J)\n\t0x00, 0x66, 0x36, 0x1E, 0x1E, 0x36, 0x66, 0x00, // Char 075 (K)\n\t0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7E, 0x00, // Char 076 (L)\n\t0x00, 0x46, 0x6E, 0x7E, 0x56, 0x46, 0x46, 0x00, // Char 077 (M)\n\t0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00, // Char 078 (N)\n\t0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 079 (O)\n\t0x00, 0x3E, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00, // Char 080 (P)\n\t0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x70, 0x00, // Char 081 (Q)\n\t0x00, 0x3E, 0x66, 0x3E, 0x1E, 0x36, 0x66, 0x00, // Char 082 (R)\n\t0x00, 0x3C, 0x66, 0x0C, 0x30, 0x66, 0x3C, 0x00, // Char 083 (S)\n\t0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // Char 084 (T)\n\t0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 085 (U)\n\t0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // Char 086 (V)\n\t0x00, 0x46, 0x46, 0x56, 0x7E, 0x6E, 0x46, 0x00, // Char 087 (W)\n\t0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, // Char 088 (X)\n\t0x00, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, // Char 089 (Y)\n\t0x00, 0x7E, 0x30, 0x18, 0x0C, 0x06, 0x7E, 0x00, // Char 090 (Z)\n\t0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, // Char 091 ([)\n\t0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00, // Char 092 (\\)\n\t0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, // Char 093 (])\n\t0x00, 0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, // Char 094 (^)\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // Char 095 (_)\n\t0x00, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, // Char 096 (`)\n\t0x00, 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x7C, 0x00, // Char 097 (a)\n\t0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x00, // Char 098 (b)\n\t0x00, 0x00, 0x3C, 0x06, 0x06, 0x06, 0x3C, 0x00, // Char 099 (c)\n\t0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, // Char 100 (d)\n\t0x00, 0x00, 0x3C, 0x66, 0x7E, 0x06, 0x3C, 0x00, // Char 101 (e)\n\t0x00, 0x38, 0x0C, 0x3E, 0x0C, 0x0C, 0x0C, 0x00, // Char 102 (f)\n\t0x00, 0x00, 0x7C, 0x66, 0x7C, 0x40, 0x3C, 0x00, // Char 103 (g)\n\t0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x00, // Char 104 (h)\n\t0x00, 0x18, 0x00, 0x1C, 0x18, 0x18, 0x3C, 0x00, // Char 105 (i)\n\t0x00, 0x30, 0x00, 0x30, 0x30, 0x30, 0x1E, 0x00, // Char 106 (j)\n\t0x00, 0x06, 0x06, 0x36, 0x1E, 0x36, 0x66, 0x00, // Char 107 (k)\n\t0x00, 0x1C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // Char 108 (l)\n\t0x00, 0x00, 0x66, 0xFE, 0xFE, 0xD6, 0xC6, 0x00, // Char 109 (m)\n\t0x00, 0x00, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x00, // Char 110 (n)\n\t0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 111 (o)\n\t0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x00, // Char 112 (p)\n\t0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00, // Char 113 (q)\n\t0x00, 0x00, 0x3E, 0x66, 0x06, 0x06, 0x06, 0x00, // Char 114 (r)\n\t0x00, 0x00, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x00, // Char 115 (s)\n\t0x00, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x70, 0x00, // Char 116 (t)\n\t0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, // Char 117 (u)\n\t0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // Char 118 (v)\n\t0x00, 0x00, 0xC6, 0xD6, 0xFE, 0x7C, 0x6C, 0x00, // Char 119 (w)\n\t0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, // Char 120 (x)\n\t0x00, 0x00, 0x66, 0x66, 0x7C, 0x60, 0x3C, 0x00, // Char 121 (y)\n\t0x00, 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x7E, 0x00, // Char 122 (z)\n\t0x00, 0x18, 0x08, 0x08, 0x04, 0x08, 0x08, 0x18, // Char 123 ({)\n\t0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, // Char 124 (|)\n\t0x00, 0x0C, 0x08, 0x08, 0x10, 0x08, 0x08, 0x0C, // Char 125 (})\n\t0x00, 0x00, 0x00, 0x4C, 0x32, 0x00, 0x00, 0x00  // Char 126 (~)\n};\n\nvoid gfx_clear_grey(u8 color)\n{\n\tmemset(gfx_ctxt.fb, color, gfx_ctxt.width * gfx_ctxt.height * 4);\n}\n\nvoid gfx_clear_partial_grey(u8 color, u32 pos_y, u32 height)\n{\n\tmemset(gfx_ctxt.fb + pos_y * gfx_ctxt.stride, color, height * 4 * gfx_ctxt.stride);\n}\n\nvoid gfx_clear_color(u32 color)\n{\n\tfor (u32 i = 0; i < gfx_ctxt.width * gfx_ctxt.height; i++)\n\t\tgfx_ctxt.fb[i] = color;\n}\n\nvoid gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride)\n{\n\tgfx_ctxt.fb = fb;\n\tgfx_ctxt.width = width;\n\tgfx_ctxt.height = height;\n\tgfx_ctxt.stride = stride;\n}\n\nvoid gfx_con_init()\n{\n\tgfx_con.gfx_ctxt = &gfx_ctxt;\n\tgfx_con.fntsz = 16;\n\tgfx_con.x = 0;\n\tgfx_con.y = 0;\n\tgfx_con.savedx = 0;\n\tgfx_con.savedy = 0;\n\tgfx_con.fgcol = TXT_CLR_DEFAULT;\n\tgfx_con.fillbg = 1;\n\tgfx_con.bgcol = TXT_CLR_BG;\n\tgfx_con.mute = 0;\n\n\tgfx_con_init_done = true;\n}\n\nvoid gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol)\n{\n\tgfx_con.fgcol = fgcol;\n\tgfx_con.fillbg = fillbg;\n\tgfx_con.bgcol = bgcol;\n}\n\nvoid gfx_con_getpos(u32 *x, u32 *y)\n{\n\t*x = gfx_con.x;\n\t*y = gfx_con.y;\n}\n\nvoid gfx_con_setpos(u32 x, u32 y)\n{\n\tgfx_con.x = x;\n\tgfx_con.y = y;\n}\n\nvoid gfx_putc(char c)\n{\n\t// Duplicate code for performance reasons.\n\tswitch (gfx_con.fntsz)\n\t{\n\tcase 16:\n\t\tif (c >= 32 && c <= 126)\n\t\t{\n\t\t\tu8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];\n\t\t\tu32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;\n\n\t\t\tfor (u32 i = 0; i < 16; i += 2)\n\t\t\t{\n\t\t\t\tu8 v = *cbuf;\n\t\t\t\tfor (u32 k = 0; k < 2; k++)\n\t\t\t\t{\n\t\t\t\t\tfor (u32 j = 0; j < 8; j++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (v & 1)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t*fb = gfx_con.fgcol;\n\t\t\t\t\t\t\tfb++;\n\t\t\t\t\t\t\t*fb = gfx_con.fgcol;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (gfx_con.fillbg)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t*fb = gfx_con.bgcol;\n\t\t\t\t\t\t\tfb++;\n\t\t\t\t\t\t\t*fb = gfx_con.bgcol;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tfb++;\n\t\t\t\t\t\tv >>= 1;\n\t\t\t\t\t\tfb++;\n\t\t\t\t\t}\n\t\t\t\t\tfb += gfx_ctxt.stride - 16;\n\t\t\t\t\tv = *cbuf;\n\t\t\t\t}\n\t\t\t\tcbuf++;\n\t\t\t}\n\t\t\tgfx_con.x += 16;\n\t\t}\n\t\telse if (c == '\\n')\n\t\t{\n\t\t\tgfx_con.x = 0;\n\t\t\tgfx_con.y += 16;\n\t\t\tif (gfx_con.y > gfx_ctxt.height - 16)\n\t\t\t\tgfx_con.y = 0;\n\t\t}\n\t\tbreak;\n\tcase 8:\n\tdefault:\n\t\tif (c >= 32 && c <= 126)\n\t\t{\n\t\t\tu8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];\n\t\t\tu32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;\n\t\t\tfor (u32 i = 0; i < 8; i++)\n\t\t\t{\n\t\t\t\tu8 v = *cbuf++;\n\t\t\t\tfor (u32 j = 0; j < 8; j++)\n\t\t\t\t{\n\t\t\t\t\tif (v & 1)\n\t\t\t\t\t\t*fb = gfx_con.fgcol;\n\t\t\t\t\telse if (gfx_con.fillbg)\n\t\t\t\t\t\t*fb = gfx_con.bgcol;\n\t\t\t\t\tv >>= 1;\n\t\t\t\t\tfb++;\n\t\t\t\t}\n\t\t\t\tfb += gfx_ctxt.stride - 8;\n\t\t\t}\n\t\t\tgfx_con.x += 8;\n\t\t}\n\t\telse if (c == '\\n')\n\t\t{\n\t\t\tgfx_con.x = 0;\n\t\t\tgfx_con.y += 8;\n\t\t\tif (gfx_con.y > gfx_ctxt.height - 8)\n\t\t\t\tgfx_con.y = 0;\n\t\t}\n\t\tbreak;\n\t}\n}\n\nvoid gfx_puts(const char *s)\n{\n\tif (!s || !gfx_con_init_done || gfx_con.mute)\n\t\treturn;\n\n\tfor (; *s; s++)\n\t\tgfx_putc(*s);\n}\n\nstatic void _gfx_putn(u32 v, int base, char fill, int fcnt)\n{\n\tstatic const char digits[] = \"0123456789ABCDEF\";\n\n\tchar *p;\n\tchar buf[65];\n\tint c = fcnt;\n\tbool negative = false;\n\n\tif (base != 10 && base != 16)\n\t\treturn;\n\n\t// Account for negative numbers.\n\tif (base == 10 && v & 0x80000000)\n\t{\n\t\tnegative = true;\n\t\tv = (int)v * -1;\n\t\tc--;\n\t}\n\n\tp = buf + 64;\n\t*p = 0;\n\tdo\n\t{\n\t\tc--;\n\t\t*--p = digits[v % base];\n\t\tv /= base;\n\t} while (v);\n\n\tif (negative)\n\t\t*--p = '-';\n\n\tif (fill != 0)\n\t{\n\t\twhile (c > 0 && p > buf)\n\t\t{\n\t\t\t*--p = fill;\n\t\t\tc--;\n\t\t}\n\t}\n\n\tgfx_puts(p);\n}\n\nvoid gfx_put_small_sep()\n{\n\tu8 prevFontSize = gfx_con.fntsz;\n\tgfx_con.fntsz = 8;\n\tgfx_putc('\\n');\n\tgfx_con.fntsz = prevFontSize;\n}\n\nvoid gfx_put_big_sep()\n{\n\tu8 prevFontSize = gfx_con.fntsz;\n\tgfx_con.fntsz = 16;\n\tgfx_putc('\\n');\n\tgfx_con.fntsz = prevFontSize;\n}\n\nvoid gfx_printf(const char *fmt, ...)\n{\n\tif (!gfx_con_init_done || gfx_con.mute)\n\t\treturn;\n\n\tva_list ap;\n\tint fill, fcnt;\n\n\tva_start(ap, fmt);\n\twhile (*fmt)\n\t{\n\t\tif (*fmt == '%')\n\t\t{\n\t\t\tfmt++;\n\t\t\tfill = 0;\n\t\t\tfcnt = 0;\n\t\t\tif ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ')\n\t\t\t{\n\t\t\t\tfcnt = *fmt;\n\t\t\t\tfmt++;\n\t\t\t\tif (*fmt >= '0' && *fmt <= '9')\n\t\t\t\t{\n\t\t\t\t\tfill = fcnt;\n\t\t\t\t\tfcnt = *fmt - '0';\n\t\t\t\t\tfmt++;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfill = ' ';\n\t\t\t\t\tfcnt -= '0';\n\t\t\t\t}\n\t\t\t}\n\t\t\tswitch(*fmt)\n\t\t\t{\n\t\t\tcase 'c':\n\t\t\t\tgfx_putc(va_arg(ap, u32));\n\t\t\t\tbreak;\n\t\t\tcase 's':\n\t\t\t\tgfx_puts(va_arg(ap, char *));\n\t\t\t\tbreak;\n\t\t\tcase 'd':\n\t\t\t\t_gfx_putn(va_arg(ap, u32), 10, fill, fcnt);\n\t\t\t\tbreak;\n\t\t\tcase 'p':\n\t\t\tcase 'P':\n\t\t\tcase 'x':\n\t\t\tcase 'X':\n\t\t\t\t_gfx_putn(va_arg(ap, u32), 16, fill, fcnt);\n\t\t\t\tbreak;\n\t\t\tcase 'k':\n\t\t\t\tgfx_con.fgcol = va_arg(ap, u32);\n\t\t\t\tbreak;\n\t\t\tcase 'K':\n\t\t\t\tgfx_con.bgcol = va_arg(ap, u32);\n\t\t\t\tgfx_con.fillbg = 1;\n\t\t\t\tbreak;\n\t\t\tcase '%':\n\t\t\t\tgfx_putc('%');\n\t\t\t\tbreak;\n\t\t\tcase '\\0':\n\t\t\t\tgoto out;\n\t\t\tdefault:\n\t\t\t\tgfx_putc('%');\n\t\t\t\tgfx_putc(*fmt);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tgfx_putc(*fmt);\n\t\tfmt++;\n\t}\n\n\tout:\n\tva_end(ap);\n}\n\nstatic void _gfx_cputs(u32 color, const char *s)\n{\n\tgfx_con.fgcol = color;\n\tgfx_puts(s);\n\tgfx_putc('\\n');\n\tgfx_con.fgcol = TXT_CLR_DEFAULT;\n}\n\nvoid gfx_wputs(const char *s) { _gfx_cputs(TXT_CLR_WARNING, s); }\nvoid gfx_eputs(const char *s) { _gfx_cputs(TXT_CLR_ERROR,   s); }\n\nvoid gfx_hexdump(u32 base, const void *buf, u32 len)\n{\n\tif (!gfx_con_init_done || gfx_con.mute)\n\t\treturn;\n\n\tu8 *buff = (u8 *)buf;\n\n\tu8 prevFontSize = gfx_con.fntsz;\n\tgfx_con.fntsz = 8;\n\tfor (u32 i = 0; i < len; i++)\n\t{\n\t\tif (i % 0x10 == 0)\n\t\t{\n\t\t\tif (i != 0)\n\t\t\t{\n\t\t\t\tgfx_puts(\"| \");\n\t\t\t\tfor (u32 j = 0; j < 0x10; j++)\n\t\t\t\t{\n\t\t\t\t\tu8 c = buff[i - 0x10 + j];\n\t\t\t\t\tif (c >= 32 && c <= 126)\n\t\t\t\t\t\tgfx_putc(c);\n\t\t\t\t\telse\n\t\t\t\t\t\tgfx_putc('.');\n\t\t\t\t}\n\t\t\t\tgfx_putc('\\n');\n\t\t\t}\n\t\t\tgfx_printf(\"%08x: \", base + i);\n\t\t}\n\t\tgfx_printf(\"%02x \", buff[i]);\n\t\tif (i == len - 1)\n\t\t{\n\t\t\tint ln = len % 0x10 != 0;\n\t\t\tu32 k = 0x10 - 1;\n\t\t\tif (ln)\n\t\t\t{\n\t\t\t\tk = (len & 0xF) - 1;\n\t\t\t\tfor (u32 j = 0; j < 0x10 - k; j++)\n\t\t\t\t\tgfx_puts(\"   \");\n\t\t\t}\n\t\t\tgfx_puts(\"| \");\n\t\t\tfor (u32 j = 0; j < (ln ? k : k + 1); j++)\n\t\t\t{\n\t\t\t\tu8 c = buff[i - k + j];\n\t\t\t\tif (c >= 32 && c <= 126)\n\t\t\t\t\tgfx_putc(c);\n\t\t\t\telse\n\t\t\t\t\tgfx_putc('.');\n\t\t\t}\n\t\t\tgfx_putc('\\n');\n\t\t}\n\t}\n\tgfx_putc('\\n');\n\tgfx_con.fntsz = prevFontSize;\n}\n\nstatic int abs(int x)\n{\n\tif (x < 0)\n\t\treturn -x;\n\treturn x;\n}\n\nvoid gfx_set_pixel(u32 x, u32 y, u32 color)\n{\n\tgfx_ctxt.fb[x + y * gfx_ctxt.stride] = color;\n}\n\nvoid gfx_line(int x0, int y0, int x1, int y1, u32 color)\n{\n\tint dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;\n\tint dy = abs(y1 - y0), sy = y0 < y1 ? 1 : -1;\n\tint err = (dx > dy ? dx : -dy) / 2, e2;\n\n\twhile (1)\n\t{\n\t\tgfx_set_pixel(x0, y0, color);\n\t\tif (x0 == x1 && y0 == y1)\n\t\t\tbreak;\n\t\te2 = err;\n\t\tif (e2 >-dx)\n\t\t{\n\t\t\terr -= dy;\n\t\t\tx0 += sx;\n\t\t}\n\t\tif (e2 < dy)\n\t\t{\n\t\t\terr += dx;\n\t\t\ty0 += sy;\n\t\t}\n\t}\n}\n\nvoid gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)\n{\n\tu32 pos = 0;\n\tfor (u32 y = pos_y; y < (pos_y + size_y); y++)\n\t{\n\t\tfor (u32 x = pos_x; x < (pos_x + size_x); x++)\n\t\t{\n\t\t\tmemset(&gfx_ctxt.fb[x + y*gfx_ctxt.stride], buf[pos], 4);\n\t\t\tpos++;\n\t\t}\n\t}\n}\n\n\nvoid gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)\n{\n\tu32 pos = 0;\n\tfor (u32 y = pos_y; y < (pos_y + size_y); y++)\n\t{\n\t\tfor (u32 x = pos_x; x < (pos_x + size_x); x++)\n\t\t{\n\t\t\tgfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[pos + 2] | (buf[pos + 1] << 8) | (buf[pos] << 16);\n\t\t\tpos+=3;\n\t\t}\n\t}\n}\n\nvoid gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)\n{\n\tu32 *ptr = (u32 *)buf;\n\tfor (u32 y = pos_y; y < (pos_y + size_y); y++)\n\t\tfor (u32 x = pos_x; x < (pos_x + size_x); x++)\n\t\t\tgfx_ctxt.fb[x + y * gfx_ctxt.stride] = *ptr++;\n}\n\nvoid gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)\n{\n\tfor (u32 y = pos_y; y < (pos_y + size_y); y++)\n\t{\n\t\tfor (u32 x = pos_x; x < (pos_x + size_x); x++)\n\t\t\tgfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[(size_y + pos_y - 1 - y ) * size_x + x - pos_x];\n\t}\n}\n"
  },
  {
    "path": "bootloader/gfx/gfx.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2021 CTCaer\n * Copyright (c) 2018 M4xw\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _GFX_H_\n#define _GFX_H_\n\n#include <bdk.h>\n\n#define TXT_CLR_BG        0xFF1B1B1B // Dark Grey.\n#define TXT_CLR_DEFAULT   0xFFCCCCCC // Light Grey.\n#define TXT_CLR_WARNING   0xFFFFDD00 // Yellow.\n#define TXT_CLR_ERROR     0xFFFF0000 // Red.\n#define TXT_CLR_CYAN_L    0xFF00CCFF // Light Cyan.\n#define TXT_CLR_TURQUOISE 0xFF00FFCC // Turquoise.\n#define TXT_CLR_ORANGE    0xFFFFBA00 // Orange.\n#define TXT_CLR_GREENISH  0xFF96FF00 // Toxic Green.\n#define TXT_CLR_GREEN_D   0xFF008800 // Dark Green.\n#define TXT_CLR_RED_D     0xFF880000 // Dark Red.\n#define TXT_CLR_GREY_D    0xFF303030 // Darkest Grey.\n#define TXT_CLR_GREY_DM   0xFF444444 // Darker Grey.\n#define TXT_CLR_GREY_M    0xFF555555 // Dark Grey.\n#define TXT_CLR_GREY      0xFF888888 // Grey.\n\n#define EPRINTF(text) gfx_eputs(text)\n#define EPRINTFARGS(text, args...) gfx_printf(\"%k\"text\"%k\\n\", TXT_CLR_ERROR,   args, TXT_CLR_DEFAULT)\n#define WPRINTF(text) gfx_wputs(text)\n#define WPRINTFARGS(text, args...) gfx_printf(\"%k\"text\"%k\\n\", TXT_CLR_WARNING, args, TXT_CLR_DEFAULT)\n\ntypedef struct _gfx_ctxt_t\n{\n\tu32 *fb;\n\tu32 width;\n\tu32 height;\n\tu32 stride;\n} gfx_ctxt_t;\n\ntypedef struct _gfx_con_t\n{\n\tgfx_ctxt_t *gfx_ctxt;\n\tu32 fntsz;\n\tu32 x;\n\tu32 y;\n\tu32 savedx;\n\tu32 savedy;\n\tu32 fgcol;\n\tint fillbg;\n\tu32 bgcol;\n\tbool mute;\n} gfx_con_t;\n\n// Global gfx console and context.\nextern gfx_ctxt_t gfx_ctxt;\nextern gfx_con_t gfx_con;\n\nvoid gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride);\nvoid gfx_clear_grey(u8 color);\nvoid gfx_clear_partial_grey(u8 color, u32 pos_y, u32 height);\nvoid gfx_clear_color(u32 color);\nvoid gfx_con_init();\nvoid gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol);\nvoid gfx_con_getpos(u32 *x, u32 *y);\nvoid gfx_con_setpos(u32 x, u32 y);\nvoid gfx_putc(char c);\nvoid gfx_puts(const char *s);\nvoid gfx_wputs(const char *s);\nvoid gfx_eputs(const char *s);\nvoid gfx_printf(const char *fmt, ...) /* __attribute__((format(printf, 1, 2))) */;\nvoid gfx_hexdump(u32 base, const void *buf, u32 len);\n\nvoid gfx_set_pixel(u32 x, u32 y, u32 color);\nvoid gfx_line(int x0, int y0, int x1, int y1, u32 color);\nvoid gfx_put_small_sep();\nvoid gfx_put_big_sep();\nvoid gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);\nvoid gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);\nvoid gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);\nvoid gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);\n\n#endif\n"
  },
  {
    "path": "bootloader/gfx/logos.c",
    "content": "/*\n * Copyright (c) 2018-2022 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <bdk.h>\n#include <libs/compr/blz.h>\n#include \"logos.h\"\n\n// 68 x 192 @8bpp Grayscale RAW.\n#define BOOTLOGO_WIDTH    68\n#define BOOTLOGO_HEIGHT   192\n#define BOOTLOGO_X        ((720  - BOOTLOGO_WIDTH)  / 2)\n#define BOOTLOGO_Y        ((1280 - BOOTLOGO_HEIGHT) / 2)\n#define BOOTLOGO_SIZE     13056\n#define BOOTLOGO_BLZ_SIZE 3988\n\nu8 bootlogo_blz[] = {\n\t0x0F, 0xF0, 0x80, 0x1B, 0x1B, 0x40, 0xF0, 0x1E, 0x1F, 0x48, 0x5A, 0x0F, 0xF0, 0x0F, 0xF0, 0xE4,\n\t0x17, 0xF0, 0x91, 0x13, 0x26, 0x28, 0x23, 0x1E, 0x0A, 0xA0, 0x0F, 0xF0, 0xC3, 0x22, 0xF0, 0xC3,\n\t0xA4, 0x1E, 0x29, 0x33, 0xDB, 0x2C, 0xEA, 0x53, 0x83, 0x0F, 0xF0, 0x38, 0xF0, 0xBC, 0x39, 0x21,\n\t0x22, 0xB0, 0x87, 0x20, 0x2F, 0x27, 0x3E, 0xDB, 0x35, 0x01, 0xA6, 0x69, 0xF2, 0x3C, 0xFD, 0x25,\n\t0x2D, 0x38, 0x77, 0x28, 0x15, 0x8A, 0x33, 0x45, 0xDB, 0x09, 0xEF, 0xBB, 0x44, 0xD0, 0xC0, 0x18,\n\t0xEF, 0x2E, 0x3B, 0xF5, 0x32, 0x25, 0x41, 0xC0, 0x83, 0x52, 0xE1, 0x07, 0xCD, 0x08, 0xF4, 0xF5,\n\t0x3B, 0x61, 0xB2, 0x95, 0xF1, 0x01, 0x10, 0xE7, 0xA3, 0x02, 0x95, 0x91, 0x3C, 0xFD, 0x41, 0x90,\n\t0x41, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x7F, 0x3D, 0x9B, 0xFA, 0x41, 0xF0, 0x41, 0xF0, 0x0F,\n\t0xF0, 0x26, 0xF0, 0x41, 0xF0, 0x41, 0xF0, 0xFE, 0x4C, 0xF0, 0x41, 0xF0, 0x41, 0xF0, 0x4D, 0xF5,\n\t0x95, 0x01, 0x9B, 0x02, 0xCD, 0x5D, 0x41, 0xF0, 0xFF, 0x41, 0xF0, 0x4D, 0xF5, 0x77, 0xC5, 0x18,\n\t0x93, 0xCD, 0x8D, 0x41, 0xF0, 0x41, 0xF0, 0xEB, 0x4D, 0xF5, 0x69, 0xFB, 0x6C, 0xF4, 0x41, 0xF0,\n\t0x4D, 0xF5, 0x65, 0x3F, 0x28, 0x01, 0x10, 0xBF, 0x03, 0x30, 0x00, 0x00, 0x2A, 0x2A, 0x2A, 0x30,\n\t0x45, 0x57, 0x03, 0xE4, 0x03, 0x41, 0xB0, 0xCD, 0xFD, 0x5D, 0x02, 0xCD, 0x1D, 0xC9, 0x1C, 0x2C,\n\t0x38, 0x3F, 0x3F, 0x01, 0x10, 0x03, 0x30, 0x00, 0x00, 0x41, 0x41, 0x41, 0x48, 0x0E, 0x56, 0x61,\n\t0xF5, 0x41, 0xED, 0xDF, 0xCD, 0xFD, 0x3D, 0xBB, 0x30, 0x2D, 0x6D, 0xB3, 0x6D, 0x4D, 0x15, 0x38,\n\t0x01, 0x10, 0xE1, 0xF6, 0xD0, 0x3C, 0x27, 0x41, 0xB0, 0xCD, 0xFD, 0xA4, 0xCD, 0x2D, 0xF0, 0x4E,\n\t0x6F, 0x6C, 0x01, 0x10, 0x03, 0x30, 0x00, 0x00, 0x73, 0x73, 0x73, 0x74, 0x75, 0x07, 0x72, 0x68,\n\t0x31, 0x22, 0x41, 0xD0, 0xA4, 0xF2, 0xCD, 0x3D, 0xE6, 0x1E, 0xF0, 0x36, 0x3D, 0x02, 0x20, 0x03,\n\t0x30, 0x00, 0x00, 0x40, 0x40, 0x40, 0x1C, 0x3F, 0x3A, 0x31, 0x84, 0x89, 0x21, 0x41, 0xF0, 0xB8,\n\t0xCB, 0x20, 0x68, 0x23, 0x26, 0x28, 0x2A, 0x2C, 0x2F, 0x2F, 0x2E, 0x00, 0x2B, 0x28, 0x28, 0x01,\n\t0x10, 0x27, 0x27, 0x27, 0x27, 0x08, 0x26, 0x24, 0x21, 0x08, 0x85, 0x41, 0xF0, 0xCB, 0xF8, 0x21,\n\t0x28, 0x38, 0x2F, 0x35, 0x38, 0x39, 0x36, 0x31, 0x2B, 0x24, 0x00, 0x1F, 0x1D, 0x01, 0x10, 0x1C,\n\t0x1C, 0x1C, 0xC3, 0x50, 0x41, 0xF0, 0xC4, 0x39, 0xF8, 0x40, 0x20, 0x2D, 0x3A, 0x56, 0xA8, 0xBE,\n\t0xBE, 0x03, 0xBE, 0xA7, 0x63, 0x34, 0x42, 0x40, 0x41, 0xF0, 0xB1, 0xF7, 0xA8, 0x02, 0xF0, 0xE5,\n\t0x06, 0x77, 0xB3, 0x8A, 0x08, 0x25, 0x30, 0x41, 0xAA, 0x11, 0xED, 0xD3, 0xAC, 0xA1, 0xAD, 0xCA,\n\t0xF5, 0xB2, 0x00, 0x39, 0x37, 0x33, 0x41, 0xF0, 0x41, 0xF0, 0x50, 0x49, 0x6D, 0x71, 0x03, 0x1B,\n\t0x5E, 0x20, 0x2D, 0x41, 0xAB, 0xE4, 0x80, 0x4E, 0x48, 0x00, 0x46, 0x4A, 0x53, 0x77, 0xE4, 0xBD,\n\t0x35, 0x24, 0x00, 0x44, 0x94, 0x41, 0xF0, 0x4D, 0xF5, 0x09, 0x15, 0x26, 0x3A, 0x7C, 0xF5, 0x0F,\n\t0x7F, 0x45, 0x37, 0x30, 0x2F, 0x32, 0x3F, 0x51, 0x00, 0x78, 0xF5, 0x74, 0x2D, 0xAE, 0x32, 0x41,\n\t0xF0, 0x4D, 0xF5, 0x9D, 0x6A, 0xF0, 0x1F, 0x2D, 0x45, 0xC1, 0xC1, 0x47, 0x30, 0x23, 0x00, 0x1F,\n\t0x1F, 0x21, 0x2A, 0x3D, 0x54, 0xC1, 0xBE, 0x00, 0x35, 0x22, 0x01, 0x10, 0x41, 0xF0, 0xA5, 0xF2,\n\t0x3D, 0x44, 0x15, 0x0A, 0x20, 0x7C, 0x33, 0x4C, 0xED, 0x88, 0x39, 0x24, 0x84, 0x10, 0x1F, 0x40,\n\t0x2F, 0x49, 0x8D, 0xED, 0x3B, 0x44, 0x0D, 0x41, 0xF0, 0x41, 0xF0, 0xE0, 0x64, 0x02, 0x27, 0x0B,\n\t0xBB, 0xB3, 0xB5, 0x13, 0x21, 0x37, 0x4F, 0x13, 0xF5, 0x49, 0x30, 0xED, 0x21, 0x1D, 0x28, 0x40,\n\t0x55, 0x08, 0xF5, 0x3F, 0x15, 0x40, 0x41, 0xF0, 0x2D, 0xF3, 0xAF, 0x07, 0x2D, 0x41, 0x50, 0xBC,\n\t0x42, 0x2C, 0xB8, 0x32, 0x24, 0x3B, 0x52, 0xF5, 0x40, 0x04, 0xB1, 0xF7, 0x1B, 0x41, 0xF0, 0x41,\n\t0xF0, 0x41, 0x41, 0xD0, 0x41, 0xF0, 0x41, 0xF0, 0xED, 0x79, 0xF7, 0x41, 0xF0, 0x41, 0xF0, 0xD0,\n\t0xD9, 0x8A, 0x8A, 0x8A, 0x8A, 0x0F, 0x8A, 0x93, 0xAC, 0x09, 0x50, 0x29, 0xB7, 0xF9, 0xF3, 0x41,\n\t0xF0, 0x8C, 0x0D, 0xF8, 0x81, 0x1F, 0x0F, 0x81, 0xBB, 0x81, 0x41, 0x10, 0x50, 0xF5, 0x22, 0x45,\n\t0x30, 0x70, 0x33, 0x29, 0x3F, 0x54, 0xF5, 0x46, 0x04, 0x30, 0x72, 0x23, 0x20, 0x71, 0xE3, 0xA5,\n\t0xF2, 0x3D, 0x20, 0x77, 0x9B, 0x3A, 0xAD, 0x16, 0x52, 0xF5, 0x52, 0x09, 0x00, 0x07, 0x10, 0x3B,\n\t0x4E, 0x31, 0x61, 0xF5, 0x54, 0x41, 0x35, 0x35, 0x35, 0x35, 0x00, 0x34, 0x30, 0x29, 0x21, 0x0D,\n\t0xF1, 0x41, 0xF0, 0x11, 0x4E, 0x36, 0x70, 0x50, 0xF5, 0xAF, 0x09, 0x00, 0x07, 0x10, 0xAA, 0xAF,\n\t0xB4, 0x18, 0xF5, 0xB1, 0xAC, 0xA9, 0xA9, 0xA9, 0xA9, 0xA8, 0x00, 0xA5, 0xA2, 0x99, 0xCE, 0x1D,\n\t0xF2, 0xA1, 0x22, 0x11, 0x3E, 0x30, 0x46, 0x3C, 0xC1, 0xC2, 0x09, 0x10, 0x06, 0x10, 0xC2, 0xC4,\n\t0xC5, 0xC3, 0x0C, 0xC1, 0xC0, 0xC0, 0xC0, 0xC0, 0xBF, 0xBD, 0xBA, 0x00, 0x2A, 0x41, 0xB0, 0x6D,\n\t0xF7, 0x41, 0x00, 0x8A, 0xA4, 0x3D, 0x8A, 0x0E, 0xA4, 0x95, 0x01, 0x27, 0x35, 0x43, 0x49, 0x09,\n\t0x00, 0x07, 0x10, 0xC2, 0x49, 0x4B, 0x4E, 0x4F, 0x4C, 0x49, 0x48, 0x48, 0x00, 0x48, 0x48, 0x46,\n\t0x40, 0x34, 0x51, 0x91, 0x41, 0xF0, 0x01, 0x10, 0xE0, 0xC7, 0x00, 0x9B, 0xBB, 0xB3, 0x4A, 0xC9,\n\t0x10, 0x25, 0x2C, 0x21, 0x01, 0x10, 0x06, 0x30, 0x31, 0x31, 0x31, 0x00, 0x00, 0x30, 0x30, 0x23,\n\t0x30, 0x2C, 0x27, 0xC9, 0x00, 0x41, 0xF0, 0xA1, 0xF2, 0x42, 0x40, 0x06, 0x60, 0xF8, 0x03, 0x30,\n\t0x00, 0x00, 0x1F, 0xDD, 0xA6, 0x41, 0xF0, 0xBF, 0xF3, 0x02, 0x20, 0xCD, 0xFD, 0xFB, 0x95, 0xF1,\n\t0x17, 0xD6, 0x62, 0x6D, 0x62, 0x2D, 0x90, 0x48, 0x29, 0x43, 0x2E, 0x03, 0x30, 0x03, 0x30, 0x00,\n\t0x00, 0x2F, 0x2F, 0x2F, 0x2B, 0x0E, 0x7D, 0xF8, 0x95, 0xF1, 0xB3, 0x9B, 0xAC, 0x95, 0x21, 0x1D,\n\t0x23, 0x23, 0x2F, 0x60, 0x66, 0x02, 0x20, 0x03, 0x30, 0x00, 0x00, 0x68, 0x68, 0x38, 0x68, 0x67,\n\t0x63, 0x5B, 0x27, 0x85, 0x10, 0x41, 0xF0, 0x0D, 0xF1, 0xE0, 0x39, 0x03, 0x28, 0x39, 0x07, 0x70,\n\t0x03, 0x30, 0x00, 0x00, 0xF5, 0xF5, 0x39, 0xF5, 0x2C, 0x20, 0x41, 0x90, 0x41, 0xF0, 0x27, 0x1B,\n\t0x25, 0x2B, 0xF5, 0x17, 0xF8, 0x34, 0x44, 0x4F, 0x02, 0x20, 0x03, 0x30, 0x00, 0x00, 0x52, 0x52,\n\t0x38, 0x52, 0x51, 0x49, 0x3A, 0x29, 0xE0, 0x12, 0x41, 0xF0, 0x2D, 0xF3, 0xE0, 0x42, 0x00, 0x20,\n\t0x28, 0x31, 0x38, 0x03, 0x30, 0x03, 0x30, 0x00, 0x00, 0xE1, 0x39, 0x39, 0x39, 0x34, 0x2C, 0x23,\n\t0xA9, 0xBF, 0xE9, 0xF2, 0xC0, 0xAC, 0x32, 0x4A, 0xBB, 0x3B, 0x27, 0x20, 0x21, 0xAC, 0xCF, 0x22,\n\t0x49, 0x22, 0xA9, 0xFF, 0xB5, 0xF3, 0xEA, 0x2F, 0x57, 0xAC, 0xAD, 0x63, 0x38, 0xF0, 0xCE, 0x41,\n\t0xF0, 0xDD, 0xFE, 0xA4, 0x9B, 0xA4, 0xBB, 0x81, 0x06, 0x60, 0x83, 0x37, 0xF0, 0x41, 0xF0, 0xD6,\n\t0xF5, 0xC3, 0x00, 0xD4, 0xC5, 0x1D, 0xF0, 0x41, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0x19, 0xF0,\n\t0x41, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x2D, 0xF0, 0x41, 0xF0, 0x03, 0x30, 0xFF, 0x00, 0x00, 0x6D,\n\t0x6D, 0xD9, 0xC1, 0x33, 0xF0, 0x41, 0xF0, 0x15, 0xFA, 0x03, 0x30, 0xF9, 0x23, 0xF0, 0x41, 0xF0,\n\t0x41, 0xF0, 0x19, 0xF0, 0xE2, 0x3F, 0x20, 0x91, 0xAD, 0x1B, 0x5F, 0x41, 0xF0, 0x24, 0xF0, 0xA6,\n\t0xD2, 0x24, 0x2A, 0x56, 0x26, 0x61, 0xD2, 0x87, 0x41, 0xF0, 0xF8, 0xCC, 0xD9, 0xC1, 0x2C, 0x39,\n\t0xF5, 0x31, 0x24, 0x07, 0x15, 0x90, 0x41, 0xF0, 0xA5, 0xF2, 0x15, 0xD0, 0x46, 0xF5, 0x15, 0x10,\n\t0x41, 0xF0, 0xCF, 0xE5, 0xF6, 0x57, 0xBB, 0x00, 0x00, 0x57, 0x57, 0x57, 0x77, 0x09, 0x7D, 0xC0,\n\t0x22, 0x38, 0x4D, 0xF5, 0x3F, 0xC9, 0x50, 0x41, 0xF0, 0xC1, 0xBC, 0xBC, 0xBB, 0x00, 0x00, 0xAC,\n\t0xAC, 0xAC, 0xA4, 0xA5, 0x92, 0x85, 0x41, 0xF0, 0x41, 0xF0, 0xD9, 0xF1, 0x41, 0xF0, 0x39, 0x4F,\n\t0xF5, 0x40, 0x0F, 0xCE, 0x14, 0x41, 0xF0, 0x41, 0xF0, 0xD5, 0x3D, 0x85, 0xF5, 0x37, 0x4B, 0xF5,\n\t0x1F, 0x3E, 0x46, 0x74, 0x41, 0xF0, 0x26, 0xF0, 0x15, 0xF0, 0x32, 0x44, 0xF5, 0x1E, 0x39, 0xEE,\n\t0x76, 0x1B, 0x41, 0xF0, 0xA5, 0xF2, 0x6D, 0xFC, 0x36, 0x7C, 0x3A, 0x2F, 0x23, 0x15, 0xB0, 0x41,\n\t0xF0, 0xA5, 0xF2, 0x71, 0xAB, 0x22, 0x28, 0x3C, 0x2A, 0x25, 0x1F, 0x15, 0x90, 0x41, 0xF0, 0xA5,\n\t0xF2, 0x11, 0xC0, 0x6E, 0x0C, 0xF8, 0xE3, 0xAE, 0x41, 0xF0, 0xA5, 0xF2, 0x41, 0xC0, 0x33, 0xF0,\n\t0x41, 0xF0, 0xA5, 0xF2, 0x0B, 0xB0, 0xFF, 0x33, 0xF0, 0x41, 0xF0, 0xA5, 0xF2, 0x0B, 0xB0, 0x33,\n\t0xF0, 0x41, 0xF0, 0xA5, 0xF2, 0x0A, 0xA0, 0xFF, 0x33, 0xF0, 0x41, 0xF0, 0xA5, 0xF2, 0x09, 0x90,\n\t0x1E, 0xF0, 0x41, 0xF0, 0xA5, 0xF2, 0x04, 0x40, 0xFF, 0x25, 0xF0, 0xD5, 0xF5, 0x41, 0xF0, 0x53,\n\t0xF2, 0x85, 0xFE, 0x4D, 0xF5, 0xE3, 0xFA, 0x81, 0x7F, 0x8A, 0x81, 0xA9, 0x3B, 0x1E, 0x21, 0x26,\n\t0x26, 0x23, 0x04, 0x1F, 0x1C, 0x33, 0xAD, 0x24, 0x28, 0x29, 0x26, 0x05, 0x89, 0x84, 0x41, 0xF0,\n\t0x47, 0x20, 0xB3, 0x93, 0x77, 0x8A, 0xB3, 0xA4, 0x03, 0x2D, 0x81, 0x24, 0x40, 0x41, 0x39, 0x28,\n\t0x1F, 0xCB, 0x18, 0x82, 0x21, 0x21, 0x20, 0x1E, 0x1B, 0x2A, 0x24, 0x68, 0x6A, 0x20, 0x62, 0x2B,\n\t0x3D, 0xA4, 0x41, 0xF0, 0x93, 0xA4, 0x58, 0x16, 0x2D, 0x4C, 0xA4, 0x93, 0x10, 0x10, 0x4C, 0x10,\n\t0x10, 0x23, 0x84, 0x09, 0x2B, 0x54, 0x35, 0x37, 0xBB, 0x07, 0x96, 0x1F, 0x4F, 0x2E, 0x00, 0x39,\n\t0x24, 0x2C, 0x41, 0xA0, 0x41, 0xF0, 0x55, 0x31, 0x3D, 0x2D, 0x23, 0x63, 0x18, 0x29, 0x34, 0x04,\n\t0xD7, 0x41, 0xC7, 0xC8, 0xC4, 0x31, 0x21, 0x0E, 0x5F, 0x46, 0x40, 0xA1, 0xB6, 0x55, 0xFE, 0x9A,\n\t0x52, 0x10, 0x70, 0x34, 0x64, 0xB2, 0x14, 0x6E, 0x2E, 0x00, 0xBF, 0x4D, 0xA5, 0xB2, 0x65, 0xFF,\n\t0xA5, 0x36, 0x6D, 0xAC, 0x10, 0x70, 0x34, 0x64, 0xCE, 0x2E, 0x40, 0x41, 0xF0, 0xD2, 0xD9, 0xBB,\n\t0x77, 0x2D, 0x1B, 0x2D, 0x07, 0x77, 0xBB, 0x6D, 0x10, 0x70, 0x34, 0x64, 0x2E, 0x40, 0x41, 0xF0,\n\t0x08, 0xE9, 0xF8, 0x98, 0x1E, 0xAC, 0x62, 0x41, 0xC0, 0x41, 0xF0, 0x41, 0xF0, 0x77, 0xC8, 0x41,\n\t0x60, 0xF9, 0x41, 0xF0, 0x41, 0xF0, 0x41, 0xF0, 0xB5, 0xF3, 0x07, 0x60, 0xA2, 0xF3, 0x41, 0xF0,\n\t0x71, 0xF3, 0xFF, 0x06, 0x20, 0x07, 0x40, 0x55, 0x32, 0x24, 0x24, 0x2B, 0x47, 0x03, 0x44, 0x09,\n\t0x41, 0xF0, 0x47, 0xBD, 0x8A, 0x81, 0x4A, 0x1B, 0x77, 0x07, 0xB3, 0xBB, 0xD5, 0x55, 0x06, 0x20,\n\t0x07, 0x40, 0x6B, 0x44, 0x05, 0x46, 0x5C, 0x5E, 0xBC, 0x08, 0x41, 0xF0, 0xC8, 0xB4, 0x93, 0x73,\n\t0x07, 0xAC, 0x62, 0x2E, 0x3D, 0x6D, 0xAC, 0x3D, 0x34, 0x06, 0x20, 0x07, 0x40, 0xD1, 0xCF, 0x38,\n\t0xCD, 0xCD, 0xCF, 0xD1, 0xD2, 0x41, 0xC0, 0x91, 0xF5, 0x77, 0x60, 0x80, 0x14, 0x8D, 0x15, 0x57,\n\t0xBB, 0xA5, 0x32, 0x40, 0xF0, 0x92, 0x52, 0x41, 0xF0, 0xF3, 0x41, 0xF0, 0x1D, 0x02, 0x3E, 0x6D,\n\t0x01, 0x10, 0x3D, 0xF0, 0x4C, 0x0A, 0x12, 0xB3, 0x41, 0xF0, 0x41, 0xF0, 0xF1, 0x1B, 0x61, 0x01,\n\t0x10, 0x29, 0xF3, 0x44, 0x21, 0x8F, 0xB7, 0x41, 0xF0, 0x03, 0x20, 0x61, 0x5B, 0x1F, 0x21, 0xFF,\n\t0x21, 0xFF, 0xD5, 0xF5, 0x03, 0x20, 0xF7, 0xAE, 0x27, 0xBB, 0x1B, 0xF6, 0x1F, 0x47, 0x51, 0x52,\n\t0x50, 0x09, 0x21, 0xAF, 0x4E, 0x4E, 0x4B, 0x44, 0x38, 0x65, 0x2F, 0x41, 0xF0, 0xC1, 0xB1, 0xF7,\n\t0x51, 0x04, 0x25, 0x32, 0x41, 0x45, 0x3F, 0x34, 0x03, 0x21, 0x0F, 0x03, 0x30, 0x00, 0x00, 0x1E,\n\t0x0F, 0x29, 0x28, 0x24, 0x02, 0x6A, 0x8F, 0x41, 0xF0, 0x45, 0xFD, 0x42, 0x34, 0x0F, 0x34, 0x24,\n\t0x01, 0x10, 0x03, 0x30, 0xCB, 0x00, 0x00, 0x1D, 0x35, 0x59, 0x41, 0xF0, 0x19, 0xF0, 0x34, 0xBF,\n\t0x1B, 0xF0, 0x41, 0xF0, 0xFD, 0x19, 0xF0, 0xB5, 0x83, 0x1E, 0xF0, 0x41, 0xF0, 0x1C, 0xF0, 0x21,\n\t0x9F, 0x2D, 0x83, 0x15, 0xF0, 0xFF, 0x41, 0xF0, 0x41, 0xF0, 0xA5, 0xF2, 0x91, 0xD5, 0x41, 0xF0,\n\t0x41, 0xF0, 0x57, 0x34, 0x3F, 0x00, 0x00, 0x03, 0x30, 0x00, 0x00, 0x26, 0x26, 0x26, 0x24, 0x21,\n\t0x07, 0x1E, 0x1C, 0x41, 0x80, 0x51, 0xF1, 0x99, 0xFE, 0x6D, 0x51, 0x04, 0x40, 0x9C, 0x45, 0x00,\n\t0x00, 0x45, 0x45, 0x45, 0x43, 0x3D, 0x32, 0x02, 0x26, 0x01, 0xDD, 0x38, 0xAC, 0xAA, 0x83, 0x41,\n\t0x50, 0xE1, 0xE1, 0x04, 0x40, 0x9E, 0xE0, 0x00, 0x00, 0xE0, 0xE0, 0xE0, 0xDF, 0xDE, 0xDA, 0x02,\n\t0x34, 0x22, 0x41, 0xC0, 0xC4, 0xA8, 0x4A, 0xB2, 0x73, 0x41, 0x50, 0x3E, 0xF0, 0xEC, 0x85, 0xF0,\n\t0xCD, 0xB0, 0x81, 0xDB, 0x31, 0x8A, 0xBB, 0x77, 0x41, 0x50, 0x8B, 0x3E, 0xF0, 0x69, 0xFB, 0xCA,\n\t0xD0, 0x57, 0xB2, 0x13, 0x9B, 0x3D, 0x65, 0x7F, 0x97, 0xDD, 0xFA, 0x41, 0xE1, 0xFA, 0xC7, 0xC0,\n\t0x8A, 0x9B, 0xB3, 0x6D, 0x0D, 0x41, 0x80, 0x7E, 0x76, 0x04, 0x40, 0x70, 0x00, 0x00, 0x70, 0x70,\n\t0x29, 0x70, 0x6E, 0x63, 0x4C, 0x35, 0xCC, 0x51, 0xF1, 0x81, 0xBB, 0x30, 0xBB, 0x6D, 0x01, 0x9D,\n\t0x6A, 0x4C, 0x04, 0x40, 0x40, 0x00, 0x00, 0xA4, 0x40, 0xD1, 0xD9, 0x41, 0xF0, 0xF5, 0x0F, 0xA4,\n\t0xAC, 0x62, 0x77, 0x0E, 0xE7, 0x02, 0xBD, 0x7C, 0x54, 0x30, 0x00, 0x00, 0x03, 0x30, 0x00, 0x00,\n\t0x22, 0x73, 0x22, 0x22, 0x21, 0x1F, 0xA5, 0xD2, 0x2D, 0xF3, 0x5F, 0x32, 0x79, 0x8C, 0xF0, 0x3A,\n\t0xD1, 0x1C, 0xF7, 0x83, 0x21, 0x2D, 0xF3, 0xAC, 0x57, 0xD7, 0x41, 0x95, 0xB3, 0x9B, 0x35, 0x1C,\n\t0xF1, 0x1B, 0x4F, 0x70, 0x46, 0x85, 0x61, 0x27, 0x6C, 0x25, 0x20, 0x6D, 0xD7, 0xD8, 0xA5, 0xCA,\n\t0x79, 0x9B, 0x7C, 0x7B, 0xB8, 0x70, 0xDC, 0xBD, 0x04, 0x34, 0x3E, 0x41, 0x80, 0x2B, 0xE5, 0x56,\n\t0x41, 0xF0, 0xC1, 0x05, 0xF9, 0x59, 0xF0, 0xF0, 0xEF, 0xDC, 0x60, 0x1D, 0x20, 0x21, 0x09, 0x05,\n\t0x4A, 0x6B, 0xB9, 0xE6, 0xFF, 0x39, 0xC9, 0x10, 0x81, 0x41, 0xF0, 0x3B, 0xF0, 0x59, 0x2A, 0x54,\n\t0x58, 0x49, 0x30, 0x21, 0x07, 0xC1, 0x50, 0x81, 0x04, 0xA4, 0x17, 0x26, 0xC5, 0x24, 0x41, 0xF0,\n\t0xC3, 0xF0, 0xF5, 0x17, 0xFB, 0x29, 0x32, 0x33, 0x2E, 0x24, 0x1E, 0xC1, 0x50, 0x7C, 0x40, 0xBC,\n\t0x80, 0x30, 0x09, 0xF5, 0xAC, 0xCF, 0xA9, 0x6F, 0x85, 0x20, 0x1F, 0x1F, 0x3E, 0x1F, 0xD3, 0x19,\n\t0x2F, 0x39, 0x49, 0xC1, 0x00, 0x2C, 0x63, 0x71, 0xE3, 0xE2, 0x5F, 0xBA, 0x00, 0x00, 0x5A, 0x0A,\n\t0x4A, 0x93, 0xBB, 0x77, 0x76, 0x53, 0x87, 0x24, 0x2B, 0x35, 0x42, 0x52, 0x98, 0xC1, 0x60, 0xF1,\n\t0x40, 0xC0, 0x90, 0x4D, 0xE9, 0xF2, 0x1B, 0x1B, 0xCE, 0xF9, 0x9B, 0x48, 0x3D, 0xEE, 0x32, 0x22,\n\t0x28, 0x31, 0x3E, 0x4D, 0x7B, 0x02, 0xBC, 0xF0, 0x1C, 0x62, 0xA6, 0x6C, 0x55, 0x42, 0x61, 0xF2,\n\t0x84, 0xD2, 0xF9, 0x93, 0xB3, 0x54, 0x1A, 0x45, 0x2D, 0x37, 0x47, 0x69, 0x19, 0xB0, 0xE0, 0x94,\n\t0x51, 0xDA, 0x36, 0x00, 0x6A, 0x45, 0x30, 0x14, 0x27, 0x21, 0x91, 0xA5, 0x41, 0xF0, 0xBF, 0x1C,\n\t0x93, 0x3D, 0x51, 0x61, 0x9C, 0x92, 0xCF, 0xF8, 0x3E, 0x60, 0x88, 0x7F, 0x51, 0x11, 0x30, 0x48,\n\t0x1F, 0x1D, 0x41, 0xF0, 0x4D, 0xC9, 0x9B, 0xAC, 0x62, 0xA1, 0x66, 0x8C, 0x32, 0x56, 0x11, 0x41,\n\t0xDA, 0xB7, 0x7C, 0x5F, 0x55, 0x04, 0x62, 0xC9, 0x10, 0x50, 0x41, 0x00, 0x41, 0xF0, 0x93, 0xB5,\n\t0xBB, 0x81, 0x3A, 0xC6, 0x54, 0x41, 0x60, 0xF8, 0xC1, 0x8A, 0x77, 0x5F, 0x4A, 0x03, 0x39, 0x35,\n\t0x41, 0x60, 0x41, 0xF0, 0x84, 0xA4, 0xBB, 0x9B, 0xD5, 0x65, 0x9C, 0x2D, 0x13, 0x89, 0x4D, 0xDA,\n\t0xAC, 0x6E, 0x49, 0x39, 0x34, 0x03, 0x49, 0x74, 0x41, 0x40, 0x41, 0xF0, 0xE0, 0xFE, 0x4D, 0x55,\n\t0x1F, 0x32, 0x3C, 0x57, 0xD1, 0xD1, 0x40, 0xF8, 0xD6, 0x9E, 0x52, 0x61, 0x04, 0x7C, 0xC6, 0xA8,\n\t0x41, 0xF0, 0x3B, 0xF0, 0x1D, 0x12, 0x3E, 0x5B, 0x80, 0x1E, 0xD1, 0x60, 0xF8, 0xD1, 0xB0, 0x3A,\n\t0x00, 0x55, 0x2F, 0x14, 0x8E, 0x91, 0x1B, 0x41, 0xF0, 0x95, 0xF1, 0x29, 0x38, 0xD1, 0x00, 0x8F,\n\t0xC1, 0x26, 0xF1, 0x8A, 0x75, 0x69, 0x43, 0x2F, 0x27, 0x21, 0x42, 0x30, 0x82, 0x41, 0xF0, 0x3A,\n\t0xF0, 0x68, 0x2B, 0xD1, 0x90, 0x98, 0x22, 0xB9, 0x72, 0x41, 0x1F, 0xF5, 0x23, 0x41, 0xF0, 0x3C,\n\t0xF0, 0xD1, 0xA0, 0x54, 0x67, 0x82, 0xB8, 0x0F, 0xE1, 0xAF, 0x53, 0xE6, 0xAF, 0xC5, 0x24, 0x41,\n\t0xF0, 0x3B, 0xF0, 0xD1, 0x90, 0xF2, 0x2F, 0x3B, 0x49, 0x5B, 0x6C, 0x90, 0xC1, 0xF1, 0x00, 0xC5,\n\t0x54, 0x1D, 0x32, 0x41, 0xF0, 0x39, 0xF0, 0xD1, 0x80, 0x23, 0x29, 0x33, 0x1F, 0x3F, 0x4F, 0x61,\n\t0x72, 0xA5, 0xD2, 0x95, 0xB1, 0x41, 0xF0, 0xC0, 0x40, 0xF0, 0xE1, 0x0D, 0xC4, 0x5D, 0x1F, 0x25,\n\t0x2C, 0x36, 0x44, 0x07, 0x55, 0x68, 0x83, 0xC1, 0xE9, 0x51, 0x41, 0x41, 0xF0, 0xAF, 0xF3, 0xE0,\n\t0xD1, 0x19, 0x25, 0x27, 0x23, 0x1E, 0x25, 0xE0, 0x3F, 0x21, 0x27, 0x31, 0x30, 0x3B, 0x4D, 0x65,\n\t0x79, 0x9C, 0xDE, 0x99, 0xDE, 0x80, 0x15, 0xFA, 0x00, 0x00, 0x8A, 0x8A, 0x8A, 0x8A, 0x49, 0x19,\n\t0x35, 0x43, 0xA9, 0x36, 0x2A, 0x2E, 0x52, 0xD9, 0x22, 0x27, 0x35, 0x4F, 0x18, 0x6B, 0x99, 0xEF,\n\t0x44, 0x41, 0xB0, 0x7D, 0xF8, 0xB3, 0x81, 0x30, 0xE9, 0x52, 0x20, 0x31, 0x4B, 0xFF, 0xB2, 0x43,\n\t0x2C, 0x01, 0x21, 0xE9, 0x61, 0x1D, 0x21, 0x2B, 0x40, 0x5E, 0xBF, 0x02, 0x9D, 0xEA, 0x41, 0xF0,\n\t0x69, 0x3F, 0x71, 0x33, 0x60, 0x98, 0x00, 0x49, 0x30, 0x2F, 0x16, 0x59, 0x1E, 0x24, 0x31, 0x48,\n\t0x80, 0x42, 0x11, 0x4A, 0x41, 0x91, 0xB5, 0x51, 0xF1, 0x31, 0x81, 0x3D, 0x1C, 0x15, 0xE7, 0x6F,\n\t0x34, 0x17, 0x25, 0x1E, 0x44, 0x41, 0x52, 0xA8, 0xF8, 0xF5, 0x37, 0x41, 0xF0, 0xC4, 0x0E, 0xAE,\n\t0x70, 0x5B, 0x45, 0x1D, 0x89, 0x2D, 0xF0, 0x81, 0x39, 0x27, 0x0F, 0x1F, 0x1C, 0x1D, 0x22, 0x2E,\n\t0x42, 0x6E, 0xD8, 0x00, 0x82, 0x20, 0xD5, 0x3F, 0xF5, 0xB7, 0x41, 0xF0, 0xB3, 0x6D, 0x8A, 0x39,\n\t0x99, 0xBD, 0x1C, 0x54, 0xAE, 0xD2, 0x10, 0xF8, 0x9D, 0x3D, 0x29, 0x09, 0x22, 0x27, 0x35, 0x4D,\n\t0x90, 0xF0, 0x18, 0x22, 0xA9, 0x40, 0x4F, 0x30, 0xF5, 0x27, 0x41, 0xF0, 0xC4, 0x7C, 0x8D, 0x69,\n\t0x1D, 0x27, 0x3C, 0x3C, 0x60, 0x9B, 0x57, 0x11, 0xFF, 0xB6, 0x46, 0x39, 0x08, 0x41, 0x5A, 0xC7,\n\t0x40, 0x20, 0xE1, 0x84, 0x4D, 0x34, 0x08, 0x24, 0xF5, 0xB7, 0x71, 0xF3, 0x8A, 0x2D, 0x42, 0x70,\n\t0x29, 0x3E, 0x26, 0x5B, 0x85, 0x05, 0x20, 0xCE, 0x65, 0x86, 0xE9, 0x7F, 0x20, 0x84, 0xBF, 0x60,\n\t0x43, 0x2F, 0x23, 0xC5, 0x10, 0x41, 0xF0, 0xE9, 0xF2, 0xE0, 0x68, 0x3B, 0x28, 0x39, 0x55, 0x75,\n\t0x56, 0x21, 0xE9, 0x82, 0x20, 0xA1, 0xE9, 0x94, 0x52, 0xEC, 0x02, 0x25, 0xDB, 0x61, 0xF2, 0x42,\n\t0xA0, 0x1E, 0x78, 0x25, 0x34, 0x4F, 0x70, 0xC1, 0x4B, 0x51, 0xC9, 0x64, 0x20, 0x47, 0x31, 0x25,\n\t0x1E, 0x41, 0xE0, 0x85, 0xF0, 0x9B, 0x2D, 0x30, 0x1B, 0x90, 0x1D, 0x22, 0x30, 0x49, 0x6A, 0xAF,\n\t0xF8, 0x01, 0xCB, 0x10, 0xF1, 0xA5, 0x5F, 0x3E, 0x2B, 0x21, 0x1D, 0x01, 0xD1, 0xE9, 0x41, 0xF0,\n\t0xBC, 0x0C, 0x3B, 0x34, 0x28, 0x17, 0x1F, 0x21, 0x23, 0x1F, 0x25, 0x2A, 0x36, 0x4C, 0x6C, 0x9D,\n\t0xF1, 0x42, 0x10, 0x80, 0x99, 0x51, 0x34, 0x28, 0x25, 0x24, 0x24, 0x22, 0x00, 0x20, 0x1E, 0x49,\n\t0xC9, 0x8D, 0xF9, 0x8B, 0x39, 0xA1, 0x16, 0x21, 0x2B, 0x3C, 0x37, 0x3D, 0x41, 0x41, 0x45, 0x4F,\n\t0x63, 0x7C, 0x00, 0x8A, 0xE9, 0x42, 0x10, 0x8C, 0x4C, 0x42, 0x40, 0x40, 0x04, 0x3F, 0x39, 0x30,\n\t0x25, 0x1E, 0x0C, 0x30, 0x41, 0xF0, 0xE5, 0xF6, 0xE0, 0x2B, 0x41, 0xC8, 0xCC, 0xCD, 0xCD, 0xCE,\n\t0xCF, 0x00, 0xD0, 0xD2, 0xD2, 0xD2, 0x37, 0x10, 0xF8, 0xD0, 0xCE, 0x10, 0xCD, 0xCD, 0xCD, 0xCA,\n\t0xC4, 0x31, 0xD9, 0x11, 0x41, 0xF0, 0xC0, 0x5B, 0xF2, 0xEC, 0x51, 0xFF, 0x3D, 0xF0, 0xD9, 0xF1,\n\t0xD8, 0xE1, 0x81, 0x8A, 0x3B, 0x81, 0xDA, 0x01, 0x9D, 0x1A, 0x66, 0x00, 0x00, 0x3E, 0xF0, 0x9D,\n\t0xFA, 0x2F, 0xE7, 0xF6, 0xB3, 0x93, 0x77, 0x8A, 0xB3, 0x3B, 0x10, 0x20, 0x38, 0x20, 0x5F, 0x01,\n\t0x10, 0xF5, 0xF3, 0x43, 0xE5, 0x36, 0x41, 0xF0, 0x25, 0x52, 0xA4, 0x76, 0x09, 0x19, 0x2D, 0x3D,\n\t0x14, 0x1F, 0x2F, 0x49, 0x99, 0xA1, 0x05, 0x02, 0x20, 0x03, 0x30, 0x00, 0x00, 0xA4, 0xA4, 0xA4,\n\t0xA3, 0x9D, 0x07, 0x8E, 0x36, 0x23, 0x41, 0x70, 0x41, 0xF0, 0x41, 0x14, 0xE5, 0x76, 0x26, 0x78,\n\t0x35, 0x45, 0x4F, 0x52, 0x4F, 0x03, 0x30, 0x4E, 0x00, 0x00, 0xA0, 0x4E, 0x4E, 0x4E, 0x4F, 0x52,\n\t0x52, 0x4B, 0x3C, 0x00, 0x2A, 0x41, 0x00, 0x41, 0xF0, 0xA5, 0xF2, 0xA1, 0x16, 0x24, 0x30, 0x3D,\n\t0x1E, 0x41, 0x3C, 0x32, 0x2D, 0x2A, 0xC0, 0x44, 0x2A, 0x2A, 0x20, 0x2A, 0x2B, 0x31, 0x3A, 0x44,\n\t0x42, 0x39, 0x28, 0x00, 0x09, 0xA5, 0x41, 0xF0, 0xAC, 0x30, 0x37, 0x6D, 0x05, 0x09, 0x1F, 0x2A,\n\t0x2B, 0x3F, 0xB1, 0xB2, 0xAD, 0x31, 0x23, 0x1D, 0x1E, 0x00, 0x20, 0x26, 0x8A, 0x04, 0x22, 0x1F,\n\t0x1D, 0x1D, 0x20, 0x04, 0x2D, 0x44, 0xC8, 0xC8, 0xC5, 0x32, 0x21, 0x41, 0xC0, 0x80, 0xA8, 0xE6,\n\t0x77, 0x2D, 0x1B, 0x2D, 0x77, 0xE5, 0x16, 0x20, 0x41, 0x34, 0x57, 0x10, 0x00, 0x3E, 0x25, 0x30,\n\t0x18, 0x68, 0x6A, 0x24, 0x43, 0x28, 0x20, 0x35, 0x5A, 0x2E, 0x00, 0x40, 0x09, 0x75, 0x41, 0xF0,\n\t0xD1, 0xB5, 0x27, 0xAC, 0x4A, 0x05, 0xAC, 0x62, 0x1B, 0xE9, 0x22, 0x10, 0x20, 0xC5, 0x30, 0x18,\n\t0x43, 0x48, 0x21, 0x3C, 0x6B, 0x2E, 0x00, 0xE9, 0xF2, 0x95, 0xF5, 0xE3, 0x3D, 0xA3, 0x16, 0x10,\n\t0x70, 0x30, 0x08, 0x74, 0x18, 0x46, 0x28, 0x4E, 0x22, 0x9E, 0x61, 0xF2, 0x95, 0xF1, 0x22, 0xF6,\n\t0x14, 0x02, 0x6E, 0x07, 0x00, 0x4D, 0x29, 0x2F, 0x2E, 0x20, 0x41, 0xF0, 0x2D, 0xF3, 0x22, 0x40,\n\t0x93, 0x10, 0x30, 0x41, 0xF0, 0x41, 0xF0, 0xEF, 0xC9, 0xF0, 0x80, 0x44, 0xBB, 0x10, 0x50, 0x41,\n\t0xF0, 0x41, 0xF0, 0x4F, 0xC5, 0xBB, 0x7B, 0x4C, 0x35, 0xB3, 0xA4, 0x10, 0x70, 0x07, 0x60, 0x2E,\n\t0x40, 0x41, 0xF0, 0xA8, 0xB2, 0xF9, 0x6D, 0xBB, 0x00, 0x00, 0x6D, 0x7A, 0x08, 0x2D, 0x41, 0x20,\n\t0x06, 0x20, 0xD4, 0xD5, 0x65, 0xCB, 0x25, 0x41, 0xF0, 0x51, 0xF1, 0x41, 0xA0, 0x06, 0x20, 0xD5,\n\t0x65, 0xCB, 0x25, 0xFF, 0x41, 0xA0, 0x41, 0xF0, 0x41, 0xF0, 0x06, 0x20, 0xD5, 0x65, 0xCB, 0x25,\n\t0x41, 0xB0, 0x41, 0xF0, 0xFF, 0xCE, 0xF4, 0x40, 0xF0, 0x33, 0x24, 0x41, 0x80, 0x41, 0xF0, 0x9A,\n\t0x21, 0x2D, 0x8A, 0x3F, 0xAC, 0x98, 0x16, 0x22, 0x3F, 0x6F, 0x01, 0x10, 0x3D, 0xF0, 0x4E, 0x62,\n\t0x29, 0x41, 0x90, 0x41, 0xF0, 0x8A, 0xAC, 0x4A, 0x1B, 0x9B, 0x06, 0xA4, 0x6D, 0xA4, 0x93, 0x1D,\n\t0x12, 0x69, 0x01, 0x10, 0xD5, 0xF1, 0xD0, 0x49, 0x1D, 0xC2, 0x85, 0xF0, 0x3D, 0x00, 0x3D, 0x1B,\n\t0x3D, 0xD5, 0x45, 0x8E, 0xD5, 0xF5, 0xD5, 0xF5, 0x41, 0xF0, 0xC7, 0x00, 0x7D, 0x14, 0xBB, 0xD5,\n\t0x25, 0xD5, 0xF5, 0xDF, 0xD5, 0xF5, 0x41, 0xF0, 0x44, 0x00, 0x8A, 0x8A, 0xCB, 0x15, 0xD5, 0x85,\n\t0xD5, 0xF5, 0xE7, 0x41, 0xF0, 0x3A, 0xB4, 0x93, 0xBB, 0x4A, 0x1B, 0x4A, 0xA4, 0x03, 0x77, 0xB5,\n\t0x13, 0x22, 0x28, 0x2A, 0x03, 0x30, 0x03, 0x30, 0x00, 0x00, 0xE2, 0x2B, 0x2B, 0x2B, 0x28, 0x24,\n\t0x1F, 0x1D, 0xD2, 0x23, 0xE2, 0xC0, 0x77, 0x4A, 0x9F, 0x12, 0xDA, 0x11, 0x23, 0x2E, 0x3A, 0x41,\n\t0x0C, 0x02, 0x20, 0x03, 0x30, 0x00, 0x00, 0x45, 0x45, 0x45, 0x43, 0x3D, 0x07, 0x32, 0x26, 0x95,\n\t0x11, 0x41, 0xF0, 0x3B, 0xF0, 0x0D, 0x11, 0x45, 0xDC, 0x3C, 0xDF, 0x02, 0x20, 0x03, 0x30, 0x00,\n\t0x00, 0xE0, 0xE0, 0xE0, 0xDF, 0x0E, 0xDE, 0xDA, 0x0D, 0x21, 0x41, 0xF0, 0xC3, 0xF0, 0x85, 0x10,\n\t0x5D, 0x01, 0x10, 0xBC, 0x3D, 0xF0, 0x41, 0x26, 0x41, 0x90, 0x41, 0xF0, 0x00, 0x00, 0x00, 0x00,\n\t0x57, 0x79, 0x57, 0x24, 0x03, 0x21, 0x3B, 0x67, 0x01, 0x10, 0x3D, 0xF0, 0x48, 0x62, 0x71, 0xA3,\n\t0x41, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xBB, 0xBB, 0x85, 0x00, 0x20, 0x4F, 0x37, 0x5E, 0x01, 0x10,\n\t0xE5, 0xF2, 0x42, 0x27, 0x01, 0x10, 0x41, 0xF0, 0xCC, 0x16, 0xC2, 0xA4, 0x81, 0xA5, 0x02, 0x2D,\n\t0x46, 0x7E, 0x8A, 0x09, 0x09, 0x10, 0x8E, 0x92, 0x61, 0x12, 0x94, 0x90, 0x8C, 0x8C, 0x09, 0x8C,\n\t0x8C, 0x8C, 0x8B, 0x83, 0x71, 0x34, 0x22, 0x00, 0x41, 0xF0, 0x1B, 0x3D, 0xF0, 0x3D, 0x41, 0x00,\n\t0x1D, 0x23, 0x2F, 0x15, 0x3B, 0x43, 0x09, 0x10, 0x4C, 0x63, 0x7C, 0x41, 0x00, 0x6F, 0x44, 0x52,\n\t0x47, 0x47, 0x47, 0x47, 0x47, 0x45, 0x3F, 0x00, 0x33, 0x27, 0x1D, 0x62, 0x41, 0xF0, 0x9A, 0xD2,\n\t0x1D, 0x20, 0x23, 0x1C, 0x25, 0x09, 0x10, 0x2D, 0x49, 0x74, 0x41, 0x00, 0x57, 0x34, 0x22, 0x27,\n\t0x27, 0x27, 0x27, 0x27, 0x26, 0x24, 0x21, 0x00, 0x1E, 0x1C, 0x41, 0xF0, 0x1B, 0x68, 0xF0, 0x6D,\n\t0x56, 0x32, 0x0B, 0x30, 0xD4, 0x23, 0x0D, 0x21, 0x50, 0x2B, 0x00, 0x00, 0x1C, 0x1C, 0x1C, 0x12,\n\t0x1C, 0x41, 0xC0, 0x41, 0xF0, 0x00, 0x00, 0x9B, 0x9B, 0x9B, 0xA4, 0x0E, 0xBB, 0xCF, 0x31, 0x41,\n\t0xF0, 0x41, 0xF0, 0x41, 0xF0, 0x00, 0x00, 0x77, 0x77, 0x3E, 0x77, 0x6D, 0x3D, 0x11, 0x50, 0x41,\n\t0xF0, 0x41, 0xF0, 0x41, 0xF0, 0x17, 0xF0, 0xF8, 0x22, 0x40, 0x70, 0x41, 0x00, 0x4F, 0x2A, 0x16,\n\t0xF0, 0x41, 0xF0, 0xC8, 0x4F, 0xF3, 0x0B, 0x30, 0x24, 0x41, 0x71, 0x41, 0x00, 0x51, 0x2B, 0x23,\n\t0x00, 0x00, 0x1D, 0x1D, 0x81, 0x93, 0x41, 0xF0, 0xDF, 0x21, 0x62, 0x03, 0x10, 0xB9, 0x62, 0x2D,\n\t0x1E, 0x22, 0x1F, 0x24, 0x29, 0x2E, 0x09, 0x10, 0x84, 0x35, 0x50, 0x78, 0x41, 0x00, 0x5D, 0x3C,\n\t0x00, 0x00, 0x2F, 0x48, 0x2F, 0x2F, 0x2B, 0x26, 0x20, 0xD9, 0xE1, 0x40, 0xA0, 0xBB, 0x60, 0xB3,\n\t0x7D, 0x20, 0xB3, 0x77, 0x85, 0x22, 0x35, 0x6A, 0x72, 0x12, 0x09, 0x10, 0x78, 0x88, 0x94, 0x38,\n\t0x00, 0x8E, 0x7D, 0x75, 0x11, 0x75, 0x75, 0x75, 0x75, 0x74, 0x6D, 0x62, 0x2B, 0x00, 0x1F, 0x0C,\n\t0x60, 0x41, 0xF0, 0x77, 0xAC, 0x57, 0x42, 0x50, 0x77, 0x46, 0xC9, 0x00, 0x30, 0x4F, 0x01, 0x10,\n\t0x3D, 0xF0, 0x39, 0xE8, 0x71, 0x41, 0xF0, 0xD9, 0xB3, 0x6D, 0x24, 0x50, 0x57, 0xAC, 0x21, 0x00,\n\t0x39, 0x63, 0x24, 0x01, 0x10, 0x3D, 0xF0, 0x45, 0x0C, 0x10, 0x41, 0xF0, 0x41, 0xF0, 0x21, 0x00,\n\t0x3A, 0x7B, 0x65, 0x07, 0x70, 0x03, 0x30, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x47, 0x0E, 0x28, 0x41,\n\t0xE0, 0x08, 0x80, 0x34, 0x70, 0xBB, 0x1B, 0x1B, 0x1F, 0x0E, 0x33, 0x55, 0xE0, 0x05, 0x50, 0x03,\n\t0x30, 0x00, 0x00, 0xE1, 0xE1, 0x38, 0xE1, 0xDD, 0x3D, 0x25, 0x0C, 0x60, 0x41, 0xF0, 0xA4, 0x8A,\n\t0x30, 0x24, 0x50, 0x81, 0xA4, 0x31, 0x01, 0x28, 0x3C, 0x52, 0x60, 0x09, 0x02, 0x20, 0x03, 0x30,\n\t0x00, 0x00, 0x65, 0x65, 0x65, 0x63, 0x58, 0x07, 0x45, 0x2F, 0x20, 0x41, 0xC0, 0x42, 0xA0, 0xBB,\n\t0x81, 0x3D, 0x18, 0x22, 0x10, 0x2D, 0x81, 0xBB, 0x57, 0x31, 0x11, 0x28, 0x30, 0x21, 0x36, 0x02,\n\t0x20, 0x03, 0x30, 0x00, 0x00, 0x39, 0x39, 0x39, 0x37, 0x0E, 0x32, 0x2B, 0x22, 0x40, 0x70, 0x21,\n\t0x34, 0x47, 0xDB, 0x08, 0x3A, 0x28, 0x43, 0xB0, 0x9B, 0xBB, 0xB3, 0xAC, 0xAC, 0x04, 0xB3, 0xBB,\n\t0xA4, 0x3F, 0x20, 0x1C, 0x1E, 0x1F, 0x04, 0x40, 0x88, 0x03, 0x30, 0x00, 0x00, 0x20, 0x20, 0x20,\n\t0x1F, 0x1F, 0xD9, 0x80, 0x83, 0x20, 0x32, 0x44, 0xDB, 0x38, 0x26, 0x12, 0xC0, 0x4A, 0x40, 0x62,\n\t0x6D, 0x6D, 0x62, 0x4A, 0x02, 0x20, 0x0F, 0xF0, 0x15, 0xF0, 0xE0, 0x20, 0x2E, 0x3B, 0xDB, 0x32,\n\t0x24, 0x05, 0x50, 0x0F, 0xF0, 0xC0, 0x0F, 0xF0, 0x15, 0xF0, 0x1E, 0x26, 0x2E, 0x31, 0x29, 0x20,\n\t0x03, 0x06, 0x60, 0x0F, 0xF0, 0x26, 0xF0, 0x42, 0xF0, 0x20, 0x23, 0x24, 0x20, 0x0F, 0x1D, 0x06,\n\t0x60, 0x0F, 0xF0, 0x0F, 0xF0, 0x13, 0xF0, 0x1C, 0x1D, 0x1D, 0x1E, 0x1C, 0x00, 0x00, 0x09, 0x90,\n\t0x03, 0x30, 0x00, 0x00, 0x1B, 0x1B, 0x1B, 0x1E, 0x94, 0x0F, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x6C, 0x23, 0x00, 0x00\n};\n\nu8 battery_icons_blz[] = {\n\t0x17, 0xC0, 0x5D, 0x51, 0x79, 0x12, 0x79, 0x48, 0x69, 0x00, 0x0D, 0x46, 0xE3, 0x0F, 0xF0, 0x20,\n\t0xF0, 0x35, 0x2E, 0x38, 0x3F, 0x40, 0xEF, 0xCF, 0x00, 0x89, 0x77, 0x00, 0x17, 0x01, 0x14, 0x09,\n\t0x90, 0x36, 0xF0, 0xA4, 0xF1, 0x62, 0x01, 0x38, 0xA1, 0x99, 0x84, 0x3E, 0x00, 0x23, 0x1F, 0x04,\n\t0x40, 0x3B, 0xF0, 0x5B, 0x4F, 0x00, 0x18, 0x25, 0x20, 0x24, 0x90, 0x57, 0x00, 0x3C, 0xC0, 0x7B,\n\t0x00, 0x63, 0x10, 0x31, 0x7C, 0x2B, 0x03, 0x30, 0x3C, 0xF0, 0xA2, 0x00, 0xCE, 0x11, 0x0F, 0x0D,\n\t0x21, 0x00, 0x9E, 0xDE, 0x00, 0x06, 0x40, 0x60, 0xF0, 0xB9, 0xA0, 0xEA, 0x70, 0x3C, 0xF0, 0xF5,\n\t0x67, 0xD4, 0x3E, 0x01, 0x54, 0x00, 0x00, 0x00, 0x57, 0x70, 0xCD, 0xB1, 0x00, 0x1E, 0xFB, 0xD9,\n\t0x15, 0xA0, 0xC9, 0xAE, 0x69, 0x30, 0x3C, 0xD0, 0x30, 0xF0, 0xE4, 0xC1, 0xA7, 0x18, 0x10, 0x0D,\n\t0x0C, 0x00, 0x49, 0x3F, 0x04, 0x00, 0x87, 0x75, 0x00, 0xC5, 0xAA, 0x2A, 0x00, 0x09, 0x40, 0xC0,\n\t0xD7, 0xBA, 0x24, 0x00, 0x0C, 0xA0, 0x33, 0xF0, 0xF7, 0xD6, 0x0C, 0x00, 0x9C, 0x3C, 0xA0, 0x07,\n\t0x06, 0x2A, 0x10, 0x7D, 0x6C, 0x00, 0xBB, 0x09, 0xA2, 0x00, 0xF3, 0xD2, 0x00, 0xE3, 0xC4, 0x0C,\n\t0xA0, 0x80, 0x3C, 0xF0, 0x41, 0x38, 0x05, 0x50, 0x3E, 0xF1, 0x03, 0x00, 0x01, 0x19, 0x01, 0x00,\n\t0x33, 0x2C, 0x00, 0x71, 0x62, 0x00, 0x00, 0xAF, 0x97, 0x00, 0xEB, 0xCB, 0x03, 0x30, 0x03, 0x30,\n\t0x3C, 0x40, 0xE0, 0x81, 0x70, 0x04, 0x40, 0x0F, 0xF0, 0x23, 0xF0, 0x2D, 0x27, 0x00, 0x1C, 0x6B,\n\t0x5D, 0x00, 0xA9, 0x92, 0x00, 0xE7, 0xC8, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xDC, 0x00, 0xBF, 0xA5,\n\t0x0E, 0xE0, 0x81, 0x0F, 0xF0, 0x19, 0xF0, 0xA5, 0x00, 0x22, 0x00, 0x65, 0x58, 0x00, 0x07, 0x67,\n\t0x59, 0x07, 0x70, 0x0F, 0xF0, 0x2A, 0xF0, 0x06, 0x09, 0x45, 0x10, 0x3C, 0x0A, 0x00, 0x00, 0x03,\n\t0x30, 0x00, 0x00, 0x49, 0x11, 0x0B, 0x47, 0x0E, 0x10, 0x0B, 0x1B, 0x06, 0x04, 0x3F, 0xF0, 0xD2,\n\t0xF0, 0xCD, 0x38, 0xE0, 0x85, 0xF8, 0xF7, 0x3A, 0x26, 0x75, 0x00, 0xD2, 0xF0, 0x33, 0x00, 0x27,\n\t0x71, 0x09, 0x06, 0x24, 0x30, 0xBD, 0x2C, 0x1D, 0x15, 0x00, 0xDB, 0x44, 0x33, 0x22, 0x00, 0x00,\n\t0x03, 0x30, 0x00, 0x00, 0x57, 0x00, 0x5D, 0x00, 0x18, 0x00, 0xFC, 0xC7, 0x2E, 0x1F, 0x00, 0x00,\n\t0x45, 0x00, 0x29, 0x09, 0x06, 0x18, 0x89, 0x30, 0x2F, 0x0B, 0x07, 0xDF, 0x34, 0x23, 0x21, 0xC0,\n\t0x81, 0x59, 0x15, 0x0E, 0x3C, 0xC0, 0x2A, 0x00, 0xF5, 0xC7, 0xE1, 0x34, 0x38, 0x23, 0x31, 0x0B,\n\t0x07, 0xC9, 0x2F, 0x1F, 0x33, 0x00, 0x80, 0x2D, 0x00, 0x1E, 0x90, 0x4D, 0x12, 0x0C, 0x2D, 0xC0,\n\t0x41, 0x0F, 0x23, 0x0A, 0x03, 0x30, 0x00, 0x00, 0xD9, 0x33, 0x22, 0xE7, 0x36, 0x06, 0x24, 0x06,\n\t0x00, 0xCB, 0x2F, 0x1F, 0x39, 0x30, 0x15, 0x05, 0x22, 0x03, 0x06, 0x60, 0x0F, 0xF0, 0x21, 0xF0,\n\t0x0F, 0x03, 0x02, 0x03, 0x00, 0x8E, 0xF9, 0x3A, 0x3C, 0xA0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0,\n\t0x3C, 0xF0, 0x30, 0xF0, 0xFC, 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C,\n\t0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0xFF, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0,\n\t0x30, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0xFF, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30,\n\t0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0xFF, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0,\n\t0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0xFF, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C,\n\t0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0xFF, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0,\n\t0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0xFF, 0x30, 0xF0, 0x3C, 0xF0, 0x3C,\n\t0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0xFF, 0x3C, 0xF0, 0x3C, 0xF0,\n\t0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0xFF, 0x3C, 0xF0, 0x0F,\n\t0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0xFF, 0x0F, 0xF0,\n\t0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0xFF, 0x27,\n\t0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0xFF,\n\t0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0x84, 0x90, 0x3F, 0x00, 0x00, 0x00, 0x0F, 0xF0,\n\t0xFF, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x02, 0x07, 0x01, 0xB1, 0x40,\n\t0x81, 0x20, 0x33, 0x0C, 0x08, 0x00, 0x00, 0x0F, 0xF0, 0xC6, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00,\n\t0x0D, 0x03, 0x02, 0x2D, 0x0A, 0x07, 0x07, 0x75, 0x30, 0x39, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x0F,\n\t0xF0, 0x1B, 0xF0, 0x03, 0x00, 0xFE, 0x39, 0x00, 0xB1, 0x29, 0x1B, 0xF3, 0x39, 0x26, 0x00, 0x00,\n\t0x81, 0x0F, 0xF0, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0xFE, 0x3B, 0x27, 0xF5, 0x0F, 0x39, 0x26,\n\t0xB3, 0x2A, 0x1C, 0x17, 0x05, 0x03, 0x00, 0xFF, 0xE4, 0x02, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x6A, 0x09, 0x00, 0x00\n};\n\nu8 *render_static_bootlogo()\n{\n\t// Clear background.\n\tgfx_clear_grey(0x1B);\n\n\t// Set default logo.\n\tu8 *logo_buf = (void *)malloc(SZ_16K);\n\tblz_uncompress_srcdest(bootlogo_blz, sizeof(bootlogo_blz), logo_buf, BOOTLOGO_SIZE);\n\tgfx_set_rect_grey(logo_buf, BOOTLOGO_WIDTH, BOOTLOGO_HEIGHT, BOOTLOGO_X, BOOTLOGO_Y);\n\n\treturn logo_buf;\n}\n\nbool render_ticker_logo(u32 boot_wait, u32 backlight)\n{\n\tu32 btn = 0;\n\n\tu32 ticker_step_us = boot_wait * 1000000;\n\tticker_step_us /= BOOTLOGO_HEIGHT;\n\n\t// Set default logo.\n\tu8 *logo_buf = render_static_bootlogo();\n\n\t// Clear line.\n\tu8 *grey = malloc(6 * BOOTLOGO_HEIGHT);\n\tmemset(grey, 0x1B, 6 * BOOTLOGO_HEIGHT);\n\tgfx_set_rect_grey(grey, 6, BOOTLOGO_HEIGHT, 362, BOOTLOGO_Y);\n\tfree(grey);\n\n\t// Enable backlight to show first frame.\n\tdisplay_backlight_brightness(backlight, 1000);\n\n\t// Animated line as ticker.\n\tfor (u32 i = 1; i <= BOOTLOGO_HEIGHT; i++)\n\t{\n\t\t// If only VOL- was pressed, exit.\n\t\tbtn = btn_read_vol();\n\t\tif (btn == BTN_VOL_DOWN)\n\t\t\tbreak;\n\n\t\t// Wait before setting next tick.\n\t\tusleep(ticker_step_us);\n\n\t\t// Set next ticker progress.\n\t\tgfx_set_rect_grey(logo_buf + BOOTLOGO_WIDTH * (BOOTLOGO_HEIGHT - i) + 36, 6, 1, 362, BOOTLOGO_Y + BOOTLOGO_HEIGHT - i);\n\t}\n\tfree(logo_buf);\n\n\treturn (btn == BTN_VOL_DOWN);\n}\n\nbool render_ticker(u32 boot_wait, u32 backlight, bool no_ticker)\n{\n\tu32 btn = 0;\n\n\tu32 ticker_step_us = boot_wait * 1000000;\n\tticker_step_us /= 1280;\n\n\t// Save bottom lines.\n\tu32 *logo_line = (u32 *)malloc(1280 * sizeof(u32) * 2);\n\tfor (u32 i = 1280; !no_ticker && i >= 1; i--)\n\t{\n\t\tlogo_line[i - 1]        = gfx_ctxt.fb[i * gfx_ctxt.width - 2];\n\t\tlogo_line[i - 1 + 1280] = gfx_ctxt.fb[i * gfx_ctxt.width - 1];\n\t}\n\n\t// Enable backlight to show first frame.\n\tdisplay_backlight_brightness(backlight, 1000);\n\n\t// Animated line as ticker.\n\tfor (u32 i = 1280; i >= 1; i--)\n\t{\n\t\t// If only VOL- was pressed, exit.\n\t\tbtn = btn_read_vol();\n\t\tif (btn == BTN_VOL_DOWN)\n\t\t\tbreak;\n\n\t\t// Wait before setting next tick.\n\t\tusleep(ticker_step_us);\n\n\t\t// Set bottom lines ticker progress.\n\t\tif (!no_ticker)\n\t\t{\n\t\t\tgfx_ctxt.fb[i * gfx_ctxt.width - 2] = TXT_CLR_DEFAULT;\n\t\t\tgfx_ctxt.fb[i * gfx_ctxt.width - 1] = TXT_CLR_DEFAULT;\n\t\t}\n\t}\n\n\t// Restore bottom lines.\n\tfor (u32 i = 1280; !no_ticker && i >= 1; i--)\n\t{\n\t\tgfx_ctxt.fb[i * gfx_ctxt.width - 2] = logo_line[i - 1];\n\t\tgfx_ctxt.fb[i * gfx_ctxt.width - 1] = logo_line[i - 1 + 1280];\n\t}\n\tfree(logo_line);\n\n\treturn (btn == BTN_VOL_DOWN);\n}\n"
  },
  {
    "path": "bootloader/gfx/logos.h",
    "content": "/*\n * Copyright (c) 2018-2022 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _GFX_LOGOS_H_\n#define _GFX_LOGOS_H_\n\n// 21 x 50 @8bpp RGB.\n#define BATTERY_EMPTY_WIDTH       21\n#define BATTERY_EMPTY_BATT_HEIGHT 38\n#define BATTERY_EMPTY_CHRG_HEIGHT 12\n#define BATTERY_EMPTY_SIZE        3150\n#define BATTERY_EMPTY_BLZ_SIZE    740\nextern u8 battery_icons_blz[];\n\nu8  *render_static_bootlogo();\nbool render_ticker_logo(u32 boot_wait, u32 backlight);\nbool render_ticker(u32 boot_wait, u32 backlight, bool no_ticker);\n\n#endif\n"
  },
  {
    "path": "bootloader/gfx/tui.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <bdk.h>\n\n#include \"tui.h\"\n#include \"../config.h\"\n\nvoid tui_sbar(bool force_update)\n{\n\tu32 cx, cy;\n\tstatic u32 sbar_time_keeping = 0;\n\n\tu32 timePassed = get_tmr_s() - sbar_time_keeping;\n\tif (!force_update)\n\t\tif (timePassed < 5)\n\t\t\treturn;\n\n\tu8 prevFontSize = gfx_con.fntsz;\n\tgfx_con.fntsz = 16;\n\tsbar_time_keeping = get_tmr_s();\n\n\tu32 battPercent = 0;\n\tint battVoltCurr = 0;\n\n\tgfx_con_getpos(&cx, &cy);\n\tgfx_con_setpos(0, 1260);\n\n\tmax17050_get_property(MAX17050_RepSOC, (int *)&battPercent);\n\tmax17050_get_property(MAX17050_VCELL, &battVoltCurr);\n\n\tgfx_clear_partial_grey(0x30, 1256, 24);\n\tgfx_printf(\"%K%k Battery: %d.%d%% (%d mV) - Charge:\", TXT_CLR_GREY_D, TXT_CLR_GREY,\n\t\t(battPercent >> 8) & 0xFF, (battPercent & 0xFF) / 26, battVoltCurr);\n\n\tmax17050_get_property(MAX17050_Current, &battVoltCurr);\n\n\tgfx_printf(\" %k%d mA%k%K\\n\", battVoltCurr >= 0 ? TXT_CLR_GREEN_D : TXT_CLR_RED_D,\n\t\t\t   battVoltCurr / 1000, TXT_CLR_DEFAULT, TXT_CLR_BG);\n\n\tgfx_con.fntsz = prevFontSize;\n\tgfx_con_setpos(cx, cy);\n}\n\nvoid tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol)\n{\n\tu32 cx, cy;\n\tif (val > 200)\n\t\tval = 200;\n\n\tgfx_con_getpos(&cx, &cy);\n\n\tgfx_con_setpos(x, y);\n\n\tgfx_printf(\"%k[%3d%%]%k\", fgcol, val, TXT_CLR_DEFAULT);\n\n\tx += 7 * gfx_con.fntsz;\n\n\tfor (u32 i = 0; i < (gfx_con.fntsz >> 3) * 6; i++)\n\t{\n\t\tgfx_line(x, y + i + 1, x + 3 * val, y + i + 1, fgcol);\n\t\tgfx_line(x + 3 * val, y + i + 1, x + 3 * 100, y + i + 1, bgcol);\n\t}\n\n\tgfx_con_setpos(cx, cy);\n\n\t// Update status bar.\n\ttui_sbar(false);\n}\n\nvoid *tui_do_menu(menu_t *menu)\n{\n\tint idx = 0, prev_idx = 0, cnt = 0x7FFFFFFF;\n\n\tgfx_clear_partial_grey(0x1B, 0, 1256);\n\ttui_sbar(true);\n\n\twhile (true)\n\t{\n\t\tgfx_con_setcol(TXT_CLR_DEFAULT, 1, TXT_CLR_BG);\n\t\tgfx_con_setpos(menu->x, menu->y);\n\t\tgfx_printf(\"[%s]\\n\\n\", menu->caption);\n\n\t\t// Skip caption or seperator lines selection.\n\t\twhile (menu->ents[idx].type == MENT_CAPTION ||\n\t\t\tmenu->ents[idx].type == MENT_CHGLINE)\n\t\t{\n\t\t\tif (prev_idx <= idx || (!idx && prev_idx == cnt - 1))\n\t\t\t{\n\t\t\t\tidx++;\n\t\t\t\tif (idx > (cnt - 1))\n\t\t\t\t{\n\t\t\t\t\tidx = 0;\n\t\t\t\t\tprev_idx = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tidx--;\n\t\t\t\tif (idx < 0)\n\t\t\t\t{\n\t\t\t\t\tidx = cnt - 1;\n\t\t\t\t\tprev_idx = cnt;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tprev_idx = idx;\n\n\t\t// Draw the menu.\n\t\tfor (cnt = 0; menu->ents[cnt].type != MENT_END; cnt++)\n\t\t{\n\t\t\tif (cnt == idx)\n\t\t\t\tgfx_con_setcol(TXT_CLR_BG, 1, TXT_CLR_DEFAULT);\n\t\t\telse\n\t\t\t\tgfx_con_setcol(TXT_CLR_DEFAULT, 1, TXT_CLR_BG);\n\t\t\tif (menu->ents[cnt].type == MENT_CAPTION)\n\t\t\t\tgfx_printf(\"%k %s\", menu->ents[cnt].color, menu->ents[cnt].caption);\n\t\t\telse if (menu->ents[cnt].type != MENT_CHGLINE)\n\t\t\t\tgfx_printf(\" %s\", menu->ents[cnt].caption);\n\t\t\tif (menu->ents[cnt].type == MENT_MENU)\n\t\t\t\tgfx_printf(\"%k...\", TXT_CLR_CYAN_L);\n\t\t\tgfx_printf(\" \\n\");\n\t\t}\n\t\tgfx_con_setcol(TXT_CLR_DEFAULT, 1, TXT_CLR_BG);\n\t\tgfx_putc('\\n');\n\n\t\t// Print errors, help and battery status.\n\t\tgfx_con_setpos(0,  1127);\n\t\tgfx_printf(\"%k Warning: %kNyx is missing!\", TXT_CLR_RED_D, TXT_CLR_GREY_M);\n\t\tgfx_con_setpos(0,  1191);\n\t\tgfx_printf(\"%k VOL: Move up/down\\n PWR: Select option%k\", TXT_CLR_GREY_M, TXT_CLR_DEFAULT);\n\n\t\tdisplay_backlight_brightness(h_cfg.backlight, 1000);\n\n\t\t// Wait for user command.\n\t\tu32 btn = btn_wait();\n\n\t\tif (btn & BTN_VOL_DOWN && idx < (cnt - 1))\n\t\t\tidx++;\n\t\telse if (btn & BTN_VOL_DOWN && idx == (cnt - 1))\n\t\t{\n\t\t\tidx = 0;\n\t\t\tprev_idx = -1;\n\t\t}\n\t\tif (btn & BTN_VOL_UP && idx > 0)\n\t\t\tidx--;\n\t\telse if (btn & BTN_VOL_UP && idx == 0)\n\t\t{\n\t\t\tidx = cnt - 1;\n\t\t\tprev_idx = cnt;\n\t\t}\n\t\tif (btn & BTN_POWER)\n\t\t{\n\t\t\tment_t *ent = &menu->ents[idx];\n\t\t\tswitch (ent->type)\n\t\t\t{\n\t\t\tcase MENT_HANDLER:\n\t\t\t\tent->handler(ent->data);\n\t\t\t\tbreak;\n\t\t\tcase MENT_MENU:\n\t\t\t\treturn tui_do_menu(ent->menu);\n\t\t\t\tbreak;\n\t\t\tcase MENT_DATA:\n\t\t\t\treturn ent->data;\n\t\t\t\tbreak;\n\t\t\tcase MENT_BACK:\n\t\t\t\treturn NULL;\n\t\t\t\tbreak;\n\t\t\tcase MENT_HDLR_RE:\n\t\t\t\tent->handler(ent);\n\t\t\t\tif (!ent->data)\n\t\t\t\t\treturn NULL;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tgfx_con.fntsz = 16;\n\t\t\tgfx_clear_partial_grey(0x1B, 0, 1256);\n\t\t}\n\t\ttui_sbar(false);\n\t}\n\n\treturn NULL;\n}\n"
  },
  {
    "path": "bootloader/gfx/tui.h",
    "content": "/*\n* Copyright (c) 2018 naehrwert\n* Copyright (c) 2018 CTCaer\n*\n* This program is free software; you can redistribute it and/or modify it\n* under the terms and conditions of the GNU General Public License,\n* version 2, as published by the Free Software Foundation.\n*\n* This program is distributed in the hope it will be useful, but WITHOUT\n* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n* more details.\n*\n* You should have received a copy of the GNU General Public License\n* along with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n#ifndef _TUI_H_\n#define _TUI_H_\n\n#include <bdk.h>\n\n#define MENT_END     0\n#define MENT_HANDLER 1\n#define MENT_MENU    2\n#define MENT_DATA    3\n#define MENT_BACK    4\n#define MENT_CAPTION 5\n#define MENT_CHGLINE 6\n#define MENT_HDLR_RE 7\n\ntypedef struct _ment_t\n{\n\tu32 type;\n\tconst char *caption;\n\tu32 color;\n\tvoid *data;\n\tunion\n\t{\n\t\tvoid(*handler)(void *);\n\t\tstruct _menu_t *menu;\n\t};\n} ment_t;\n\ntypedef struct _menu_t\n{\n\tment_t *ents;\n\tconst char *caption;\n\tu32 x;\n\tu32 y;\n} menu_t;\n\n#define MDEF_END() {MENT_END}\n#define MDEF_HANDLER(caption, _handler) { MENT_HANDLER, caption, 0, NULL, { .handler = _handler } }\n#define MDEF_HANDLER_EX(caption, data, _handler) { MENT_HANDLER, caption, 0, data, { .handler = _handler } }\n#define MDEF_MENU(caption, _menu) { MENT_MENU, caption, 0, NULL, { .menu = _menu } }\n#define MDEF_BACK() { MENT_BACK, \"Back\" }\n#define MDEF_CAPTION(caption, color) { MENT_CAPTION, caption, color }\n#define MDEF_CHGLINE() {MENT_CHGLINE}\n\nvoid tui_sbar(bool force_update);\nvoid tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol);\nvoid *tui_do_menu(menu_t *menu);\n\n#endif\n"
  },
  {
    "path": "bootloader/hos/hos.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018 st4rk\n * Copyright (c) 2018 Ced2911\n * Copyright (c) 2018-2026 CTCaer\n * Copyright (c) 2018 balika011\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <bdk.h>\n\n#include \"hos.h\"\n#include \"hos_config.h\"\n#include \"secmon_exo.h\"\n#include \"../frontend/fe_tools.h\"\n#include \"../config.h\"\n#include \"../storage/emummc.h\"\n\n//#define DPRINTF(...) gfx_printf(__VA_ARGS__)\n#define DPRINTF(...)\n\n#define EHPRINTFARGS(text, args...) \\\n\t({  gfx_con.mute = false; \\\n\t\tgfx_printf(\"%k\"text\"%k\\n\", TXT_CLR_ERROR, args, TXT_CLR_DEFAULT); })\n\nstatic const u8 eks_keyseeds[HOS_MKEY_VER_600 - HOS_MKEY_VER_100 + 1][SE_KEY_128_SIZE] = {\n\t{ 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3 }, // 1.0.0.\n\t{ 0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC }, // 3.0.0.\n\t{ 0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B }, // 3.0.1.\n\t{ 0x2D, 0x1F, 0x48, 0x80, 0xED, 0xEC, 0xED, 0x3E, 0x3C, 0xF2, 0x48, 0xB5, 0x65, 0x7D, 0xF7, 0xBE }, // 4.0.0.\n\t{ 0xBB, 0x5A, 0x01, 0xF9, 0x88, 0xAF, 0xF5, 0xFC, 0x6C, 0xFF, 0x07, 0x9E, 0x13, 0x3C, 0x39, 0x80 }, // 5.0.0.\n\t{ 0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0 }  // 6.0.0.\n};\n\nstatic const u8 cmac_keyseed[SE_KEY_128_SIZE] =\n\t{ 0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5 };\n\nstatic const u8 master_keyseed_retail[SE_KEY_128_SIZE] =\n\t{ 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C };\n\nstatic const u8 master_keyseed_4xx[SE_KEY_128_SIZE] =\n\t{ 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 };\n\nstatic const u8 master_kekseed_620[SE_KEY_128_SIZE] =\n\t{ 0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A };\n\n//!TODO: Update on tsec/mkey changes.\nstatic const u8 master_kekseed_t210_tsec_v4[HOS_MKEY_VER_MAX - HOS_MKEY_VER_810 + 1][SE_KEY_128_SIZE] = {\n\t{ 0xDE, 0xDC, 0xE3, 0x39, 0x30, 0x88, 0x16, 0xF8, 0xAE, 0x97, 0xAD, 0xEC, 0x64, 0x2D, 0x41, 0x41 }, // 8.1.0.\n\t{ 0x1A, 0xEC, 0x11, 0x82, 0x2B, 0x32, 0x38, 0x7A, 0x2B, 0xED, 0xBA, 0x01, 0x47, 0x7E, 0x3B, 0x67 }, // 9.0.0.\n\t{ 0x30, 0x3F, 0x02, 0x7E, 0xD8, 0x38, 0xEC, 0xD7, 0x93, 0x25, 0x34, 0xB5, 0x30, 0xEB, 0xCA, 0x7A }, // 9.1.0.\n\t{ 0x84, 0x67, 0xB6, 0x7F, 0x13, 0x11, 0xAE, 0xE6, 0x58, 0x9B, 0x19, 0xAF, 0x13, 0x6C, 0x80, 0x7A }, // 12.1.0.\n\t{ 0x68, 0x3B, 0xCA, 0x54, 0xB8, 0x6F, 0x92, 0x48, 0xC3, 0x05, 0x76, 0x87, 0x88, 0x70, 0x79, 0x23 }, // 13.0.0.\n\t{ 0xF0, 0x13, 0x37, 0x9A, 0xD5, 0x63, 0x51, 0xC3, 0xB4, 0x96, 0x35, 0xBC, 0x9C, 0xE8, 0x76, 0x81 }, // 14.0.0.\n\t{ 0x6E, 0x77, 0x86, 0xAC, 0x83, 0x0A, 0x8D, 0x3E, 0x7D, 0xB7, 0x66, 0xA0, 0x22, 0xB7, 0x6E, 0x67 }, // 15.0.0.\n\t{ 0x99, 0x22, 0x09, 0x57, 0xA7, 0xF9, 0x5E, 0x94, 0xFE, 0x78, 0x7F, 0x41, 0xD6, 0xE7, 0x56, 0xE6 }, // 16.0.0.\n\t{ 0x71, 0xB9, 0xA6, 0xC0, 0xFF, 0x97, 0x6B, 0x0C, 0xB4, 0x40, 0xB9, 0xD5, 0x81, 0x5D, 0x81, 0x90 }, // 17.0.0.\n\t{ 0x00, 0x04, 0x5D, 0xF0, 0x4D, 0xCD, 0x14, 0xA3, 0x1C, 0xBF, 0xDE, 0x48, 0x55, 0xBA, 0x35, 0xC1 }, // 18.0.0.\n\t{ 0xD7, 0x63, 0x74, 0x46, 0x4E, 0xBA, 0x78, 0x0A, 0x7C, 0x9D, 0xB3, 0xE8, 0x7A, 0x3D, 0x71, 0xE3 }, // 19.0.0.\n\t{ 0xA1, 0x7D, 0x34, 0xDB, 0x2D, 0x9D, 0xDA, 0xE5, 0xF8, 0x15, 0x63, 0x4C, 0x8F, 0xE7, 0x6C, 0xD8 }, // 20.0.0.\n\t{ 0x66, 0xC8, 0xCB, 0x3D, 0xEC, 0xF4, 0x59, 0x73, 0x54, 0x88, 0xE1, 0x2E, 0xE6, 0x3D, 0x68, 0x46 }, // 21.0.0.\n\t{ 0x15, 0xAC, 0x96, 0x34, 0xF5, 0x32, 0x56, 0x68, 0xFE, 0x5B, 0x9D, 0xD7, 0xED, 0x19, 0xB7, 0x8E }, // 22.0.0.\n};\n\n//!TODO: Update on mkey changes.\nstatic const u8 master_kekseed_t210b01[HOS_MKEY_VER_MAX - HOS_MKEY_VER_600 + 1][SE_KEY_128_SIZE] = {\n\t{ 0x77, 0x60, 0x5A, 0xD2, 0xEE, 0x6E, 0xF8, 0x3C, 0x3F, 0x72, 0xE2, 0x59, 0x9D, 0xAC, 0x5E, 0x56 }, // 6.0.0.\n\t{ 0x1E, 0x80, 0xB8, 0x17, 0x3E, 0xC0, 0x60, 0xAA, 0x11, 0xBE, 0x1A, 0x4A, 0xA6, 0x6F, 0xE4, 0xAE }, // 6.2.0.\n\t{ 0x94, 0x08, 0x67, 0xBD, 0x0A, 0x00, 0x38, 0x84, 0x11, 0xD3, 0x1A, 0xDB, 0xDD, 0x8D, 0xF1, 0x8A }, // 7.0.0.\n\t{ 0x5C, 0x24, 0xE3, 0xB8, 0xB4, 0xF7, 0x00, 0xC2, 0x3C, 0xFD, 0x0A, 0xCE, 0x13, 0xC3, 0xDC, 0x23 }, // 8.1.0.\n\t{ 0x86, 0x69, 0xF0, 0x09, 0x87, 0xC8, 0x05, 0xAE, 0xB5, 0x7B, 0x48, 0x74, 0xDE, 0x62, 0xA6, 0x13 }, // 9.0.0.\n\t{ 0x0E, 0x44, 0x0C, 0xED, 0xB4, 0x36, 0xC0, 0x3F, 0xAA, 0x1D, 0xAE, 0xBF, 0x62, 0xB1, 0x09, 0x82 }, // 9.1.0.\n\t{ 0xE5, 0x41, 0xAC, 0xEC, 0xD1, 0xA7, 0xD1, 0xAB, 0xED, 0x03, 0x77, 0xF1, 0x27, 0xCA, 0xF8, 0xF1 }, // 12.1.0.\n\t{ 0x52, 0x71, 0x9B, 0xDF, 0xA7, 0x8B, 0x61, 0xD8, 0xD5, 0x85, 0x11, 0xE4, 0x8E, 0x4F, 0x74, 0xC6 }, // 13.0.0.\n\t{ 0xD2, 0x68, 0xC6, 0x53, 0x9D, 0x94, 0xF9, 0xA8, 0xA5, 0xA8, 0xA7, 0xC8, 0x8F, 0x53, 0x4B, 0x7A }, // 14.0.0.\n\t{ 0xEC, 0x61, 0xBC, 0x82, 0x1E, 0x0F, 0x5A, 0xC3, 0x2B, 0x64, 0x3F, 0x9D, 0xD6, 0x19, 0x22, 0x2D }, // 15.0.0.\n\t{ 0xA5, 0xEC, 0x16, 0x39, 0x1A, 0x30, 0x16, 0x08, 0x2E, 0xCF, 0x09, 0x6F, 0x5E, 0x7C, 0xEE, 0xA9 }, // 16.0.0.\n\t{ 0x8D, 0xEE, 0x9E, 0x11, 0x36, 0x3A, 0x9B, 0x0A, 0x6A, 0xC7, 0xBB, 0xE9, 0xD1, 0x03, 0xF7, 0x80 }, // 17.0.0.\n\t{ 0x4F, 0x41, 0x3C, 0x3B, 0xFB, 0x6A, 0x01, 0x2A, 0x68, 0x9F, 0x83, 0xE9, 0x53, 0xBD, 0x16, 0xD2 }, // 18.0.0.\n\t{ 0x31, 0xBE, 0x25, 0xFB, 0xDB, 0xB4, 0xEE, 0x49, 0x5C, 0x77, 0x05, 0xC2, 0x36, 0x9F, 0x34, 0x80 }, // 19.0.0.\n\t{ 0x1A, 0x31, 0x62, 0x87, 0xA8, 0x09, 0xCA, 0xF8, 0x69, 0x15, 0x45, 0xC2, 0x6B, 0xAA, 0x5A, 0x8A }, // 20.0.0.\n\t{ 0xEB, 0xF3, 0x5B, 0x2D, 0x4A, 0x2D, 0xCE, 0x45, 0x3A, 0x6F, 0x61, 0x38, 0x0B, 0x00, 0x3B, 0x46 }, // 21.0.0.\n\t{ 0x82, 0xE2, 0x0A, 0x59, 0x67, 0xDF, 0xBF, 0x51, 0x47, 0x62, 0x11, 0xF2, 0x41, 0xD3, 0xEE, 0x13 }, // 22.0.0.\n};\n\nstatic const u8 console_keyseed[SE_KEY_128_SIZE] =\n\t{ 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 };\n\nstatic const u8 console_keyseed_4xx[SE_KEY_128_SIZE] =\n\t{ 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 };\n\nconst u8 package2_keyseed[SE_KEY_128_SIZE] =\n\t{ 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 };\n\nstatic void _hos_crit_error(const char *text)\n{\n\tgfx_con.mute = false;\n\tgfx_printf(\"%k%s%k\\n\", TXT_CLR_ERROR, text, TXT_CLR_DEFAULT);\n}\n\nstatic void _se_lock(bool lock_se)\n{\n\tif (lock_se)\n\t{\n\t\t// Disable aes key read.\n\t\tfor (u32 i = 0; i < 16; i++)\n\t\t\tse_key_acc_ctrl(i, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG);\n\n\t\t// Disable RSA key read.\n\t\tfor (u32 i = 0; i < 2; i++)\n\t\t\tse_rsa_acc_ctrl(i, SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG);\n\n\t\tSE(SE_TZRAM_SECURITY_REG) = 0;                // Make SE TZRAM secure only.\n\t\tSE(SE_CRYPTO_SECURITY_PERKEY_REG) = 0;        // Make all AES keys access secure only.\n\t\tSE(SE_RSA_SECURITY_PERKEY_REG) = 0;           // Make all RSA keys access secure only.\n\t\tSE(SE_SE_SECURITY_REG) &= ~SE_PERKEY_SETTING; // Make access lock regs secure only.\n\t}\n\n\tmemset((void *)IPATCH_BASE, 0, (IPATCH_CAM_ENTRIES + 1) * sizeof(u32));\n\tSB(SB_CSR) = SB_CSR_PIROM_DISABLE;\n}\n\nstatic int _hos_eks_rw_try(u8 *buf, bool write)\n{\n\tfor (u32 i = 0; i < 3; i++)\n\t{\n\t\tif (!write)\n\t\t{\n\t\t\tif (!sdmmc_storage_read(&sd_storage, 0, 1, buf))\n\t\t\t\treturn 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (!sdmmc_storage_write(&sd_storage, 0, 1, buf))\n\t\t\t\treturn 0;\n\t\t}\n\t}\n\n\treturn 1;\n}\n\nstatic void _hos_eks_get()\n{\n\t// Check if Erista based unit.\n\tif (h_cfg.t210b01)\n\t\treturn;\n\n\t// Check if EKS already found and parsed.\n\tif (!h_cfg.eks)\n\t{\n\t\t// Read EKS blob.\n\t\tu8 *mbr = malloc(SD_BLOCKSIZE);\n\t\tif (_hos_eks_rw_try(mbr, false))\n\t\t\tgoto out;\n\n\t\t// Decrypt EKS blob.\n\t\thos_eks_mbr_t *eks = (hos_eks_mbr_t *)(mbr + 0x80);\n\t\tse_aes_crypt_ecb(14, DECRYPT, eks, eks, sizeof(hos_eks_mbr_t));\n\n\t\t// Check if valid and for this unit.\n\t\tif (eks->magic == HOS_EKS_MAGIC && eks->lot0 == FUSE(FUSE_OPT_LOT_CODE_0))\n\t\t{\n\t\t\th_cfg.eks = eks;\n\t\t\treturn;\n\t\t}\n\nout:\n\t\tfree(mbr);\n\t}\n}\n\nstatic void _hos_eks_save()\n{\n\t// Check if Erista based unit.\n\tif (h_cfg.t210b01)\n\t\treturn;\n\n\t// EKS save. Only for 7.0.0 and up.\n\tbool new_eks = false;\n\tif (!h_cfg.eks)\n\t{\n\t\th_cfg.eks = zalloc(sizeof(hos_eks_mbr_t));\n\t\tnew_eks = true;\n\t}\n\n\t// If matching blob doesn't exist, create it.\n\tif (h_cfg.eks->enabled != HOS_EKS_TSEC_VER)\n\t{\n\t\t// Read EKS blob.\n\t\tu8 *mbr = malloc(SD_BLOCKSIZE);\n\t\tif (_hos_eks_rw_try(mbr, false))\n\t\t{\n\t\t\tif (new_eks)\n\t\t\t{\n\t\t\t\tfree(h_cfg.eks);\n\t\t\t\th_cfg.eks = NULL;\n\t\t\t}\n\n\t\t\tgoto out;\n\t\t}\n\n\t\t// Get keys.\n\t\tu8 *keys = (u8 *)zalloc(SZ_8K);\n\t\tse_aes_ctx_get_keys(keys + SZ_4K, keys, SE_KEY_128_SIZE);\n\n\t\t// Set magic and personalized info.\n\t\th_cfg.eks->magic   = HOS_EKS_MAGIC;\n\t\th_cfg.eks->enabled = HOS_EKS_TSEC_VER;\n\t\th_cfg.eks->lot0    = FUSE(FUSE_OPT_LOT_CODE_0);\n\n\t\t// Copy new keys.\n\t\tmemcpy(h_cfg.eks->tsec,      keys + 12 * SE_KEY_128_SIZE, SE_KEY_128_SIZE);\n\t\tmemcpy(h_cfg.eks->troot,     keys + 13 * SE_KEY_128_SIZE, SE_KEY_128_SIZE);\n\t\tmemcpy(h_cfg.eks->troot_dev, keys + 11 * SE_KEY_128_SIZE, SE_KEY_128_SIZE);\n\n\t\t// Encrypt EKS blob.\n\t\tu8 *eks = malloc(sizeof(hos_eks_mbr_t));\n\t\tmemcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t));\n\t\tse_aes_crypt_ecb(14, ENCRYPT, eks, eks, sizeof(hos_eks_mbr_t));\n\n\t\t// Write EKS blob to SD.\n\t\tmemcpy(mbr + 0x80, eks, sizeof(hos_eks_mbr_t));\n\t\t_hos_eks_rw_try(mbr, true);\n\n\t\tfree(eks);\n\t\tfree(keys);\nout:\n\t\tfree(mbr);\n\t}\n}\n\nstatic void _hos_eks_clear(u32 mkey)\n{\n\t// Check if Erista based unit.\n\tif (h_cfg.t210b01)\n\t\treturn;\n\n\tif (h_cfg.eks && mkey >= HOS_MKEY_VER_700)\n\t{\n\t\t// Check if current Master key is enabled.\n\t\tif (h_cfg.eks->enabled)\n\t\t{\n\t\t\t// Read EKS blob.\n\t\t\tu8 *mbr = malloc(SD_BLOCKSIZE);\n\t\t\tif (_hos_eks_rw_try(mbr, false))\n\t\t\t\tgoto out;\n\n\t\t\t// Disable current Master key version.\n\t\t\th_cfg.eks->enabled = 0;\n\n\t\t\t// Encrypt EKS blob.\n\t\t\tu8 *eks = malloc(sizeof(hos_eks_mbr_t));\n\t\t\tmemcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t));\n\t\t\tse_aes_crypt_ecb(14, ENCRYPT, eks, eks, sizeof(hos_eks_mbr_t));\n\n\t\t\t// Write EKS blob to SD.\n\t\t\tmemcpy(mbr + 0x80, eks, sizeof(hos_eks_mbr_t));\n\t\t\t_hos_eks_rw_try(mbr, true);\n\n\t\t\tfree(eks);\nout:\n\t\t\tfree(mbr);\n\t\t}\n\t}\n}\n\ntypedef struct _tsec_keys_t\n{\n\tu8 tsec[SE_KEY_128_SIZE];\n\tu8 tsec_root[SE_KEY_128_SIZE];\n\tu8 tmp[SE_KEY_128_SIZE];\n} tsec_keys_t;\n\nstatic int _hos_keygen(pkg1_eks_t *eks, u32 mkey, tsec_ctxt_t *tsec_ctxt, bool stock, bool is_exo)\n{\n\tstatic bool sbk_is_set = true;\n\n\tu32 retries = 0;\n\tbool use_tsec = false;\n\ttsec_keys_t tsec_keys;\n\n\tif (mkey > HOS_MKEY_VER_MAX)\n\t\treturn 1;\n\n\t// Do Mariko keygen.\n\tif (h_cfg.t210b01)\n\t{\n\t\t// Use SBK as Device key 4x unsealer and KEK for mkey in T210B01 units.\n\t\tse_aes_unwrap_key(10, 14, console_keyseed_4xx);\n\n\t\t// Derive master key.\n\t\tse_aes_unwrap_key(7, 12, master_kekseed_t210b01[mkey - HOS_MKEY_VER_600]);\n\t\tse_aes_unwrap_key(7, 7,  master_keyseed_retail);\n\n\t\t// Derive latest pkg2 key.\n\t\tse_aes_unwrap_key(8, 7, package2_keyseed);\n\n\t\treturn 0;\n\t}\n\n\t// Do Erista keygen.\n\n\t// Check if SBK is wiped and try to restore it from fuses.\n\tif (!sbk_is_set)\n\t{\n\t\tif (fuse_set_sbk())\n\t\t\tsbk_is_set = true;\n\t\telse\n\t\t\treturn 0; // Continue with current SE keys.\n\t}\n\n\t// Use HOS EKS if it exists.\n\t_hos_eks_get();\n\n\t// Use tsec keygen for old firmware or if EKS keys does not exist for newer.\n\tif (mkey <= HOS_MKEY_VER_620 || !h_cfg.eks || (h_cfg.eks->enabled != HOS_EKS_TSEC_VER))\n\t\tuse_tsec = true;\n\n\tif (mkey <= HOS_MKEY_VER_600)\n\t{\n\t\ttsec_ctxt->size = 0xF00;\n\t\ttsec_ctxt->type = TSEC_FW_TYPE_OLD;\n\t}\n\telse if (mkey == HOS_MKEY_VER_620)\n\t{\n\t\ttsec_ctxt->size = 0x2900;\n\t\ttsec_ctxt->type = TSEC_FW_TYPE_EMU;\n\n\t\t// Prepare smmu tsec page for 6.2.0.\n\t\tu8 *tsec_paged = (u8 *)smmu_page_zalloc(3);\n\t\tmemcpy(tsec_paged, (void *)tsec_ctxt->fw, tsec_ctxt->size);\n\t\ttsec_ctxt->fw = tsec_paged;\n\t}\n\telse if (use_tsec) // 7.0.0+\n\t{\n\t\t/*\n\t\t * 7.0.0/8.1.0 tsec fw are 0x3000/0x3300.\n\t\t * Unused here because of THK.\n\t\t */\n\n\t\t// Use custom TSEC Hovi Keygen firmware.\n\t\ttsec_ctxt->fw = sd_file_read(\"bootloader/sys/thk.bin\", NULL);\n\t\tif (!tsec_ctxt->fw)\n\t\t{\n\t\t\t_hos_crit_error(\"Failed to load thk.bin\");\n\t\t\treturn 1;\n\t\t}\n\n\t\ttsec_ctxt->size = 0x1F00;\n\t\ttsec_ctxt->type = TSEC_FW_TYPE_NEW;\n\t}\n\telse if (h_cfg.eks)\n\t{\n\t\t// EKS found. Set TSEC keys.\n\t\tse_aes_key_set(12, h_cfg.eks->tsec, SE_KEY_128_SIZE);\n\t\tse_aes_key_set(13, h_cfg.eks->troot, SE_KEY_128_SIZE);\n\t\tse_aes_key_set(11, h_cfg.eks->troot_dev, SE_KEY_128_SIZE);\n\t}\n\n\t// Get TSEC key.\n\twhile (use_tsec && tsec_query(&tsec_keys, tsec_ctxt) < 0)\n\t{\n\t\tmemset(&tsec_keys, 0x00, 0x20);\n\t\tretries++;\n\n\t\t// We rely on racing conditions, make sure we cover even the unluckiest cases.\n\t\tif (retries > 15)\n\t\t{\n\t\t\t_hos_crit_error(\"Failed to get TSEC keys.\");\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\tif (mkey >= HOS_MKEY_VER_700)\n\t{\n\t\t// For 7.0.0 and up, save EKS slot if it doesn't exist.\n\t\tif (use_tsec)\n\t\t{\n\t\t\t_hos_eks_save();\n\t\t\tfree(tsec_ctxt->fw);\n\t\t}\n\n\t\t// Use 8.1.0 for 7.0.0 otherwise the proper one.\n\t\tu32 mkey_idx = 0;\n\t\tif (mkey >= HOS_MKEY_VER_810)\n\t\t\tmkey_idx = mkey - HOS_MKEY_VER_810;\n\n\t\tif (!is_exo)\n\t\t{\n\t\t\t// Derive Package2 key in secmon compatible way.\n\t\t\tse_aes_unwrap_key(7, 13, master_kekseed_t210_tsec_v4[mkey_idx]);\n\t\t\tse_aes_unwrap_key(7, 7, master_keyseed_retail);\n\t\t\tse_aes_unwrap_key(8, 7, package2_keyseed);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Decrypt eks and set keyslots.\n\t\t\tse_aes_crypt_ecb(12, DECRYPT, tsec_keys.tmp, eks_keyseeds[0], SE_KEY_128_SIZE);\n\t\t\tse_aes_unwrap_key(15, 14, tsec_keys.tmp);\n\n\t\t\t// Derive device keys.\n\t\t\tse_aes_unwrap_key(10, 15, console_keyseed_4xx);\n\t\t\tse_aes_unwrap_key(15, 15, console_keyseed);\n\n\t\t\t// Derive master kek.\n\t\t\tse_aes_unwrap_key(13, 13, master_kekseed_t210_tsec_v4[mkey_idx]);\n\n\t\t\t// Derive device master key and master key.\n\t\t\tse_aes_unwrap_key(12, 13, master_keyseed_4xx);\n\t\t\tse_aes_unwrap_key(13, 13, master_keyseed_retail);\n\n\t\t\t// Package2 key.\n\t\t\tse_aes_unwrap_key(8, 13, package2_keyseed);\n\t\t}\n\t}\n\telse if (mkey == HOS_MKEY_VER_620)\n\t{\n\t\t// Set TSEC key.\n\t\tse_aes_key_set(12, tsec_keys.tsec, SE_KEY_128_SIZE);\n\t\t// Set TSEC root key.\n\t\tse_aes_key_set(13, tsec_keys.tsec_root, SE_KEY_128_SIZE);\n\n\t\tif (!is_exo)\n\t\t{\n\t\t\t// Derive Package2 key in secmon compatible way.\n\t\t\tse_aes_key_set(8, tsec_keys.tsec_root, SE_KEY_128_SIZE);\n\t\t\tse_aes_unwrap_key(8, 8, master_kekseed_620);\n\t\t\tse_aes_unwrap_key(8, 8, master_keyseed_retail);\n\t\t\tse_aes_unwrap_key(8, 8, package2_keyseed);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Decrypt eks and set keyslots for Exosphere 2.\n\t\t\tse_aes_crypt_ecb(12, DECRYPT, tsec_keys.tmp, eks_keyseeds[0], SE_KEY_128_SIZE);\n\t\t\tse_aes_unwrap_key(15, 14, tsec_keys.tmp);\n\n\t\t\t// Derive device keys.\n\t\t\tse_aes_unwrap_key(10, 15, console_keyseed_4xx);\n\t\t\tse_aes_unwrap_key(15, 15, console_keyseed);\n\n\t\t\t// Derive master kek.\n\t\t\tse_aes_unwrap_key(13, 13, master_kekseed_620);\n\n\t\t\t// Derive device master key and master key.\n\t\t\tse_aes_unwrap_key(12, 13, master_keyseed_4xx);\n\t\t\tse_aes_unwrap_key(13, 13, master_keyseed_retail);\n\n\t\t\t// Package2 key.\n\t\t\tse_aes_unwrap_key(8, 13, package2_keyseed);\n\t\t}\n\t}\n\telse\n\t{\n\t\tse_key_acc_ctrl(13, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG);\n\t\tse_key_acc_ctrl(14, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG);\n\n\t\t// Set TSEC key.\n\t\tse_aes_key_set(13, tsec_keys.tsec, SE_KEY_128_SIZE);\n\n\t\t// Derive eks keys from TSEC+SBK.\n\t\tse_aes_crypt_ecb(13, DECRYPT, tsec_keys.tsec, eks_keyseeds[0], SE_KEY_128_SIZE);\n\t\tse_aes_unwrap_key(15, 14, tsec_keys.tsec);\n\t\tse_aes_crypt_ecb(13, DECRYPT, tsec_keys.tsec, eks_keyseeds[mkey], SE_KEY_128_SIZE);\n\t\tse_aes_unwrap_key(13, 14, tsec_keys.tsec);\n\n\t\t// Clear SBK.\n\t\t//se_aes_key_clear(14);\n\n/*\n\t\t// Verify eks CMAC.\n\t\tu8 cmac[SE_KEY_128_SIZE];\n\t\tse_aes_unwrap_key(11, 13, cmac_keyseed);\n\t\tse_aes_hash_cmac(cmac, SE_KEY_128_SIZE, 11, (void *)eks->ctr, sizeof(eks->ctr) + sizeof(eks->keys));\n\t\tif (!memcmp(eks->cmac, cmac, SE_KEY_128_SIZE))\n\t\t\treturn 1;\n*/\n\n\t\tse_aes_crypt_ecb(13, DECRYPT, tsec_keys.tsec, cmac_keyseed, SE_KEY_128_SIZE);\n\t\tse_aes_unwrap_key(11, 13, cmac_keyseed);\n\n\t\t// Decrypt eks and set keyslots.\n\t\tse_aes_crypt_ctr(13, &eks->keys, &eks->keys, sizeof(eks_keys_t), eks->ctr);\n\t\tse_aes_key_set(11, eks->keys.package1_key,   SE_KEY_128_SIZE);\n\t\tse_aes_key_set(12, eks->keys.master_kekseed, SE_KEY_128_SIZE);\n\t\tse_aes_key_set(13, eks->keys.master_kekseed, SE_KEY_128_SIZE);\n\n\t\tse_aes_crypt_ecb(12, DECRYPT, tsec_keys.tsec, master_keyseed_retail, SE_KEY_128_SIZE);\n\n\t\tif (!is_exo)\n\t\t{\n\t\t\tswitch (mkey)\n\t\t\t{\n\t\t\tcase HOS_MKEY_VER_100:\n\t\t\tcase HOS_MKEY_VER_300:\n\t\t\tcase HOS_MKEY_VER_301:\n\t\t\t\tse_aes_unwrap_key(13, 15, console_keyseed);\n\t\t\t\tse_aes_unwrap_key(12, 12, master_keyseed_retail);\n\t\t\t\tbreak;\n\t\t\tcase HOS_MKEY_VER_400:\n\t\t\t\tse_aes_unwrap_key(13, 15, console_keyseed_4xx);\n\t\t\t\tse_aes_unwrap_key(15, 15, console_keyseed);\n\t\t\t\tse_aes_unwrap_key(14, 12, master_keyseed_4xx);\n\t\t\t\tse_aes_unwrap_key(12, 12, master_keyseed_retail);\n\t\t\t\tsbk_is_set = false;\n\t\t\t\tbreak;\n\t\t\tcase HOS_MKEY_VER_500:\n\t\t\tcase HOS_MKEY_VER_600:\n\t\t\t\tse_aes_unwrap_key(10, 15, console_keyseed_4xx);\n\t\t\t\tse_aes_unwrap_key(15, 15, console_keyseed);\n\t\t\t\tse_aes_unwrap_key(14, 12, master_keyseed_4xx);\n\t\t\t\tse_aes_unwrap_key(12, 12, master_keyseed_retail);\n\t\t\t\tsbk_is_set = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse // Exosphere 2.\n\t\t{\n\t\t\tse_aes_unwrap_key(10, 15, console_keyseed_4xx);\n\t\t\tse_aes_unwrap_key(15, 15, console_keyseed);\n\t\t\tse_aes_unwrap_key(13, 12, master_keyseed_retail);\n\t\t\tse_aes_unwrap_key(12, 12, master_keyseed_4xx);\n\t\t}\n\n\t\t// Package2 key.\n\t\tse_key_acc_ctrl(8, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG);\n\t\tse_aes_unwrap_key(8, !is_exo ? 12 : 13, package2_keyseed);\n\t}\n\n\treturn 0;\n}\n\nstatic int _read_emmc_pkg1(launch_ctxt_t *ctxt)\n{\n\tconst u32 pk1_offset = h_cfg.t210b01 ? sizeof(bl_hdr_t210b01_t) : 0; // Skip T210B01 OEM header.\n\tu32 bootloader_offset = PKG1_BOOTLOADER_MAIN_OFFSET;\n\tctxt->pkg1 = (void *)malloc(PKG1_BOOTLOADER_SIZE);\n\ntry_load:\n\t// Read package1.\n\temummc_storage_set_mmc_partition(EMMC_BOOT0);\n\temummc_storage_read(bootloader_offset, PKG1_BOOTLOADER_SIZE / EMMC_BLOCKSIZE, ctxt->pkg1);\n\n\tctxt->pkg1_id = pkg1_identify(ctxt->pkg1 + pk1_offset);\n\tif (!ctxt->pkg1_id)\n\t{\n\t\t// Check if wrong pkg1 was flashed.\n\t\tbool wrong_pkg1;\n\n\t\tconst u32 pkg1_erista_check = ((bl_hdr_t210b01_t *)ctxt->pkg1)->entrypoint;\n\t\tconst u32 pkg1_mariko_check = *(u32 *)(ctxt->pkg1 + sizeof(pk1_hdr_t) * 2);\n\n\t\tif (!h_cfg.t210b01) // For Erista check if start is 0 and entrypoint matches Mariko.\n\t\t\twrong_pkg1 = *(u32 *)ctxt->pkg1 == 0 && pkg1_erista_check == PKG1_MARIKO_ON_ERISTA_MAGIC;\n\t\telse                // For Mariko check if start is not 0 and build id. It works for 8.0.0 Erista pkg1 and up.\n\t\t\twrong_pkg1 = *(u32 *)ctxt->pkg1 != 0 && pkg1_mariko_check == PKG1_ERISTA_ON_MARIKO_MAGIC;\n\n\t\tif (wrong_pkg1)\n\t\t{\n\t\t\t_hos_crit_error(\"Wrong pkg1 flashed:\");\n\t\t\tEPRINTFARGS(\"%s pkg1 on %s!\",\n\t\t\t\t!h_cfg.t210b01 ? \"Mariko\" : \"Erista\", !h_cfg.t210b01 ? \"Erista\" : \"Mariko\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_hos_crit_error(\"Unknown pkg1 version.\");\n\t\t\tEPRINTFARGS(\"HOS version not supported!%s\",\n\t\t\t\t(emu_cfg.enabled && !h_cfg.emummc_force_disable) ? \"\\nOr emuMMC corrupt!\" : \"\");\n\t\t}\n\n\t\t// Try backup bootloader.\n\t\tif (bootloader_offset != PKG1_BOOTLOADER_BACKUP_OFFSET)\n\t\t{\n\t\t\tEPRINTF(\"\\nTrying backup bootloader...\");\n\t\t\tbootloader_offset = PKG1_BOOTLOADER_BACKUP_OFFSET;\n\t\t\tgoto try_load;\n\t\t}\n\n\t\treturn 1;\n\t}\n\tgfx_printf(\"Identified pkg1 and mkey %d\\n\\n\", ctxt->pkg1_id->mkey);\n\n\t// Read the correct eks for older HOS versions.\n\tif (ctxt->pkg1_id->mkey <= HOS_MKEY_VER_600)\n\t{\n\t\tconst u32 eks_size = sizeof(pkg1_eks_t);\n\t\tctxt->eks = (pkg1_eks_t *)malloc(eks_size);\n\t\temummc_storage_read(PKG1_HOS_EKS_OFFSET + (ctxt->pkg1_id->mkey * eks_size) / EMMC_BLOCKSIZE,\n\t\t\t\t\t\t\teks_size / EMMC_BLOCKSIZE, ctxt->eks);\n\t}\n\n\treturn 0;\n}\n\nstatic u8 *_read_emmc_pkg2(launch_ctxt_t *ctxt)\n{\n\tu8 *nx_bc = NULL;\n\n\temummc_storage_set_mmc_partition(EMMC_GPP);\n\n\t// Parse eMMC GPT.\n\tLIST_INIT(gpt);\n\temmc_gpt_parse(&gpt);\nDPRINTF(\"Parsed GPT\\n\");\n\t// Find package2 partition.\n\temmc_part_t *pkg2_part = emmc_part_find(&gpt, \"BCPKG2-1-Normal-Main\");\n\tif (!pkg2_part)\n\t\tgoto out;\n\n\t// Read in package2 header and get package2 real size.\n\tstatic const u32 PKG2_OFFSET = SZ_16K;\n\tnx_bc = (u8 *)malloc(sizeof(nx_bc_t));\n\temmc_part_read(pkg2_part, PKG2_OFFSET / EMMC_BLOCKSIZE, 1, nx_bc);\n\tu32 *hdr = (u32 *)(nx_bc + 0x100);\n\tu32 pkg2_size = hdr[0] ^ hdr[2] ^ hdr[3];\nDPRINTF(\"pkg2 size on emmc is %08X\\n\", pkg2_size);\n\n\t// Check that size is valid.\n\tif (!pkg2_size || pkg2_size > SZ_8M)\n\t\tgoto out;\n\n\t// Read in NX Boot Config.\n\temmc_part_read(pkg2_part, 0, sizeof(nx_bc_t) / EMMC_BLOCKSIZE, nx_bc);\n\n\t// Read in package2.\n\tu32 pkg2_size_aligned = ALIGN(pkg2_size, EMMC_BLOCKSIZE);\nDPRINTF(\"pkg2 size aligned is %08X\\n\", pkg2_size_aligned);\n\tctxt->pkg2 = malloc(pkg2_size_aligned);\n\tctxt->pkg2_size = pkg2_size;\n\temmc_part_read(pkg2_part, PKG2_OFFSET / EMMC_BLOCKSIZE, pkg2_size_aligned / EMMC_BLOCKSIZE, ctxt->pkg2);\nout:\n\temmc_gpt_free(&gpt);\n\n\treturn nx_bc;\n}\n\nstatic void _free_launch_components(launch_ctxt_t *ctxt)\n{\n\t// Free the malloc'ed guaranteed addresses.\n\tfree(ctxt->pkg3);\n\tfree(ctxt->eks);\n\tfree(ctxt->pkg1);\n\tfree(ctxt->pkg2);\n\tfree(ctxt->warmboot);\n\tfree(ctxt->kip1_patches);\n}\n\nstatic bool _get_fs_exfat_compatible(link_t *info, u32 *hos_revision)\n{\n\tu32 fs_ids_cnt;\n\tu32 sha_buf[32 / sizeof(u32)];\n\tkip1_id_t *kip_ids;\n\n\tLIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, info, link)\n\t{\n\t\tif (strcmp((char *)ki->kip1->name, \"FS\"))\n\t\t\tcontinue;\n\n\t\tif (se_sha_hash_256_oneshot(sha_buf, ki->kip1, ki->size))\n\t\t\tbreak;\n\n\t\tpkg2_get_ids(&kip_ids, &fs_ids_cnt);\n\n\t\tfor (int fs_idx = fs_ids_cnt - 1; fs_idx >= 0; fs_idx--)\n\t\t{\n\t\t\tif (!memcmp(sha_buf, kip_ids[fs_idx].hash, 8))\n\t\t\t{\n\t\t\t\t// HOS Api special handling.\n\t\t\t\tif ((fs_idx & ~1) == 16)      // Check if it's 5.1.0.\n\t\t\t\t\t*hos_revision = 1;\n\t\t\t\telse if ((fs_idx & ~1) == 34) // Check if it's 10.2.0.\n\t\t\t\t\t*hos_revision = 2;\n\n\t\t\t\t// Check if FAT32-only.\n\t\t\t\tif (!(fs_idx & 1))\n\t\t\t\t\treturn false;\n\n\t\t\t\t// FS is FAT32 + exFAT.\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tbreak;\n\t}\n\n\t// FAT32 + exFAT or unknown FS version.\n\treturn true;\n}\n\nvoid hos_launch(ini_sec_t *cfg)\n{\n\tu8 mkey;\n\tu32 secmon_base;\n\tu32 warmboot_base;\n\tbool is_exo = false;\n\tlaunch_ctxt_t ctxt = {0};\n\ttsec_ctxt_t tsec_ctxt = {0};\n\n\tminerva_change_freq(FREQ_1600);\n\tlist_init(&ctxt.kip1_list);\n\n\tctxt.cfg = cfg;\n\n\tif (!gfx_con.mute)\n\t\tgfx_clear_grey(0x1B);\n\tgfx_con_setpos(0, 0);\n\n\tgfx_puts(\"Initializing...\\n\\n\");\n\n\t// Initialize eMMC/emuMMC.\n\tint res = emummc_storage_init_mmc();\n\tif (res)\n\t{\n\t\t_hos_crit_error(res == 2 ? \"Failed to init eMMC.\" : \"Failed to init emuMMC.\");\n\n\t\tgoto error;\n\t}\n\n\t// Check if SD Card is GPT.\n\tif (sd_is_gpt())\n\t{\n\t\t_hos_crit_error(\"SD has GPT only! Run Fix Hybrid MBR!\");\n\t\tgoto error;\n\t}\n\n\t// Try to parse config if present.\n\tif (hos_parse_boot_config(&ctxt))\n\t{\n\t\t_hos_crit_error(\"Wrong ini cfg or missing/corrupt files!\");\n\t\tgoto error;\n\t}\n\n\t// Read package1 and the correct eks.\n\tif (_read_emmc_pkg1(&ctxt))\n\t{\n\t\t// Check if stock is enabled and device can boot in OFW.\n\t\tif (ctxt.stock && (h_cfg.t210b01 || !tools_autorcm_enabled()))\n\t\t{\n\t\t\temmc_end();\n\n\t\t\tWPRINTF(\"\\nRebooting to OFW in 5s...\");\n\t\t\tmsleep(5000);\n\n\t\t\tpower_set_state(REBOOT_BYPASS_FUSES);\n\t\t}\n\t\tgoto error;\n\t}\n\n\tmkey = ctxt.pkg1_id->mkey;\n\n\tbool emummc_enabled = emu_cfg.enabled && !h_cfg.emummc_force_disable;\n\n\t// Enable emummc patching.\n\tif (emummc_enabled)\n\t{\n\t\tif (ctxt.stock)\n\t\t{\n\t\t\t_hos_crit_error(\"Stock emuMMC is not supported yet!\");\n\t\t\tgoto error;\n\t\t}\n\n\t\tctxt.patch_krn_proc_id = true; // Set kernel process id patching in case of no pkg3.\n\t\thos_config_kip1patch(&ctxt, \"emummc\");\n\t}\n\telse if (!emu_cfg.enabled && ctxt.emummc_forced)\n\t{\n\t\t_hos_crit_error(\"emuMMC is forced but not enabled!\");\n\t\tgoto error;\n\t}\n\n\t// If Auto NOGC is enabled, check if burnt fuses lower than installed HOS fuses and apply NOGC patch.\n\t// For emuMMC, unconditionally enable NOGC when burnt fuses are higher than installed HOS fuses.\n\t// Disable Auto NOGC in stock to prevent black screen (fatal error). Use kip1patch=nogc to force it.\n\tif (!ctxt.stock)\n\t{\n\t\tu32 fuses = fuse_read_odm(7);\n\t\tif ((h_cfg.autonogc && // Prevent GC fuse burning (sysMMC and emuMMC).\n\t\t\t  (\n\t\t\t\t(!(fuses &    ~0xF) && (ctxt.pkg1_id->fuses >=  5)) || // LAFW v2,  4.0.0+\n\t\t\t\t(!(fuses &  ~0x3FF) && (ctxt.pkg1_id->fuses >= 11)) || // LAFW v3,  9.0.0+\n\t\t\t\t(!(fuses & ~0x1FFF) && (ctxt.pkg1_id->fuses >= 14)) || // LAFW v4, 11.0.0+\n\t\t\t\t// Detection broken! Use kip1patch=nogc                // LAFW v5, 12.0.0+\n\t\t\t\t(!(fuses & ~0x3FFF) && (ctxt.pkg1_id->fuses >= 15))    // LAFW v5, 12.0.2+\n\t\t\t  )\n\t\t\t)\n\t\t|| ((emummc_enabled) && // Force NOGC if already burnt (only emuMMC).\n\t\t\t  (\n\t\t\t\t((fuses & BIT(10)) && (ctxt.pkg1_id->fuses <= 10)) || // HOS  9.0.0+ fuses burnt.\n\t\t\t\t((fuses & BIT(13)) && (ctxt.pkg1_id->fuses <= 13)) || // HOS 11.0.0+ fuses burnt.\n\t\t\t\t// Detection broken! Use kip1patch=nogc               // HOS 12.0.0+\n\t\t\t\t((fuses & BIT(14)) && (ctxt.pkg1_id->fuses <= 14))    // HOS 12.0.2+ fuses burnt.\n\t\t\t  )\n\t\t\t))\n\t\t\thos_config_kip1patch(&ctxt, \"nogc\");\n\t}\n\n\tgfx_printf(\"Loaded config and pkg1\\n%s mode\\n\", ctxt.stock ? \"Stock\" : \"CFW\");\n\n\t// Check if secmon is exosphere.\n\tif (ctxt.secmon)\n\t\tis_exo = !memcmp((void *)((u8 *)ctxt.secmon + ctxt.secmon_size - 4), \"LENY\", 4);\n\n\t// Get secmon and warmboot bases.\n\tconst pkg1_id_t *pk1_latest = pkg1_get_latest();\n\tsecmon_base   = is_exo ? pk1_latest->secmon_base   : ctxt.pkg1_id->secmon_base;\n\twarmboot_base = is_exo ? pk1_latest->warmboot_base : ctxt.pkg1_id->warmboot_base;\n\n\t// Set package1 and tsec fw offsets.\n\ttsec_ctxt.fw        = (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off;\n\ttsec_ctxt.pkg1      = ctxt.pkg1;\n\ttsec_ctxt.pkg11_off = ctxt.pkg1_id->pkg11_off;\n\n\t// Generate keys.\n\tif (_hos_keygen(ctxt.eks, mkey, &tsec_ctxt, ctxt.stock, is_exo))\n\t\tgoto error;\n\tgfx_puts(\"Generated keys\\n\");\n\n\t// Decrypt and unpack package1 if we require parts of it.\n\tif (!ctxt.warmboot || !ctxt.secmon)\n\t{\n\t\t// Decrypt PK1 or PK11.\n\t\tif (mkey <= HOS_MKEY_VER_600 || h_cfg.t210b01)\n\t\t{\n\t\t\tif (!pkg1_decrypt(ctxt.pkg1_id, ctxt.pkg1))\n\t\t\t{\n\t\t\t\t_hos_crit_error(\"Pkg1 decryption failed!\");\n\n\t\t\t\t// Check if T210B01 BEK is missing or wrong.\n\t\t\t\tif (h_cfg.t210b01)\n\t\t\t\t{\n\t\t\t\t\tu32 bek_vector[4] = {0};\n\t\t\t\t\tse_aes_crypt_ecb(13, ENCRYPT, bek_vector, bek_vector, SE_KEY_128_SIZE);\n\t\t\t\t\tif (bek_vector[0] == 0x59C14895) // Encrypted zeroes first 32bits.\n\t\t\t\t\t\tEPRINTF(\"Pkg1 corrupt?\");\n\t\t\t\t\telse\n\t\t\t\t\t\tEPRINTF(\"BEK is missing!\");\n\t\t\t\t}\n\t\t\t\tgoto error;\n\t\t\t}\n\t\t}\n\n\t\t// Unpack PK11.\n\t\tif (h_cfg.t210b01 || (mkey <= HOS_MKEY_VER_620 && !emummc_enabled))\n\t\t{\n\t\t\t// Skip T210B01 OEM header.\n\t\t\tu32 pk1_offset = 0;\n\t\t\tif (h_cfg.t210b01)\n\t\t\t\tpk1_offset = sizeof(bl_hdr_t210b01_t);\n\n\t\t\tpkg1_unpack((void *)warmboot_base, &ctxt.warmboot_size,\n\t\t\t\t!is_exo ? (void *)ctxt.pkg1_id->secmon_base : NULL, NULL,\n\t\t\t\tctxt.pkg1_id, ctxt.pkg1 + pk1_offset);\n\n\t\t\tgfx_puts(\"Decrypted & unpacked pkg1\\n\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_hos_crit_error(\"No mandatory pkg1 files provided!\");\n\t\t\tgoto error;\n\t\t}\n\t}\n\n\t// Configure and manage Warmboot binary.\n\tif (pkg1_warmboot_config(&ctxt, warmboot_base, ctxt.pkg1_id->fuses, mkey))\n\t{\n\t\t// Can only happen on T210B01.\n\t\t_hos_crit_error(\"\\nFailed to match warmboot with fuses!\\nIf you continue, sleep wont work!\");\n\n\t\tgfx_puts(\"\\nPress POWER to continue.\\nPress VOL to go to the menu.\\n\");\n\t\tdisplay_backlight_brightness(h_cfg.backlight, 1000);\n\n\t\tif (!(btn_wait() & BTN_POWER))\n\t\t\tgoto error;\n\t}\n\n\t// Replace 'warmboot.bin' if requested.\n\tif (ctxt.warmboot)\n\t\tmemcpy((void *)warmboot_base, ctxt.warmboot, ctxt.warmboot_size);\n\telse if (!h_cfg.t210b01)\n\t{\n\t\t// Patch warmboot on T210 to allow downgrading.\n\t\tif (mkey >= HOS_MKEY_VER_700)\n\t\t{\n\t\t\t_hos_crit_error(\"No warmboot provided!\");\n\t\t\tgoto error;\n\t\t}\n\n\t\tpkg1_warmboot_patch((void *)&ctxt);\n\t}\n\n\t// Replace 'SecureMonitor' if requested or patch Pkg2 checks if needed.\n\tif (ctxt.secmon)\n\t\tmemcpy((void *)secmon_base, ctxt.secmon, ctxt.secmon_size);\n\telse\n\t\tpkg1_secmon_patch((void *)&ctxt, secmon_base, h_cfg.t210b01);\n\n\tgfx_puts(\"Loaded warmboot and secmon\\n\");\n\n\t// Read package2.\n\tu8 *pkg2_nx_bc = _read_emmc_pkg2(&ctxt);\n\tif (!pkg2_nx_bc)\n\t{\n\t\t_hos_crit_error(\"Pkg2 read failed!\");\n\t\tgoto error;\n\t}\n\n\tgfx_puts(\"Read pkg2\\n\");\n\n\t// Decrypt package2 and parse KIP1 blobs in INI1 section.\n\tpkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2, mkey, is_exo);\n\tif (!pkg2_hdr)\n\t{\n\t\t_hos_crit_error(\"Pkg2 decryption failed!\\npkg1/pkg2 mismatch or old hekate!\");\n\n\t\t// Clear EKS slot, in case something went wrong with tsec keygen.\n\t\t_hos_eks_clear(mkey);\n\t\tgoto error;\n\t}\n\n\tLIST_INIT(kip1_info);\n\tif (pkg2_parse_kips(&kip1_info, pkg2_hdr, &ctxt.new_pkg2))\n\t{\n\t\t_hos_crit_error(\"INI1 parsing failed!\");\n\t\tgoto error;\n\t}\n\n\tgfx_puts(\"Parsed ini1\\n\");\n\n\t// Use the kernel included in package2 in case we didn't load one already.\n\tif (!ctxt.kernel)\n\t{\n\t\tctxt.kernel = pkg2_hdr->data;\n\t\tctxt.kernel_size = pkg2_hdr->sec_size[PKG2_SEC_KERNEL];\n\n\t\tif (!ctxt.stock && (ctxt.svcperm || ctxt.debugmode || ctxt.patch_krn_proc_id))\n\t\t{\n\t\t\t// Hash only Kernel when it embeds INI1.\n\t\t\tu8 kernel_hash[0x20];\n\t\t\tif (!ctxt.new_pkg2)\n\t\t\t\tse_sha_hash_256_oneshot(kernel_hash, ctxt.kernel, ctxt.kernel_size);\n\t\t\telse\n\t\t\t\tse_sha_hash_256_oneshot(kernel_hash, ctxt.kernel + PKG2_NEWKERN_START,\n\t\t\t\t\tpkg2_newkern_ini1_start - PKG2_NEWKERN_START);\n\n\t\t\tctxt.pkg2_kernel_id = pkg2_identify(kernel_hash);\n\t\t\tif (!ctxt.pkg2_kernel_id)\n\t\t\t{\n\t\t\t\t_hos_crit_error(\"Failed to identify kernel!\");\n\n\t\t\t\tgoto error;\n\t\t\t}\n\n\t\t\t// In case a kernel patch option is set; allows to disable SVC verification or/and enable debug mode.\n\t\t\tconst kernel_patch_t *kernel_patchset = ctxt.pkg2_kernel_id->kernel_patchset;\n\t\t\tif (kernel_patchset != NULL)\n\t\t\t{\n\t\t\t\tgfx_printf(\"%kPatching kernel%k\\n\", TXT_CLR_ORANGE, TXT_CLR_DEFAULT);\n\t\t\t\tu32 *temp;\n\t\t\t\tfor (u32 i = 0; kernel_patchset[i].id != 0xFFFFFFFF; i++)\n\t\t\t\t{\n\t\t\t\t\tif ((ctxt.svcperm && kernel_patchset[i].id == SVC_VERIFY_DS)\n\t\t\t\t\t|| (ctxt.debugmode && kernel_patchset[i].id == DEBUG_MODE_EN && !(ctxt.patch_krn_proc_id && ctxt.secmon))\n\t\t\t\t\t|| (ctxt.patch_krn_proc_id && kernel_patchset[i].id == ATM_GEN_PATCH))\n\t\t\t\t\t\t*(vu32 *)(ctxt.kernel + kernel_patchset[i].off) = kernel_patchset[i].val;\n\t\t\t\t\telse if (ctxt.patch_krn_proc_id && kernel_patchset[i].id == ATM_ARR_PATCH)\n\t\t\t\t\t{\n\t\t\t\t\t\ttemp = (u32 *)kernel_patchset[i].ptr;\n\t\t\t\t\t\tfor (u32 j = 0; j < kernel_patchset[i].val; j++)\n\t\t\t\t\t\t\t*(vu32 *)(ctxt.kernel + kernel_patchset[i].off + (j << 2)) = temp[j];\n\t\t\t\t\t}\n\t\t\t\t\telse if (kernel_patchset[i].id < SVC_VERIFY_DS)\n\t\t\t\t\t\t*(vu32 *)(ctxt.kernel + kernel_patchset[i].off) = kernel_patchset[i].val;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Merge extra KIP1s into loaded ones.\n\tLIST_FOREACH_ENTRY(merge_kip_t, mki, &ctxt.kip1_list, link)\n\t\tpkg2_merge_kip(&kip1_info, (pkg2_kip1_t *)mki->kip1);\n\n\t// Check if FS is compatible with exFAT and if 5.1.0 or 10.2.0.\n\tif (!ctxt.stock && (sd_fs.fs_type == FS_EXFAT || mkey == HOS_MKEY_VER_500 || ctxt.pkg1_id->fuses == 13))\n\t{\n\t\tbool exfat_compat = _get_fs_exfat_compatible(&kip1_info, &ctxt.exo_ctx.hos_revision);\n\n\t\tif (sd_fs.fs_type == FS_EXFAT && !exfat_compat)\n\t\t{\n\t\t\t_hos_crit_error(\"SD Card is exFAT but installed HOS driver\\nonly supports FAT32!\");\n\n\t\t\tgoto error;\n\t\t}\n\t}\n\n\t// Patch kip1s in memory if needed.\n\tconst char *failed_patch = pkg2_patch_kips(&kip1_info, ctxt.kip1_patches);\n\tif (failed_patch != NULL)\n\t{\n\t\tEHPRINTFARGS(\"Failed to apply '%s'!\", failed_patch);\n\n\t\tbool emu_patch_failed = !strcmp(failed_patch, \"emummc\");\n\t\tif (!emu_patch_failed)\n\t\t{\n\t\t\tgfx_puts(\"\\nPress POWER to continue.\\nPress VOL to go to the menu.\\n\");\n\t\t\tdisplay_backlight_brightness(h_cfg.backlight, 1000);\n\t\t}\n\n\t\tif (emu_patch_failed || !(btn_wait() & BTN_POWER))\n\t\t\tgoto error; // MUST stop here, because if user requests 'nogc' but it's not applied, their GC controller gets updated!\n\t}\n\n\t// Rebuild and encrypt package2.\n\tpkg2_build_encrypt((void *)PKG2_LOAD_ADDR, &ctxt, &kip1_info, is_exo);\n\n\t// Configure Exosphere if secmon is replaced.\n\tif (is_exo)\n\t\tconfig_exosphere(&ctxt, warmboot_base);\n\n\t// Unmount SD card and eMMC.\n\tsd_end();\n\temmc_end();\n\n\t// Close AHB aperture. Important when stock old secmon is used.\n\tmc_disable_ahb_redirect();\n\n\tgfx_printf(\"Rebuilt & loaded pkg2\\n\\n%kBooting...%k\\n\", TXT_CLR_GREENISH, TXT_CLR_DEFAULT);\n\n\t// Clear pkg1/pkg2 keys.\n\tse_aes_key_clear(8);\n\tse_aes_key_clear(11);\n\n\t// Clear derived master key in case of Erista and 7.0.0+\n\tse_aes_key_clear(9);\n\n\t// Set secmon mailbox pkg2 ready state.\n\tu32 pkg1_state_pkg2_ready = PKG1_STATE_PKG2_READY;\n\n\t// Finalize per firmware key access. Skip access control if Exosphere 2.\n\tswitch (mkey | (is_exo << 7))\n\t{\n\tcase HOS_MKEY_VER_100:\n\tcase HOS_MKEY_VER_300:\n\tcase HOS_MKEY_VER_301:\n\t\tse_key_acc_ctrl(12, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_LOCK_FLAG);\n\t\tse_key_acc_ctrl(13, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_LOCK_FLAG);\n\t\tpkg1_state_pkg2_ready = PKG1_STATE_PKG2_READY_OLD;\n\t\tbreak;\n\tcase HOS_MKEY_VER_400:\n\tcase HOS_MKEY_VER_500:\n\tcase HOS_MKEY_VER_600:\n\t\tse_key_acc_ctrl(12, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_LOCK_FLAG);\n\t\tse_key_acc_ctrl(15, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_LOCK_FLAG);\n\t\tbreak;\n\t}\n\n\t// Finalize MC carveout.\n\tif (mkey <= HOS_MKEY_VER_301 && !is_exo)\n\t\tmc_config_carveout_hos();\n\n\t// Lock SE before starting secmon if < 6.2.0, otherwise lock bootrom and ipatches.\n\t_se_lock(mkey <= HOS_MKEY_VER_600 && !is_exo);\n\n\t// Reset sysctr0 counters. Mandatory for 6.2.0 and up.\n\tfor (u32 i = 0; i < SYSCTR0_COUNTERS; i++)\n\t\tSYSCTR0(SYSCTR0_COUNTERS_BASE + i * sizeof(u32)) = 0;\n\n\t// NX Bootloader locks LP0 Carveout secure scratch registers.\n\t//pmc_scratch_lock(PMC_SEC_LOCK_LP0_PARAMS);\n\n\t// Copy the read NX BC to the correct address.\n\tnx_bc_t *nxbc = (mkey >= HOS_MKEY_VER_600 || is_exo) ?\n\t\t\t\t\t(nx_bc_t *)NX_BC6_ADDR :\n\t\t\t\t\t(nx_bc_t *)NX_BC1_ADDR;\n\tmemcpy(nxbc, pkg2_nx_bc, sizeof(nx_bc_t)); // NX bootloader copies 4KB.\n\n\t// Set NX BIT mailbox address and clear it.\n\tnx_bit_t *nxbit = (mkey >= HOS_MKEY_VER_700 || is_exo) ?\n\t\t\t\t\t  (nx_bit_t *)NX_BIT7_MAILBOX_ADDR :\n\t\t\t\t\t  (nx_bit_t *)NX_BIT1_MAILBOX_ADDR;\n\tmemset(nxbit, 0, sizeof(nx_bit_t));\n\n\t// Set used NX BIT parameters.\n\tnxbit->bl_attribute = 0;\n\tnxbit->boot_type    = BIT_BOOT_TYPE_COLD;\n\n\t// Start directly from PKG2 ready signal and reset secmon state.\n\tnxbit->secldr_state = pkg1_state_pkg2_ready;\n\tnxbit->secmon_state = SECMON_STATE_NOT_READY;\n\n\t// Disable display.\n\tdisplay_end();\n\tclock_disable_host1x();\n\n\t// Override uCID if set.\n\tEMC(EMC_SCRATCH0) = ctxt.ucid;\n\n\t// Hold USBD, USB2, AHBDMA and APBDMA in reset for SoC state validation on sleep.\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_USBD);\n\tCLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = BIT(CLK_H_AHBDMA) | BIT(CLK_H_APBDMA) | BIT(CLK_H_USB2);\n\n\t// Reset arbiter.\n\thw_config_arbiter(true);\n\n\t// Scale down RAM OC if enabled.\n\tminerva_prep_boot_hos();\n\n\t// Flush cache and disable MMU.\n\tbpmp_mmu_disable();\n\tbpmp_clk_rate_set(BPMP_CLK_NORMAL);\n\n\t// Launch secmon.\n\tccplex_boot_cpu0(secmon_base, true);\n\n\t// Halt ourselves in wait-event state.\n\twhile (true)\n\t\tbpmp_halt();\n\nerror:\n\t_free_launch_components(&ctxt);\n\temmc_end();\n\n\tEPRINTF(\"\\nFailed to launch HOS!\");\n}\n"
  },
  {
    "path": "bootloader/hos/hos.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _HOS_H_\n#define _HOS_H_\n\n#include <bdk.h>\n\n#include \"pkg1.h\"\n#include \"pkg2.h\"\n\n#include <assert.h>\n\n//!TODO: Update on mkey changes.\nenum {\n\tHOS_MKEY_VER_100  = 0,\n\tHOS_MKEY_VER_300  = 1,\n\tHOS_MKEY_VER_301  = 2,\n\tHOS_MKEY_VER_400  = 3,\n\tHOS_MKEY_VER_500  = 4,\n\tHOS_MKEY_VER_600  = 5,\n\tHOS_MKEY_VER_620  = 6,\n\tHOS_MKEY_VER_700  = 7,\n\tHOS_MKEY_VER_810  = 8,\n\tHOS_MKEY_VER_900  = 9,\n\tHOS_MKEY_VER_910  = 10,\n\tHOS_MKEY_VER_1210 = 11,\n\tHOS_MKEY_VER_1300 = 12,\n\tHOS_MKEY_VER_1400 = 13,\n\tHOS_MKEY_VER_1500 = 14,\n\tHOS_MKEY_VER_1600 = 15,\n\tHOS_MKEY_VER_1700 = 16,\n\tHOS_MKEY_VER_1800 = 17,\n\tHOS_MKEY_VER_1900 = 18,\n\tHOS_MKEY_VER_2000 = 19,\n\tHOS_MKEY_VER_2100 = 20,\n\tHOS_MKEY_VER_2200 = 21,\n\tHOS_MKEY_VER_MAX  = HOS_MKEY_VER_2200\n};\n\n#define HOS_TSEC_VERSION 4 //! TODO: Update on TSEC Root Key changes.\n\n#define HOS_PKG11_MAGIC  0x31314B50\n#define HOS_EKS_MAGIC    0x31534B45 // EKS1.\n#define HOS_EKS_TSEC_VER (HOS_MKEY_VER_700 + HOS_TSEC_VERSION)\n\n// Use official Mariko secmon when in stock. Needs access to TZRAM.\n//#define HOS_MARIKO_STOCK_SECMON\n\ntypedef struct _exo_ctxt_t\n{\n\tu32   hos_revision;\n\tbool  no_user_exceptions;\n\tbool  user_pmu;\n\tbool *force_mem_mode;\n\tbool *usb3_force;\n\tbool *cal0_blank;\n\tbool *cal0_allow_writes_sys;\n} exo_ctxt_t;\n\ntypedef struct _hos_eks_mbr_t\n{\n\tu32 magic;\n\tu32 enabled;\n\tu32 lot0;\n\tu32 rsvd;\n\tu8  tsec[SE_KEY_128_SIZE];\n\tu8  troot[SE_KEY_128_SIZE];\n\tu8  troot_dev[SE_KEY_128_SIZE];\n} hos_eks_mbr_t;\n\nstatic_assert(sizeof(hos_eks_mbr_t) == 64, \"HOS EKS size is wrong!\");\n\ntypedef struct _launch_ctxt_t\n{\n\tpkg1_eks_t *eks;\n\n\tvoid *pkg1;\n\tconst pkg1_id_t *pkg1_id;\n\tconst pkg2_kernel_id_t *pkg2_kernel_id;\n\n\tvoid *warmboot;\n\tu32   warmboot_size;\n\tvoid *secmon;\n\tu32   secmon_size;\n\tvoid *exofatal;\n\tu32   exofatal_size;\n\n\tvoid *pkg2;\n\tu32   pkg2_size;\n\tbool  new_pkg2;\n\n\tvoid *kernel;\n\tu32   kernel_size;\n\n\tlink_t kip1_list;\n\tchar  *kip1_patches;\n\n\tbool svcperm;\n\tbool debugmode;\n\tbool stock;\n\tbool emummc_forced;\n\n\tvoid *pkg3;\n\tu32   pkg3_hosver;\n\tbool  patch_krn_proc_id;\n\n\tint ucid;\n\n\texo_ctxt_t exo_ctx;\n\n\tini_sec_t *cfg;\n} launch_ctxt_t;\n\ntypedef struct _merge_kip_t\n{\n\tvoid *kip1;\n\tlink_t link;\n} merge_kip_t;\n\nvoid hos_launch(ini_sec_t *cfg);\n\n#endif\n"
  },
  {
    "path": "bootloader/hos/hos_config.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <bdk.h>\n\n#include \"hos.h\"\n#include \"hos_config.h\"\n#include \"pkg3.h\"\n#include <libs/fatfs/ff.h>\n\n//#define DPRINTF(...) gfx_printf(__VA_ARGS__)\n#define DPRINTF(...)\n\nstatic int _config_warmboot(launch_ctxt_t *ctxt, const char *value)\n{\n\tctxt->warmboot = sd_file_read(value, &ctxt->warmboot_size);\n\tif (!ctxt->warmboot)\n\t\treturn 1;\n\n\treturn 0;\n}\n\nstatic int _config_secmon(launch_ctxt_t *ctxt, const char *value)\n{\n\tctxt->secmon = sd_file_read(value, &ctxt->secmon_size);\n\tif (!ctxt->secmon)\n\t\treturn 1;\n\n\treturn 0;\n}\n\nstatic int _config_kernel(launch_ctxt_t *ctxt, const char *value)\n{\n\tctxt->kernel = sd_file_read(value, &ctxt->kernel_size);\n\tif (!ctxt->kernel)\n\t\treturn 1;\n\n\treturn 0;\n}\n\nstatic int _config_kip1(launch_ctxt_t *ctxt, const char *value)\n{\n\tu32 size;\n\n\tif (value[strlen(value) - 1] == '*')\n\t{\n\t\tchar *dir = (char *)malloc(256);\n\t\tstrcpy(dir, value);\n\n\t\tu32 dirlen = 0;\n\t\tdir[strlen(dir) - 2] = 0;\n\t\tdirlist_t *filelist = dirlist(dir, \"*.kip*\", 0);\n\n\t\tstrcat(dir, \"/\");\n\t\tdirlen = strlen(dir);\n\n\t\tu32 i = 0;\n\t\tif (filelist)\n\t\t{\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tif (!filelist->name[i])\n\t\t\t\t\tbreak;\n\n\t\t\t\tstrcpy(dir + dirlen, filelist->name[i]);\n\n\t\t\t\tmerge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));\n\t\t\t\tmkip1->kip1 = sd_file_read(dir, &size);\n\t\t\t\tif (!mkip1->kip1)\n\t\t\t\t{\n\t\t\t\t\tfree(mkip1);\n\t\t\t\t\tfree(dir);\n\t\t\t\t\tfree(filelist);\n\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\tDPRINTF(\"Loaded kip1 from SD (size %08X)\\n\", size);\n\t\t\t\tlist_append(&ctxt->kip1_list, &mkip1->link);\n\n\t\t\t\ti++;\n\t\t\t}\n\t\t}\n\n\t\tfree(dir);\n\t\tfree(filelist);\n\t}\n\telse\n\t{\n\t\tmerge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));\n\t\tmkip1->kip1 = sd_file_read(value, &size);\n\t\tif (!mkip1->kip1)\n\t\t{\n\t\t\tfree(mkip1);\n\n\t\t\treturn 1;\n\t\t}\n\t\tDPRINTF(\"Loaded kip1 from SD (size %08X)\\n\", size);\n\t\tlist_append(&ctxt->kip1_list, &mkip1->link);\n\t}\n\n\treturn 0;\n}\n\nint hos_config_kip1patch(launch_ctxt_t *ctxt, const char *value)\n{\n\tint len = strlen(value);\n\tif (!len)\n\t\treturn 1;\n\n\tif (ctxt->kip1_patches == NULL)\n\t{\n\t\tctxt->kip1_patches = malloc(len + 1);\n\t\tmemcpy(ctxt->kip1_patches, value, len);\n\t\tctxt->kip1_patches[len] = 0;\n\t}\n\telse\n\t{\n\t\tchar *old_addr = ctxt->kip1_patches;\n\t\tint old_len = strlen(old_addr);\n\n\t\tctxt->kip1_patches = malloc(old_len + 1 + len + 1);\n\t\tmemcpy(ctxt->kip1_patches, old_addr, old_len);\n\t\tfree(old_addr);\n\n\t\tctxt->kip1_patches[old_len++] = ',';\n\t\tmemcpy(&ctxt->kip1_patches[old_len], value, len);\n\t\tctxt->kip1_patches[old_len + len] = 0;\n\t}\n\n\treturn 0;\n}\n\nstatic int _config_svcperm(launch_ctxt_t *ctxt, const char *value)\n{\n\tif (*value == '1')\n\t{\n\t\tDPRINTF(\"Disabled SVC verification\\n\");\n\t\tctxt->svcperm = true;\n\t}\n\n\treturn 0;\n}\n\nstatic int _config_debugmode(launch_ctxt_t *ctxt, const char *value)\n{\n\tif (*value == '1')\n\t{\n\t\tDPRINTF(\"Enabled Debug mode\\n\");\n\t\tctxt->debugmode = true;\n\t}\n\n\treturn 0;\n}\n\nstatic int _config_stock(launch_ctxt_t *ctxt, const char *value)\n{\n\tif (*value == '1')\n\t{\n\t\tDPRINTF(\"Enabled stock mode\\n\");\n\t\tctxt->stock = true;\n\t}\n\n\treturn 0;\n}\n\nstatic int _config_emummc_forced(launch_ctxt_t *ctxt, const char *value)\n{\n\tif (*value == '1')\n\t{\n\t\tDPRINTF(\"Forced emuMMC\\n\");\n\t\tctxt->emummc_forced = true;\n\t}\n\n\treturn 0;\n}\n\nstatic int _config_kernel_proc_id(launch_ctxt_t *ctxt, const char *value)\n{\n\tif (*value == '1')\n\t{\n\t\tDPRINTF(\"Enabled kernel process id send/recv patching\\n\");\n\t\tctxt->patch_krn_proc_id = true;\n\t}\n\n\treturn 0;\n}\n\nstatic int _config_dis_exo_user_exceptions(launch_ctxt_t *ctxt, const char *value)\n{\n\tif (*value == '1')\n\t{\n\t\tDPRINTF(\"Disabled exosphere user exception handlers\\n\");\n\t\tctxt->exo_ctx.no_user_exceptions = true;\n\t}\n\n\treturn 0;\n}\n\nstatic int _config_exo_user_pmu_access(launch_ctxt_t *ctxt, const char *value)\n{\n\tif (*value == '1')\n\t{\n\t\tDPRINTF(\"Enabled user access to PMU\\n\");\n\t\tctxt->exo_ctx.user_pmu = true;\n\t}\n\n\treturn 0;\n}\n\nstatic int _config_exo_force_mem_mode(launch_ctxt_t *ctxt, const char *value)\n{\n\t// Override key found.\n\tctxt->exo_ctx.force_mem_mode = zalloc(sizeof(bool));\n\n\tif (*value == '1')\n\t{\n\t\tDPRINTF(\"Enabled Auto Memory Mode\\n\");\n\t\t*ctxt->exo_ctx.force_mem_mode = true;\n\t}\n\n\treturn 0;\n}\n\nstatic int _config_exo_usb3_force(launch_ctxt_t *ctxt, const char *value)\n{\n\t// Override key found.\n\tctxt->exo_ctx.usb3_force = zalloc(sizeof(bool));\n\n\tif (*value == '1')\n\t{\n\t\tDPRINTF(\"Enabled USB 3.0\\n\");\n\t\t*ctxt->exo_ctx.usb3_force = true;\n\t}\n\n\treturn 0;\n}\n\nstatic int _config_exo_cal0_blanking(launch_ctxt_t *ctxt, const char *value)\n{\n\t// Override key found.\n\tctxt->exo_ctx.cal0_blank = zalloc(sizeof(bool));\n\n\tif (*value == '1')\n\t{\n\t\tDPRINTF(\"Enabled prodinfo blanking\\n\");\n\t\t*ctxt->exo_ctx.cal0_blank = true;\n\t}\n\n\treturn 0;\n}\n\nstatic int _config_exo_cal0_writes_enable(launch_ctxt_t *ctxt, const char *value)\n{\n\t// Override key found.\n\tctxt->exo_ctx.cal0_allow_writes_sys = zalloc(sizeof(bool));\n\n\tif (*value == '1')\n\t{\n\t\tDPRINTF(\"Enabled prodinfo writes\\n\");\n\t\t*ctxt->exo_ctx.cal0_allow_writes_sys = true;\n\t}\n\n\treturn 0;\n}\n\nstatic int _config_pkg3(launch_ctxt_t *ctxt, const char *value)\n{\n\treturn parse_pkg3(ctxt, value);\n}\n\nstatic int _config_exo_fatal_payload(launch_ctxt_t *ctxt, const char *value)\n{\n\tctxt->exofatal = sd_file_read(value, &ctxt->exofatal_size);\n\tif (!ctxt->exofatal)\n\t\treturn 1;\n\n\treturn 0;\n}\n\nstatic int _config_ucid(launch_ctxt_t *ctxt, const char *value)\n{\n\t// Override uCID if set.\n\tctxt->ucid = atoi(value);\n\n\treturn 0;\n}\n\ntypedef struct _cfg_handler_t\n{\n\tconst char *key;\n\tint (*handler)(launch_ctxt_t *ctxt, const char *value);\n} cfg_handler_t;\n\nstatic const cfg_handler_t _config_handlers[] = {\n\t{ \"stock\",            _config_stock },\n\t{ \"warmboot\",         _config_warmboot },\n\t{ \"secmon\",           _config_secmon },\n\t{ \"kernel\",           _config_kernel },\n\t{ \"kip1\",             _config_kip1 },\n\t{ \"kip1patch\",        hos_config_kip1patch },\n\t{ \"fullsvcperm\",      _config_svcperm },\n\t{ \"debugmode\",        _config_debugmode },\n\t{ \"kernelprocid\",     _config_kernel_proc_id },\n\n\t// To override elements from PKG3, it should be set before others.\n\t{ \"pkg3\",             _config_pkg3 },\n\t{ \"fss0\",             _config_pkg3 },\n\n\t{ \"exofatal\",         _config_exo_fatal_payload},\n\t{ \"emummcforce\",      _config_emummc_forced },\n\t{ \"nouserexceptions\", _config_dis_exo_user_exceptions },\n\t{ \"userpmu\",          _config_exo_user_pmu_access },\n\t{ \"memmode\",          _config_exo_force_mem_mode },\n\t{ \"usb3force\",        _config_exo_usb3_force },\n\t{ \"cal0blank\",        _config_exo_cal0_blanking },\n\t{ \"cal0writesys\",     _config_exo_cal0_writes_enable },\n\t{ \"ucid\",             _config_ucid },\n\t{ NULL, NULL },\n};\n\nint hos_parse_boot_config(launch_ctxt_t *ctxt)\n{\n\tif (!ctxt->cfg)\n\t\treturn 0;\n\n\t// Check each config key.\n\tLIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)\n\t{\n\t\tfor (u32 i = 0; _config_handlers[i].key; i++)\n\t\t{\n\t\t\t// If key matches, call its handler.\n\t\t\tif (!strcmp(_config_handlers[i].key, kv->key))\n\t\t\t{\n\t\t\t\tif (_config_handlers[i].handler(ctxt, kv->val))\n\t\t\t\t{\n\t\t\t\t\tgfx_con.mute = false;\n\t\t\t\t\tEPRINTFARGS(\"Error while loading %s:\\n%s\", kv->key, kv->val);\n\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "bootloader/hos/hos_config.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _HOS_CONFIG_H_\n#define _HOS_CONFIG_H_\n\n#include \"hos.h\"\n\nint hos_parse_boot_config(launch_ctxt_t *ctxt);\nint hos_config_kip1patch(launch_ctxt_t *ctxt, const char *value);\n\n#endif\n\n"
  },
  {
    "path": "bootloader/hos/pkg1.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018 st4rk\n * Copyright (c) 2018-2026 CTCaer\n * Copyright (c) 2018 balika011\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n#include <stdlib.h>\n\n#include <bdk.h>\n\n#include \"hos.h\"\n#include \"pkg1.h\"\n#include \"../config.h\"\n#include <libs/compr/lz4.h>\n\n// Secmon package2 signature/hash checks patches for Erista.\n#define SM_100_ADR 0x4002B020 // Original: 0x40014020.\nPATCHSET_DEF(_secmon_1_patchset,\n\t// Patch the relocator to be able to run from SM_100_ADR.\n\t{ 0x1E0, _ADRP(0, TZRAM_BASE + 0x3000 - _PAGEOFF(SM_100_ADR)) },\n\t// Patch package2 signature/hash checks.\n\t{ 0x9F0 + 0xADC, _NOP() }\n);\n\nPATCHSET_DEF(_secmon_2_patchset,\n\t// Patch package2 signature/hash checks.\n\t{ 0xAC8 + 0xAAC, _NOP() }\n);\n\nPATCHSET_DEF(_secmon_3_patchset,\n\t// Patch package2 signature/hash checks.\n\t{ 0xAC8 + 0xA30, _NOP() }\n);\n\nPATCHSET_DEF(_secmon_4_patchset,\n\t// Patch package2 signature/hash checks.\n\t{ 0x2300 + 0x5EFC, _NOP() }\n);\n\nPATCHSET_DEF(_secmon_5_patchset,\n\t// Patch package2 signature/hash checks.\n\t{ 0xDA8 + 0xC9C, _NOP() }\n);\n\nPATCHSET_DEF(_secmon_6_patchset,\n\t// Patch package2 signature/hash checks.\n\t{ 0xDC8 + 0xE90, _NOP() }\n\t// Fix sleep mode for debug.\n\t// { 0x1A68 + 0x3854, 0x94000E45 }, //gpio_config_for_uart.\n\t// { 0x1A68 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.\n\t// { 0x1A68 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.\n\t// { 0x1A68 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.\n\t// { 0x1A68 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.\n\t// { 0x1A68 + 0x3868, 0x94000C8C }, //uart_configure.\n\t// { 0x1A68 + 0x3A6C, _NOP() }      // warmboot UARTA cfg.\n);\n\nPATCHSET_DEF(_secmon_62_patchset,\n\t// Patch package2 signature/hash checks.\n\t{ 0xDC8 + 0xC74, _NOP() }\n\t// Fix sleep mode for debug.\n\t// { 0x2AC8 + 0x3854, 0x94000F42 }, //gpio_config_for_uart.\n\t// { 0x2AC8 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.\n\t// { 0x2AC8 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.\n\t// { 0x2AC8 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.\n\t// { 0x2AC8 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.\n\t// { 0x2AC8 + 0x3868, 0x94000D89 }, //uart_configure.\n\t// { 0x2AC8 + 0x3A6C, _NOP() }      // warmboot UARTA cfg.\n);\n\n// Secmon patches for Mariko.\n#define TZRAM_PROG_ADDR               (TZRAM_BASE + 0x800)\n#define TZRAM_COMPR_PROG_OFF          0xE04\n#define TZRAM_PROG_PK2_SIG_PATCH      (TZRAM_PROG_ADDR + 0xC10)\n#define TZRAM_PROG_PK2_SIG_PATCH_1000 (TZRAM_PROG_ADDR + 0xD70)\nPATCHSET_DEF(_secmon_6_mariko_patchset,\n\t// Patch package2 decryption and signature/hash checks.\n\t{ 0xDC8 + 0xE94, _NOP() }\n);\n\nPATCHSET_DEF(_secmon_620_mariko_patchset,\n\t// Patch package2 decryption and signature/hash checks.\n\t{ 0xDC8 + 0xC78, _NOP() }\n);\n\n// From 7.0.0 and above secmon is compressed.\nPATCHSET_DEF(_secmon_7_mariko_patchset,\n\t// Patch out decompression of program payload.\n\t{ 0x82C, _NOP() }\n);\n\nconst u16 _secmon_mariko_prog_comp_size[] = {\n\t0x6B03, // 7.0.0.  Patch offset: 0xC10.\n\t0x6B16, // 7.0.1.  Patch offset: 0xC10.\n\t0x6B23, // 8.0.0.  Patch offset: 0xC10.\n\t0x6B84, // 8.1.0.  Patch offset: 0xC10.\n\t0x6C90, // 9.0.0.  Patch offset: 0xC10.\n\t0x6CE5, // 9.1.0.  Patch offset: 0xC10.\n\t0x6EE9, // 10.0.0. Patch offset: 0xD70.\n};\n\n// Erista fuse check warmboot patches.\n#define _NOPv7() 0xE320F000\nPATCHSET_DEF(_warmboot_1_patchset,\n\t{ 0x4DC, _NOPv7() } // Fuse check.\n);\n\nPATCHSET_DEF(_warmboot_3_patchset,\n\t{ 0x4DC, _NOPv7() }, // Fuse check.\n\t{ 0x4F0, _NOPv7() }  // Segment id check.\n);\n\nPATCHSET_DEF(_warmboot_4_patchset,\n\t{ 0x544, _NOPv7() }, // Fuse check.\n\t{ 0x558, _NOPv7() }  // Segment id check.\n);\n\n/*\n * package1.1 header: <wb, ldr, sm>\n * package1.1 layout:\n * 1.0:  {sm, ldr, wb} { 2, 1, 0 }\n * 2.0+: {wb, ldr, sm} { 0, 1, 2 }\n * 4.0+: {ldr, sm, wb} { 1, 2, 0 }\n */\n\nstatic const u8 sec_map_100[3] = { PK11_SECTION_SM, PK11_SECTION_LD, PK11_SECTION_WB };\nstatic const u8 sec_map_2xx[3] = { PK11_SECTION_WB, PK11_SECTION_LD, PK11_SECTION_SM };\nstatic const u8 sec_map_4xx[3] = { PK11_SECTION_LD, PK11_SECTION_SM, PK11_SECTION_WB };\n\n\t// Timestamp  MK  FU   TSEC    PK11     SECMON     Warmboot\nstatic const pkg1_id_t _pkg1_ids[] = {\n\t{ \"20161121\",  0,  1, 0x1900, 0x3FE0, SM_100_ADR, 0x8000D000, _secmon_1_patchset }, // 1.0.0 (Patched relocator).\n\t{ \"20170210\",  0,  2, 0x1900, 0x3FE0, 0x4002D000, 0x8000D000, _secmon_2_patchset }, // 2.0.0 - 2.3.0.\n\t{ \"20170519\",  1,  3, 0x1A00, 0x3FE0, 0x4002D000, 0x8000D000, _secmon_3_patchset }, // 3.0.0.\n\t{ \"20170710\",  2,  4, 0x1A00, 0x3FE0, 0x4002D000, 0x8000D000, _secmon_3_patchset }, // 3.0.1 - 3.0.2.\n\t{ \"20170921\",  3,  5, 0x1800, 0x3FE0, 0x4002B000, 0x4003B000, _secmon_4_patchset }, // 4.0.0 - 4.1.0.\n\t{ \"20180220\",  4,  6, 0x1900, 0x3FE0, 0x4002B000, 0x4003B000, _secmon_5_patchset }, // 5.0.0 - 5.1.0.\n\t{ \"20180802\",  5,  7, 0x1900, 0x3FE0, 0x4002B000, 0x4003D800, _secmon_6_patchset }, // 6.0.0 - 6.1.0.\n\t{ \"20181107\",  6,  8, 0x0E00, 0x6FE0, 0x4002B000, 0x4003D800, _secmon_62_patchset}, // 6.2.0.\n\t{ \"20181218\",  7,  9, 0x0F00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, //  7.0.0.\n\t{ \"20190208\",  7,  9, 0x0F00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, //  7.0.1.\n\t{ \"20190314\",  7,  9, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, //  8.0.0 - 8.0.1.\n\t{ \"20190531\",  8, 10, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, //  8.1.0 - 8.1.1.\n\t{ \"20190809\",  9, 11, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, //  9.0.0 - 9.0.1.\n\t{ \"20191021\", 10, 12, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, //  9.1.0 - 9.2.0.\n\t{ \"20200303\", 10, 13, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 10.0.0 - 10.2.0.\n\t{ \"20201030\", 10, 14, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 11.0.0 - 11.0.1.\n\t{ \"20210129\", 10, 14, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 12.0.0 - 12.0.1.\n\t{ \"20210422\", 10, 15, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 12.0.2 - 12.0.3.\n\t{ \"20210607\", 11, 15, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 12.1.0.\n\t{ \"20210805\", 12, 15, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 13.0.0 - 13.2.0.\n\t{ \"20220105\", 12, 16, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 13.2.1.\n\t{ \"20220209\", 13, 16, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 14.0.0 - 14.1.2.\n\t{ \"20220801\", 14, 17, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 15.0.0 - 15.0.1.\n\t{ \"20230111\", 15, 18, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 16.0.0 - 16.1.0.\n\t{ \"20230906\", 16, 19, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 17.0.0 - 17.0.1.\n\t{ \"20240207\", 17, 19, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 18.0.0 - 18.1.0.\n\t{ \"20240808\", 18, 20, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 19.0.0 - 19.0.1.\n\t{ \"20250206\", 19, 21, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 20.0.0 - 20.5.0.\n\t{ \"20251009\", 20, 22, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 21.0.0 - 21.2.0.\n\t{ \"20260123\", 21, 23, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 22.0.0+\n};\n\nconst pkg1_id_t *pkg1_get_latest()\n{\n\treturn &_pkg1_ids[ARRAY_SIZE(_pkg1_ids) - 1];\n}\n\nconst pkg1_id_t *pkg1_identify(u8 *pkg1)\n{\n\tchar build_date[15];\n\tpk1_hdr_t *hdr = (pk1_hdr_t *)pkg1;\n\n\tmemcpy(build_date, hdr->timestamp, 14);\n\tbuild_date[14] = 0;\n\tgfx_printf(\"Found pkg1 ('%s').\\n\\n\", build_date);\n\n\tfor (int i = ARRAY_SIZE(_pkg1_ids) - 1; i >= 0; i--)\n\t\tif (!memcmp(hdr->timestamp, _pkg1_ids[i].id, 8))\n\t\t\treturn &_pkg1_ids[i];\n\n\treturn NULL;\n}\n\nbool pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1)\n{\n\tpk11_hdr_t *hdr;\n\n\t// Decrypt package1.\n\tif (!h_cfg.t210b01)\n\t{\n\t\tu8 *pkg11 = pkg1 + id->pkg11_off;\n\t\tu32 pkg11_size = *(u32 *)pkg11;\n\t\thdr = (pk11_hdr_t *)(pkg11 + 0x20);\n\t\tse_aes_crypt_ctr(11, hdr, hdr, pkg11_size, pkg11 + 0x10);\n\t}\n\telse\n\t{\n\t\tbl_hdr_t210b01_t *oem_hdr = (bl_hdr_t210b01_t *)pkg1;\n\t\tpkg1 += sizeof(bl_hdr_t210b01_t);\n\t\thdr = (pk11_hdr_t *)(pkg1 + id->pkg11_off + 0x20);\n\n\t\t// Use BEK for T210B01.\n\t\t// Additionally, skip 0x20 bytes from decryption to maintain the header.\n\t\tse_aes_iv_clear(13);\n\t\tse_aes_crypt_cbc(13, DECRYPT, pkg1 + 0x20, pkg1 + 0x20, oem_hdr->size - 0x20);\n\t}\n\n\t// Return if header is valid.\n\treturn (hdr->magic == PKG1_MAGIC);\n}\n\nconst u8 *pkg1_unpack(void *wm_dst, u32 *wb_sz, void *sm_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1)\n{\n\tconst u8 *sec_map;\n\tconst pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + id->pkg11_off + 0x20);\n\n\tu32 sec_size[3] = { hdr->wb_size, hdr->ldr_size, hdr->sm_size };\n\n\t// Get correct header mapping.\n\tif (id->fuses == 1)                        // 1.0.0.\n\t\tsec_map = sec_map_100;\n\telse if (id->fuses >= 2 && id->fuses <= 4) // 2.0.0 - 3.0.2.\n\t\tsec_map = sec_map_2xx;\n\telse                                       // 4.0.0+\n\t\tsec_map = sec_map_4xx;\n\n\t// Copy secmon, warmboot and nx bootloader payloads.\n\tu8 *pdata = (u8 *)hdr + sizeof(pk11_hdr_t);\n\tfor (u32 i = 0; i < 3; i++)\n\t{\n\t\tu32 ssize = sec_size[sec_map[i]];\n\t\tswitch (sec_map[i])\n\t\t{\n\t\tcase PK11_SECTION_WB:\n\t\t\tif (wm_dst)\n\t\t\t\tmemcpy(wm_dst,  pdata, ssize);\n\t\t\tif (wb_sz)\n\t\t\t\t*wb_sz = ssize;\n\t\t\tbreak;\n\t\tcase PK11_SECTION_LD:\n\t\t\tif (ldr_dst)\n\t\t\t\tmemcpy(ldr_dst, pdata, ssize);\n\t\t\tbreak;\n\t\tcase PK11_SECTION_SM:\n\t\t\tif (sm_dst)\n\t\t\t\tmemcpy(sm_dst,  pdata, ssize);\n\t\t\tbreak;\n\t\t}\n\t\tpdata += ssize;\n\t}\n\n\treturn sec_map;\n}\n\nvoid pkg1_secmon_patch(void *hos_ctxt, u32 secmon_base, bool t210b01)\n{\n\tconst patch_t *secmon_patchset;\n\tlaunch_ctxt_t *ctxt = (launch_ctxt_t *)hos_ctxt;\n\n\t// Patch Secmon to allow for an unsigned package2 and patched kernel.\n\tif (!t210b01 && ctxt->pkg1_id->secmon_patchset)\n\t{\n\t\t// For T210 till 6.2.0 the patching is used as is, because of no compression.\n\t\tsecmon_patchset = ctxt->pkg1_id->secmon_patchset;\n\t}\n#ifdef HOS_MARIKO_STOCK_SECMON\n\telse if (t210b01)\n\t{\n\t\t// For T210B01 we patch 6.X.X as is. Otherwise we decompress the program payload.\n\t\tif (ctxt->pkg1_id->mkey      == HOS_MKEY_VER_600)\n\t\t\tsecmon_patchset = _secmon_6_mariko_patchset;\n\t\telse if (ctxt->pkg1_id->mkey == HOS_MKEY_VER_620)\n\t\t\tsecmon_patchset = _secmon_620_mariko_patchset;\n\t\telse\n\t\t{\n\t\t\t// Patch uncompress of program payload clear TZRAM.\n\t\t\tsecmon_patchset = _secmon_7_mariko_patchset;\n\t\t\tmemset((void *)TZRAM_PROG_ADDR, 0, 0x38800);\n\n\t\t\t// Get size of compressed program payload and set patch offset.\n\t\t\tu32 idx = ctxt->pkg1_id->mkey - HOS_MKEY_VER_700;\n\t\t\tu32 patch_offset = TZRAM_PROG_PK2_SIG_PATCH;\n\t\t\tif (ctxt->pkg1_id->mkey >= HOS_MKEY_VER_1210 || !memcmp(ctxt->pkg1_id->id, \"20200303\", 8)) //TODO: Add 11.0.0 support.\n\t\t\t{\n\t\t\t\tidx++;\n\t\t\t\tpatch_offset = TZRAM_PROG_PK2_SIG_PATCH_1000;\n\t\t\t}\n\n\t\t\t// Uncompress directly to TZRAM.\n\t\t\tLZ4_decompress_fast((const char*)(secmon_base + TZRAM_COMPR_PROG_OFF),\n\t\t\t\t(char *)TZRAM_PROG_ADDR, _secmon_mariko_prog_comp_size[idx]);\n\n\t\t\t// Patch package2 signature/hash checks.\n\t\t\t*(vu32 *)patch_offset = _NOP();\n\t\t}\n\t}\n#endif\n\telse\n\t\treturn;\n\n\t// Patch Secmon.\n\tgfx_printf(\"%kPatching Secure Monitor%k\\n\", TXT_CLR_ORANGE, TXT_CLR_DEFAULT);\n\tfor (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++)\n\t\t*(vu32 *)(secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val;\n}\n\nvoid pkg1_warmboot_patch(void *hos_ctxt)\n{\n\tlaunch_ctxt_t *ctxt = (launch_ctxt_t *)hos_ctxt;\n\tconst patch_t *warmboot_patchset;\n\n\t// Patch warmboot on T210 to allow downgrading.\n\tswitch (ctxt->pkg1_id->mkey)\n\t{\n\tcase 0:\n\t\twarmboot_patchset = _warmboot_1_patchset;\n\t\tbreak;\n\tcase 1 ... 2:\n\t\twarmboot_patchset = _warmboot_3_patchset;\n\t\tbreak;\n\tdefault: // 4.0.0 - 6.2.0.\n\t\twarmboot_patchset = _warmboot_4_patchset;\n\t\tbreak;\n\t}\n\tgfx_printf(\"%kPatching Warmboot%k\\n\", TXT_CLR_ORANGE, TXT_CLR_DEFAULT);\n\tfor (u32 i = 0; warmboot_patchset[i].off != 0xFFFFFFFF; i++)\n\t\t*(vu32 *)(ctxt->pkg1_id->warmboot_base + warmboot_patchset[i].off) = warmboot_patchset[i].val;\n}\n\nint pkg1_warmboot_config(void *hos_ctxt, u32 warmboot_base, u32 fuses_fw, u8 mkey)\n{\n\tlaunch_ctxt_t *ctxt = (launch_ctxt_t *)hos_ctxt;\n\tint res = 0;\n\n\tif (h_cfg.t210b01)\n\t{\n\t\tu8  burnt_fuses = bit_count(fuse_read_odm(7));\n\n\t\t// Check if not overridden.\n\t\tif (!ctxt->warmboot)\n\t\t{\n\t\t\tchar path[32];\n\t\t\tstrcpy(path, \"warmboot_mariko/wb_00.bin\");\n\t\t\titoa(fuses_fw, &path[19 + (fuses_fw < 0x10 ? 1 : 0)], 16);\n\t\t\tpath[21] = '.';\n\n\t\t\t//!OBSOLETE: Check if warmboot fw does not exist and save it.\n\t\t\tif (ctxt->warmboot_size && warmboot_base && f_stat(path, NULL))\n\t\t\t{\n\t\t\t\tf_mkdir(\"warmboot_mariko\");\n\t\t\t\tsd_save_to_file((void *)warmboot_base, ctxt->warmboot_size, path);\n\t\t\t}\n\n\t\t\t// Load sc7exit-fw from storage if low.\n\t\t\tif (burnt_fuses > fuses_fw)\n\t\t\t{\n\t\t\t\t//!TODO: Update on fuse burns.\n\t\t\t\tvoid *warmboot_fw = sd_file_read(\"bootloader/sys/l4t/sc7exit_b01.bin\", &ctxt->warmboot_size);\n\t\t\t\tfuses_fw = *(u32 *)warmboot_fw;\n\n\t\t\t\t// Check if high enough.\n\t\t\t\tif (!warmboot_fw || burnt_fuses > fuses_fw)\n\t\t\t\t\tres = 1;\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tctxt->warmboot = warmboot_fw + sizeof(u32);\n\t\t\t\t\tctxt->warmboot_size -= sizeof(u32) * 2;\n\t\t\t\t\tburnt_fuses = fuses_fw;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse // Replace burnt fuses with higher count.\n\t\t\t\tburnt_fuses = fuses_fw;\n\t\t}\n\n\t\t// Configure warmboot parameters. Anything lower than 6.0.0 is not supported.\n\t\t// From 7.0.0 and up, it's not derived from PA segment but it's 0x21 * fuses.\n\t\tu32 pa_id = 0x21 * burnt_fuses;\n\t\tif (burnt_fuses <= 8) // Old method.\n\t\t\tpa_id -= 0x60;\n\n\t\t// Set Warmboot Physical Address ID and lock SECURE_SCRATCH32 register.\n\t\tPMC(APBDEV_PMC_SECURE_SCRATCH32) = pa_id;\n\t\tPMC(APBDEV_PMC_SEC_DISABLE3) |= BIT(16);\n\t}\n\telse\n\t{\n\t\t// Set Warmboot address in PMC if required.\n\t\tif (mkey <= HOS_MKEY_VER_301)\n\t\t\tPMC(APBDEV_PMC_SCRATCH1) = warmboot_base;\n\n\t\t// Set Warmboot Physical Address ID for 3.0.0 - 3.0.2. For 4.0.0 and up, secmon does it.\n\t\t// The check is already patched so it's actually irrelevant.\n\t\tif (mkey == HOS_MKEY_VER_300)\n\t\t\tPMC(APBDEV_PMC_SECURE_SCRATCH32) = 0xE3;  // Warmboot 3.0.0 PA ID.\n\t\telse if (mkey == HOS_MKEY_VER_301)\n\t\t\tPMC(APBDEV_PMC_SECURE_SCRATCH32) = 0x104; // Warmboot 3.0.1/.2 PA ID.\n\t}\n\n\treturn res;\n}\n\nvoid pkg1_warmboot_rsa_mod(u32 warmboot_base)\n{\n\t// Set warmboot binary rsa modulus.\n\tu8 *rsa_mod = (u8 *)malloc(EMMC_BLOCKSIZE);\n\n\temmc_set_partition(EMMC_BOOT0);\n\n\tu32 sector;\n\tu8  mod0, mod1;\n\n\t// Get the correct RSA modulus byte masks.\n\tnx_emmc_get_autorcm_masks(&mod0, &mod1);\n\n\t// Iterate BCTs.\n\tfor (u32 i = 0; i < 4; i++)\n\t{\n\t\tsector = 1 + (32 * i); // 0x4000 bct + 0x200 offset.\n\t\tsdmmc_storage_read(&emmc_storage, sector, 1, rsa_mod);\n\n\t\t// Check if 2nd byte of modulus is correct.\n\t\tif (rsa_mod[0x11] != mod1)\n\t\t\tcontinue;\n\n\t\t// Patch AutoRCM out.\n\t\trsa_mod[0x10] = mod0;\n\n\t\tbreak;\n\t}\n\n\tmemcpy((void *)(warmboot_base + 0x10), rsa_mod + 0x10, 0x100);\n}\n"
  },
  {
    "path": "bootloader/hos/pkg1.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2022-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _PKG1_H_\n#define _PKG1_H_\n\n#include <bdk.h>\n\n#define PKG1_MAGIC 0x31314B50\n\n#define PK11_SECTION_WB 0\n#define PK11_SECTION_LD 1\n#define PK11_SECTION_SM 2\n\n#define PKG1_BOOTLOADER_SIZE          SZ_256K\n#define PKG1_BOOTLOADER_MAIN_OFFSET   (0x100000 / EMMC_BLOCKSIZE)\n#define PKG1_BOOTLOADER_BACKUP_OFFSET (0x140000 / EMMC_BLOCKSIZE)\n#define PKG1_BOOTLOADER_SAFE_OFFSET   (0x000000 / EMMC_BLOCKSIZE)\n#define PKG1_HOS_EKS_OFFSET           (0x180000 / EMMC_BLOCKSIZE)\n\n#define PKG1_ERISTA_ON_MARIKO_MAGIC 0xE59FD00C // For 4.0.0 Erista and up.\n#define PKG1_MARIKO_ON_ERISTA_MAGIC 0x40010040 // Mariko pkg1 entrypoint.\n\ntypedef struct _patch_t\n{\n\tu32 off;\n\tu32 val;\n} patch_t;\n\n#define PATCHSET_DEF(name, ...) \\\n\tconst patch_t name[] = { \\\n\t\t__VA_ARGS__, \\\n\t\t{ 0xFFFFFFFF, 0xFFFFFFFF } \\\n\t}\n\ntypedef struct _bl_hdr_t210b01_t\n{\n/* 0x000 */\tu8  aes_mac[0x10];\n/* 0x010 */\tu8  rsa_sig[0x100];\n/* 0x110 */\tu8  salt[0x20];\n/* 0x130 */\tu8  sha256[0x20];\n/* 0x150 */\tu32 version;\n/* 0x154 */\tu32 size;\n/* 0x158 */\tu32 load_addr;\n/* 0x15C */\tu32 entrypoint;\n/* 0x160 */\tu8  rsvd[0x10];\n} bl_hdr_t210b01_t;\n\ntypedef struct _eks_keys_t\n{\n\tu8 master_kekseed[SE_KEY_128_SIZE];\n\tu8 random_data[0x70];\n\tu8 package1_key[SE_KEY_128_SIZE];\n} eks_keys_t;\n\ntypedef struct _pkg1_eks_t\n{\n\tu8 cmac[SE_KEY_128_SIZE];\n\tu8 ctr[SE_AES_IV_SIZE];\n\teks_keys_t keys;\n\tu8 padding[0x150];\n} pkg1_eks_t;\n\ntypedef struct _pk1_hdr_t\n{\n/* 0x00 */\tu32 si_sha256; // Secure Init.\n/* 0x04 */\tu32 sm_sha256; // Secure Monitor.\n/* 0x08 */\tu32 sl_sha256; // Secure Loader.\n/* 0x0C */\tu32 unk;       // what's this? It's not warmboot.\n/* 0x10 */\tchar timestamp[14];\n/* 0x1E */\tu8 keygen;\n/* 0x1F */\tu8 version;\n} pk1_hdr_t;\n\ntypedef struct _pkg1_id_t\n{\n\tconst char *id;\n\tu16 mkey;\n\tu16 fuses;\n\tu16 tsec_off;\n\tu16 pkg11_off;\n\tu32 secmon_base;\n\tu32 warmboot_base;\n\tconst patch_t *secmon_patchset;\n} pkg1_id_t;\n\ntypedef struct _pk11_hdr_t\n{\n/* 0x00 */\tu32 magic;\n/* 0x04 */\tu32 wb_size;\n/* 0x08 */\tu32 wb_off;\n/* 0x0C */\tu32 pad;\n/* 0x10 */\tu32 ldr_size;\n/* 0x14 */\tu32 ldr_off;\n/* 0x18 */\tu32 sm_size;\n/* 0x1C */\tu32 sm_off;\n} pk11_hdr_t;\n\n/*\n * NX BIT - Secure monitor mailbox\n *\n * On older versions the Tegra BIT was remaining intact.\n * The bootloader info from BCT was copied in the mailbox at 0x40002E10.\n * On >= 4.0.0 the boot reason was replaced by BCT boot type.\n * On newer versions (>= 7.0.0) the Tegra BIT is replaced with NX BIT.\n * That also includes secmon state mailbox and pkg1 and pkg11 headers.\n */\n#define NX_BIT1_MAILBOX_ADDR 0x40002E00\n#define NX_BIT7_MAILBOX_ADDR 0x40000000\n\nenum\n{\n\tSECMON_STATE_NOT_READY    = 0,\n\n\tPKG1_STATE_NOT_READY      = 0,\n\tPKG1_STATE_NXBC_COPIED    = 1,\n\tPKG1_STATE_DRAM_READY     = 2,\n\tPKG1_STATE_PKG2_READY_OLD = 3,\n\tPKG1_STATE_PKG2_READY     = 4\n};\n\n#define NX_BIT_BL_ATTR_SAFE_MODE              BIT(0)\n#define NX_BIT_BL_ATTR_SMC_BLACKLIST_STANDARD BIT(1) // Accounted only on >= 8.0.0.\n#define NX_BIT_BL_ATTR_SMC_BLACKLIST_DEVICEUD BIT(2) // Accounted only on >= 8.0.0.\n#define NX_BIT_BL_ATTR_SMC_BLACKLIST_SAFEMODE BIT(3) // Accounted only on >= 8.0.0.\n\ntypedef struct _nx_bit_t\n{\n/* 0x00 */\tu32 secldr_tmr_start;\n/* 0x04 */\tu32 secldr_tmr_end;\n/* 0x08 */\tu32 secmon_tmr_start;\n/* 0x0C */\tu32 secmon_tmr_end;\n/* 0x10 */\tu32 bl_version;\n/* 0x14 */\tu32 bl_start_block;\n/* 0x18 */\tu32 bl_start_page;\n/* 0x1C */\tu32 bl_attribute; // bit0: Safe, bit1-4: SMC blacklist mask.\n/* 0x20 */\tu32 boot_type;    // 0: None, 1: Coldboot, 2: RMC, 3: UART, 4: Exit RCM.\n/* 0x24 */\tu8  padding_nxbit[12];\n\n/* 0x30 */\tpk1_hdr_t  pk1_hdr;  // (>= 7.0.0).\n/* 0x50 */\tpk11_hdr_t pk11_hdr; // (>= 7.0.0).\n/* 0x70 */  u8 padding_pkg1[0x88];\n\n/* 0xF8 */\tvu32 secldr_state;\n/* 0xFC */\tvu32 secmon_state;\n\t\t\tu8   padding_mail[0x100];\n} nx_bit_t;\n\nconst pkg1_id_t *pkg1_get_latest();\nconst pkg1_id_t *pkg1_identify(u8 *pkg1);\nbool  pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1);\nconst u8 *pkg1_unpack(void *wm_dst, u32 *wb_sz, void *sm_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1);\nvoid pkg1_secmon_patch(void *hos_ctxt, u32 secmon_base, bool t210b01);\nvoid pkg1_warmboot_patch(void *hos_ctxt);\nint  pkg1_warmboot_config(void *hos_ctxt, u32 warmboot_base, u32 fuses_fw, u8 mkey);\nvoid pkg1_warmboot_rsa_mod(u32 warmboot_base);\n\n#endif\n"
  },
  {
    "path": "bootloader/hos/pkg2.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <bdk.h>\n\n#include \"hos.h\"\n#include \"pkg2.h\"\n#include \"pkg2_ini_kippatch.h\"\n\n#include \"../config.h\"\n#include <libs/compr/blz.h>\n#include <libs/fatfs/ff.h>\n#include \"../storage/emummc.h\"\n\n//#define DPRINTF(...) gfx_printf(__VA_ARGS__)\n#define DPRINTF(...)\n\nextern const u8 package2_keyseed[];\n\nu32 pkg2_newkern_ini1_info;\nu32 pkg2_newkern_ini1_start;\nu32 pkg2_newkern_ini1_end;\nu32 pkg2_newkern_ini1_rela;\n\n#define KIP_PATCH_SECTION_SHIFT  (29)\n#define KIP_PATCH_SECTION_MASK   (7 << KIP_PATCH_SECTION_SHIFT)\n#define KIP_PATCH_OFFSET_MASK    (~KIP_PATCH_SECTION_MASK)\n#define GET_KIP_PATCH_SECTION(x) (((x) >> KIP_PATCH_SECTION_SHIFT) & 7)\n#define GET_KIP_PATCH_OFFSET(x)  ((x) & KIP_PATCH_OFFSET_MASK)\n#define KPS(x)                   ((u32)(x) << KIP_PATCH_SECTION_SHIFT)\n\n#include \"pkg2_patches.inl\"\n\nstatic kip1_id_t *_kip_id_sets = (kip1_id_t *)_kip_ids;\nstatic u32 _kip_id_sets_cnt = ARRAY_SIZE(_kip_ids);\n\nvoid pkg2_get_ids(kip1_id_t **ids, u32 *entries)\n{\n\t*ids = _kip_id_sets;\n\t*entries = _kip_id_sets_cnt;\n}\n\nstatic void parse_external_kip_patches()\n{\n\tstatic bool ext_patches_parsed = false;\n\n\tif (ext_patches_parsed)\n\t\treturn;\n\n\text_patches_parsed = true;\n\n\tLIST_INIT(ini_kip_sections);\n\tif (ini_patch_parse(&ini_kip_sections, \"bootloader/patches.ini\"))\n\t\treturn;\n\n\t// Copy ids into a new patchset.\n\t_kip_id_sets = zalloc(sizeof(kip1_id_t) * 256); // Max 256 kip ids.\n\tmemcpy(_kip_id_sets, _kip_ids, sizeof(_kip_ids));\n\n\t// Parse patchsets and glue them together.\n\tLIST_FOREACH_ENTRY(ini_kip_sec_t, ini_psec, &ini_kip_sections, link)\n\t{\n\t\tkip1_id_t *kip = NULL;\n\t\tbool found = false;\n\t\tfor (u32 kip_idx = 0; kip_idx < _kip_id_sets_cnt + 1; kip_idx++)\n\t\t{\n\t\t\tkip = &_kip_id_sets[kip_idx];\n\n\t\t\t// Check if reached the end of predefined list.\n\t\t\tif (!kip->name)\n\t\t\t\tbreak;\n\n\t\t\t// Check if name and hash match.\n\t\t\tif (!strcmp(kip->name, ini_psec->name) && !memcmp(kip->hash, ini_psec->hash, 8))\n\t\t\t{\n\t\t\t\tfound = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!kip)\n\t\t\tcontinue;\n\n\t\t// If not found, create a new empty entry.\n\t\tif (!found)\n\t\t{\n\t\t\tkip->name = ini_psec->name;\n\t\t\tmemcpy(kip->hash, ini_psec->hash, 8);\n\t\t\tkip->patchset = zalloc(sizeof(kip1_patchset_t));\n\n\t\t\t_kip_id_sets_cnt++;\n\t\t}\n\n\t\tkip1_patchset_t *patchsets = (kip1_patchset_t *)zalloc(sizeof(kip1_patchset_t) * 16); // Max 16 patchsets per kip.\n\n\t\tu32 patchset_idx;\n\t\tfor (patchset_idx = 0; kip->patchset[patchset_idx].name != NULL; patchset_idx++)\n\t\t{\n\t\t\tpatchsets[patchset_idx].name    = kip->patchset[patchset_idx].name;\n\t\t\tpatchsets[patchset_idx].patches = kip->patchset[patchset_idx].patches;\n\t\t}\n\n\t\tkip->patchset = patchsets;\n\t\tbool first_ext_patch = true;\n\t\tu32 patch_idx = 0;\n\n\t\t// Parse patches and glue them together to a patchset.\n\t\tkip1_patch_t *patches = zalloc(sizeof(kip1_patch_t) * 32); // Max 32 patches per set.\n\t\tLIST_FOREACH_ENTRY(ini_patchset_t, pt, &ini_psec->pts, link)\n\t\t{\n\t\t\tif (first_ext_patch)\n\t\t\t{\n\t\t\t\tfirst_ext_patch = false;\n\t\t\t\tpatchsets[patchset_idx].name    = pt->name;\n\t\t\t\tpatchsets[patchset_idx].patches = patches;\n\t\t\t}\n\t\t\telse if (strcmp(pt->name, patchsets[patchset_idx].name))\n\t\t\t{\n\t\t\t\t// New patchset name found, create a new set.\n\t\t\t\tpatchset_idx++;\n\t\t\t\tpatch_idx = 0;\n\t\t\t\tpatches = zalloc(sizeof(kip1_patch_t) * 32); // Max 32 patches per set.\n\n\t\t\t\tpatchsets[patchset_idx].name    = pt->name;\n\t\t\t\tpatchsets[patchset_idx].patches = patches;\n\t\t\t}\n\n\t\t\tif (pt->length)\n\t\t\t{\n\t\t\t\tpatches[patch_idx].offset = pt->offset;\n\t\t\t\tpatches[patch_idx].length = pt->length;\n\n\t\t\t\tpatches[patch_idx].src_data = (char *)pt->src_data;\n\t\t\t\tpatches[patch_idx].dst_data = (char *)pt->dst_data;\n\t\t\t}\n\t\t\telse\n\t\t\t\tpatches[patch_idx].src_data = malloc(1); // Empty patches check. Keep everything else as 0.\n\n\t\t\tpatch_idx++;\n\t\t}\n\t\tpatchset_idx++;\n\t\tpatchsets[patchset_idx].name = NULL;\n\t\tpatchsets[patchset_idx].patches = NULL;\n\t}\n}\n\nconst pkg2_kernel_id_t *pkg2_identify(const u8 *hash)\n{\n\tfor (u32 i = 0; i < ARRAY_SIZE(_pkg2_kernel_ids); i++)\n\t{\n\t\tif (!memcmp(hash, _pkg2_kernel_ids[i].hash, sizeof(_pkg2_kernel_ids[0].hash)))\n\t\t\treturn &_pkg2_kernel_ids[i];\n\t}\n\treturn NULL;\n}\n\nstatic u32 _pkg2_calc_kip1_size(pkg2_kip1_t *kip1)\n{\n\tu32 size = sizeof(pkg2_kip1_t);\n\tfor (u32 j = 0; j < KIP1_NUM_SECTIONS; j++)\n\t\tsize += kip1->sections[j].size_comp;\n\treturn size;\n}\n\nstatic void _pkg2_get_newkern_info(u8 *kern_data)\n{\n\tu32 crt_start  = 0;\n\tpkg2_newkern_ini1_info  = 0;\n\tpkg2_newkern_ini1_start = 0;\n\tpkg2_newkern_ini1_rela  = 0;\n\n\tu32 first_op = *(u32 *)kern_data;\n\tif ((first_op & 0xFE000000) == 0x14000000)\n\t\tcrt_start = (first_op & 0x1FFFFFF) << 2;\n\n\t// Find static OP offset that is close to INI1 offset.\n\tu32 counter_ops = 0x100;\n\twhile (counter_ops)\n\t{\n\t\tif (*(u32 *)(kern_data + crt_start + 0x100 - counter_ops) == PKG2_NEWKERN_GET_INI1_HEURISTIC)\n\t\t{\n\t\t\t// OP found. Add 12 for the INI1 info offset.\n\t\t\tpkg2_newkern_ini1_info = crt_start + 0x100 - counter_ops + 12;\n\n\t\t\t// On v2 kernel with dynamic crt there's a NOP after heuristic. Offset one op.\n\t\t\tif (crt_start)\n\t\t\t\tpkg2_newkern_ini1_info += 4;\n\t\t\tbreak;\n\t\t}\n\n\t\tcounter_ops -= 4;\n\t}\n\n\t// Offset not found?\n\tif (!counter_ops)\n\t\treturn;\n\n\tu32 info_op = *(u32 *)(kern_data + pkg2_newkern_ini1_info);\n\tpkg2_newkern_ini1_info += ((info_op & 0xFFFF) >> 3); // Parse ADR and PC.\n\n\tpkg2_newkern_ini1_start = *(u32 *)(kern_data + pkg2_newkern_ini1_info);\n\tpkg2_newkern_ini1_end   = *(u32 *)(kern_data + pkg2_newkern_ini1_info + 0x8);\n\n\t// On v2 kernel with dynamic crt, values are relative to value address.\n\tif (crt_start)\n\t{\n\t\tpkg2_newkern_ini1_rela   = pkg2_newkern_ini1_info;\n\t\tpkg2_newkern_ini1_start += pkg2_newkern_ini1_info;\n\t\tpkg2_newkern_ini1_end   += pkg2_newkern_ini1_info + 0x8;\n\t}\n}\n\nint pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2)\n{\n\tu8 *ptr;\n\t// Check for new pkg2 type.\n\tif (!pkg2->sec_size[PKG2_SEC_INI1])\n\t{\n\t\t_pkg2_get_newkern_info(pkg2->data);\n\n\t\tif (!pkg2_newkern_ini1_start)\n\t\t\treturn 1;\n\n\t\tptr = pkg2->data + pkg2_newkern_ini1_start;\n\t\t*new_pkg2 = true;\n\t}\n\telse\n\t\tptr = pkg2->data + pkg2->sec_size[PKG2_SEC_KERNEL];\n\n\tpkg2_ini1_t *ini1 = (pkg2_ini1_t *)ptr;\n\tptr += sizeof(pkg2_ini1_t);\n\n\tfor (u32 i = 0; i < ini1->num_procs; i++)\n\t{\n\t\tpkg2_kip1_t *kip1 = (pkg2_kip1_t *)ptr;\n\t\tpkg2_kip1_info_t *ki = (pkg2_kip1_info_t *)malloc(sizeof(pkg2_kip1_info_t));\n\t\tki->kip1 = kip1;\n\t\tki->size = _pkg2_calc_kip1_size(kip1);\n\t\tlist_append(info, &ki->link);\n\t\tptr += ki->size;\nDPRINTF(\" kip1 %d:%s @ %08X (%08X)\\n\", i, kip1->name, (u32)kip1, ki->size);\n\t}\n\n\treturn 0;\n}\n\nbool pkg2_has_kip(link_t *info, u64 tid)\n{\n\tLIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, info, link)\n\t\tif (ki->kip1->tid == tid)\n\t\t\treturn true;\n\treturn false;\n}\n\nvoid pkg2_replace_kip(link_t *info, u64 tid, pkg2_kip1_t *kip1)\n{\n\tLIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, info, link)\n\t{\n\t\tif (ki->kip1->tid == tid)\n\t\t{\n\t\t\tki->kip1 = kip1;\n\t\t\tki->size = _pkg2_calc_kip1_size(kip1);\nDPRINTF(\"replaced kip %s (new size %08X)\\n\", kip1->name, ki->size);\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nvoid pkg2_add_kip(link_t *info, pkg2_kip1_t *kip1)\n{\n\tpkg2_kip1_info_t *ki = (pkg2_kip1_info_t *)malloc(sizeof(pkg2_kip1_info_t));\n\tki->kip1 = kip1;\n\tki->size = _pkg2_calc_kip1_size(kip1);\nDPRINTF(\"added kip %s (size %08X)\\n\", kip1->name, ki->size);\n\tlist_append(info, &ki->link);\n}\n\nvoid pkg2_merge_kip(link_t *info, pkg2_kip1_t *kip1)\n{\n\tif (pkg2_has_kip(info, kip1->tid))\n\t\tpkg2_replace_kip(info, kip1->tid, kip1);\n\telse\n\t\tpkg2_add_kip(info, kip1);\n}\n\nstatic int _decompress_kip(pkg2_kip1_info_t *ki, u32 sectsToDecomp)\n{\n\tu32 compClearMask = ~sectsToDecomp;\n\tif ((ki->kip1->flags & compClearMask) == ki->kip1->flags)\n\t\treturn 0; // Already decompressed, nothing to do.\n\n\tpkg2_kip1_t hdr;\n\tmemcpy(&hdr, ki->kip1, sizeof(hdr));\n\n\tu32 new_kip_size = sizeof(hdr);\n\tfor (u32 sect_idx = 0; sect_idx < KIP1_NUM_SECTIONS; sect_idx++)\n\t{\n\t\tu32 comp_bit_mask = BIT(sect_idx);\n\t\t// For compressed, cant get actual decompressed size without doing it, so use safe \"output size\".\n\t\tif (sect_idx < 3 && (sectsToDecomp & comp_bit_mask) && (hdr.flags & comp_bit_mask))\n\t\t\tnew_kip_size += hdr.sections[sect_idx].size_decomp;\n\t\telse\n\t\t\tnew_kip_size += hdr.sections[sect_idx].size_comp;\n\t}\n\n\tpkg2_kip1_t *new_kip = malloc(new_kip_size);\n\tu8 *dst_data = new_kip->data;\n\tconst u8 *src_data = ki->kip1->data;\n\tfor (u32 sect_idx = 0; sect_idx < KIP1_NUM_SECTIONS; sect_idx++)\n\t{\n\t\tu32 comp_bit_mask = BIT(sect_idx);\n\t\t// Easy copy path for uncompressed or ones we dont want to uncompress.\n\t\tif (sect_idx >= 3 || !(sectsToDecomp & comp_bit_mask) || !(hdr.flags & comp_bit_mask))\n\t\t{\n\t\t\tu32 dataSize = hdr.sections[sect_idx].size_comp;\n\t\t\tif (dataSize == 0)\n\t\t\t\tcontinue;\n\n\t\t\tmemcpy(dst_data, src_data, dataSize);\n\t\t\tsrc_data += dataSize;\n\t\t\tdst_data += dataSize;\n\t\t\tcontinue;\n\t\t}\n\n\t\tu32 comp_size = hdr.sections[sect_idx].size_comp;\n\t\tu32 output_size = hdr.sections[sect_idx].size_decomp;\n\t\tgfx_printf(\"Decomping '%s', sect %d, size %d..\\n\", (char *)hdr.name, sect_idx, comp_size);\n\t\tif (blz_uncompress_srcdest(src_data, comp_size, dst_data, output_size) == 0)\n\t\t{\n\t\t\tgfx_con.mute = false;\n\t\t\tgfx_printf(\"%kERROR decomping sect %d of '%s'!%k\\n\", TXT_CLR_ERROR, sect_idx, (char *)hdr.name, TXT_CLR_DEFAULT);\n\t\t\tfree(new_kip);\n\n\t\t\treturn 1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tDPRINTF(\"Done! Decompressed size is %d!\\n\", output_size);\n\t\t}\n\t\thdr.sections[sect_idx].size_comp = output_size;\n\t\tsrc_data += comp_size;\n\t\tdst_data += output_size;\n\t}\n\n\thdr.flags &= compClearMask;\n\tmemcpy(new_kip, &hdr, sizeof(hdr));\n\tnew_kip_size = dst_data - (u8 *)(new_kip);\n\n\tfree(ki->kip1);\n\tki->kip1 = new_kip;\n\tki->size = new_kip_size;\n\n\treturn 0;\n}\n\nstatic int _kipm_inject(const char *kipm_path, char *target_name, pkg2_kip1_info_t *ki)\n{\n\tif (strcmp((char *)ki->kip1->name, target_name))\n\t\treturn 1;\n\n\tu32 size = 0;\n\tu8 *kipm_data = (u8 *)sd_file_read(kipm_path, &size);\n\tif (!kipm_data)\n\t\treturn 1;\n\n\tu32 inject_size = size - sizeof(ki->kip1->caps);\n\tu8 *kip_patched_data = (u8 *)malloc(ki->size + inject_size);\n\n\t// Copy headers.\n\tmemcpy(kip_patched_data, ki->kip1, sizeof(pkg2_kip1_t));\n\n\tpkg2_kip1_t *fs_kip = ki->kip1;\n\tki->kip1 = (pkg2_kip1_t *)kip_patched_data;\n\tki->size = ki->size + inject_size;\n\n\t// Patch caps.\n\tmemcpy(&ki->kip1->caps, kipm_data, sizeof(ki->kip1->caps));\n\t// Copy our .text data.\n\tmemcpy(&ki->kip1->data, kipm_data + sizeof(ki->kip1->caps), inject_size);\n\n\tu32 new_offset = 0;\n\n\tfor (u32 section_idx = 0; section_idx < KIP1_NUM_SECTIONS - 2; section_idx++)\n\t{\n\t\tif (!section_idx) // .text.\n\t\t{\n\t\t\tmemcpy(ki->kip1->data + inject_size, fs_kip->data, fs_kip->sections[0].size_comp);\n\t\t\tki->kip1->sections[0].size_decomp += inject_size;\n\t\t\tki->kip1->sections[0].size_comp += inject_size;\n\t\t}\n\t\telse // Others.\n\t\t{\n\t\t\tif (section_idx < 3)\n\t\t\t\tmemcpy(ki->kip1->data + new_offset + inject_size, fs_kip->data + new_offset, fs_kip->sections[section_idx].size_comp);\n\t\t\tki->kip1->sections[section_idx].offset += inject_size;\n\t\t}\n\t\tnew_offset += fs_kip->sections[section_idx].size_comp;\n\t}\n\n\t// Patch PMC capabilities for 1.0.0.\n\tif (!emu_cfg.fs_ver)\n\t{\n\t\tfor (u32 i = 0; i < 0x20; i++)\n\t\t{\n\t\t\tif (ki->kip1->caps[i] == 0xFFFFFFFF)\n\t\t\t{\n\t\t\t\tki->kip1->caps[i] = 0x07000E7F;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tfree(kipm_data);\n\treturn 0;\n}\n\nconst char *pkg2_patch_kips(link_t *info, char *patch_names)\n{\n\tbool emummc_patch_selected = false;\n\n\tif (patch_names == NULL || patch_names[0] == 0)\n\t\treturn NULL;\n\n\tgfx_printf(\"%kPatching kips%k\\n\", TXT_CLR_ORANGE, TXT_CLR_DEFAULT);\n\n\tstatic const u32 MAX_NUM_PATCHES_REQUESTED = sizeof(u32) * 8;\n\tchar *patches[MAX_NUM_PATCHES_REQUESTED];\n\n\tu32 patches_num = 1;\n\tpatches[0] = patch_names;\n\t{\n\t\tfor (char *p = patch_names; *p != 0; p++)\n\t\t{\n\t\t\tif (*p == ',')\n\t\t\t{\n\t\t\t\t*p = 0;\n\t\t\t\tpatches[patches_num++] = p + 1;\n\t\t\t\tif (patches_num >= MAX_NUM_PATCHES_REQUESTED)\n\t\t\t\t\treturn \"too_many_patches\";\n\t\t\t}\n\t\t\telse if (*p >= 'A' && *p <= 'Z') // Convert to lowercase.\n\t\t\t\t*p += 0x20;\n\t\t}\n\t}\n\n\tu32 patches_applied = 0; // Bitset over patches.\n\tfor (u32 i = 0; i < patches_num; i++)\n\t{\n\t\t// Eliminate leading spaces.\n\t\tfor (const char *p = patches[i]; *p != 0; p++)\n\t\t{\n\t\t\tif (*p == ' ' || *p == '\\t' || *p == '\\r' || *p == '\\n')\n\t\t\t\tpatches[i]++;\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\n\t\tint patch_len = strlen(patches[i]);\n\t\tif (patch_len == 0)\n\t\t\tcontinue;\n\n\t\t// Eliminate trailing spaces.\n\t\tfor (int chIdx = patch_len - 1; chIdx >= 0; chIdx--)\n\t\t{\n\t\t\tconst char *p = patches[i] + chIdx;\n\t\t\tif (*p == ' ' || *p == '\\t' || *p == '\\r' || *p == '\\n')\n\t\t\t\tpatch_len = chIdx;\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t\tpatches[i][patch_len] = 0;\n\n\t\tDPRINTF(\"Requested patch: '%s'\\n\", patches[i]);\n\t}\n\n\t// Parse external patches if needed.\n\tfor (u32 i = 0; i < patches_num; i++)\n\t{\n\t\tif (!strcmp(patches[i], \"emummc\"))\n\t\t{\n\t\t\t// emuMMC patch is managed on its own.\n\t\t\temummc_patch_selected = true;\n\t\t\tpatches_applied |= BIT(i);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (strcmp(patches[i], \"nogc\"))\n\t\t\tparse_external_kip_patches();\n\t}\n\n\tu32 kip_hash[SE_SHA_256_SIZE / sizeof(u32)];\n\tLIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, info, link)\n\t{\n\t\t// Reset hash so it can be calculated for the new kip.\n\t\tkip_hash[0] = 0;\n\n\t\tbool emummc_patch_apply = emummc_patch_selected && !strcmp((char *)ki->kip1->name, \"FS\");\n\n\t\t// Check all SHA256 ID sets. (IDs are grouped per KIP. IDs are still unique.)\n\t\tfor (u32 kip_id_idx = 0; kip_id_idx < _kip_id_sets_cnt; kip_id_idx++)\n\t\t{\n\t\t\t// Check if KIP name macthes ID's KIP name.\n\t\t\tif (strcmp((char *)ki->kip1->name, _kip_id_sets[kip_id_idx].name) != 0)\n\t\t\t\tcontinue;\n\n\t\t\t// Check if there are patches to apply.\n\t\t\tbool patches_found = false;\n\t\t\tconst kip1_patchset_t *patchset = _kip_id_sets[kip_id_idx].patchset;\n\t\t\twhile (patchset != NULL && patchset->name != NULL && !patches_found)\n\t\t\t{\n\t\t\t\tfor (u32 i = 0; i < patches_num; i++)\n\t\t\t\t{\n\t\t\t\t\t// Continue if patch name does not match.\n\t\t\t\t\tif (strcmp(patchset->name, patches[i]) != 0)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tpatches_found = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tpatchset++;\n\t\t\t}\n\n\t\t\t// Don't bother hashing this KIP if no patches are enabled for it.\n\t\t\tif (!patches_found && !emummc_patch_apply)\n\t\t\t\tcontinue;\n\n\t\t\t// Check if current KIP not hashed and hash it.\n\t\t\tif (kip_hash[0] == 0)\n\t\t\t\tif (se_sha_hash_256_oneshot(kip_hash, ki->kip1, ki->size))\n\t\t\t\t\tmemset(kip_hash, 0, sizeof(kip_hash));\n\n\t\t\t// Check if kip is the expected version.\n\t\t\tif (memcmp(kip_hash, _kip_id_sets[kip_id_idx].hash, sizeof(_kip_id_sets[0].hash)) != 0)\n\t\t\t\tcontinue;\n\n\t\t\t// Find out which sections are affected by the enabled patches, in order to decompress them.\n\t\t\tu32 sections_affected = 0;\n\t\t\tpatchset = _kip_id_sets[kip_id_idx].patchset;\n\t\t\twhile (patchset != NULL && patchset->name != NULL)\n\t\t\t{\n\t\t\t\tif (patchset->patches != NULL)\n\t\t\t\t{\n\t\t\t\t\tfor (u32 patch_idx = 0; patch_idx < patches_num; patch_idx++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (strcmp(patchset->name, patches[patch_idx]))\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tfor (const kip1_patch_t *patch = patchset->patches; patch != NULL && (patch->length != 0); patch++)\n\t\t\t\t\t\t\tsections_affected |= BIT(GET_KIP_PATCH_SECTION(patch->offset));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tpatchset++;\n\t\t\t}\n\n\t\t\t// If emuMMC is enabled, set its affected section.\n\t\t\tif (emummc_patch_apply)\n\t\t\t\tsections_affected |= BIT(KIP_TEXT);\n\n\t\t\t// Got patches to apply to this kip, have to decompress it.\n\t\t\tif (_decompress_kip(ki, sections_affected))\n\t\t\t\treturn (char *)ki->kip1->name; // Failed to decompress.\n\n\t\t\t// Apply all patches for matched ID.\n\t\t\tpatchset = _kip_id_sets[kip_id_idx].patchset;\n\t\t\twhile (patchset != NULL && patchset->name != NULL)\n\t\t\t{\n\t\t\t\tfor (u32 patch_idx = 0; patch_idx < patches_num; patch_idx++)\n\t\t\t\t{\n\t\t\t\t\t// Check if patchset name matches requested patch.\n\t\t\t\t\tif (strcmp(patchset->name, patches[patch_idx]))\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tu32 applied_mask = BIT(patch_idx);\n\n\t\t\t\t\t// Check if patchset is empty.\n\t\t\t\t\tif (patchset->patches == NULL)\n\t\t\t\t\t{\n\t\t\t\t\t\tDPRINTF(\"Patch '%s' not necessary for %s\\n\", patchset->name, (char *)ki->kip1->name);\n\t\t\t\t\t\tpatches_applied |= applied_mask;\n\n\t\t\t\t\t\tcontinue; // Continue in case it's double defined.\n\t\t\t\t\t}\n\n\t\t\t\t\t// Apply patches per section.\n\t\t\t\t\tu8 *kip_sect_data = ki->kip1->data;\n\t\t\t\t\tfor (u32 section_idx = 0; section_idx < KIP1_NUM_SECTIONS; section_idx++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (sections_affected & BIT(section_idx))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tgfx_printf(\"Applying '%s' on %s, sect %d\\n\", patchset->name, (char *)ki->kip1->name, section_idx);\n\t\t\t\t\t\t\tfor (const kip1_patch_t *patch = patchset->patches; patch != NULL && patch->src_data != NULL; patch++)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Check if patch is in current section.\n\t\t\t\t\t\t\t\tif (GET_KIP_PATCH_SECTION(patch->offset) != section_idx)\n\t\t\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\t\t\t// Check if patch is empty.\n\t\t\t\t\t\t\t\tif (!patch->length)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tgfx_con.mute = false;\n\t\t\t\t\t\t\t\t\tgfx_printf(\"%kPatch empty!%k\\n\", TXT_CLR_ERROR, TXT_CLR_DEFAULT);\n\t\t\t\t\t\t\t\t\treturn patchset->name; // MUST stop here as it's not probably intended.\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// If source does not match and is not already patched, throw an error.\n\t\t\t\t\t\t\t\tu32 patch_offset = GET_KIP_PATCH_OFFSET(patch->offset);\n\t\t\t\t\t\t\t\tif (patch->src_data != KIP1_PATCH_SRC_NO_CHECK                                  &&\n\t\t\t\t\t\t\t\t\t(memcmp(&kip_sect_data[patch_offset], patch->src_data, patch->length) != 0) &&\n\t\t\t\t\t\t\t\t\t(memcmp(&kip_sect_data[patch_offset], patch->dst_data, patch->length) != 0))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tgfx_con.mute = false;\n\t\t\t\t\t\t\t\t\tgfx_printf(\"%kPatch mismatch at 0x%x!%k\\n\", TXT_CLR_ERROR, patch_offset, TXT_CLR_DEFAULT);\n\t\t\t\t\t\t\t\t\treturn patchset->name; // MUST stop here as kip is likely corrupt.\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tDPRINTF(\"Patching %d bytes at offset 0x%x\\n\", patch->length, patch_offset);\n\t\t\t\t\t\t\t\t\tmemcpy(&kip_sect_data[patch_offset], patch->dst_data, patch->length);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tkip_sect_data += ki->kip1->sections[section_idx].size_comp;\n\t\t\t\t\t}\n\n\t\t\t\t\tpatches_applied |= applied_mask;\n\t\t\t\t}\n\n\t\t\t\tpatchset++;\n\t\t\t}\n\n\t\t\t// emuMMC must be applied after all other patches, since it affects TEXT offset.\n\t\t\tif (emummc_patch_apply)\n\t\t\t{\n\t\t\t\t// Encode ID.\n\t\t\t\temu_cfg.fs_ver = kip_id_idx;\n\t\t\t\tif (kip_id_idx)\n\t\t\t\t\temu_cfg.fs_ver--;\n\t\t\t\tif (kip_id_idx > 17)\n\t\t\t\t\temu_cfg.fs_ver -= 2;\n\n\t\t\t\t// Inject emuMMC code.\n\t\t\t\tgfx_printf(\"Injecting emuMMC. FS ID: %d\\n\", emu_cfg.fs_ver);\n\t\t\t\tif (_kipm_inject(\"bootloader/sys/emummc.kipm\", \"FS\", ki))\n\t\t\t\t\treturn \"emummc\";\n\n\t\t\t\t// Skip checking again.\n\t\t\t\temummc_patch_selected = false;\n\t\t\t\temummc_patch_apply    = false;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check if all patches were applied.\n\tfor (u32 i = 0; i < patches_num; i++)\n\t{\n\t\tif ((patches_applied & BIT(i)) == 0)\n\t\t\treturn patches[i];\n\t}\n\n\t// Check if emuMMC was applied.\n\tif (emummc_patch_selected)\n\t\treturn \"emummc\";\n\n\treturn NULL;\n}\n\n// Master key 7 encrypted with 8.  (7.0.0 with 8.1.0). AES-ECB\nstatic const u8 mkey_vector_7xx[SE_KEY_128_SIZE] =\n\t{ 0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29 };\n\nu8 pkg2_keyslot;\npkg2_hdr_t *pkg2_decrypt(void *data, u8 mkey, bool is_exo)\n{\n\tu8 *pdata = (u8 *)data;\n\n\t// Skip signature.\n\tpdata += 0x100;\n\n\tpkg2_hdr_t *hdr = (pkg2_hdr_t *)pdata;\n\n\t// Skip header.\n\tpdata += sizeof(pkg2_hdr_t);\n\n\t// Set pkg2 key slot to default. If 7.0.0 it will change to 9.\n\tpkg2_keyslot = 8;\n\n\t// Decrypt 7.0.0 pkg2 via 8.1.0 mkey on Erista.\n\tif (!h_cfg.t210b01 && mkey == HOS_MKEY_VER_700)\n\t{\n\t\tu8 tmp_mkey[SE_KEY_128_SIZE];\n\n\t\t// Decrypt 7.0.0 encrypted mkey.\n\t\tse_aes_crypt_ecb(!is_exo ? 7 : 13, DECRYPT, tmp_mkey, mkey_vector_7xx, SE_KEY_128_SIZE);\n\n\t\t// Set and unwrap pkg2 key.\n\t\tse_aes_key_set(9, tmp_mkey, SE_KEY_128_SIZE);\n\t\tse_aes_unwrap_key(9, 9, package2_keyseed);\n\n\t\tpkg2_keyslot = 9;\n\t}\n\n\t// Decrypt header.\n\tse_aes_crypt_ctr(pkg2_keyslot, hdr, hdr, sizeof(pkg2_hdr_t), hdr);\n\n\tif (hdr->magic != PKG2_MAGIC)\n\t\treturn NULL;\n\n\t// Decrypt sections.\n\tfor (u32 i = 0; i < 4; i++)\n\t{\nDPRINTF(\"sec %d has size %08X\\n\", i, hdr->sec_size[i]);\n\t\tif (!hdr->sec_size[i])\n\t\t\tcontinue;\n\n\t\tse_aes_crypt_ctr(pkg2_keyslot, pdata, pdata, hdr->sec_size[i], hdr->sec_ctr[i]);\n\n\t\tpdata += hdr->sec_size[i];\n\t}\n\n\treturn hdr;\n}\n\nstatic u32 _pkg2_ini1_build(u8 *pdst, u8 *psec, pkg2_hdr_t *hdr, link_t *kips_info, bool new_pkg2)\n{\n\t// Calculate INI1 size.\n\tu32 ini1_size = sizeof(pkg2_ini1_t);\n\tLIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, kips_info, link)\n\t{\n\t\tini1_size += ki->size;\n\t}\n\n\t// Align size and set it.\n\tini1_size = ALIGN(ini1_size, 4);\n\n\t// For new kernel if INI1 fits in the old one, use it.\n\tbool use_old_ini_region = psec && ini1_size <= (pkg2_newkern_ini1_end - pkg2_newkern_ini1_start);\n\tif (use_old_ini_region)\n\t\tpdst = psec + pkg2_newkern_ini1_start;\n\n\t// Set initial header and magic.\n\tpkg2_ini1_t *ini1 = (pkg2_ini1_t *)pdst;\n\tmemset(ini1, 0, sizeof(pkg2_ini1_t));\n\tini1->magic = INI1_MAGIC;\n\tini1->size  = ini1_size;\n\tpdst += sizeof(pkg2_ini1_t);\n\n\t// Merge KIPs into INI1.\n\tLIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, kips_info, link)\n\t{\nDPRINTF(\"adding kip1 '%s' @ %08X (%08X)\\n\", (char *)ki->kip1->name, (u32)ki->kip1, ki->size);\n\t\tmemcpy(pdst, ki->kip1, ki->size);\n\t\tpdst += ki->size;\n\t\tini1->num_procs++;\n\t}\n\n\t// Encrypt INI1 in its own section if old pkg2. Otherwise it gets embedded into Kernel.\n\tif (!new_pkg2)\n\t{\n\t\thdr->sec_size[PKG2_SEC_INI1] = ini1_size;\n\t\thdr->sec_off[PKG2_SEC_INI1] = 0x14080000;\n\t\tse_aes_crypt_ctr(8, ini1, ini1, ini1_size, hdr->sec_ctr[PKG2_SEC_INI1]);\n\t}\n\telse\n\t{\n\t\thdr->sec_size[PKG2_SEC_INI1] = 0;\n\t\thdr->sec_off[PKG2_SEC_INI1] = 0;\n\t}\n\n\treturn !use_old_ini_region ? ini1_size : 0;\n}\n\nvoid pkg2_build_encrypt(void *dst, void *hos_ctxt, link_t *kips_info, bool is_exo)\n{\n\tlaunch_ctxt_t *ctxt = (launch_ctxt_t *)hos_ctxt;\n\tu32 meso_magic = *(u32 *)(ctxt->kernel + 4);\n\tu32 kernel_size = ctxt->kernel_size;\n\tu8 mkey = ctxt->pkg1_id->mkey;\n\tu8 *pdst = (u8 *)dst;\n\n\t// Force new Package2 if Mesosphere.\n\tbool is_meso = (meso_magic & 0xF0FFFFFF) == ATM_MESOSPHERE;\n\tif (is_meso)\n\t\tctxt->new_pkg2 = true;\n\n\t// Set key version. For Erista 7.0.0, use 8.1.0 because of a bug in Exo2?\n\tu8 key_ver = mkey ? mkey + 1 : 0;\n\tif (pkg2_keyslot == 9)\n\t{\n\t\tkey_ver = HOS_MKEY_VER_810 + 1;\n\t\tpkg2_keyslot = 8;\n\t}\n\n\t// Signature.\n\tmemset(pdst, 0, 0x100);\n\tpdst += 0x100;\n\n\t// Header.\n\tpkg2_hdr_t *hdr = (pkg2_hdr_t *)pdst;\n\tmemset(hdr, 0, sizeof(pkg2_hdr_t));\n\n\t// Set initial header values.\n\thdr->magic = PKG2_MAGIC;\n\thdr->bl_ver = 0;\n\thdr->pkg2_ver = 0xFF;\n\n\tif (!ctxt->new_pkg2)\n\t\thdr->base = 0x10000000;\n\telse\n\t\thdr->base = 0x60000;\nDPRINTF(\"%s @ %08X (%08X)\\n\", is_meso ? \"Mesosphere\": \"kernel\",(u32)ctxt->kernel, kernel_size);\n\n\tpdst += sizeof(pkg2_hdr_t);\n\n\t// Kernel.\n\tmemcpy(pdst, ctxt->kernel, kernel_size);\n\tif (!ctxt->new_pkg2)\n\t\thdr->sec_off[PKG2_SEC_KERNEL] = 0x10000000;\n\telse\n\t{\n\t\t// Build INI1 for new Package2.\n\t\tu32 ini1_size = _pkg2_ini1_build(pdst + kernel_size, is_meso ? NULL : pdst, hdr, kips_info, true);\n\t\thdr->sec_off[PKG2_SEC_KERNEL] = 0x60000;\n\n\t\t// Set new INI1 offset to kernel.\n\t\tu32 meso_meta_offset = *(u32 *)(pdst + 8);\n\t\tif (is_meso && (meso_magic & 0x0F000000)) // MSS1.\n\t\t\t*(u32 *)(pdst + meso_meta_offset) = kernel_size - meso_meta_offset;\n\t\telse if (ini1_size)\n\t\t{\n\t\t\tif (is_meso) // MSS0.\n\t\t\t\t*(u32 *)(pdst + 8) = kernel_size;\n\t\t\telse\n\t\t\t\t*(u32 *)(pdst + pkg2_newkern_ini1_info) = kernel_size - pkg2_newkern_ini1_rela;\n\t\t}\n\n\t\tkernel_size += ini1_size;\n\t}\n\thdr->sec_size[PKG2_SEC_KERNEL] = kernel_size;\n\tse_aes_crypt_ctr(pkg2_keyslot, pdst, pdst, kernel_size, hdr->sec_ctr[PKG2_SEC_KERNEL]);\n\tpdst += kernel_size;\nDPRINTF(\"kernel encrypted\\n\");\n\n\t// Build INI1 for old Package2.\n\tu32 ini1_size = 0;\n\tif (!ctxt->new_pkg2)\n\t\tini1_size = _pkg2_ini1_build(pdst, NULL, hdr, kips_info, false);\nDPRINTF(\"INI1 encrypted\\n\");\n\n\tif (!is_exo) // Not needed on Exosphere 1.0.0 and up.\n\t{\n\t\t// Calculate SHA256 over encrypted sections. Only 3 have valid hashes.\n\t\tu8 *pk2_hash_data = (u8 *)dst + 0x100 + sizeof(pkg2_hdr_t);\n\t\tfor (u32 i = PKG2_SEC_KERNEL; i <= PKG2_SEC_UNUSED; i++)\n\t\t{\n\t\t\tse_sha_hash_256_oneshot(hdr->sec_sha256[i], (void *)pk2_hash_data, hdr->sec_size[i]);\n\t\t\tpk2_hash_data += hdr->sec_size[i];\n\t\t}\n\t}\n\n\t// Encrypt header.\n\t*(u32 *)hdr->ctr = 0x100 + sizeof(pkg2_hdr_t) + kernel_size + ini1_size;\n\thdr->ctr[4] = key_ver;\n\tse_aes_crypt_ctr(pkg2_keyslot, hdr, hdr, sizeof(pkg2_hdr_t), hdr);\n\tmemset(hdr->ctr, 0 , SE_AES_IV_SIZE);\n\t*(u32 *)hdr->ctr = 0x100 + sizeof(pkg2_hdr_t) + kernel_size + ini1_size;\n\thdr->ctr[4] = key_ver;\n}\n"
  },
  {
    "path": "bootloader/hos/pkg2.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _PKG2_H_\n#define _PKG2_H_\n\n#include <bdk.h>\n\n#define PKG2_LOAD_ADDR  0xA9800000\n\n#define PKG2_MAGIC      0x31324B50\n#define PKG2_SEC_BASE   0x80000000\n#define PKG2_SEC_KERNEL 0\n#define PKG2_SEC_INI1   1\n#define PKG2_SEC_UNUSED 2\n\n#define INI1_MAGIC 0x31494E49\n\n//! TODO: Update on kernel change if needed.\n// Offset of OP + 12 is the INI1 offset. On v2 with dynamic crt0 it's + 16.\n#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // MOV X21, #0.\n#define PKG2_NEWKERN_START 0x800\n\n#define ATM_MESOSPHERE 0x3053534D\n\nextern u32 pkg2_newkern_ini1_info;\nextern u32 pkg2_newkern_ini1_start;\nextern u32 pkg2_newkern_ini1_end;\n\ntypedef struct _kernel_patch_t\n{\n\tu32  id;\n\tu32  off;\n\tu32  val;\n\tconst u32 *ptr;\n} kernel_patch_t;\n\n#define KERNEL_PATCHSET_DEF(name, ...) \\\n\tstatic const kernel_patch_t name[] = { \\\n\t\t__VA_ARGS__, \\\n\t\t{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, (u32 *)0xFFFFFFFF} \\\n\t}\n\nenum\n{\n\t// Always applied.\n\tSVC_GENERIC   = 0,\n\t// Generic instruction patches.\n\tSVC_VERIFY_DS = 0x10,\n\tDEBUG_MODE_EN = 0x11,\n\tATM_GEN_PATCH = 0x12,\n\tATM_SYSM_INCR = ATM_GEN_PATCH,\n\t// >4 bytes patches. Value is a pointer of a u32 array.\n\tATM_ARR_PATCH = 0x13,\n};\n\ntypedef struct _pkg2_hdr_t\n{\n/* 0x000 */\tu8  ctr[0x10];\n/* 0x010 */\tu8  sec_ctr[4][SE_AES_IV_SIZE];\n/* 0x050 */\tu32 magic;\n/* 0x054 */\tu32 base;\n/* 0x058 */\tu32 pad0;\n/* 0x05C */\tu8  pkg2_ver;\n/* 0x05D */\tu8  bl_ver;\n/* 0x05E */\tu16 pad1;\n/* 0x060 */\tu32 sec_size[4];\n/* 0x070 */\tu32 sec_off[4];\n/* 0x080 */\tu8  sec_sha256[4][SE_SHA_256_SIZE];\n/* 0x100 */\tu8  data[];\n} pkg2_hdr_t;\n\ntypedef struct _pkg2_ini1_t\n{\n\tu32 magic;\n\tu32 size;\n\tu32 num_procs;\n\tu32 pad;\n} pkg2_ini1_t;\n\nenum kip_offset_section\n{\n\tKIP_TEXT    = 0,\n\tKIP_RODATA  = 1,\n\tKIP_DATA    = 2,\n\tKIP_BSS     = 3,\n\tKIP_UNKSEC1 = 4,\n\tKIP_UNKSEC2 = 5\n};\n\n#define KIP1_NUM_SECTIONS 6\n\ntypedef struct _pkg2_kip1_sec_t\n{\n\tu32 offset;\n\tu32 size_decomp;\n\tu32 size_comp;\n\tu32 attrib;\n} pkg2_kip1_sec_t;\n\ntypedef struct _pkg2_kip1_t\n{\n/* 0x000 */\tu32 magic;\n/* 0x004 */\tchar name[12];\n/* 0x010 */\tu64 tid;\n/* 0x018 */\tu32 proc_cat;\n/* 0x01C */\tu8 main_thrd_prio;\n/* 0x01D */\tu8 def_cpu_core;\n/* 0x01E */\tu8 res;\n/* 0x01F */\tu8 flags;\n/* 0x020 */\tpkg2_kip1_sec_t sections[KIP1_NUM_SECTIONS];\n/* 0x080 */\tu32 caps[0x20];\n/* 0x100 */\tu8 data[];\n} pkg2_kip1_t;\n\ntypedef struct _pkg2_kip1_info_t\n{\n\tpkg2_kip1_t *kip1;\n\tu32 size;\n\tlink_t link;\n} pkg2_kip1_info_t;\n\ntypedef struct _pkg2_kernel_id_t\n{\n\tu8 hash[8];\n\tconst kernel_patch_t *kernel_patchset;\n} pkg2_kernel_id_t;\n\n#define KIP1_PATCH_SRC_NO_CHECK (char *)(-1)\n\ntypedef struct _kip1_patch_t\n{\n\tu32   offset;   // section+offset of patch to apply.\n\tu32   length;   // In bytes, 0 means last patch.\n\tchar *src_data; // That must match.\n\tchar *dst_data; // That it gets replaced by.\n} kip1_patch_t;\n\ntypedef struct _kip1_patchset_t\n{\n\tchar *name;            // NULL means end.\n\tconst kip1_patch_t *patches; // NULL means not necessary.\n} kip1_patchset_t;\n\ntypedef struct _kip1_id_t\n{\n\tconst char *name;\n\tu8 hash[8];\n\tconst kip1_patchset_t *patchset;\n} kip1_id_t;\n\n/*\n * NX NC - Package2 BOOT Configuration\n *\n * This is taken from the first 1KB of a Package2 partition.\n * On retail, it's not zeroes, but on devkits it has actual data.\n * The signed part is reserved for special in-house devkits.\n */\n#define NX_BC1_ADDR 0x4003D000\n#define NX_BC6_ADDR 0x4003F800\n\n#define NX_BC_DBG_FLAG00_DEV_MODE  BIT(1)\n#define NX_BC_DBG_FLAG00_SERROR    BIT(2)\n#define NX_BC_DBG_FLAG00_ALL_FLAGS 0xFF\n\n#define NX_BC_HW_FLAG01_ALL_FLAGS  0xFF\n#define NX_BC_HW_FLAG03_MEM_MODE   0xFF\n#define NX_BC_HW_FLAG04_CNTCV_SET  BIT(0)\n\n#define NX_BC_PKG2_FLAG_DECRYPTED  BIT(0)\n#define NX_BC_PKG2_FLAG_UNSIGNED   BIT(1)\n\n#define NX_BC_NCA_FLAG_UNSIGNED    BIT(0)\n\ntypedef struct _nx_bc_t {\n\t/* Unsigned section */\n\tu32 version;\n\tu32 rsvd0[3];\n\tu8  dbg_flags[0x10]; // Normally all are set to 0xFF if devkit.\n\tu8  hw_flags[0x10];\n\tu64 cntcv_value;\n\tu8  padding0[0x1C8];\n\n\tu8 rsa_pss_signature[0x100];\n\n\t/* Signed section */\n\tu32 version_signed;\n\tu32 rsvd1;\n\tu8  pkg2_flags;\n\tu8  padding1[7];\n\tu32 ecid[4];\n\tu8  nca_flags[0x10];\n\tu8  unk_flags[0x10];\n\tu8  padding2[0xC0];\n} nx_bc_t;\n\nint  pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2);\nbool pkg2_has_kip(link_t *info, u64 tid);\nvoid pkg2_replace_kip(link_t *info, u64 tid, pkg2_kip1_t *kip1);\nvoid pkg2_add_kip(link_t *info, pkg2_kip1_t *kip1);\nvoid pkg2_merge_kip(link_t *info, pkg2_kip1_t *kip1);\nvoid pkg2_get_ids(kip1_id_t **ids, u32 *entries);\nconst char *pkg2_patch_kips(link_t *info, char *patch_names);\n\nconst pkg2_kernel_id_t *pkg2_identify(const u8 *hash);\npkg2_hdr_t *pkg2_decrypt(void *data, u8 mkey, bool is_exo);\nvoid pkg2_build_encrypt(void *dst, void *hos_ctxt, link_t *kips_info, bool is_exo);\n\n#endif\n"
  },
  {
    "path": "bootloader/hos/pkg2_ini_kippatch.c",
    "content": "/*\n * Copyright (c) 2019-2024 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n#include <stdlib.h>\n\n#include <bdk.h>\n\n#include \"pkg2_ini_kippatch.h\"\n#include <libs/fatfs/ff.h>\n\n#define KPS(x) ((u32)(x) << 29)\n\nstatic u8 *_htoa(u8 *result, const char *ptr, u8 byte_len, u8 *buf)\n{\n\tchar ch = *ptr;\n\tu32 ascii_len = byte_len * 2;\n\tif (!result)\n\t\tresult = buf;\n\tu8 *dst = result;\n\n\twhile (ch == ' ' || ch == '\\t')\n\t\tch = *(++ptr);\n\n\tbool shift = true;\n\twhile (ascii_len)\n\t{\n\t\tu8 tmp = 0;\n\t\tif (ch >= '0' && ch <= '9')\n\t\t\ttmp = (ch - '0');\n\t\telse if (ch >= 'A' && ch <= 'F')\n\t\t\ttmp = (ch - 'A' + 10);\n\t\telse if (ch >= 'a' && ch <= 'f')\n\t\t\ttmp = (ch - 'a' + 10);\n\n\t\tif (shift)\n\t\t\t*dst = (tmp << 4) & 0xF0;\n\t\telse\n\t\t{\n\t\t\t*dst |= (tmp & 0x0F);\n\t\t\tdst++;\n\t\t}\n\n\t\tascii_len--;\n\t\tch = *(++ptr);\n\t\tshift = !shift;\n\t}\n\n\treturn result;\n}\n\nstatic u32 _find_patch_section_name(char *lbuf, u32 lblen, char schar)\n{\n\tu32 i;\n\t// Depends on 'FF_USE_STRFUNC 2' that removes \\r.\n\tfor (i = 0; i < lblen  && lbuf[i] != schar && lbuf[i] != '\\n'; i++)\n\t\t;\n\tlbuf[i] = 0;\n\n\treturn i;\n}\n\nstatic ini_kip_sec_t *_ini_create_kip_section(link_t *dst, ini_kip_sec_t *ksec, char *name)\n{\n\tif (ksec)\n\t\tlist_append(dst, &ksec->link);\n\n\t// Calculate total allocation size.\n\tu32 len = strlen(name);\n\tchar *buf = zalloc(sizeof(ini_kip_sec_t) + len + 1);\n\n\tksec = (ini_kip_sec_t *)buf;\n\tu32 i = _find_patch_section_name(name, len, ':') + 1;\n\tksec->name = strcpy_ns(buf + sizeof(ini_kip_sec_t), name);\n\n\t// Get hash section.\n\t_htoa(ksec->hash, &name[i], 8, NULL);\n\n\t// Initialize list.\n\tlist_init(&ksec->pts);\n\n\treturn ksec;\n}\n\nint ini_patch_parse(link_t *dst, const char *ini_path)\n{\n\tFIL fp;\n\tu32 lblen;\n\tchar *lbuf;\n\tini_kip_sec_t *ksec = NULL;\n\n\t// Open ini.\n\tif (f_open(&fp, ini_path, FA_READ) != FR_OK)\n\t\treturn 1;\n\n\tlbuf = malloc(512);\n\n\tdo\n\t{\n\t\t// Fetch one line.\n\t\tlbuf[0] = 0;\n\t\tf_gets(lbuf, 512, &fp);\n\t\tlblen = strlen(lbuf);\n\n\t\t// Remove trailing newline. Depends on 'FF_USE_STRFUNC 2' that removes \\r.\n\t\tif (lblen && lbuf[lblen - 1] == '\\n')\n\t\t\tlbuf[lblen - 1] = 0;\n\n\t\tif (lblen > 2 && lbuf[0] == '[') // Create new section.\n\t\t{\n\t\t\t_find_patch_section_name(lbuf, lblen, ']');\n\n\t\t\t// Set patchset kip name and hash.\n\t\t\tksec = _ini_create_kip_section(dst, ksec, &lbuf[1]);\n\t\t}\n\t\telse if (ksec && lbuf[0] == '.') // Extract key/value.\n\t\t{\n\t\t\tu32 str_start = 0;\n\t\t\tu32 pos = _find_patch_section_name(lbuf, lblen, '=');\n\n\t\t\t// Calculate total allocation size.\n\t\t\tchar *buf = zalloc(sizeof(ini_patchset_t) + strlen(&lbuf[1]) + 1);\n\t\t\tini_patchset_t *pt = (ini_patchset_t *)buf;\n\n\t\t\t// Set patch name.\n\t\t\tpt->name = strcpy_ns(buf + sizeof(ini_patchset_t), &lbuf[1]);\n\n\t\t\tu8 kip_sidx = lbuf[pos + 1] - '0';\n\t\t\tpos += 3;\n\n\t\t\tif (kip_sidx < 6)\n\t\t\t{\n\t\t\t\t// Set patch offset.\n\t\t\t\tpt->offset = KPS(kip_sidx);\n\t\t\t\tstr_start = _find_patch_section_name(&lbuf[pos], lblen - pos, ':');\n\t\t\t\tpt->offset |= strtol(&lbuf[pos], NULL, 16);\n\t\t\t\tpos += str_start + 1;\n\n\t\t\t\t// Set patch size.\n\t\t\t\tstr_start = _find_patch_section_name(&lbuf[pos], lblen - pos, ':');\n\t\t\t\tpt->length = strtol(&lbuf[pos], NULL, 16);\n\t\t\t\tpos += str_start + 1;\n\n\t\t\t\tu8 *data = malloc(pt->length * 2);\n\n\t\t\t\t// Set patch source data.\n\t\t\t\tstr_start = _find_patch_section_name(&lbuf[pos], lblen - pos, ',');\n\t\t\t\tpt->src_data = _htoa(NULL, &lbuf[pos], pt->length, data);\n\t\t\t\tpos += str_start + 1;\n\n\t\t\t\t// Set patch destination data.\n\t\t\t\tpt->dst_data = _htoa(NULL, &lbuf[pos], pt->length, data + pt->length);\n\t\t\t}\n\n\t\t\tlist_append(&ksec->pts, &pt->link);\n\t\t}\n\t} while (!f_eof(&fp));\n\n\tf_close(&fp);\n\n\tif (ksec)\n\t\tlist_append(dst, &ksec->link);\n\n\tfree(lbuf);\n\n\treturn 0;\n}\n"
  },
  {
    "path": "bootloader/hos/pkg2_ini_kippatch.h",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _INIPATCH_H_\n#define _INIPATCH_H_\n\n#include <bdk.h>\n\ntypedef struct _ini_patchset_t\n{\n\tchar *name;\n\tu32 offset;   // section + offset of patch to apply.\n\tu32 length;   // In bytes, 0 means last patch.\n\tu8 *src_data; // That must match.\n\tu8 *dst_data; // Gets replaced with.\n\tlink_t link;\n} ini_patchset_t;\n\ntypedef struct _ini_kip_sec_t\n{\n\tchar *name;\n\tu8 hash[8];\n\tlink_t pts;\n\tlink_t link;\n} ini_kip_sec_t;\n\nint ini_patch_parse(link_t *dst, const char *ini_path);\n\n#endif\n"
  },
  {
    "path": "bootloader/hos/pkg2_patches.inl",
    "content": "/*\n * Copyright (c) 2018-2026 CTCaer\n * Copyright (c) 2018 Atmosphère-NX\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n//TODO: Replace hardcoded AArch64 instructions with instruction macros.\n//TODO: Reduce hardcoded values without searching kernel for patterns?\n// The process ID send/receive kernel patches were taken from Atmosphère's kernel patches.\n// They should only be used when running Atmosphère.\n#define CODE_OFF_1ST_100  0x4797C\n#define CODE_OFF_1ST_200  0x6486C\n#define CODE_OFF_1ST_300  0x494A4\n#define CODE_OFF_1ST_302  0x494BC\n#define CODE_OFF_1ST_400  0x52890\n#define CODE_OFF_1ST_500  0x5C020\n#define CODE_OFF_1ST_600  0x5EE00\n#define CODE_OFF_1ST_700  0x5FEC0\n#define CODE_OFF_1ST_800  0x607F0\n#define CODE_OFF_1ST_900  0x65780\n#define CODE_OFF_1ST_1000 0x67790\n#define CODE_OFF_1ST_1100 0x49EE8\n#define CODE_OFF_1ST_1200 0x48810\n\n#define ID_SND_OFF_100  0x23CC0\n#define ID_SND_OFF_200  0x3F134\n#define ID_SND_OFF_300  0x26080\n#define ID_SND_OFF_302  0x26080\n#define ID_SND_OFF_400  0x2AF64\n#define ID_SND_OFF_500  0x2AD34\n#define ID_SND_OFF_600  0x2BB8C\n#define ID_SND_OFF_700  0x2D044\n#define ID_SND_OFF_800  0x2F1FC\n#define ID_SND_OFF_900  0x329A0\n#define ID_SND_OFF_1000 0x34404\n#define ID_SND_OFF_1100 0x245B4\n#define ID_SND_OFF_1101 0x245B8\n#define ID_SND_OFF_1200 0x24CF4\n\n#define ID_RCV_OFF_100  0x219F0\n#define ID_RCV_OFF_200  0x3D1A8\n#define ID_RCV_OFF_300  0x240F0\n#define ID_RCV_OFF_302  0x240F0\n#define ID_RCV_OFF_400  0x28F6C\n#define ID_RCV_OFF_500  0x28DAC\n#define ID_RCV_OFF_600  0x29B6C\n#define ID_RCV_OFF_700  0x2B23C\n#define ID_RCV_OFF_800  0x2D424\n#define ID_RCV_OFF_900  0x309B4\n#define ID_RCV_OFF_1000 0x322F8\n#define ID_RCV_OFF_1100 0x22B24\n#define ID_RCV_OFF_1101 0x22B28\n#define ID_RCV_OFF_1200 0x23424\n\nstatic const u32 PRC_ID_SND_100[] =\n{\n\t0xA9BF2FEA, 0x2A0E03EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B,\n\t0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9412948,\t0xA8C12FEA\n};\n#define CODE_OFF_2ND_100 (CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100) + sizeof(u32))\nstatic const u32 PRC_ID_RCV_100[] =\n{\n\t0xA9BF2FEA, 0x2A1C03EA, 0xD37EF54A, 0xF86A69AA, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A,\n\t0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9412968, 0xA8C12FEA\n};\n\nstatic const u32 PRC_ID_SND_200[] =\n{\n\t0xA9BF2FEA, 0x2A1803EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B,\n\t0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9413148, 0xA8C12FEA\n};\n#define CODE_OFF_2ND_200 (CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200) + sizeof(u32))\nstatic const u32 PRC_ID_RCV_200[] =\n{\n\t0xA9BF2FEA, 0x2A0F03EA, 0xD37EF54A, 0xF9405FEB, 0xF86A696A, 0xF9407BEB, 0x92FFFFE9, 0x8A090148,\n\t0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9413168, 0xA8C12FEA\n};\n\nstatic const u32 PRC_ID_SND_300[] =\n{\n\t0xA9BF2FEA, 0x2A1803EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B,\n\t0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9415548, 0xA8C12FEA\n};\n#define CODE_OFF_2ND_300 (CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300) + sizeof(u32))\nstatic const u32 PRC_ID_RCV_300[] =\n{\n\t0xA9BF2FEA, 0x2A0F03EA, 0xD37EF54A, 0xF9405FEB, 0xF86A696A, 0xF9407BEB, 0x92FFFFE9, 0x8A090148,\n\t0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9415568, 0xA8C12FEA\n};\n\n#define CODE_OFF_2ND_302 (CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_300) + sizeof(u32))\n\nstatic const u32 PRC_ID_SND_400[] =\n{\n\t0x2A1703EA, 0xD37EF54A, 0xF86A6B8A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9,\n\t0xEB09015F, 0x54000060, 0xF94053EA, 0xF9415948, 0xF94053EA\n};\n#define CODE_OFF_2ND_400 (CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400) + sizeof(u32))\nstatic const u32 PRC_ID_RCV_400[] =\n{\n\t0xF9403BED, 0x2A0E03EA, 0xD37EF54A, 0xF86A69AA, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A,\n\t0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9415B28, 0xD503201F\n};\n\nstatic const u32 PRC_ID_SND_500[] =\n{\n\t0x2A1703EA, 0xD37EF54A, 0xF86A6B6A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9,\n\t0xEB09015F, 0x54000060, 0xF94043EA, 0xF9415948, 0xF94043EA\n};\n#define CODE_OFF_2ND_500 (CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500) + sizeof(u32))\nstatic const u32 PRC_ID_RCV_500[] =\n{\n\t0xF9403BED, 0x2A1503EA, 0xD37EF54A, 0xF86A69AA, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A,\n\t0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9415B08, 0xF9406FEA\n};\n\nstatic const u32 PRC_ID_SND_600[] =\n{\n\t0xA9BF2FEA, 0xF94037EB, 0x2A1503EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,\n\t0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400308, 0xF9401D08, 0xAA1803E0,\n\t0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0\n};\n#define CODE_OFF_2ND_600 (CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600) + sizeof(u32))\nstatic const u32 PRC_ID_RCV_600[] =\n{\n\t0xA9BF2FEA, 0xF94043EB, 0x2A1503EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,\n\t0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400308, 0xF9401D08, 0xAA1803E0,\n\t0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0\n};\n\nstatic const u32 PRC_ID_SND_700[] =\n{\n\t0xA9BF2FEA, 0xF9403BEB, 0x2A1903EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,\n\t0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002A8, 0xF9401D08, 0xAA1503E0,\n\t0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0\n};\n#define CODE_OFF_2ND_700 (CODE_OFF_1ST_700 + sizeof(PRC_ID_SND_700) + sizeof(u32))\nstatic const u32 PRC_ID_RCV_700[] =\n{\n\t0xA9BF2FEA, 0xF9404FEB, 0x2A1603EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,\n\t0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400368, 0xF9401D08, 0xAA1B03E0,\n\t0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0\n};\n\n#define CODE_OFF_2ND_800 (CODE_OFF_1ST_800 + sizeof(PRC_ID_SND_700) + sizeof(u32))\n\nstatic const u32 PRC_ID_SND_900[] =\n{\n\t0xA9BF2FEA, 0xF94037EB, 0x2A1603EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,\n\t0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002E8, 0xF9401D08, 0xAA1703E0,\n\t0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0\n};\n#define CODE_OFF_2ND_900 (CODE_OFF_1ST_900 + sizeof(PRC_ID_SND_900) + sizeof(u32))\nstatic const u32 PRC_ID_RCV_900[] =\n{\n\t0xA9BF2FEA, 0xF9404BEB, 0x2A1703EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,\n\t0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400368, 0xF9401D08, 0xAA1B03E0,\n\t0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0\n};\n\nstatic const u32 PRC_ID_SND_1000[] =\n{\n\t0xA9BF2FEA, 0xF94063EB, 0x2A1603EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,\n\t0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002E8, 0xF9401D08, 0xAA1703E0,\n\t0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0\n};\n#define CODE_OFF_2ND_1000 (CODE_OFF_1ST_1000 + sizeof(PRC_ID_SND_1000) + sizeof(u32))\nstatic const u32 PRC_ID_RCV_1000[] =\n{\n\t0xA9BF2FEA, 0xF94067EB, 0x2A1A03EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,\n\t0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400388, 0xF9401D08, 0xAA1C03E0,\n\t0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0\n};\n\nstatic const u32 PRC_ID_SND_1100[] =\n{\n\t0xA9BF2FEA, 0xF94043EB, 0x5280006A, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,\n\t0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002A8, 0xF9401D08, 0xAA1503E0,\n\t0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0\n};\n#define CODE_OFF_2ND_1100 (CODE_OFF_1ST_1100 + sizeof(PRC_ID_SND_1100) + sizeof(u32))\nstatic const u32 PRC_ID_RCV_1100[] =\n{\n\t0xA9BF2FEA, 0xF94073EB, 0x5280006A, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,\n\t0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400308, 0xF9401D08, 0xAA1803E0,\n\t0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0\n};\n\nstatic const u32 PRC_ID_SND_1200[] =\n{\n\t0xA9BF2FEA, 0xF9404FEB, 0x5280006A, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,\n\t0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002C8, 0xF9401D08, 0xAA1603E0,\n\t0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0\n};\n#define CODE_OFF_2ND_1200 (CODE_OFF_1ST_1200 + sizeof(PRC_ID_SND_1200) + sizeof(u32))\nstatic const u32 PRC_ID_RCV_1200[] =\n{\n\t0xA9BF2FEA, 0xF94073EB, 0x5280006A, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,\n\t0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400388, 0xF9401D08, 0xAA1C03E0,\n\t0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0\n};\n\n// Include kernel patches here, so we can utilize pkg1 id\nKERNEL_PATCHSET_DEF(_kernel_1_patchset,\n\t{ SVC_VERIFY_DS, 0x3764C, _NOP(),          NULL }, // Disable SVC verifications\n\t{ DEBUG_MODE_EN, 0x44074, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch\n\t// Atmosphère kernel patches.\n\t{ ATM_GEN_PATCH, ID_SND_OFF_100,   _B(ID_SND_OFF_100, CODE_OFF_1ST_100), NULL },           // Send process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_1ST_100, sizeof(PRC_ID_SND_100) >> 2,          PRC_ID_SND_100 }, // Send process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100),                                // Branch back and skip 1 instruction.\n\t\t_B(CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100), ID_SND_OFF_100 + 0x4), NULL },\n\t{ ATM_GEN_PATCH, ID_RCV_OFF_100,   _B(ID_RCV_OFF_100, CODE_OFF_2ND_100), NULL },           // Receive process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_2ND_100, sizeof(PRC_ID_RCV_100) >> 2,          PRC_ID_RCV_100 }, // Receive process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_2ND_100 + sizeof(PRC_ID_RCV_100),                                // Branch back and skip 1 instruction.\n\t\t_B(CODE_OFF_2ND_100 + sizeof(PRC_ID_RCV_100), ID_RCV_OFF_100 + 0x4), NULL }\n);\n\nKERNEL_PATCHSET_DEF(_kernel_2_patchset,\n\t{ SVC_VERIFY_DS, 0x54834, _NOP(),          NULL }, // Disable SVC verifications\n\t{ DEBUG_MODE_EN, 0x6086C, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch\n\t// Atmosphère kernel patches.\n\t{ ATM_GEN_PATCH, ID_SND_OFF_200, _B(ID_SND_OFF_200, CODE_OFF_1ST_200),   NULL },           // Send process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_1ST_200, sizeof(PRC_ID_SND_200) >> 2,          PRC_ID_SND_200 }, // Send process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200),                                // Branch back and skip 1 instruction.\n\t\t_B(CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200), ID_SND_OFF_200 + 0x4), NULL },\n\t{ ATM_GEN_PATCH, ID_RCV_OFF_200, _B(ID_RCV_OFF_200, CODE_OFF_2ND_200),   NULL },           // Receive process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_2ND_200, sizeof(PRC_ID_RCV_200) >> 2,          PRC_ID_RCV_200 }, // Receive process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_2ND_200 + sizeof(PRC_ID_RCV_200),                                // Branch back and skip 1 instruction.\n\t\t_B(CODE_OFF_2ND_200 + sizeof(PRC_ID_RCV_200), ID_RCV_OFF_200 + 0x4), NULL }\n);\n\nKERNEL_PATCHSET_DEF(_kernel_3_patchset,\n\t{ SVC_VERIFY_DS, 0x3BD24, _NOP(),          NULL }, // Disable SVC verifications\n\t{ DEBUG_MODE_EN, 0x483FC, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch\n\t// Atmosphère kernel patches.\n\t{ ATM_GEN_PATCH, ID_SND_OFF_300, _B(ID_SND_OFF_300, CODE_OFF_1ST_300),   NULL },           // Send process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_1ST_300, sizeof(PRC_ID_SND_300) >> 2,          PRC_ID_SND_300 }, // Send process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300),                                // Branch back and skip 1 instruction.\n\t\t_B(CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300), ID_SND_OFF_300 + 0x4), NULL },\n\t{ ATM_GEN_PATCH, ID_RCV_OFF_300, _B(ID_RCV_OFF_300, CODE_OFF_2ND_300),   NULL },           // Receive process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_2ND_300, sizeof(PRC_ID_RCV_300) >> 2,          PRC_ID_RCV_300 }, // Receive process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_2ND_300 + sizeof(PRC_ID_RCV_300),                                // Branch back and skip 1 instruction.\n\t\t_B(CODE_OFF_2ND_300 + sizeof(PRC_ID_RCV_300), ID_RCV_OFF_300 + 0x4), NULL }\n);\n\nKERNEL_PATCHSET_DEF(_kernel_302_patchset,\n\t{ SVC_VERIFY_DS, 0x3BD24, _NOP(),          NULL }, // Disable SVC verifications\n\t{ DEBUG_MODE_EN, 0x48414, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch\n\t// Atmosphère kernel patches.\n\t{ ATM_GEN_PATCH, ID_SND_OFF_302, _B(ID_SND_OFF_302, CODE_OFF_1ST_302),   NULL },           // Send process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_1ST_302, sizeof(PRC_ID_SND_300) >> 2,          PRC_ID_SND_300 }, // Send process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_300),                                // Branch back and skip 1 instruction.\n\t\t_B(CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_300), ID_SND_OFF_302 + 0x4), NULL },\n\t{ ATM_GEN_PATCH, ID_RCV_OFF_302, _B(ID_RCV_OFF_302, CODE_OFF_2ND_302),   NULL },           // Receive process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_2ND_302, sizeof(PRC_ID_RCV_300) >> 2,          PRC_ID_RCV_300 }, // Receive process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_2ND_302 + sizeof(PRC_ID_RCV_300),                                // Branch back and skip 1 instruction.\n\t\t_B(CODE_OFF_2ND_302 + sizeof(PRC_ID_RCV_300), ID_RCV_OFF_302 + 0x4), NULL }\n);\n\nKERNEL_PATCHSET_DEF(_kernel_4_patchset,\n\t{ SVC_VERIFY_DS, 0x41EB4, _NOP(),          NULL }, // Disable SVC verifications\n\t{ DEBUG_MODE_EN, 0x4EBFC, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch\n\t// Atmosphère kernel patches.\n\t{ ATM_GEN_PATCH, ID_SND_OFF_400, _B(ID_SND_OFF_400, CODE_OFF_1ST_400),       NULL },           // Send process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_1ST_400, sizeof(PRC_ID_SND_400) >> 2,              PRC_ID_SND_400 }, // Send process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400),                                    // Branch back and skip 2 instructions.\n\t\t_B(CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400), ID_SND_OFF_400 + 0x4 * 2), NULL },\n\t{ ATM_GEN_PATCH, ID_RCV_OFF_400, _B(ID_RCV_OFF_400, CODE_OFF_2ND_400),       NULL },           // Receive process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_2ND_400, sizeof(PRC_ID_RCV_400) >> 2,              PRC_ID_RCV_400 }, // Receive process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_2ND_400 + sizeof(PRC_ID_RCV_400),                                    // Branch back and skip 1 instruction.\n\t\t_B(CODE_OFF_2ND_400 + sizeof(PRC_ID_RCV_400), ID_RCV_OFF_400 + 0x4),     NULL }\n);\n\nKERNEL_PATCHSET_DEF(_kernel_5_patchset,\n\t{ SVC_GENERIC,   0x38C2C, _NOP(),          NULL }, // Allow same process on svcControlCodeMemory.\n\t{ SVC_VERIFY_DS, 0x45E6C, _NOP(),          NULL }, // Disable SVC verifications\n\t{ DEBUG_MODE_EN, 0x5513C, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch\n\t// Atmosphère kernel patches.\n\t{ ATM_SYSM_INCR, 0x54E30, _MOVZW(8, 0x1E00, LSL16), NULL }, // System memory pool increase.\n\t{ ATM_GEN_PATCH, ID_SND_OFF_500, _B(ID_SND_OFF_500, CODE_OFF_1ST_500),       NULL },           // Send process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_1ST_500, sizeof(PRC_ID_SND_500) >> 2,              PRC_ID_SND_500 }, // Send process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500),                                    // Branch back and skip 2 instructions.\n\t\t_B(CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500), ID_SND_OFF_500 + 0x4 * 2), NULL },\n\t{ ATM_GEN_PATCH, ID_RCV_OFF_500, _B(ID_RCV_OFF_500, CODE_OFF_2ND_500),       NULL },           // Receive process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_2ND_500, sizeof(PRC_ID_RCV_500) >> 2,              PRC_ID_RCV_500 }, // Receive process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_2ND_500 + sizeof(PRC_ID_RCV_500),                                    // Branch back and skip 2 instructions.\n\t\t_B(CODE_OFF_2ND_500 + sizeof(PRC_ID_RCV_500), ID_RCV_OFF_500 + 0x4 * 2), NULL }\n);\n\nKERNEL_PATCHSET_DEF(_kernel_6_patchset,\n\t{ SVC_GENERIC,   0x3A8CC, _NOP(),          NULL }, // Allow same process on svcControlCodeMemory.\n\t{ SVC_VERIFY_DS, 0x47EA0, _NOP(),          NULL }, // Disable SVC verifications\n\t{ DEBUG_MODE_EN, 0x57548, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch\n\t// Atmosphère kernel patches.\n\t{ ATM_SYSM_INCR, 0x57330, _MOVZW(8, 0x1D80, LSL16), NULL }, // System memory pool increase.\n\t{ ATM_GEN_PATCH, ID_SND_OFF_600, _B(ID_SND_OFF_600, CODE_OFF_1ST_600),       NULL },           // Send process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_1ST_600, sizeof(PRC_ID_SND_600) >> 2,              PRC_ID_SND_600 }, // Send process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600),                                    // Branch back and skip 4 instructions.\n\t\t_B(CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600), ID_SND_OFF_600 + 0x4 * 4), NULL },\n\t{ ATM_GEN_PATCH, ID_RCV_OFF_600, _B(ID_RCV_OFF_600, CODE_OFF_2ND_600),       NULL },           // Receive process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_2ND_600, sizeof(PRC_ID_RCV_600) >> 2,              PRC_ID_RCV_600 }, // Receive process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_2ND_600 + sizeof(PRC_ID_RCV_600),                                    // Branch back and skip 4 instructions.\n\t\t_B(CODE_OFF_2ND_600 + sizeof(PRC_ID_RCV_600), ID_RCV_OFF_600 + 0x4 * 4), NULL }\n);\n\nKERNEL_PATCHSET_DEF(_kernel_7_patchset,\n\t{ SVC_GENERIC,   0x3C6E0, _NOP(),          NULL }, // Allow same process on svcControlCodeMemory.\n\t{ SVC_VERIFY_DS, 0x49E5C, _NOP(),          NULL }, // Disable SVC verifications\n\t{ DEBUG_MODE_EN, 0x581B0, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch\n\t// Atmosphère kernel patches.\n\t{ ATM_SYSM_INCR, 0x57F98, _MOVZW(8, 0x1D80, LSL16), NULL }, // System memory pool increase.\n\t{ ATM_GEN_PATCH, ID_SND_OFF_700, _B(ID_SND_OFF_700, CODE_OFF_1ST_700),       NULL },           // Send process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_1ST_700, sizeof(PRC_ID_SND_700) >> 2,              PRC_ID_SND_700 }, // Send process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_1ST_700 + sizeof(PRC_ID_SND_700),                                    // Branch back and skip 4 instructions.\n\t\t_B(CODE_OFF_1ST_700 + sizeof(PRC_ID_SND_700), ID_SND_OFF_700 + 0x4 * 4), NULL },\n\t{ ATM_GEN_PATCH, ID_RCV_OFF_700, _B(ID_RCV_OFF_700, CODE_OFF_2ND_700),       NULL },           // Receive process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_2ND_700, sizeof(PRC_ID_RCV_700) >> 2,              PRC_ID_RCV_700 }, // Receive process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_2ND_700 + sizeof(PRC_ID_RCV_700),                                    // Branch back and skip 4 instructions.\n\t\t_B(CODE_OFF_2ND_700 + sizeof(PRC_ID_RCV_700), ID_RCV_OFF_700 + 0x4 * 4), NULL }\n);\n\nKERNEL_PATCHSET_DEF(_kernel_8_patchset,\n\t{ SVC_GENERIC,   0x3FAD0, _NOP(),          NULL }, // Allow same process on svcControlCodeMemory.\n\t{ SVC_VERIFY_DS, 0x4D15C, _NOP(),          NULL }, // Disable SVC verifications\n\t{ DEBUG_MODE_EN, 0x5BFAC, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch\n\t// Atmosphère kernel patches.\n\t{ ATM_SYSM_INCR, 0x5F9A4, _MOVZW(19, 0x1D80, LSL16), NULL }, // System memory pool increase.\n\t{ ATM_GEN_PATCH, ID_SND_OFF_800, _B(ID_SND_OFF_800, CODE_OFF_1ST_800),       NULL },           // Send process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_1ST_800, sizeof(PRC_ID_SND_700) >> 2,              PRC_ID_SND_700 }, // Send process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_1ST_800 + sizeof(PRC_ID_SND_700),                                    // Branch back and skip 4 instructions.\n\t\t_B(CODE_OFF_1ST_800 + sizeof(PRC_ID_SND_700), ID_SND_OFF_800 + 0x4 * 4), NULL },\n\t{ ATM_GEN_PATCH, ID_RCV_OFF_800, _B(ID_RCV_OFF_800, CODE_OFF_2ND_800),       NULL },           // Receive process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_2ND_800, sizeof(PRC_ID_RCV_700) >> 2,              PRC_ID_RCV_700 }, // Receive process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_2ND_800 + sizeof(PRC_ID_RCV_700),                                    // Branch back and skip 4 instructions.\n\t\t_B(CODE_OFF_2ND_800 + sizeof(PRC_ID_RCV_700), ID_RCV_OFF_800 + 0x4 * 4), NULL }\n);\n\nKERNEL_PATCHSET_DEF(_kernel_9_patchset,\n\t{ SVC_GENERIC,   0x43DFC, _NOP(),          NULL }, // Allow same process on svcControlCodeMemory.\n\t{ SVC_VERIFY_DS, 0x50628, _NOP(),          NULL }, // Disable SVC verifications\n\t{ DEBUG_MODE_EN, 0x609E8, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch\n\t// Atmosphère kernel patches.\n\t{ ATM_SYSM_INCR, 0x6493C, _MOVZW(19, 0x1D80, LSL16), NULL }, // System memory pool increase.\n\t{ ATM_GEN_PATCH, ID_SND_OFF_900, _B(ID_SND_OFF_900, CODE_OFF_1ST_900),       NULL },           // Send process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_1ST_900, sizeof(PRC_ID_SND_900) >> 2,              PRC_ID_SND_900 }, // Send process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_1ST_900 + sizeof(PRC_ID_SND_900),                                    // Branch back and skip 4 instructions.\n\t\t_B(CODE_OFF_1ST_900 + sizeof(PRC_ID_SND_900), ID_SND_OFF_900 + 0x4 * 4), NULL },\n\t{ ATM_GEN_PATCH, ID_RCV_OFF_900, _B(ID_RCV_OFF_900, CODE_OFF_2ND_900),       NULL },           // Receive process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_2ND_900, sizeof(PRC_ID_RCV_900) >> 2,              PRC_ID_RCV_900 }, // Receive process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_2ND_900 + sizeof(PRC_ID_RCV_900),                                    // Branch back and skip 4 instructions.\n\t\t_B(CODE_OFF_2ND_900 + sizeof(PRC_ID_RCV_900), ID_RCV_OFF_900 + 0x4 * 4), NULL }\n);\n\nKERNEL_PATCHSET_DEF(_kernel_10_patchset,\n\t{ SVC_GENERIC,   0x45DAC, _NOP(),          NULL }, // Allow same process on svcControlCodeMemory.\n\t{ SVC_VERIFY_DS, 0x523E4, _NOP(),          NULL }, // Disable SVC verifications.\n\t{ DEBUG_MODE_EN, 0x62B14, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch.\n\t// Atmosphère kernel patches.\n\t{ ATM_SYSM_INCR, 0x66950, _MOVZW(19, 0x1D80, LSL16), NULL }, // System memory pool increase.\n\t{ ATM_GEN_PATCH, ID_SND_OFF_1000, _B(ID_SND_OFF_1000, CODE_OFF_1ST_1000),       NULL },            // Send process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_1ST_1000, sizeof(PRC_ID_SND_1000) >> 2,               PRC_ID_SND_1000 }, // Send process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_1ST_1000 + sizeof(PRC_ID_SND_1000),                                      // Branch back and skip 4 instructions.\n\t\t_B(CODE_OFF_1ST_1000 + sizeof(PRC_ID_SND_1000), ID_SND_OFF_1000 + 0x4 * 4), NULL },\n\t{ ATM_GEN_PATCH, ID_RCV_OFF_1000, _B(ID_RCV_OFF_1000, CODE_OFF_2ND_1000),       NULL },            // Receive process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_2ND_1000, sizeof(PRC_ID_RCV_1000) >> 2,               PRC_ID_RCV_1000 }, // Receive process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_2ND_1000 + sizeof(PRC_ID_RCV_1000),                                      // Branch back and skip 4 instructions.\n\t\t_B(CODE_OFF_2ND_1000 + sizeof(PRC_ID_RCV_1000), ID_RCV_OFF_1000 + 0x4 * 4), NULL }\n);\n\nKERNEL_PATCHSET_DEF(_kernel_11_patchset,\n\t{ SVC_GENERIC,   0x2FCE0, _NOP(),          NULL }, // Allow same process on svcControlCodeMemory.\n\t{ SVC_VERIFY_DS, 0x39194, _NOP(),          NULL }, // Disable SVC verifications.\n\t{ DEBUG_MODE_EN, 0x460C0, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch.\n\t// Atmosphère kernel patches.\n\t{ ATM_SYSM_INCR, 0x490C4, _MOVZW(21, 0x1D80, LSL16), NULL }, // System memory pool increase.\n\t{ ATM_GEN_PATCH, ID_SND_OFF_1100, _B(ID_SND_OFF_1100, CODE_OFF_1ST_1100),       NULL},            // Send process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_1ST_1100, sizeof(PRC_ID_SND_1100) >> 2,               PRC_ID_SND_1100}, // Send process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_1ST_1100 + sizeof(PRC_ID_SND_1100),                                     // Branch back and skip 4 instructions.\n\t\t_B(CODE_OFF_1ST_1100 + sizeof(PRC_ID_SND_1100), ID_SND_OFF_1100 + 0x4 * 4), NULL},\n\t{ ATM_GEN_PATCH, ID_RCV_OFF_1100, _B(ID_RCV_OFF_1100, CODE_OFF_2ND_1100),       NULL},            // Receive process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_2ND_1100, sizeof(PRC_ID_RCV_1100) >> 2,               PRC_ID_RCV_1100}, // Receive process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_2ND_1100 + sizeof(PRC_ID_RCV_1100),                                     // Branch back and skip 4 instructions.\n\t\t_B(CODE_OFF_2ND_1100 + sizeof(PRC_ID_RCV_1100), ID_RCV_OFF_1100 + 0x4 * 4), NULL}\n);\n\nKERNEL_PATCHSET_DEF(_kernel_1101_patchset,\n\t{ SVC_GENERIC,   0x2FD04, _NOP(),          NULL }, // Allow same process on svcControlCodeMemory.\n\t{ SVC_VERIFY_DS, 0x39194, _NOP(),          NULL }, // Disable SVC verifications.\n\t{ DEBUG_MODE_EN, 0x460C0, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch.\n\t// Atmosphère kernel patches.\n\t{ ATM_SYSM_INCR, 0x490C4, _MOVZW(21, 0x1D80, LSL16), NULL }, // System memory pool increase.\n\t{ ATM_GEN_PATCH, ID_SND_OFF_1101, _B(ID_SND_OFF_1101, CODE_OFF_1ST_1100),       NULL},            // Send process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_1ST_1100, sizeof(PRC_ID_SND_1100) >> 2,               PRC_ID_SND_1100}, // Send process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_1ST_1100 + sizeof(PRC_ID_SND_1100),                                     // Branch back and skip 4 instructions.\n\t\t_B(CODE_OFF_1ST_1100 + sizeof(PRC_ID_SND_1100), ID_SND_OFF_1101 + 0x4 * 4), NULL},\n\t{ ATM_GEN_PATCH, ID_RCV_OFF_1101, _B(ID_RCV_OFF_1101, CODE_OFF_2ND_1100),       NULL},            // Receive process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_2ND_1100, sizeof(PRC_ID_RCV_1100) >> 2,               PRC_ID_RCV_1100}, // Receive process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_2ND_1100 + sizeof(PRC_ID_RCV_1100),                                     // Branch back and skip 4 instructions.\n\t\t_B(CODE_OFF_2ND_1100 + sizeof(PRC_ID_RCV_1100), ID_RCV_OFF_1101 + 0x4 * 4), NULL}\n);\n\nKERNEL_PATCHSET_DEF(_kernel_12_patchset,\n\t{ SVC_GENERIC,   0x2FCB4, _NOP(),          NULL }, // Allow same process on svcControlCodeMemory.\n\t{ SVC_VERIFY_DS, 0x38440, _NOP(),          NULL }, // Disable SVC verifications.\n\t{ DEBUG_MODE_EN, 0x45118, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch.\n\t// Atmosphère kernel patches.\n\t{ ATM_SYSM_INCR, 0x4809C, _MOVZW(21, 0x1D80, LSL16), NULL }, // System memory pool increase.\n\t{ ATM_GEN_PATCH, ID_SND_OFF_1200, _B(ID_SND_OFF_1200, CODE_OFF_1ST_1200),       NULL},            // Send process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_1ST_1200, sizeof(PRC_ID_SND_1200) >> 2,               PRC_ID_SND_1200}, // Send process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_1ST_1200 + sizeof(PRC_ID_SND_1200),                                     // Branch back and skip 4 instructions.\n\t\t_B(CODE_OFF_1ST_1200 + sizeof(PRC_ID_SND_1200), ID_SND_OFF_1200 + 0x4 * 4), NULL},\n\t{ ATM_GEN_PATCH, ID_RCV_OFF_1200, _B(ID_RCV_OFF_1200, CODE_OFF_2ND_1200),       NULL},            // Receive process id branch.\n\t{ ATM_ARR_PATCH, CODE_OFF_2ND_1200, sizeof(PRC_ID_RCV_1200) >> 2,               PRC_ID_RCV_1200}, // Receive process id code.\n\t{ ATM_GEN_PATCH, CODE_OFF_2ND_1200 + sizeof(PRC_ID_RCV_1200),                                     // Branch back and skip 4 instructions.\n\t\t_B(CODE_OFF_2ND_1200 + sizeof(PRC_ID_RCV_1200), ID_RCV_OFF_1200 + 0x4 * 4), NULL}\n);\n\n// Kernel sha256 hashes. Offset 0x800 up to INI1 start.\nstatic const pkg2_kernel_id_t _pkg2_kernel_ids[] =\n{\n\t{ \"\\xb8\\xc5\\x0c\\x68\\x25\\xa9\\xb9\\x5b\", _kernel_1_patchset },   //  1.0.0\n\t{ \"\\x64\\x0b\\x51\\xff\\x28\\x01\\xb8\\x30\", _kernel_2_patchset },   //  2.0.0 - 2.3.0\n\t{ \"\\x50\\x84\\x23\\xac\\x6f\\xa1\\x5d\\x3b\", _kernel_3_patchset },   //  3.0.0 - 3.0.1\n\t{ \"\\x81\\x9d\\x08\\xbe\\xe4\\x5e\\x1f\\xbb\", _kernel_302_patchset }, //  3.0.2\n\t{ \"\\xe6\\xc0\\xb7\\xe3\\x2f\\xf9\\x44\\x51\", _kernel_4_patchset },   //  4.0.0 - 4.1.0\n\t{ \"\\xb2\\x38\\x61\\xa8\\xe1\\xe2\\xe4\\xe4\", _kernel_5_patchset },   //  5.0.0 - 5.1.0\n\t{ \"\\x85\\x97\\x40\\xf6\\xc0\\x3e\\x3d\\x44\", _kernel_6_patchset },   //  6.0.0 - 6.2.0\n\t{ \"\\xa2\\x5e\\x47\\x0c\\x8e\\x6d\\x2f\\xd7\", _kernel_7_patchset },   //  7.0.0 - 7.0.1\n\t{ \"\\xf1\\x5e\\xc8\\x34\\xfd\\x68\\xf0\\xf0\", _kernel_8_patchset },   //  8.0.0 - 8.1.0. Kernel only.\n\t{ \"\\x69\\x00\\x39\\xdf\\x21\\x56\\x70\\x6b\", _kernel_9_patchset },   //  9.0.0 - 9.1.0. Kernel only.\n\t{ \"\\xa2\\xe3\\xad\\x1c\\x98\\xd8\\x7a\\x62\", _kernel_9_patchset },   //  9.2.0. Kernel only.\n\t{ \"\\x21\\xc1\\xd7\\x24\\x8e\\xcd\\xbd\\xa8\", _kernel_10_patchset },  // 10.0.0 - 10.2.0. Kernel only.\n\t{ \"\\xD5\\xD0\\xBA\\x5D\\x52\\xB9\\x77\\x85\", _kernel_11_patchset },  // 11.0.0. Kernel only.\n\t{ \"\\xF8\\x1E\\xE0\\x30\\x3C\\x7A\\x08\\x04\", _kernel_1101_patchset },// 11.0.1. Kernel only.\n\t{ \"\\xA6\\xD8\\xFF\\xF3\\x67\\x4A\\x33\\xFC\", _kernel_12_patchset },  // 12.0.0 - 12.1.0. Kernel only.\n\t//! TODO: Mesosphere is now mandatory. Missing patches: 13.0.0+\n};\n\n#define KIP1_FS_NOGC_PATCH_SDMMC3 \"\\x80\" // Replace SDMMC2 with SDMMC3.\n#define KIP1_FS_NOGC_PATCH_NOINIT \"\\xE0\\x03\\x1F\\x2A\\xC0\\x03\\x5F\\xD6\"\n\n// All kip patch offsets are without the 0x100-sized header.\nstatic const kip1_patchset_t _fs_patches_100[] = {\n\t{ \"nogc\",     NULL },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_40x[] = {\n\t{ KPS(KIP_TEXT) | 0xA3459, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ KPS(KIP_TEXT) | 0xAAB44, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_40x[] = {\n\t{ \"nogc\",     _fs_nogc_40x },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_410[] = {\n\t{ KPS(KIP_TEXT) | 0xA34BD, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ KPS(KIP_TEXT) | 0xAABA8, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_410[] = {\n\t{ \"nogc\",     _fs_nogc_410 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_50x[] = {\n\t{ KPS(KIP_TEXT) | 0xCF3C5, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ KPS(KIP_TEXT) | 0xD73A0, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_50x[] = {\n\t{ \"nogc\",     _fs_nogc_50x },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_510[] = {\n\t{ KPS(KIP_TEXT) | 0xCF795, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ KPS(KIP_TEXT) | 0xD7770, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_510[] = {\n\t{ \"nogc\",     _fs_nogc_510 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_600[] = {\n\t{ KPS(KIP_TEXT) | 0x12CC20, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x1538F5, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_600_exfat[] = {\n\t{ KPS(KIP_TEXT) | 0x138320, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x15EFF5, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_600[] = {\n\t{ \"nogc\",     _fs_nogc_600 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_600_exfat[] = {\n\t{ \"nogc\",     _fs_nogc_600_exfat },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_700[] = {\n\t{ KPS(KIP_TEXT) | 0x134160, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x15BF05, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_700_exfat[] = {\n\t{ KPS(KIP_TEXT) | 0x13F710, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x1674B5, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_700[] = {\n\t{ \"nogc\",     _fs_nogc_700 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_700_exfat[] = {\n\t{ \"nogc\",     _fs_nogc_700_exfat },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_800[] = {\n\t{ KPS(KIP_TEXT) | 0x136800, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x15EB95, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_800_exfat[] = {\n\t{ KPS(KIP_TEXT) | 0x141DB0, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x16A145, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_800[] = {\n\t{ \"nogc\",     _fs_nogc_800 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_800_exfat[] = {\n\t{ \"nogc\",     _fs_nogc_800_exfat },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_900[] = {\n\t{ KPS(KIP_TEXT) | 0x129420, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x143269, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_900[] = {\n\t{ \"nogc\",     _fs_nogc_900 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_910[] = {\n\t{ KPS(KIP_TEXT) | 0x129430, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x143279, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_910[] = {\n\t{ \"nogc\",     _fs_nogc_910 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1000[] = {\n\t{ KPS(KIP_TEXT) | 0x13BE90, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x14DE09, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1000[] = {\n\t{ \"nogc\",     _fs_nogc_1000 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1020[] = {\n\t{ KPS(KIP_TEXT) | 0x13C2F0, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x14E269, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1020[] = {\n\t{ \"nogc\",     _fs_nogc_1020 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1100[] = {\n\t{ KPS(KIP_TEXT) | 0x1398B4, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x156EB9, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1100[] = {\n\t{ \"nogc\",     _fs_nogc_1100 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1200[] = {\n\t{ KPS(KIP_TEXT) | 0x13EA24, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x155369, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1200[] = {\n\t{ \"nogc\",     _fs_nogc_1200 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1203[] = {\n\t{ KPS(KIP_TEXT) | 0x13EB34, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x155479, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1203[] = {\n\t{ \"nogc\",     _fs_nogc_1203 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1300[] = {\n\t{ KPS(KIP_TEXT) | 0x1425D0, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x159019, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1300[] = {\n\t{ \"nogc\",     _fs_nogc_1300 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1310[] = {\n\t{ KPS(KIP_TEXT) | 0x142570, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x158FB9, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1310[] = {\n\t{ \"nogc\",     _fs_nogc_1310 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1400[] = {\n\t{ KPS(KIP_TEXT) | 0x164230, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x18A2E9, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1400[] = {\n\t{ \"nogc\",     _fs_nogc_1400 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1400_exfat[] = {\n\t{ KPS(KIP_TEXT) | 0x16F5B0, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x195669, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1400_exfat[] = {\n\t{ \"nogc\",     _fs_nogc_1400_exfat },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1500[] = {\n\t{ KPS(KIP_TEXT) | 0x15ECE4, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x184159, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1500[] = {\n\t{ \"nogc\",     _fs_nogc_1500 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1500_exfat[] = {\n\t{ KPS(KIP_TEXT) | 0x169C74, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x18F0E9, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1500_exfat[] = {\n\t{ \"nogc\",     _fs_nogc_1500_exfat },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1600[] = {\n\t{ KPS(KIP_TEXT) | 0x160B70, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x1865D9, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1600[] = {\n\t{ \"nogc\",     _fs_nogc_1600 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1600_exfat[] = {\n\t{ KPS(KIP_TEXT) | 0x16B850, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x1912B9, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1600_exfat[] = {\n\t{ \"nogc\",     _fs_nogc_1600_exfat },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1603[] = {\n\t{ KPS(KIP_TEXT) | 0x160BC0, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x186629, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1603[] = {\n\t{ \"nogc\",     _fs_nogc_1603 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1603_exfat[] = {\n\t{ KPS(KIP_TEXT) | 0x16B8A0, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x191309, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1603_exfat[] = {\n\t{ \"nogc\",     _fs_nogc_1603_exfat },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1700[] = {\n\t{ KPS(KIP_TEXT) | 0x165100, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x18B049, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1700[] = {\n\t{ \"nogc\",     _fs_nogc_1700 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1700_exfat[] = {\n\t{ KPS(KIP_TEXT) | 0x16FF60, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x195EA9, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1700_exfat[] = {\n\t{ \"nogc\",     _fs_nogc_1700_exfat },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1800[] = {\n\t{ KPS(KIP_TEXT) | 0x164A50, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x18AE49, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1800[] = {\n\t{ \"nogc\",     _fs_nogc_1800 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1800_exfat[] = {\n\t{ KPS(KIP_TEXT) | 0x16FAE0, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x195ED9, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1800_exfat[] = {\n\t{ \"nogc\",     _fs_nogc_1800_exfat },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1900[] = {\n\t{ KPS(KIP_TEXT) | 0x16F070, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x195B75, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ KPS(KIP_TEXT) | 0x195D75, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1900[] = {\n\t{ \"nogc\",     _fs_nogc_1900 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_1900_exfat[] = {\n\t{ KPS(KIP_TEXT) | 0x17A8A0, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x1A13A5, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ KPS(KIP_TEXT) | 0x1A15A5, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_1900_exfat[] = {\n\t{ \"nogc\",     _fs_nogc_1900_exfat },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_2000[] = {\n\t{ KPS(KIP_TEXT) | 0x17C150, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x1A7D25, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ KPS(KIP_TEXT) | 0x1A7F25, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_2000[] = {\n\t{ \"nogc\",     _fs_nogc_2000 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_2000_exfat[] = {\n\t{ KPS(KIP_TEXT) | 0x187A70, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x1B3645, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ KPS(KIP_TEXT) | 0x1B3845, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_2000_exfat[] = {\n\t{ \"nogc\",     _fs_nogc_2000_exfat },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_2100[] = {\n\t{ KPS(KIP_TEXT) | 0x17FAE0, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x1AC8ED, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ KPS(KIP_TEXT) | 0x1AC905, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_2100[] = {\n\t{ \"nogc\",     _fs_nogc_2100 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_2100_exfat[] = {\n\t{ KPS(KIP_TEXT) | 0x18AC40, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x1B7A4D, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ KPS(KIP_TEXT) | 0x1B7A65, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_2100_exfat[] = {\n\t{ \"nogc\",     _fs_nogc_2100_exfat },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_2200[] = {\n\t{ KPS(KIP_TEXT) | 0x182F60, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x1B013D, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ KPS(KIP_TEXT) | 0x1B0155, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_2200[] = {\n\t{ \"nogc\",     _fs_nogc_2200 },\n\t{ NULL, NULL }\n};\n\nstatic const kip1_patch_t _fs_nogc_2200_exfat[] = {\n\t{ KPS(KIP_TEXT) | 0x18E150, 8, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_NOINIT },\n\t{ KPS(KIP_TEXT) | 0x1BB32D, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ KPS(KIP_TEXT) | 0x1BB345, 1, KIP1_PATCH_SRC_NO_CHECK, KIP1_FS_NOGC_PATCH_SDMMC3 },\n\t{ 0, 0, NULL, NULL }\n};\n\nstatic const kip1_patchset_t _fs_patches_2200_exfat[] = {\n\t{ \"nogc\",     _fs_nogc_2200_exfat },\n\t{ NULL, NULL }\n};\n\n// SHA256 hashes.\nstatic const kip1_id_t _kip_ids[] =\n{\n\t{ \"FS\", \"\\xDE\\x9F\\xDD\\xA4\\x08\\x5D\\xD5\\xFE\", _fs_patches_100 },        // FS 1.0.0\n\t{ \"FS\", \"\\xFC\\x3E\\x80\\x99\\x1D\\xCA\\x17\\x96\", _fs_patches_100 },        // FS 1.0.0 exFAT\n\t{ \"FS\", \"\\xCD\\x7B\\xBE\\x18\\xD6\\x13\\x0B\\x28\", _fs_patches_100 },        // FS 2.0.0\n\t{ \"FS\", \"\\xE7\\x66\\x92\\xDF\\xAA\\x04\\x20\\xE9\", _fs_patches_100 },        // FS 2.0.0 exFAT\n\t{ \"FS\", \"\\x0D\\x70\\x05\\x62\\x7B\\x07\\x76\\x7C\", _fs_patches_100 },        // FS 2.1.0\n\t{ \"FS\", \"\\xDB\\xD8\\x5F\\xCA\\xCC\\x19\\x3D\\xA8\", _fs_patches_100 },        // FS 2.1.0 exFAT\n\t{ \"FS\", \"\\xA8\\x6D\\xA5\\xE8\\x7E\\xF1\\x09\\x7B\", _fs_patches_100 },        // FS 3.0.0\n\t{ \"FS\", \"\\x98\\x1C\\x57\\xE7\\xF0\\x2F\\x70\\xF7\", _fs_patches_100 },        // FS 3.0.0 exFAT\n\t{ \"FS\", \"\\x57\\x39\\x7C\\x06\\x3F\\x10\\xB6\\x31\", _fs_patches_100 },        // FS 3.0.1\n\t{ \"FS\", \"\\x07\\x30\\x99\\xD7\\xC6\\xAD\\x7D\\x89\", _fs_patches_100 },        // FS 3.0.1 exFAT\n\t{ \"FS\", \"\\x06\\xE9\\x07\\x19\\x59\\x5A\\x01\\x0C\", _fs_patches_40x },        // FS 4.0.1\n\t{ \"FS\", \"\\x54\\x9B\\x0F\\x8D\\x6F\\x72\\xC4\\xE9\", _fs_patches_40x },        // FS 4.0.1 exFAT\n\t{ \"FS\", \"\\x80\\x96\\xAF\\x7C\\x6A\\x35\\xAA\\x82\", _fs_patches_410 },        // FS 4.1.0\n\t{ \"FS\", \"\\x02\\xD5\\xAB\\xAA\\xFD\\x20\\xC8\\xB0\", _fs_patches_410 },        // FS 4.1.0 exFAT\n\t{ \"FS\", \"\\xA6\\xF2\\x7A\\xD9\\xAC\\x7C\\x73\\xAD\", _fs_patches_50x },        // FS 5.0.0\n\t{ \"FS\", \"\\xCE\\x3E\\xCB\\xA2\\xF2\\xF0\\x62\\xF5\", _fs_patches_50x },        // FS 5.0.0 exFAT\n\t{ \"FS\", \"\\x76\\xF8\\x74\\x02\\xC9\\x38\\x7C\\x0F\", _fs_patches_510 },        // FS 5.1.0\n\t{ \"FS\", \"\\x10\\xB2\\xD8\\x16\\x05\\x48\\x85\\x99\", _fs_patches_510 },        // FS 5.1.0 exFAT\n\t{ \"FS\", \"\\x1B\\x82\\xCB\\x22\\x18\\x67\\xCB\\x52\", _fs_patches_600 },        // FS 6.0.0-4.0\n\t{ \"FS\", \"\\x96\\x6A\\xDD\\x3D\\x20\\xB6\\x27\\x13\", _fs_patches_600_exfat },  // FS 6.0.0-4.0 exFAT\n\t{ \"FS\", \"\\x3A\\x57\\x4D\\x43\\x61\\x86\\x19\\x1D\", _fs_patches_600 },        // FS 6.0.0-5.0\n\t{ \"FS\", \"\\x33\\x05\\x53\\xF6\\xB5\\xFB\\x55\\xC4\", _fs_patches_600_exfat },  // FS 6.0.0-5.0 exFAT\n\t{ \"FS\", \"\\x2A\\xDB\\xE9\\x7E\\x9B\\x5F\\x41\\x77\", _fs_patches_700 },        // FS 7.0.0\n\t{ \"FS\", \"\\x2C\\xCE\\x65\\x9C\\xEC\\x53\\x6A\\x8E\", _fs_patches_700_exfat },  // FS 7.0.0 exFAT\n\t{ \"FS\", \"\\xB2\\xF5\\x17\\x6B\\x35\\x48\\x36\\x4D\", _fs_patches_800 },        // FS 8.0.0\n\t{ \"FS\", \"\\xDB\\xD9\\x41\\xC0\\xC5\\x3C\\x52\\xCC\", _fs_patches_800_exfat },  // FS 8.0.0 exFAT\n\t{ \"FS\", \"\\x6B\\x09\\xB6\\x7B\\x29\\xC0\\x20\\x24\", _fs_patches_800 },        // FS 8.1.0\n\t{ \"FS\", \"\\xB4\\xCA\\xE1\\xF2\\x49\\x65\\xD9\\x2E\", _fs_patches_800_exfat },  // FS 8.1.0 exFAT\n\t{ \"FS\", \"\\x46\\x87\\x40\\x76\\x1E\\x19\\x3E\\xB7\", _fs_patches_900 },        // FS 9.0.0\n\t{ \"FS\", \"\\x7C\\x95\\x13\\x76\\xE5\\xC1\\x2D\\xF8\", _fs_patches_900 },        // FS 9.0.0 exFAT\n\t{ \"FS\", \"\\xB5\\xE7\\xA6\\x4C\\x6F\\x5C\\x4F\\xE3\", _fs_patches_910 },        // FS 9.1.0\n\t{ \"FS\", \"\\xF1\\x96\\xD1\\x44\\xD0\\x44\\x45\\xB6\", _fs_patches_910 },        // FS 9.1.0 exFAT\n\t{ \"FS\", \"\\x3E\\xEB\\xD9\\xB7\\xBC\\xD1\\xB5\\xE0\", _fs_patches_1000 },       // FS 10.0.0\n\t{ \"FS\", \"\\x81\\x7E\\xA2\\xB0\\xB7\\x02\\xC1\\xF3\", _fs_patches_1000 },       // FS 10.0.0 exFAT\n\t{ \"FS\", \"\\xA9\\x52\\xB6\\x57\\xAD\\xF9\\xC2\\xBA\", _fs_patches_1020 },       // FS 10.2.0\n\t{ \"FS\", \"\\x16\\x0D\\x3E\\x10\\x4E\\xAD\\x61\\x76\", _fs_patches_1020 },       // FS 10.2.0 exFAT\n\t{ \"FS\", \"\\xE3\\x99\\x15\\x6E\\x84\\x4E\\xB0\\xAA\", _fs_patches_1100 },       // FS 11.0.0\n\t{ \"FS\", \"\\x0B\\xA1\\x5B\\xB3\\x04\\xB5\\x05\\x63\", _fs_patches_1100 },       // FS 11.0.0 exFAT\n\t{ \"FS\", \"\\xDC\\x2A\\x08\\x49\\x96\\xBB\\x3C\\x01\", _fs_patches_1200 },       // FS 12.0.0\n\t{ \"FS\", \"\\xD5\\xA5\\xBF\\x36\\x64\\x0C\\x49\\xEA\", _fs_patches_1200 },       // FS 12.0.0 exFAT\n\t{ \"FS\", \"\\xC8\\x67\\x62\\xBE\\x19\\xA5\\x1F\\xA0\", _fs_patches_1203 },       // FS 12.0.3\n\t{ \"FS\", \"\\xE1\\xE8\\xD3\\xD6\\xA2\\xFE\\x0B\\x10\", _fs_patches_1203 },       // FS 12.0.3 exFAT\n\t{ \"FS\", \"\\x7D\\x20\\x05\\x47\\x17\\x8A\\x83\\x6A\", _fs_patches_1300 },       // FS 13.0.0\n\t{ \"FS\", \"\\x51\\xEB\\xFA\\x9C\\xCF\\x66\\xC0\\x9E\", _fs_patches_1300 },       // FS 13.0.0 exFAT\n\t{ \"FS\", \"\\x91\\xBA\\x65\\xA2\\x1C\\x1D\\x50\\xAE\", _fs_patches_1310 },       // FS 13.1.0\n\t{ \"FS\", \"\\x76\\x38\\x27\\xEE\\x9C\\x20\\x7E\\x5B\", _fs_patches_1310 },       // FS 13.1.0 exFAT\n\t{ \"FS\", \"\\x88\\x7A\\xC1\\x50\\x80\\x6C\\x75\\xCC\", _fs_patches_1400 },       // FS 14.0.0\n\t{ \"FS\", \"\\xD4\\x88\\xD1\\xF2\\x92\\x17\\x35\\x5C\", _fs_patches_1400_exfat }, // FS 14.0.0 exFAT\n\t{ \"FS\", \"\\xD0\\xD4\\x49\\x18\\x14\\xB5\\x62\\xAF\", _fs_patches_1500 },       // FS 15.0.0\n\t{ \"FS\", \"\\x34\\xC0\\xD9\\xED\\x6A\\xD1\\x87\\x3D\", _fs_patches_1500_exfat }, // FS 15.0.0 exFAT\n\t{ \"FS\", \"\\x56\\xE8\\x56\\x56\\x6C\\x38\\xD8\\xBE\", _fs_patches_1600 },       // FS 16.0.0\n\t{ \"FS\", \"\\xCF\\xAB\\x45\\x0C\\x2C\\x53\\x9D\\xA9\", _fs_patches_1600_exfat }, // FS 16.0.0 exFAT\n\t{ \"FS\", \"\\x39\\xEE\\x1F\\x1E\\x0E\\xA7\\x32\\x5D\", _fs_patches_1603 },       // FS 16.0.3\n\t{ \"FS\", \"\\x62\\xC6\\x5E\\xFD\\x9A\\xBF\\x7C\\x43\", _fs_patches_1603_exfat }, // FS 16.0.3 exFAT\n\t{ \"FS\", \"\\x27\\x07\\x3B\\xF0\\xA1\\xB8\\xCE\\x61\", _fs_patches_1700 },       // FS 17.0.0\n\t{ \"FS\", \"\\xEE\\x0F\\x4B\\xAC\\x6D\\x1F\\xFC\\x4B\", _fs_patches_1700_exfat }, // FS 17.0.0 exFAT\n\t{ \"FS\", \"\\x79\\x5F\\x5A\\x5E\\xB0\\xC6\\x77\\x9E\", _fs_patches_1800 },       // FS 18.0.0\n\t{ \"FS\", \"\\x1E\\x2C\\x64\\xB1\\xCC\\xE2\\x78\\x24\", _fs_patches_1800_exfat }, // FS 18.0.0 exFAT\n\t{ \"FS\", \"\\xA3\\x39\\xF0\\x1C\\x95\\xBF\\xA7\\x68\", _fs_patches_1800 },       // FS 18.1.0\n\t{ \"FS\", \"\\x20\\x4C\\xBA\\x86\\xDE\\x08\\x44\\x6A\", _fs_patches_1800_exfat }, // FS 18.1.0 exFAT\n\t{ \"FS\", \"\\xD9\\x4C\\x68\\x15\\xF8\\xF5\\x0A\\x20\", _fs_patches_1900 },       // FS 19.0.0\n\t{ \"FS\", \"\\xED\\xA8\\x78\\x68\\xA4\\x49\\x07\\x50\", _fs_patches_1900_exfat }, // FS 19.0.0 exFAT\n\t{ \"FS\", \"\\x63\\x54\\x96\\x9E\\x60\\xA7\\x97\\x7B\", _fs_patches_2000 },       // FS 20.0.0\n\t{ \"FS\", \"\\x47\\x41\\x07\\x10\\x65\\x4F\\xA4\\x3F\", _fs_patches_2000_exfat }, // FS 20.0.0 exFAT\n\t{ \"FS\", \"\\xED\\x34\\xB4\\x50\\x58\\x4A\\x5B\\x43\", _fs_patches_2000 },       // FS 20.1.0\n\t{ \"FS\", \"\\xA5\\x1A\\xA4\\x92\\x6C\\x41\\x87\\x59\", _fs_patches_2000_exfat }, // FS 20.1.0 exFAT\n\t{ \"FS\", \"\\xEE\\x4B\\x30\\x12\\xA6\\x84\\x02\\x25\", _fs_patches_2100 },       // FS 21.0.0\n\t{ \"FS\", \"\\x6E\\x2B\\xD9\\xBA\\xA3\\xB9\\x10\\xF1\", _fs_patches_2100_exfat }, // FS 21.0.0 exFAT\n\t{ \"FS\", \"\\xAF\\x1D\\xBD\\xC7\\x82\\x98\\x3C\\xBD\", _fs_patches_2100 },       // FS 21.2.0\n\t{ \"FS\", \"\\x56\\x25\\x17\\xA1\\x92\\xC3\\xC8\\xF0\", _fs_patches_2100_exfat }, // FS 21.2.0 exFAT\n\t{ \"FS\", \"\\xB7\\xA2\\x97\\x39\\xB7\\xED\\xDE\\xFC\", _fs_patches_2200 },       // FS 22.0.0\n\t{ \"FS\", \"\\xFB\\x0B\\x68\\xDB\\x24\\x03\\xD1\\x19\", _fs_patches_2200_exfat }, // FS 22.0.0 exFAT\n};\n"
  },
  {
    "path": "bootloader/hos/pkg3.c",
    "content": "/*\n * Atmosphère Package 3 parser.\n *\n * Copyright (c) 2019-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <bdk.h>\n\n#include \"pkg3.h\"\n#include \"hos.h\"\n#include \"../config.h\"\n#include <libs/fatfs/ff.h>\n#include \"../storage/emummc.h\"\n\n//#define DPRINTF(...) gfx_printf(__VA_ARGS__)\n#define DPRINTF(...)\n\nextern bool is_ipl_updated(void *buf, u32 size, const char *path, bool force);\n\n#define PKG3_KIP_SKIP_MAX 16\n\n// PKG3 Magic and Meta header offset.\n#define PKG3_MAGIC 0x30535346 // FSS0.\n#define PKG3_META_OFFSET 0x4\n#define PKG3_VERSION_0_17_0 0x110000\n\n// PKG3 Content Types.\n#define CNT_TYPE_FSP 0\n#define CNT_TYPE_EXO 1  // Exosphere (Secure Monitor).\n#define CNT_TYPE_WBT 2  // Warmboot (SC7Exit fw).\n#define CNT_TYPE_RBT 3  // Rebootstub (Warmboot based reboot fw).\n#define CNT_TYPE_SP1 4  // Sept Primary (TSEC and Sept Secondary loader).\n#define CNT_TYPE_SP2 5  // Sept Secondary (Acts as pkg11 and derives keys).\n#define CNT_TYPE_KIP 6  // KIP1 (Used for replacement or addition).\n#define CNT_TYPE_BMP 7\n#define CNT_TYPE_EMC 8\n#define CNT_TYPE_KLD 9  // Kernel Loader.\n#define CNT_TYPE_KRN 10 // Kernel.\n#define CNT_TYPE_EXF 11 // Exosphere Mariko fatal payload.\n#define CNT_TYPE_TKG 12 // Tsec Keygen.\n\n// PKG3 Content Flags.\n#define CNT_FLAG0_EXPERIMENTAL BIT(0)\n\n// PKG3 Meta Header.\ntypedef struct _pkg3_meta_t\n{\n\tu32 magic;\n\tu32 size;\n\tu32 crt0_off;\n\tu32 cnt_off;\n\tu32 cnt_count;\n\tu32 hos_ver;\n\tu32 version;\n\tu32 git_rev;\n} pkg3_meta_t;\n\n// PKG3 Content Header.\ntypedef struct _pkg3_content_t\n{\n\tu32 offset;\n\tu32 size;\n\tu8 type;\n\tu8 flags0;\n\tu8 flags1;\n\tu8 flags2;\n\tu32 rsvd1;\n\tchar name[0x10];\n} pkg3_content_t;\n\nstatic void _pkg3_update_r2p()\n{\n\tu32 size = 0;\n\tu8 *r2p_payload = sd_file_read(\"atmosphere/reboot_payload.bin\", &size);\n\n\tis_ipl_updated(r2p_payload, size, \"atmosphere/reboot_payload.bin\", h_cfg.updater2p ? true : false);\n\n\tfree(r2p_payload);\n}\n\nstatic int _pkg3_kip1_skip(char ***pkg3_kip1_skip, u32 *pkg3_kip1_skip_num, char *value)\n{\n\tint len = strlen(value);\n\tif (!len || (*pkg3_kip1_skip_num) >= PKG3_KIP_SKIP_MAX)\n\t\treturn 1;\n\n\t// Allocate pointer list memory.\n\tif (!(*pkg3_kip1_skip))\n\t\t(*pkg3_kip1_skip) = zalloc(PKG3_KIP_SKIP_MAX * sizeof(char *));\n\n\t// Set first kip name.\n\t(*pkg3_kip1_skip)[(*pkg3_kip1_skip_num)++] = value;\n\n\t// Check if more names are set separated by comma.\n\tfor (char *c = value; *c != 0; c++)\n\t{\n\t\tif (*c == ',')\n\t\t{\n\t\t\t*c = 0; // Null termination.\n\n\t\t\t// Set next kip name to the list.\n\t\t\t(*pkg3_kip1_skip)[(*pkg3_kip1_skip_num)++] = c + 1;\n\n\t\t\tif ((*pkg3_kip1_skip_num) >= PKG3_KIP_SKIP_MAX)\n\t\t\t\treturn 1;\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nint parse_pkg3(launch_ctxt_t *ctxt, const char *path)\n{\n\tFIL fp;\n\n\tchar **pkg3_kip1_skip = NULL;\n\tu32    pkg3_kip1_skip_num = 0;\n\n\tbool stock = false;\n\tbool experimental = false;\n\n\t// Skip if stock and Exosphere and warmboot are not needed.\n\tbool pkg1_old = ctxt->pkg1_id->mkey <= HOS_MKEY_VER_620; // Should check if t210b01?\n\tbool emummc_disabled = !emu_cfg.enabled || h_cfg.emummc_force_disable;\n\n\tLIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)\n\t{\n\t\tif (!strcmp(\"stock\", kv->key))\n\t\t\tif (kv->val[0] == '1')\n\t\t\t\tstock = true;\n\n\t\tif (!strcmp(\"pkg3ex\", kv->key))\n\t\t\tif (kv->val[0] == '1')\n\t\t\t\texperimental = true;\n\n\t\tif (!strcmp(\"pkg3kip1skip\", kv->key))\n\t\t\t_pkg3_kip1_skip(&pkg3_kip1_skip, &pkg3_kip1_skip_num, kv->val);\n\t}\n\n#ifdef HOS_MARIKO_STOCK_SECMON\n\tif (stock && emummc_disabled && (pkg1_old || h_cfg.t210b01))\n\t\treturn 0;\n#else\n\tif (stock && emummc_disabled && pkg1_old)\n\t\treturn 0;\n#endif\n\n\t// Try to open PKG3.\n\tif (f_open(&fp, path, FA_READ) != FR_OK)\n\t\treturn 1;\n\n\tvoid *pkg3 = malloc(f_size(&fp));\n\n\t// Read first 1024 bytes of the PKG3 file.\n\tf_read(&fp, pkg3, 1024, NULL);\n\n\t// Get PKG3 Meta header offset.\n\tu32 pkg3_meta_addr = *(u32 *)(pkg3 + PKG3_META_OFFSET);\n\tpkg3_meta_t *pkg3_meta = (pkg3_meta_t *)(pkg3 + pkg3_meta_addr);\n\n\t// Check if valid PKG3 and parse it.\n\tif (pkg3_meta->magic == PKG3_MAGIC)\n\t{\n\t\tgfx_printf(\"Atmosphere %d.%d.%d-%08x via PKG3\\n\"\n\t\t\t\"Max HOS: %d.%d.%d\\n\"\n\t\t\t\"Unpacking..  \",\n\t\t\tpkg3_meta->version >> 24, (pkg3_meta->version >> 16) & 0xFF, (pkg3_meta->version >> 8) & 0xFF, pkg3_meta->git_rev,\n\t\t\tpkg3_meta->hos_ver >> 24, (pkg3_meta->hos_ver >> 16) & 0xFF, (pkg3_meta->hos_ver >> 8) & 0xFF);\n\n\t\tctxt->patch_krn_proc_id = true;\n\t\tctxt->pkg3_hosver = pkg3_meta->hos_ver;\n\n\t\t// Parse PKG3 contents.\n\t\tpkg3_content_t *curr_pkg3_cnt = (pkg3_content_t *)(pkg3 + pkg3_meta->cnt_off);\n\t\tvoid *content;\n\t\tfor (u32 i = 0; i < pkg3_meta->cnt_count; i++)\n\t\t{\n\t\t\tcontent = (void *)(pkg3 + curr_pkg3_cnt[i].offset);\n\n\t\t\t// Check if offset is inside limits.\n\t\t\tif ((curr_pkg3_cnt[i].offset + curr_pkg3_cnt[i].size) > pkg3_meta->size)\n\t\t\t\tcontinue;\n\n\t\t\t// If content is experimental and experimental config is not enabled, skip it.\n\t\t\tif ((curr_pkg3_cnt[i].flags0 & CNT_FLAG0_EXPERIMENTAL) && !experimental)\n\t\t\t\tcontinue;\n\n\t\t\t// Prepare content.\n\t\t\tswitch (curr_pkg3_cnt[i].type)\n\t\t\t{\n\t\t\tcase CNT_TYPE_KIP:\n\t\t\t\tif (stock)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tbool should_skip = false;\n\t\t\t\tfor (u32 k = 0; k < pkg3_kip1_skip_num; k++)\n\t\t\t\t{\n\t\t\t\t\tif (!strcmp(curr_pkg3_cnt[i].name, pkg3_kip1_skip[k]))\n\t\t\t\t\t{\n\t\t\t\t\t\tgfx_printf(\"Skipped %s.kip1 from PKG3\\n\", curr_pkg3_cnt[i].name);\n\t\t\t\t\t\tshould_skip = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (should_skip)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tmerge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));\n\t\t\t\tmkip1->kip1 = content;\n\t\t\t\tlist_append(&ctxt->kip1_list, &mkip1->link);\n\t\t\t\tDPRINTF(\"Loaded %s.kip1 from PKG3 (size %08X)\\n\", curr_pkg3_cnt[i].name, curr_pkg3_cnt[i].size);\n\t\t\t\tbreak;\n\n\t\t\tcase CNT_TYPE_KRN:\n\t\t\t\tif (stock)\n\t\t\t\t\tcontinue;\n\t\t\t\tctxt->kernel_size = curr_pkg3_cnt[i].size;\n\t\t\t\tctxt->kernel = content;\n\t\t\t\tbreak;\n\n\t\t\tcase CNT_TYPE_EXO:\n\t\t\t\tctxt->secmon_size = curr_pkg3_cnt[i].size;\n\t\t\t\tctxt->secmon = content;\n\t\t\t\tbreak;\n\n\t\t\tcase CNT_TYPE_EXF:\n\t\t\t\tctxt->exofatal_size = curr_pkg3_cnt[i].size;\n\t\t\t\tctxt->exofatal = content;\n\t\t\t\tbreak;\n\n\t\t\tcase CNT_TYPE_WBT:\n\t\t\t\tif (h_cfg.t210b01)\n\t\t\t\t\tcontinue;\n\t\t\t\tctxt->warmboot_size = curr_pkg3_cnt[i].size;\n\t\t\t\tctxt->warmboot = content;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Load content to launch context.\n\t\t\tf_lseek(&fp, curr_pkg3_cnt[i].offset);\n\t\t\tf_read(&fp, content, curr_pkg3_cnt[i].size, NULL);\n\t\t}\n\n\t\tgfx_printf(\"Done!\\n\");\n\t\tf_close(&fp);\n\n\t\tctxt->pkg3 = pkg3;\n\n\t\t// Update r2p if needed.\n\t\t_pkg3_update_r2p();\n\n\t\tfree(pkg3_kip1_skip);\n\n\t\treturn 0;\n\t}\n\n\t// Failed. Close and free all.\n\tf_close(&fp);\n\n\tfree(pkg3_kip1_skip);\n\tfree(pkg3);\n\n\treturn 1;\n}\n"
  },
  {
    "path": "bootloader/hos/pkg3.h",
    "content": "/*\n * Copyright (c) 2019-2021 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _PKG3_H_\n#define _PKG3_H_\n\n#include \"hos.h\"\n\nint parse_pkg3(launch_ctxt_t *ctxt, const char *path);\n\n#endif\n"
  },
  {
    "path": "bootloader/hos/secmon_exo.c",
    "content": "/*\n * Copyright (c) 2018-2026 CTCaer\n * Copyright (c) 2019 Atmosphère-NX\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n#include <stdlib.h>\n\n#include <bdk.h>\n\n#include \"hos.h\"\n#include \"../config.h\"\n#include <libs/fatfs/ff.h>\n#include \"../storage/emummc.h\"\n\nenum emuMMC_Type\n{\n\temuMMC_None = 0,\n\temuMMC_Partition,\n\temuMMC_File,\n\temuMMC_MAX\n};\n\n/* \"EFS0\" */\n#define EMUMMC_MAGIC 0x30534645\n#define EMUMMC_FILE_PATH_MAX 0x80\n\ntypedef struct\n{\n\tu32 magic;\n\tu32 type;\n\tu32 id;\n\tu32 fs_ver;\n} emummc_base_config_t;\n\ntypedef struct\n{\n\tu64 start_sector;\n} emummc_partition_config_t;\n\ntypedef struct\n{\n\tchar path[EMUMMC_FILE_PATH_MAX];\n} emummc_file_config_t;\n\ntypedef struct\n{\n\temummc_base_config_t base_cfg;\n\tunion\n\t{\n\t\temummc_partition_config_t partition_cfg;\n\t\temummc_file_config_t file_cfg;\n\t};\n\tchar nintendo_path[EMUMMC_FILE_PATH_MAX];\n} exo_emummc_config_t;\n\ntypedef struct _exo_cfg_t\n{\n\tu32 magic;\n\tu32 fwno;\n\tu32 flags[2];\n\tu16 display_id;\n\tu8  uart_port;\n\tu8  uart_invert;\n\tu32 uart_baudrate;\n\tu32 rsvd1[2];\n\texo_emummc_config_t emummc_cfg;\n} exo_cfg_t;\n\ntypedef struct _atm_meta_t\n{\n\tu32 magic;\n\tu32 fwno;\n} wb_cfg_t;\n\n// Atmosphère reboot-to-fatal-error.\ntypedef struct _atm_fatal_error_ctx\n{\n\tu32 magic;\n\tu32 error_desc;\n\tu64 title_id;\n\tunion\n\t{\n\t\tu64 gprs[32];\n\t\tstruct\n\t\t{\n\t\t\tu64 _gprs[29];\n\t\t\tu64 fp;\n\t\t\tu64 lr;\n\t\t\tu64 sp;\n\t\t};\n\t};\n\tu64 pc;\n\tu64 module_base;\n\tu32 pstate;\n\tu32 afsr0;\n\tu32 afsr1;\n\tu32 esr;\n\tu64 far;\n\tu64 report_identifier; // Normally just system tick.\n\tu64 stack_trace_size;\n\tu64 stack_dump_size;\n\tu64 stack_trace[0x20];\n\tu8  stack_dump[0x100];\n\tu8  tls[0x100];\n} atm_fatal_error_ctx;\n\n#define ATM_FATAL_ERR_CTX_ADDR 0x4003E000\n#define  ATM_FATAL_MAGIC       0x30454641 // AFE0\n\n#define ATM_EXO_FATAL_ADDR     0x80020000\n#define  ATM_EXO_FATAL_SIZE    SZ_128K\n\n#define ATM_WB_HEADER_OFF      0x244\n#define  ATM_WB_MAGIC          0x30544257 // WBT0\n\n// Exosphère mailbox defines.\n#define EXO_CFG_ADDR             0x8000F000\n#define  EXO_MAGIC_VAL           0x304F5845\n#define  EXO_FLAG_DBG_PRIV        BIT(1)\n#define  EXO_FLAG_DBG_USER        BIT(2)\n#define  EXO_FLAG_NO_USER_EXC     BIT(3)\n#define  EXO_FLAG_USER_PMU        BIT(4)\n#define  EXO_FLAG_CAL0_BLANKING   BIT(5)\n#define  EXO_FLAG_CAL0_WRITES_SYS BIT(6)\n#define  EXO_FLAG_ENABLE_USB3     BIT(7)\n#define  EXO_FLAG_BC_MEM_MODE     BIT(8)\n\n#define EXO_FW_VER(mj, mn) (((mj) << 24) | ((mn) << 16))\n\nvoid config_exosphere(launch_ctxt_t *ctxt, u32 warmboot_base)\n{\n\tu32 exo_fw_no;\n\tu32 exo_flags = 0;\n\tbool usb3_force = false;\n\tbool user_debug = false;\n\tbool bc_mem_mode = false;\n\tbool cal0_blanking = false;\n\tbool cal0_allow_writes_sys = false;\n\n\tmemset((exo_cfg_t *)EXO_CFG_ADDR, 0, sizeof(exo_cfg_t));\n\n\tvolatile exo_cfg_t *exo_cfg = (exo_cfg_t *)EXO_CFG_ADDR;\n\n\t//! TODO: Replace current HOS version decoding (as it's bound to break in the future).\n\n\t// Old exosphere target versioning.\n\tif (ctxt->pkg1_id->mkey >= HOS_MKEY_VER_1210)                     // 12.1.0+\n\t\texo_fw_no = ctxt->pkg1_id->mkey + 4;\n\telse if (ctxt->pkg1_id->fuses <= 3 || ctxt->pkg1_id->fuses >= 10) // 1.0.0 - 3.0.0, 8.1.0 - 12.0.3.\n\t\texo_fw_no = ctxt->pkg1_id->fuses;\n\telse\n\t\texo_fw_no = ctxt->pkg1_id->fuses - 1;                         // 3.0.1 - 7.0.1, 8.0.x.\n\n\t// Handle versions that change API and do not burn new fuse.\n\tif (!memcmp(ctxt->pkg1_id->id, \"20190314\", 8) || //  8.0.x, same fuses with  7.0.1.\n\t\t!memcmp(ctxt->pkg1_id->id, \"20210129\", 8)    // 12.0.0, same fuses with 11.0.0.\n\t   )\n\t\texo_fw_no++;\n\n\t// Set 12.1.0 specific revision.\n\tif (ctxt->pkg1_id->mkey == HOS_MKEY_VER_1210)\n\t\tctxt->exo_ctx.hos_revision = 1;\n\n\t// Feed old exosphere target versioning to new.\n\tswitch (exo_fw_no)\n\t{\n\tcase 1 ... 4:\n\tcase 6:\n\t\texo_fw_no = EXO_FW_VER(exo_fw_no, 0);\n\t\tbreak;\n\tcase 5:\n\t\texo_fw_no = EXO_FW_VER(5, ctxt->exo_ctx.hos_revision);\n\t\tbreak;\n\tcase 7:\n\t\texo_fw_no = EXO_FW_VER(6, 2);\n\t\tbreak;\n\tcase 8 ... 9:\n\t\texo_fw_no = EXO_FW_VER(exo_fw_no - 1, 0);\n\t\tbreak;\n\tcase 10:\n\t\texo_fw_no = EXO_FW_VER(8, 1);\n\t\tbreak;\n\tcase 11:\n\t\texo_fw_no = EXO_FW_VER(9, 0);\n\t\tbreak;\n\tcase 12:\n\t\texo_fw_no = EXO_FW_VER(9, 1);\n\t\tbreak;\n\tcase 13 ... 25: //!TODO: Update on API changes. 25: 22.0.0.\n\t\texo_fw_no = EXO_FW_VER(exo_fw_no - 3, ctxt->exo_ctx.hos_revision);\n\t\tbreak;\n\t}\n\n\t// Parse exosphere.ini.\n\tif (!ctxt->stock)\n\t{\n\t\tLIST_INIT(ini_exo_sections);\n\t\tif (!ini_parse(&ini_exo_sections, \"exosphere.ini\", false))\n\t\t{\n\t\t\tLIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_exo_sections, link)\n\t\t\t{\n\t\t\t\t// Only parse exosphere section.\n\t\t\t\tif (!(ini_sec->type == INI_CHOICE) || strcmp(ini_sec->name, \"exosphere\"))\n\t\t\t\t\tcontinue;\n\n\t\t\t\tLIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)\n\t\t\t\t{\n\t\t\t\t\tif (!strcmp(\"debugmode_user\", kv->key))\n\t\t\t\t\t\tuser_debug = atoi(kv->val);\n\t\t\t\t\telse if (!strcmp(\"log_port\", kv->key))\n\t\t\t\t\t\texo_cfg->uart_port = atoi(kv->val);\n\t\t\t\t\telse if (!strcmp(\"log_inverted\", kv->key))\n\t\t\t\t\t\texo_cfg->uart_invert = atoi(kv->val);\n\t\t\t\t\telse if (!strcmp(\"log_baud_rate\", kv->key))\n\t\t\t\t\t\texo_cfg->uart_baudrate = atoi(kv->val);\n\t\t\t\t\telse if (!strcmp(\"enable_mem_mode\", kv->key))\n\t\t\t\t\t\tbc_mem_mode = atoi(kv->val);\n\t\t\t\t\telse if (emu_cfg.enabled && !h_cfg.emummc_force_disable)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!strcmp(\"blank_prodinfo_emummc\", kv->key))\n\t\t\t\t\t\t\tcal0_blanking = atoi(kv->val);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!strcmp(\"blank_prodinfo_sysmmc\", kv->key))\n\t\t\t\t\t\t\tcal0_blanking = atoi(kv->val);\n\t\t\t\t\t\telse if (!strcmp(\"allow_writing_to_cal_sysmmc\", kv->key))\n\t\t\t\t\t\t\tcal0_allow_writes_sys = atoi(kv->val);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Parse usb mtim settings. Avoid parsing if it's overridden.\n\t\tif (!ctxt->exo_ctx.usb3_force)\n\t\t{\n\t\t\tLIST_INIT(ini_sys_sections);\n\t\t\tif (!ini_parse(&ini_sys_sections, \"atmosphere/config/system_settings.ini\", false))\n\t\t\t{\n\t\t\t\tLIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sys_sections, link)\n\t\t\t\t{\n\t\t\t\t\t// Only parse usb section.\n\t\t\t\t\tif (!(ini_sec->type == INI_CHOICE) || strcmp(ini_sec->name, \"usb\"))\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tLIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!strcmp(\"usb30_force_enabled\", kv->key))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tusb3_force = !strcmp(\"u8!0x1\", kv->val);\n\t\t\t\t\t\t\tbreak; // Only parse usb30_force_enabled key.\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Private debug mode always on for CFW mode.\n\tif (!ctxt->stock)\n\t\texo_flags |= EXO_FLAG_DBG_PRIV;\n\n\t// Enable user debug.\n\tif (user_debug)\n\t\texo_flags |= EXO_FLAG_DBG_USER;\n\n\t// Disable proper failure handling.\n\tif (ctxt->exo_ctx.no_user_exceptions)\n\t\texo_flags |= EXO_FLAG_NO_USER_EXC;\n\n\t// Enable user access to PMU.\n\tif (ctxt->exo_ctx.user_pmu)\n\t\texo_flags |= EXO_FLAG_USER_PMU;\n\n\t// Enable Boot Config Memory Mode. Check if system_settings ini value is overridden. If not, check if enabled in ini.\n\tif ((ctxt->exo_ctx.force_mem_mode && *ctxt->exo_ctx.force_mem_mode)\n\t\t\t|| (!ctxt->exo_ctx.force_mem_mode && bc_mem_mode))\n\t\texo_flags |= EXO_FLAG_BC_MEM_MODE;\n\n\t// Enable USB 3.0. Check if system_settings ini value is overridden. If not, check if enabled in ini.\n\tif ((ctxt->exo_ctx.usb3_force && *ctxt->exo_ctx.usb3_force)\n\t\t\t|| (!ctxt->exo_ctx.usb3_force && usb3_force))\n\t\texo_flags |= EXO_FLAG_ENABLE_USB3;\n\n\t// Enable prodinfo blanking. Check if exo ini value is overridden. If not, check if enabled in exo ini.\n\tif ((ctxt->exo_ctx.cal0_blank && *ctxt->exo_ctx.cal0_blank)\n\t\t\t|| (!ctxt->exo_ctx.cal0_blank && cal0_blanking))\n\t\texo_flags |= EXO_FLAG_CAL0_BLANKING;\n\n\t// Allow prodinfo writes. Check if exo ini value is overridden. If not, check if enabled in exo ini.\n\tif ((ctxt->exo_ctx.cal0_allow_writes_sys && *ctxt->exo_ctx.cal0_allow_writes_sys)\n\t\t\t|| (!ctxt->exo_ctx.cal0_allow_writes_sys && cal0_allow_writes_sys))\n\t\texo_flags |= EXO_FLAG_CAL0_WRITES_SYS;\n\n\t// Set mailbox values.\n\texo_cfg->magic = EXO_MAGIC_VAL;\n\texo_cfg->fwno = exo_fw_no;\n\texo_cfg->flags[0] = exo_flags;\n\n\t// If warmboot is lp0fw, add in RSA modulus.\n\tvolatile wb_cfg_t *wb_cfg = (wb_cfg_t *)(warmboot_base + ATM_WB_HEADER_OFF);\n\n\tif (wb_cfg->magic == ATM_WB_MAGIC)\n\t{\n\t\twb_cfg->fwno = exo_fw_no;\n\n\t\t// Set warmboot binary rsa modulus.\n\t\tpkg1_warmboot_rsa_mod(warmboot_base);\n\t}\n\n\tif (emu_cfg.enabled && !h_cfg.emummc_force_disable)\n\t{\n\t\texo_cfg->emummc_cfg.base_cfg.magic = EMUMMC_MAGIC;\n\t\texo_cfg->emummc_cfg.base_cfg.type = emu_cfg.sector ? emuMMC_Partition : emuMMC_File;\n\t\texo_cfg->emummc_cfg.base_cfg.fs_ver = emu_cfg.fs_ver;\n\t\texo_cfg->emummc_cfg.base_cfg.id = emu_cfg.id;\n\n\t\tif (emu_cfg.sector)\n\t\t\texo_cfg->emummc_cfg.partition_cfg.start_sector = emu_cfg.sector;\n\t\telse\n\t\t\tstrcpy((char *)exo_cfg->emummc_cfg.file_cfg.path, emu_cfg.path);\n\n\t\tif (!ctxt->stock && emu_cfg.nintendo_path && emu_cfg.nintendo_path[0])\n\t\t\tstrcpy((char *)exo_cfg->emummc_cfg.nintendo_path, emu_cfg.nintendo_path);\n\t\telse\n\t\t\tstrcpy((char *)exo_cfg->emummc_cfg.nintendo_path, \"Nintendo\");\n\t}\n\n\t// Copy over exosphere fatal for Mariko.\n\tif (h_cfg.t210b01)\n\t{\n\t\tmemset((void *)ATM_EXO_FATAL_ADDR, 0, ATM_EXO_FATAL_SIZE);\n\t\tif (ctxt->exofatal)\n\t\t\tmemcpy((void *)ATM_EXO_FATAL_ADDR, ctxt->exofatal, ctxt->exofatal_size);\n\n\t\t// Set display id.\n\t\texo_cfg->display_id = display_get_decoded_panel_id();\n\t}\n\n#ifdef DEBUG_UART_PORT\n\t// Ovverride logging parameters if set in compile time.\n\tif (!ctxt->stock)\n\t{\n\t\texo_cfg->uart_port = DEBUG_UART_PORT;\n\t\texo_cfg->uart_invert = DEBUG_UART_INVERT;\n\t\texo_cfg->uart_baudrate = DEBUG_UART_BAUDRATE;\n\t}\n#endif\n}\n\nstatic const char *get_error_desc(u32 error_desc)\n{\n\tswitch (error_desc)\n\t{\n\tcase 0x100:\n\t\treturn \"IABRT\"; // Instruction Abort.\n\tcase 0x101:\n\t\treturn \"DABRT\"; // Data Abort.\n\tcase 0x102:\n\t\treturn \"IUA\";   // Instruction Unaligned Access.\n\tcase 0x103:\n\t\treturn \"DUA\";   // Data Unaligned Access.\n\tcase 0x104:\n\t\treturn \"UDF\";   // Undefined Instruction.\n\tcase 0x106:\n\t\treturn \"SYS\";   // System Error.\n\tcase 0x301:\n\t\treturn \"SVC\";   // Bad arguments or unimplemented SVC.\n\tcase 0xF00:\n\t\treturn \"KRNL\";  // Kernel panic.\n\tcase 0xFFD:\n\t\treturn \"SO\";    // Stack Overflow.\n\tcase 0xFFE:\n\t\treturn \"std::abort\";\n\tdefault:\n\t\treturn \"UNK\";\n\t}\n}\n\nvoid secmon_exo_check_panic()\n{\n\tvolatile atm_fatal_error_ctx *rpt = (atm_fatal_error_ctx *)ATM_FATAL_ERR_CTX_ADDR;\n\n\t// Mask magic to maintain compatibility with any AFE version, thanks to additive struct members.\n\tif ((rpt->magic & 0xF0FFFFFF) != ATM_FATAL_MAGIC)\n\t\treturn;\n\n\tgfx_clear_grey(0x1B);\n\tgfx_con_setpos(0, 0);\n\n\tWPRINTF(\"Atmosphere panic occurred!\\n\\n\");\n\tWPRINTFARGS(\"Title ID: %08X%08X\", (u32)((u64)rpt->title_id >> 32), (u32)rpt->title_id);\n\tWPRINTFARGS(\"Error:    %s (0x%x)\\n\", get_error_desc(rpt->error_desc), rpt->error_desc);\n\n\t// Save context to the SD card.\n\tchar filepath[0x40];\n\tf_mkdir(\"atmosphere/fatal_errors\");\n\tstrcpy(filepath, \"atmosphere/fatal_errors/report_\");\n\titoa((u32)((u64)rpt->report_identifier >> 32), filepath + strlen(filepath), 16);\n\titoa((u32)(rpt->report_identifier), filepath + strlen(filepath), 16);\n\tstrcat(filepath, \".bin\");\n\n\tif (!sd_save_to_file((void *)rpt, sizeof(atm_fatal_error_ctx), filepath))\n\t{\n\t\tgfx_con.fntsz = 8;\n\t\tWPRINTFARGS(\"Report saved to %s\\n\", filepath);\n\t\tgfx_con.fntsz = 16;\n\t}\n\n\t// Change magic to invalid, to prevent double-display of error/bootlooping.\n\trpt->magic = 0;\n\n\tgfx_printf(\"\\n\\nPress POWER to continue.\\n\");\n\tgfx_con_setpos(0, 0);\n\n\tdisplay_backlight_brightness(150, 1000);\n\tmsleep(1000);\n\n\twhile (!(btn_wait() & BTN_POWER))\n\t\t;\n}\n"
  },
  {
    "path": "bootloader/hos/secmon_exo.h",
    "content": "/*\n * Copyright (c) 2018-2021 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _SECMON_EXO_H_\n#define _SECMON_EXO_H_\n\n#include <bdk.h>\n\nvoid config_exosphere(launch_ctxt_t *ctxt, u32 warmboot_base);\nvoid secmon_exo_check_panic();\n\n#endif\n"
  },
  {
    "path": "bootloader/l4t/l4t.c",
    "content": "/*\n * L4T Loader for Tegra X1\n *\n * Copyright (c) 2020-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <bdk.h>\n\n#include \"../hos/hos.h\"\n#include \"../hos/pkg1.h\"\n#include \"l4t.h\"\n#include \"l4t_config.inl\"\n\n/*\n * API Revision info\n *\n * 0: Base.\n * 1: SDMMC1 LA programming for SDMMC1 UHS DDR200.\n * 2: Arachne Register Cell v1.\n * 3: Arachne Register Cell v2. PTSA Rework support.\n * 4: Arachne Register Cell v3. DRAM OPT and DDR200 changes.\n * 5: Arachne Register Cell v4. DRAM FREQ and DDR200 changes.\n * 6: Arachne Register Cell v5. Signal quality and performance changes. TZ param changes.\n * 7: Arachne Register Cell v6. Decouple of rd/wr latencies.\n */\n\n#define L4T_LOADER_API_REV 7\n#define L4T_FIRMWARE_REV   0x37524556 // REV7.\n\n#ifdef DEBUG_UART_PORT\n #include <soc/uart.h>\n #define UPRINTF(...) uart_printf(__VA_ARGS__)\n#else\n #define UPRINTF(...)\n#endif\n\n#if CARVEOUT_NVDEC_TSEC_ENABLE && CARVEOUT_SECFW_ENABLE\n#error \"NVDEC and SECFW carveouts can't be used together!\"\n#endif\n\n#if CARVEOUT_NVDEC_TSEC_ENABLE\n #define TZDRAM_SIZE_CFG  SZ_8M\n#else\n #define TZDRAM_SIZE_CFG  SZ_1M\n#endif\n\n// TZDRAM addresses and sizes.\n#define TZDRAM_SIZE       TZDRAM_SIZE_CFG                  // Secure Element.\n#define TZDRAM_BASE       (0xFFFFFFFF - TZDRAM_SIZE + 1)   // 0xFFF00000 or 0xFF800000.\n#define TZDRAM_COLD_ENTRY (TZDRAM_BASE)\n#define TZDRAM_WARM_ENTRY (TZDRAM_BASE + 0x200)\n#define TZ_PARAM_SIZE     SZ_4K\n#define TZ_PARAM_BASE     (0xFFFFFFFF - TZ_PARAM_SIZE + 1) // 0xFFFFF000.\n\n// Carveout sizes.\n#define CARVEOUT_NVDEC_SIZE  SZ_1M\n#define CARVEOUT_TSEC_SIZE   SZ_1M\n#define CARVEOUT_SECFW_SIZE  SZ_1M\n#define CARVEOUT_GPUFW_SIZE  SZ_256K\n#if CARVEOUT_NVDEC_TSEC_ENABLE\n #define CARVEOUT_GPUWPR_SIZE CARVEOUT_GPUWPR_SIZE_CFG\n#else\n #define CARVEOUT_GPUWPR_SIZE (SZ_512K + SZ_256K)\n#endif\n\n#define SC7ENTRY_HDR_SIZE 0x400\n\n// Always start 1MB below TZDRAM for Secure Firmware or NVDEC.\n#define GEN_CARVEOUT_TOP       (TZDRAM_BASE - SZ_1M)\n\n// NVDEC and SECFW bases.\n#define NVDFW_BASE             GEN_CARVEOUT_TOP // 0xFF700000.\n#define SECFW_BASE             GEN_CARVEOUT_TOP // 0xFFE00000.\n\n// Secure Elements addresses for T210.\n#define SC7ENTRY_HDR_BASE      (SECFW_BASE + 0)\n#define SC7ENTRY_BASE          (SECFW_BASE + SC7ENTRY_HDR_SIZE) // After header.\n#define SC7EXIT_BASE           (SECFW_BASE + SZ_64K)            //  64KB after SECFW_BASE.\n#define R2P_PAYLOAD_BASE       (SECFW_BASE + SZ_256K)           // 256KB after SECFW_BASE.\n#define MTCTABLE_BASE          (SECFW_BASE + SZ_512K)           // 512KB after SECFW_BASE.\n#define BPMPFW_BASE            (SECFW_BASE + SZ_512K + SZ_256K) // 768KB after SECFW_BASE.\n#define BPMPFW_ENTRYPOINT      (BPMPFW_BASE + 0x100)            // Used internally also.\n\n// Secure Elements addresses for T210B01.\n#define BPMPFW_B01_BASE       (SECFW_BASE)                         // !! DTS carveout-start must match !!\n#define BPMPFW_B01_ENTRYPOINT (BPMPFW_B01_BASE + 0x40)             // Used internally also.\n#define BPMPFW_B01_HEAP_BASE  (BPMPFW_B01_BASE + SZ_256K - SZ_1K)  // 255KB after BPMPFW_B01_BASE.\n#define BPMPFW_B01_EDTB_BASE  (BPMPFW_B01_BASE + SZ_1M - 0)        // Top BPMPFW carveout minus EMC DTB size.\n#define BPMPFW_B01_ADTB_BASE  (BPMPFW_B01_BASE + 0x26008)          // Attached BPMP-FW DTB address.\n#define SC7EXIT_B01_BASE      (BPMPFW_B01_HEAP_BASE - SZ_4K)       // 4KB before BPMP heap.\n\n// BPMP-FW defines. Offsets are 0xD8 below real main binary.\n#define BPMPFW_B01_DTB_ADDR   (BPMPFW_B01_BASE + 0x14)    // u32. DTB address if not attached.\n#define BPMPFW_B01_CC_INIT_OP (BPMPFW_B01_BASE + 0x17324) // u8.  Initial table training OP. 0: OP_SWITCH, 1: OP_TRAIN, 2: OP_TRAIN_SWITCH. Default: OP_TRAIN.\n#define BPMPFW_B01_LOGLEVEL   (BPMPFW_B01_BASE + 0x2547C) // u32. Log level. Default 3.\n#define BPMPFW_B01_LOGLEVEL   (BPMPFW_B01_BASE + 0x2547C) // u32. Log level. Default 3.\n#define BPMPFW_B01_CC_PT_TIME (BPMPFW_B01_BASE + 0x25644) // u32. Periodic training period (in ms). Default 100 ms.\n#define BPMPFW_B01_CC_DEBUG   (BPMPFW_B01_BASE + 0x257F8) // u32. EMC Clock Change debug mask. Default: 0x50000101.\n\n// BPMP-FW attached DTB defines. Can be generalized.\n#define BPMPFW_B01_DTB_EMC_ENTRIES           4\n#define BPMPFW_B01_DTB_SERIAL_PORT_VAL       (BPMPFW_B01_ADTB_BASE + 0x5B) // u8. DTB UART port offset. 0: Disabled.\n#define BPMPFW_B01_DTB_SET_SERIAL_PORT(port) (*(u8 *)BPMPFW_B01_DTB_SERIAL_PORT_VAL = port)\n#define BPMPFW_B01_DTB_EMC_TBL_OFF           (BPMPFW_B01_ADTB_BASE + 0xA0)\n#define BPMPFW_B01_DTB_EMC_TBL_SZ            0x1120\n#define BPMPFW_B01_DTB_EMC_NAME_VAL          0xA\n#define BPMPFW_B01_DTB_EMC_ENABLE_OFF        0x20\n#define BPMPFW_B01_DTB_EMC_VALUES_OFF        0x4C\n#define BPMPFW_B01_DTB_EMC_FREQ_VAL          0x8C\n#define BPMPFW_B01_DTB_EMC_OPT_VAL           0xEDC\n#define BPMPFW_B01_DTB_EMC_TBL_START(idx)             (BPMPFW_B01_DTB_EMC_TBL_OFF + BPMPFW_B01_DTB_EMC_TBL_SZ * (idx))\n#define BPMPFW_B01_DTB_EMC_TBL_SET_VAL(idx, off, val) (*(u32 *)(BPMPFW_B01_DTB_EMC_TBL_START(idx) + (off)) = (val))\n#define BPMPFW_B01_DTB_EMC_TBL_SET_FREQ(idx, freq)    (*(u32 *)(BPMPFW_B01_DTB_EMC_TBL_START(idx) + BPMPFW_B01_DTB_EMC_FREQ_VAL) = (freq))\n#define BPMPFW_B01_DTB_EMC_TBL_SET_OPTC(idx, opt)     (*(u32 *)(BPMPFW_B01_DTB_EMC_TBL_START(idx) + BPMPFW_B01_DTB_EMC_OPT_VAL) = (opt))\n#define BPMPFW_B01_DTB_EMC_TBL_SET_NAME(idx, name)    (strcpy((char *)(BPMPFW_B01_DTB_EMC_TBL_START(idx) + BPMPFW_B01_DTB_EMC_NAME_VAL), (name)))\n#define BPMPFW_B01_DTB_EMC_TBL_ENABLE(idx)            (*(char *)(BPMPFW_B01_DTB_EMC_TBL_START(idx) + BPMPFW_B01_DTB_EMC_ENABLE_OFF) = 'n')\n#define BPMPFW_B01_DTB_EMC_TBL_OFFSET(idx)            ((void *)(BPMPFW_B01_DTB_EMC_TBL_START(idx) + BPMPFW_B01_DTB_EMC_VALUES_OFF))\n\n// MTC table defines for T210B01.\n#define BPMPFW_B01_MTC_TABLE_BASE            0xA0000000\n#define BPMPFW_B01_MTC_FREQ_TABLE_SIZE       4300\n#define BPMPFW_B01_MTC_TABLE_SIZE            (BPMPFW_B01_MTC_FREQ_TABLE_SIZE * 3)\n#define BPMPFW_B01_MTC_TABLE(idx)                     (BPMPFW_B01_MTC_TABLE_BASE + BPMPFW_B01_MTC_TABLE_SIZE * (idx))\n#define BPMPFW_B01_MTC_TABLE_OFFSET(idx, fidx)        ((void *)(BPMPFW_B01_MTC_TABLE(idx) + BPMPFW_B01_MTC_FREQ_TABLE_SIZE * (fidx)))\n\n// BL31 Enable IRAM based config.\n#define BL31_IRAM_PARAMS           0x4D415249 // \"IRAM\".\n#define BL31_EXTRA_FEATURES_ENABLE 0x52545845 // \"EXTR\".\n\n// BL31 Flags.\n#define FLAGS_PMC_NON_SECURE          BIT(0)\n#define FLAGS_SC7_NO_BASE_RESTRICTION BIT(1)\n\n// BL31 config.\n#define PARAM_EP            1\n#define PARAM_BL31          3\n#define PARAM_EP_SECURE\t    0\n#define PARAM_EP_NON_SECURE\t1\n#define VERSION_1           1\n#define SPSR_EL2T           BIT(3)\n\n// BL33 config.\n#define BL33_LOAD_BASE        0xAA000000                 // DTB is loaded at 0xA8000000, so 32MB above.\n#define BL33_ENV_BASE         (BL33_LOAD_BASE - SZ_256K) // Before BL33_LOAD_BASE.\n#define BL33_ENV_MAGIC_OFFSET (BL33_ENV_BASE - 4)\n#define BL33_ENV_MAGIC        0x33334C42\n#define BL33_DTB_OFFSET       (BL33_LOAD_BASE + 0x10)    // After code end.\n#define BL33_DTB_BASE         (BL33_LOAD_BASE + *(u32 *)BL33_DTB_OFFSET)\n#define BL33_DTB_UART_STATUS  0x1C94\n#define BL33_DTB_UART_STS_OF  0x12C\n#define BL33_DTB_STDOUT_PATH  0x3F34\n#define BL33_DTB_STDERR_PATH  0x3F54\n#define BL33_DTB_SET_UART_STATUS(port) (strcpy((char *)(BL33_DTB_BASE + BL33_DTB_UART_STATUS + (port - 1) * BL33_DTB_UART_STS_OF), \"okay\"))\n#define BL33_DTB_SET_STDOUT_PATH(path) (strcpy((char *)(BL33_DTB_BASE + BL33_DTB_STDOUT_PATH), (path)))\n#define BL33_DTB_SET_STDERR_PATH(path) (strcpy((char *)(BL33_DTB_BASE + BL33_DTB_STDERR_PATH), (path)))\n\n// Misc.\n#define DTB_MAGIC             0xEDFE0DD0 // D00DFEED.\n#define FALCON_DMA_PAGE_SIZE  0x100\n#define SOC_ID_T210           0x210\n#define SOC_ID_T210B01        0x214\n#define SKU_NX                0x83\n#define HDCP22                2\n\ntypedef struct _tsec_init_t {\n\tu32 sku;\n\tu32 hdcp;\n\tu32 soc;\n} tsec_init_t;\n\ntypedef struct _param_header {\n\tu8  type;    // type of the structure.\n\tu8  version; // version of this structure.\n\tu16 size;    // size of this structure in bytes.\n\tu32 attr;    // attributes: unused bits SBZ.\n} param_header_t;\n\ntypedef struct _aapcs64_params {\n\tu64 x0;\n\tu64 x1;\n\tu64 x2;\n\tu64 x3;\n\tu64 x4;\n\tu64 x5;\n\tu64 x6;\n\tu64 x7;\n} aapcs64_params_t;\n\ntypedef struct _entry_point_info {\n\tparam_header_t hdr;\n\tu64 pc;\n\tu32 spsr;\n\tu32 align0; // Alignment to u64 for the above member.\n\taapcs64_params_t args;\n} entry_point_info_t;\n\ntypedef struct _image_info {\n\tparam_header_t hdr;\n\tu64 image_base; // physical address of base of image.\n\tu32 image_size; // bytes read from image file.\n\tu32 image_max_size;\n} image_info_t;\n\ntypedef struct _bl_v1_params {\n\tparam_header_t hdr;\n\tu64 bl31_image_info;\n\tu64 bl32_ep_info;\n\tu64 bl32_image_info;\n\tu64 bl33_ep_info;\n\tu64 bl33_image_info;\n} bl31_v1_params_t;\n\ntypedef struct _plat_params_from_bl2 {\n\t// TZDRAM.\n\tu64 tzdram_size;\n\tu64 tzdram_base;\n\n\ts32 uart_id;                  // UART port ID.\n\ts32 l2_ecc_parity_prot_dis;   // L2 ECC parity protection disable flag.\n\tu64 boot_profiler_shmem_base; // SHMEM base address for storing the boot logs.\n\n\t// SC7-Entry firmware.\n\tu64 sc7entry_fw_size;\n\tu64 sc7entry_fw_base;\n\n\ts32 enable_ccplex_lock_step;  // Enable dual execution.\n\n\t// Enable below features.\n\ts32 enable_extra_features;\n\n\t// MTC table.\n\tu64 emc_table_size;\n\tu64 emc_table_base;\n\n\t// Initial R2P payload.\n\tu64 r2p_payload_size;\n\tu64 r2p_payload_base;\n\n\tu64 flags;                    // Platform flags.\n} bl31_plat_params_from_bl2_t;\n\ntypedef struct _l4t_fw_t\n{\n\tu32   addr;\n\tchar *name;\n} l4t_fw_t;\n\ntypedef struct _l4t_ctxt_t\n{\n\tchar *path;\n\n\tchar *ram_oc_txt;\n\tint   ram_oc_freq;\n\tint   ram_oc_vdd2;\n\tint   ram_oc_vddq;\n\tint   ram_oc_opt;\n\n\tu32   serial_port;\n\tbool  sld_type;\n\n\tu32   sc7entry_size;\n\n\temc_table_t *mtc_table;\n\n\tbl31_v1_params_t            bl31_v1_params;\n\tbl31_plat_params_from_bl2_t bl31_plat_params;\n\tentry_point_info_t          bl33_ep_info;\n} l4t_ctxt_t;\n\n#define DRAM_VDD2_OC_MIN_VOLTAGE   1050\n#define DRAM_VDD2_OC_MAX_VOLTAGE   1175\n#define DRAM_VDD2Q_OC_MAX_VOLTAGE  1237\n#define DRAM_VDDQ_OC_MIN_VOLTAGE   550\n#define DRAM_VDDQ_OC_MAX_VOLTAGE   650\n#define DRAM_T210B01_TBL_MAX_FREQ 1600000\n\n#define NA 0 // Default to 0 for incorrect dram ids.\n\n//!TODO: Update on dram config changes.\nstatic const u8 mtc_table_idx_t210b01[] = {\n/*\t00  01  02  03  04  05  06  07  08  09  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34 */\n\tNA, NA, NA,  7, NA,  7,  7, NA,  0,  1,  2,  3,  0,  1,  2,  3, NA,  4,  5,  4,  8,  8,  8,  5,  4,  6,  6,  6,  5,  9,  9,  9, 10, 10, 10\n};\n\n#undef NA\n\nstatic const l4t_fw_t l4t_fw[] = {\n\t{ TZDRAM_BASE,               \"bl31.bin\"        },\n\t{ BL33_LOAD_BASE,            \"bl33.bin\"        },\n\t{ SC7ENTRY_BASE,             \"sc7entry.bin\"    },\n\t{ SC7EXIT_BASE,              \"sc7exit.bin\"     },\n\t{ BPMPFW_BASE,               \"bpmpfw.bin\"      },\n\t{ BPMPFW_B01_BASE,           \"bpmpfw_b01.bin\"  },\n\t{ BPMPFW_B01_MTC_TABLE_BASE, \"mtc_tbl_b01.bin\" },\n};\n\nenum {\n\tBL31_FW            = 0,\n\tBL33_FW            = 1,\n\tSC7ENTRY_FW        = 2,\n\tSC7EXIT_FW         = 3,\n\tBPMPFW_FW          = 4,\n\tBPMPFW_B01_FW      = 5,\n\tBPMPFW_B01_MTC_TBL = 6\n};\n\nstatic void _l4t_crit_error(const char *text, bool needs_update)\n{\n\tgfx_con.mute = false;\n\tgfx_printf(\"%kL4T Error: %s!%sFailed to launch L4T!\\n%k\",\n\t\tTXT_CLR_ERROR, text, needs_update ? \"\\nUpdate bootloader folder!\\n\\n\" : \"\\n\\n\", TXT_CLR_DEFAULT);\n}\n\nchar *sd_path;\nu32 sd_path_len;\nstatic int _l4t_sd_load(u32 idx)\n{\n\tFIL fp;\n\tvoid *load_address = (void *)l4t_fw[idx].addr;\n\n\tstrcpy(sd_path + sd_path_len, l4t_fw[idx].name);\n\n\tif (f_open(&fp, sd_path, FA_READ) != FR_OK)\n\t\treturn 0;\n\n\tu32 size = f_size(&fp);\n\tif (f_read(&fp, load_address, size, NULL) != FR_OK)\n\t\tsize = 0;\n\n\tf_close(&fp);\n\n\tu32 rev = *(u32 *)(load_address + size - sizeof(u32));\n\tif (idx >= SC7ENTRY_FW && rev != L4T_FIRMWARE_REV)\n\t\treturn 0;\n\n\treturn size;\n}\n\nstatic void _l4t_sdram_lp0_save_params(bool t210b01)\n{\n\tpmc_regs_t210_t *pmc = (pmc_regs_t210_t *)PMC_BASE;\n\n#define _REG_S(base, off) *(u32 *)((base) + (off))\n#define MC_S(off) _REG_S(MC_BASE, off)\n\n#define pack(src, src_bits, dst, dst_bits) { \\\n\t\tu32 mask = 0xFFFFFFFF >> (31 - ((1 ? src_bits) - (0 ? src_bits))); \\\n\t\tdst &= ~(mask << (0 ? dst_bits)); \\\n\t\tdst |= ((src >> (0 ? src_bits)) & mask) << (0 ? dst_bits); }\n\n#define s(param, src_bits, pmcreg, dst_bits) \\\n\tpack(MC_S(param), src_bits, pmc->pmc_ ## pmcreg, dst_bits)\n\n// 32 bits version of s macro.\n#define s32(param, pmcreg) pmc->pmc_ ## pmcreg = MC_S(param)\n\n\t// Only save changed carveout registers into PMC for SC7 Exit.\n\n\t// VPR.\n#if CARVEOUT_NVDEC_TSEC_ENABLE\n\ts32(MC_VIDEO_PROTECT_GPU_OVERRIDE_0, secure_scratch12);\n\ts(MC_VIDEO_PROTECT_GPU_OVERRIDE_1, 15:0, secure_scratch49, 15:0);\n#endif\n\ts(MC_VIDEO_PROTECT_BOM,     31:20, secure_scratch52, 26:15);\n\ts(MC_VIDEO_PROTECT_SIZE_MB, 11:0,  secure_scratch53, 11:0);\n\tif (!t210b01) {\n\t\ts(MC_VIDEO_PROTECT_REG_CTRL, 1:0, secure_scratch13, 31:30);\n\t} else {\n\t\ts(MC_VIDEO_PROTECT_REG_CTRL, 1:0, secure_scratch14, 31:30);\n\t}\n\n\t// TZDRAM.\n\ts(MC_SEC_CARVEOUT_BOM,     31:20, secure_scratch53, 23:12);\n\ts(MC_SEC_CARVEOUT_SIZE_MB, 11:0,  secure_scratch54, 11:0);\n\tif (!t210b01) {\n\t\ts(MC_SEC_CARVEOUT_REG_CTRL, 0:0, secure_scratch18, 30:30);\n\t} else {\n\t\ts(MC_SEC_CARVEOUT_REG_CTRL, 0:0, secure_scratch19, 29:29);\n\t}\n\n\t// NVDEC or SECFW.\n\ts(MC_SECURITY_CARVEOUT1_BOM,        31:17, secure_scratch50, 29:15);\n\ts(MC_SECURITY_CARVEOUT1_SIZE_128KB, 11:0,  secure_scratch57, 11:0);\n\ts32(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0,  secure_scratch59);\n\ts32(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1,  secure_scratch60);\n\ts32(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2,  secure_scratch61);\n\ts32(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3,  secure_scratch62);\n\tif (!t210b01)\n\t{\n\t\ts(MC_SECURITY_CARVEOUT1_CFG0,  2:0,  secure_scratch56, 27:25);\n\t\ts(MC_SECURITY_CARVEOUT1_CFG0,  6:3,  secure_scratch41, 28:25);\n\t\ts(MC_SECURITY_CARVEOUT1_CFG0, 13:7,  secure_scratch42, 31:25);\n\t\ts(MC_SECURITY_CARVEOUT1_CFG0, 17:14, secure_scratch43, 28:25);\n\t\ts(MC_SECURITY_CARVEOUT1_CFG0, 21:18, secure_scratch44, 28:25);\n\t\ts(MC_SECURITY_CARVEOUT1_CFG0, 25:22, secure_scratch56, 31:28);\n\t\ts(MC_SECURITY_CARVEOUT1_CFG0, 26:26, secure_scratch57, 24:24);\n\t}\n\telse\n\t{\n\t\ts(MC_SECURITY_CARVEOUT1_CFG0,  1:0,  secure_scratch56, 31:30);\n\t\ts(MC_SECURITY_CARVEOUT1_CFG0,  2:2,  secure_scratch57, 24:24);\n\t\ts(MC_SECURITY_CARVEOUT1_CFG0,  6:3,  secure_scratch42, 28:25);\n\t\ts(MC_SECURITY_CARVEOUT1_CFG0, 10:7,  secure_scratch43, 28:25);\n\t\ts(MC_SECURITY_CARVEOUT1_CFG0, 13:11, secure_scratch42, 31:29);\n\t\ts(MC_SECURITY_CARVEOUT1_CFG0, 17:14, secure_scratch44, 28:25);\n\t\ts(MC_SECURITY_CARVEOUT1_CFG0, 21:18, secure_scratch47, 25:22);\n\t\ts(MC_SECURITY_CARVEOUT1_CFG0, 26:22, secure_scratch57, 29:25);\n\t}\n\n\t// GPU FW.\n\ts(MC_SECURITY_CARVEOUT2_BOM,        31:17, secure_scratch51, 29:15);\n\ts(MC_SECURITY_CARVEOUT2_SIZE_128KB, 11:0,  secure_scratch56, 23:12);\n\tif (!t210b01)\n\t{\n\t\ts(MC_SECURITY_CARVEOUT2_CFG0,  2:0,  secure_scratch55, 27:25);\n\t\ts(MC_SECURITY_CARVEOUT2_CFG0,  6:3,  secure_scratch19, 31:28);\n\t\ts(MC_SECURITY_CARVEOUT2_CFG0, 10:7,  secure_scratch20, 31:28);\n\t\ts(MC_SECURITY_CARVEOUT2_CFG0, 13:11, secure_scratch41, 31:29);\n\t\ts(MC_SECURITY_CARVEOUT2_CFG0, 17:14, secure_scratch39, 30:27);\n\t\ts(MC_SECURITY_CARVEOUT2_CFG0, 21:18, secure_scratch40, 30:27);\n\t\ts(MC_SECURITY_CARVEOUT2_CFG0, 25:22, secure_scratch55, 31:28);\n\t\ts(MC_SECURITY_CARVEOUT2_CFG0, 26:26, secure_scratch56, 24:24);\n\t}\n\telse\n\t{\n\t\ts(MC_SECURITY_CARVEOUT2_CFG0,  1:0,  secure_scratch55, 31:30);\n\t\ts(MC_SECURITY_CARVEOUT2_CFG0,  2:2,  secure_scratch56, 24:24);\n\t\ts(MC_SECURITY_CARVEOUT2_CFG0,  6:3,  secure_scratch20, 31:28);\n\t\ts(MC_SECURITY_CARVEOUT2_CFG0, 10:7,  secure_scratch39, 30:27);\n\t\ts(MC_SECURITY_CARVEOUT2_CFG0, 13:11, secure_scratch41, 31:29);\n\t\ts(MC_SECURITY_CARVEOUT2_CFG0, 17:14, secure_scratch40, 30:27);\n\t\ts(MC_SECURITY_CARVEOUT2_CFG0, 21:18, secure_scratch41, 28:25);\n\t\ts(MC_SECURITY_CARVEOUT2_CFG0, 26:22, secure_scratch56, 29:25);\n\t}\n\n\t// GPU WPR.\n\ts(MC_SECURITY_CARVEOUT3_BOM,        31:17, secure_scratch50, 14:0);\n\ts(MC_SECURITY_CARVEOUT3_SIZE_128KB, 11:0,  secure_scratch56, 11:0);\n\ts32(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2,  secure_scratch71);\n\ts32(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4,  secure_scratch73);\n\tif (!t210b01)\n\t{\n\t\ts(MC_SECURITY_CARVEOUT3_CFG0,  2:0,  secure_scratch57, 27:25);\n\t\ts(MC_SECURITY_CARVEOUT3_CFG0, 10:3,  secure_scratch47, 29:22);\n\t\ts(MC_SECURITY_CARVEOUT3_CFG0, 13:11, secure_scratch43, 31:29);\n\t\ts(MC_SECURITY_CARVEOUT3_CFG0, 21:14, secure_scratch48, 29:22);\n\t\ts(MC_SECURITY_CARVEOUT3_CFG0, 25:22, secure_scratch57, 31:28);\n\t\ts(MC_SECURITY_CARVEOUT3_CFG0, 26:26, secure_scratch58, 0:0);\n\t}\n\telse\n\t{\n\t\ts(MC_SECURITY_CARVEOUT3_CFG0,  1:0,  secure_scratch57, 31:30);\n\t\ts(MC_SECURITY_CARVEOUT3_CFG0,  2:2,  secure_scratch58, 0:0);\n\t\ts(MC_SECURITY_CARVEOUT3_CFG0,  6:3,  secure_scratch47, 29:26);\n\t\ts(MC_SECURITY_CARVEOUT3_CFG0, 10:7, secure_scratch48, 25:22);\n\t\ts(MC_SECURITY_CARVEOUT3_CFG0, 13:11, secure_scratch43, 31:29);\n\t\ts(MC_SECURITY_CARVEOUT3_CFG0, 17:14, secure_scratch48, 29:26);\n\t\ts(MC_SECURITY_CARVEOUT3_CFG0, 21:18, secure_scratch52, 30:27);\n\t\ts(MC_SECURITY_CARVEOUT3_CFG0, 26:22, secure_scratch58, 5:1);\n\t}\n\n\t// TSECA.\n\ts(MC_SECURITY_CARVEOUT4_BOM,        31:17, secure_scratch51, 14:0);\n\ts(MC_SECURITY_CARVEOUT4_SIZE_128KB, 11:0,  secure_scratch55, 23:12);\n\ts(MC_SECURITY_CARVEOUT4_CFG0,       26:0,  secure_scratch39, 26:0);\n\n\t// TSECB.\n\ts(MC_SECURITY_CARVEOUT5_BOM,        31:17, secure_scratch52, 14:0);\n\ts(MC_SECURITY_CARVEOUT5_SIZE_128KB, 11:0,  secure_scratch57, 23:12);\n\ts(MC_SECURITY_CARVEOUT5_CFG0,       26:0,  secure_scratch40, 26:0);\n}\n\nstatic void _l4t_mc_config_carveout(bool t210b01)\n{\n#if CARVEOUT_NVDEC_TSEC_ENABLE\n\t// Re-enable access for TSEC clients.\n\tMC(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) &= ~BIT(22);\n\tMC(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) &= ~(BIT(15) | BIT(14) | BIT(13));\n#endif\n\n\t// Disabled VPR carveout. DT decides if enabled or not.\n\tMC(MC_VIDEO_PROTECT_BOM)      = 0;\n\tMC(MC_VIDEO_PROTECT_SIZE_MB)  = 0;\n\tMC(MC_VIDEO_PROTECT_REG_CTRL) = VPR_CTRL_TZ_SECURE | VPR_CTRL_LOCKED;\n\n\t// Temporarily disable TZDRAM carveout. For launching coldboot TZ.\n\tMC(MC_SEC_CARVEOUT_BOM)      = 0;\n\tMC(MC_SEC_CARVEOUT_SIZE_MB)  = 0;\n\tMC(MC_SEC_CARVEOUT_REG_CTRL) = 0;\n\n\t// Print real one, not temp disabled.\n\tUPRINTF(\"TZD: TZDRAM Carveout: %08X - %08X\\n\", TZDRAM_BASE, TZDRAM_BASE - 1 + TZDRAM_SIZE);\n\n\t// Configure generalized security carveouts.\n\tu32 carveout_base = GEN_CARVEOUT_TOP;\n\n#if CARVEOUT_NVDEC_TSEC_ENABLE\n\n\t// Set NVDEC keyslot sticky bits.\n\tclock_enable_nvdec();\n\tclock_enable_nvjpg();\n\tNVDEC(NVDEC_SA_KEYSLOT_GLOBAL_RW) = 0xFFFF;     // Read disable.\n\tNVDEC(NVDEC_SA_KEYSLOT_TZ)        = 0xFFFFFFFF; // TZ enable.\n\tNVDEC(NVDEC_SA_KEYSLOT_FALCON)    = 0;          // Falcon disable.\n\tNVDEC(NVDEC_SA_KEYSLOT_OTF)       = 0;          // OTF disable.\n\tNVDEC(NVDEC_VPR_ALL_OTF_GOTO_VPR) = 1;          // Enable.\n\tclock_disable_nvjpg();\n\tclock_disable_nvdec();\n\n\t// Set NVDEC carveout. Only for NVDEC bl/prod.\n\tcarveout_base -= ALIGN(CARVEOUT_NVDEC_SIZE, SZ_1M);\n\tMC(MC_SECURITY_CARVEOUT1_BOM)        = carveout_base;\n\tMC(MC_SECURITY_CARVEOUT1_BOM_HI)     = 0;\n\tMC(MC_SECURITY_CARVEOUT1_SIZE_128KB) = CARVEOUT_NVDEC_SIZE / SZ_128K;\n\tMC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0) = 0;\n\tMC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1) = 0;\n\tMC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2) = SEC_CARVEOUT_CA2_R_TSEC  | SEC_CARVEOUT_CA2_W_TSEC;\n\tMC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3) = SEC_CARVEOUT_CA3_R_NVDEC | SEC_CARVEOUT_CA3_W_NVDEC;\n\tMC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4) = 0;\n\tMC(MC_SECURITY_CARVEOUT1_CFG0) = SEC_CARVEOUT_CFG_LOCKED            |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_SEC            |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_FALCON_LS      |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_FALCON_HS      |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_WR_FALCON_HS      |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_APERTURE_ID(1)    |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH;\n\tUPRINTF(\"GSC1: NVDEC Carveout: %08X - %08X\\n\",\n\t\tMC(MC_SECURITY_CARVEOUT1_BOM), MC(MC_SECURITY_CARVEOUT1_BOM) + MC(MC_SECURITY_CARVEOUT1_SIZE_128KB) * SZ_128K);\n\n#elif CARVEOUT_SECFW_ENABLE\n\n\t// Flush data to ram.\n\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);\n\n\t// Set SC7-Entry/SC7-Exit/R2P/MTC Table or SC7-Exit/BPMP-FW carveout. Only BPMP, CCPLEX and AHB have R/W access.\n\tMC(MC_SECURITY_CARVEOUT1_BOM)        = carveout_base;\n\tMC(MC_SECURITY_CARVEOUT1_BOM_HI)     = 0;\n\tMC(MC_SECURITY_CARVEOUT1_SIZE_128KB) = CARVEOUT_SECFW_SIZE / SZ_128K;\n\tMC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0) = SEC_CARVEOUT_CA0_R_BPMP_C     |\n\t\t\t\t\t\t\t\t\t\t\t   SEC_CARVEOUT_CA0_R_PPCSAHBSLV;\n\tMC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1) = SEC_CARVEOUT_CA1_W_BPMP_C     |\n\t\t\t\t\t\t\t\t\t\t\t   SEC_CARVEOUT_CA1_R_CCPLEX_C   |\n\t\t\t\t\t\t\t\t\t\t\t   SEC_CARVEOUT_CA1_R_CCPLEXLP_C |\n\t\t\t\t\t\t\t\t\t\t\t   SEC_CARVEOUT_CA1_W_CCPLEX_C   |\n\t\t\t\t\t\t\t\t\t\t\t   SEC_CARVEOUT_CA1_W_CCPLEXLP_C |\n\t\t\t\t\t\t\t\t\t\t\t   SEC_CARVEOUT_CA1_W_PPCSAHBSLV;\n\tMC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2) = 0;\n\tMC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3) = 0;\n\tMC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4) = 0;\n\tMC(MC_SECURITY_CARVEOUT1_CFG0) = SEC_CARVEOUT_CFG_RD_NS  |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_SEC |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_WR_NS  |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_WR_SEC |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_LOCKED;\n\tUPRINTF(\"GSC1: SECFW Carveout: %08X - %08X\\n\",\n\t\tMC(MC_SECURITY_CARVEOUT1_BOM), MC(MC_SECURITY_CARVEOUT1_BOM) + MC(MC_SECURITY_CARVEOUT1_SIZE_128KB) * SZ_128K);\n\n#endif\n\n\t// Set GPU FW WPR carveout. Same value is used for GPU WPR carveout calculation if not full TOS.\n\tcarveout_base -= ALIGN(CARVEOUT_GPUFW_SIZE, SZ_1M);\n\n\t// Sanitize it and enable GSC3 for ACR.\n\tmemset((void *)carveout_base, 0, CARVEOUT_GPUFW_SIZE);\n\t*(u32 *)(carveout_base + CARVEOUT_GPUFW_SIZE - sizeof(u32)) = ACR_GSC3_ENABLE_MAGIC;\n\n\ttsec_init_t *tsec_init = (tsec_init_t *)(carveout_base + CARVEOUT_GPUFW_SIZE - FALCON_DMA_PAGE_SIZE);\n\n\t// Set TSEC init info.\n\ttsec_init->sku  = SKU_NX;\n\ttsec_init->hdcp = HDCP22;\n\ttsec_init->soc  = t210b01 ? SOC_ID_T210B01 : SOC_ID_T210;\n\n\t// Flush data to ram.\n\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);\n\n\t// Set carveout config.\n\tMC(MC_SECURITY_CARVEOUT2_BOM)        = carveout_base;\n\tMC(MC_SECURITY_CARVEOUT2_BOM_HI)     = 0;\n\tMC(MC_SECURITY_CARVEOUT2_SIZE_128KB) = CARVEOUT_GPUFW_SIZE / SZ_128K;\n\tMC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0) = 0;\n\tMC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1) = 0;\n\tMC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2) = SEC_CARVEOUT_CA2_R_GPU  | SEC_CARVEOUT_CA2_W_GPU | SEC_CARVEOUT_CA2_R_TSEC;\n\tMC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3) = 0;\n\tMC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4) = SEC_CARVEOUT_CA4_R_GPU2 | SEC_CARVEOUT_CA4_W_GPU2;\n\tMC(MC_SECURITY_CARVEOUT2_CFG0) = SEC_CARVEOUT_CFG_LOCKED            |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_NS             |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_SEC            |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_FALCON_LS      |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_FALCON_HS      |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_WR_FALCON_LS      |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_WR_FALCON_HS      |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_APERTURE_ID(2)    |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_SEND_CFG_TO_GPU   |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH; // SEC_CARVEOUT_CFG_IS_WPR is set from GPU.\n\tUPRINTF(\"GSC2: GPUFW Carveout: %08X - %08X\\n\",\n\t\tMC(MC_SECURITY_CARVEOUT2_BOM), MC(MC_SECURITY_CARVEOUT2_BOM) + MC(MC_SECURITY_CARVEOUT2_SIZE_128KB) * SZ_128K);\n\n\t// Set GPU WPR carveout.\n#if CARVEOUT_NVDEC_TSEC_ENABLE\n\tcarveout_base -= ALIGN(CARVEOUT_GPUWPR_SIZE, SZ_1M);\n\tMC(MC_SECURITY_CARVEOUT3_BOM) = carveout_base;\n#else\n\tMC(MC_SECURITY_CARVEOUT3_BOM) = carveout_base + CARVEOUT_GPUFW_SIZE;\n#endif\n\tMC(MC_SECURITY_CARVEOUT3_BOM_HI)     = 0x0;\n\tMC(MC_SECURITY_CARVEOUT3_SIZE_128KB) = CARVEOUT_GPUWPR_SIZE / SZ_128K;\n\tMC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0) = 0;\n\tMC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1) = 0;\n\tMC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2) = 0; // HOS: SEC_CARVEOUT_CA2_R_GPU  | SEC_CARVEOUT_CA2_W_GPU\n\tMC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3) = 0;\n\tMC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4) = 0; // HOS: SEC_CARVEOUT_CA4_R_GPU2 | SEC_CARVEOUT_CA4_W_GPU2\n\tMC(MC_SECURITY_CARVEOUT3_CFG0) = SEC_CARVEOUT_CFG_LOCKED            |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_NS             |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_SEC            |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_FALCON_LS      |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_FALCON_HS      |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_WR_FALCON_LS      |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_WR_FALCON_HS      |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_APERTURE_ID(3)    |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_SEND_CFG_TO_GPU   |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH; // SEC_CARVEOUT_CFG_IS_WPR is set from GPU.\n\tUPRINTF(\"GSC3: GPUW2 Carveout: %08X - %08X\\n\",\n\t\tMC(MC_SECURITY_CARVEOUT3_BOM), MC(MC_SECURITY_CARVEOUT3_BOM) + MC(MC_SECURITY_CARVEOUT3_SIZE_128KB) * SZ_128K);\n\n\t/*\n\t * Set TSECA/B carveout. Only for NVDEC bl/prod and TSEC.\n\t *\n\t * Otherwise disabled.\n\t *\n\t * With HOS SC7-Exit fw, it gets set to disallow RAM access for BPMP. But TZ can change it.\n\t * We lock the carveout and save it in restore scratch registers so SC7-Exit can't touch it.\n\t */\n\tcarveout_base -= CARVEOUT_NVDEC_TSEC_ENABLE ? ALIGN(CARVEOUT_TSEC_SIZE, SZ_1M) : 0;\n\tMC(MC_SECURITY_CARVEOUT4_BOM)        = CARVEOUT_NVDEC_TSEC_ENABLE ? carveout_base : 0;\n\tMC(MC_SECURITY_CARVEOUT4_BOM_HI)     = 0x0;\n\tMC(MC_SECURITY_CARVEOUT4_SIZE_128KB) = CARVEOUT_NVDEC_TSEC_ENABLE ? CARVEOUT_TSEC_SIZE / SZ_128K : 0;\n\tMC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2) = SEC_CARVEOUT_CA2_R_TSEC  | SEC_CARVEOUT_CA2_W_TSEC;\n\tMC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4) = SEC_CARVEOUT_CA4_R_TSECB | SEC_CARVEOUT_CA4_W_TSECB;\n\tMC(MC_SECURITY_CARVEOUT4_CFG0) = SEC_CARVEOUT_CFG_LOCKED         |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_FALCON_HS   |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_WR_FALCON_HS   |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_APERTURE_ID(4) |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH;\n\tUPRINTF(\"GSC4: TSEC1 Carveout: %08X - %08X\\n\",\n\t\tMC(MC_SECURITY_CARVEOUT4_BOM), MC(MC_SECURITY_CARVEOUT4_BOM) + MC(MC_SECURITY_CARVEOUT4_SIZE_128KB) * SZ_128K);\n\n\t// Set TSECA carveout. Only for NVDEC bl/prod and TSEC. Otherwise disabled.\n\tcarveout_base -= CARVEOUT_NVDEC_TSEC_ENABLE ? ALIGN(CARVEOUT_TSEC_SIZE, SZ_1M) : 0;\n\tMC(MC_SECURITY_CARVEOUT5_BOM)        = CARVEOUT_NVDEC_TSEC_ENABLE ? carveout_base : 0;\n\tMC(MC_SECURITY_CARVEOUT5_BOM_HI)     = 0x0;\n\tMC(MC_SECURITY_CARVEOUT5_SIZE_128KB) = CARVEOUT_NVDEC_TSEC_ENABLE ? CARVEOUT_TSEC_SIZE / SZ_128K : 0;\n\tMC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2) = SEC_CARVEOUT_CA2_R_TSEC | SEC_CARVEOUT_CA2_W_TSEC;\n\tMC(MC_SECURITY_CARVEOUT5_CFG0) = SEC_CARVEOUT_CFG_LOCKED         |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_RD_FALCON_HS   |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_WR_FALCON_HS   |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_APERTURE_ID(5) |\n\t\t\t\t\t\t\t\t\t SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH;\n\tUPRINTF(\"GSC5: TSEC2 Carveout: %08X - %08X\\n\",\n\t\tMC(MC_SECURITY_CARVEOUT5_BOM), MC(MC_SECURITY_CARVEOUT5_BOM) + MC(MC_SECURITY_CARVEOUT5_SIZE_128KB) * SZ_128K);\n\n\tUPRINTF(\"DRAM  Bank 0 TOP:     %08X\\n\", carveout_base);\n\n\t// Save carveouts to lp0 pmc registers.\n\t_l4t_sdram_lp0_save_params(t210b01);\n}\n\nstatic void _l4t_late_hw_config(bool t210b01)\n{\n\t// Reset System Counters.\n\tfor (u32 i = 0; i < SYSCTR0_COUNTERS; i += sizeof(u32))\n\t\tSYSCTR0(SYSCTR0_COUNTERS_BASE + i) = 0;\n\n\t/*\n\t * PMIC config scratch register\n\t *\n\t * bit00:    active cluster slow\n\t * bit01:    Set: max77621/max77812. Unset: OVR/OVR2.\n\t * bit02-07: unused\n\t * bit08-15: pmic cpu i2c address\n\t * bit16:23: pmic cpu i2c en reg\n\t * bit24:31: pmic cpu i2c en val\n\t */\n\tPMC(APBDEV_PMC_SCRATCH201) = BIT(1);\n\n\t// Clear PLLM override for SC7.\n\tPMC(APBDEV_PMC_PLLP_WB0_OVERRIDE) &= ~PMC_PLLP_WB0_OVR_PLLM_OVR_ENABLE;\n\n\t// Set spare reg to 0xE0000 and clear everything else.\n\tif (t210b01 && (SYSREG(AHB_AHB_SPARE_REG) & 0xE0000000) != 0xE0000000)\n\t\tSYSREG(AHB_AHB_SPARE_REG) = 0xE0000 << 12u;\n\n\t// HDA loopback disable on prod.\n\tPMC(APBDEV_PMC_STICKY_BITS) = PMC_STICKY_BITS_HDA_LPBK_DIS;\n\n\t// Clear any MC error.\n\tMC(MC_INTSTATUS) = MC(MC_INTSTATUS);\n\n\t// Enable Wrap burst for BPMP, GPU and PCIE.\n\tMSELECT(MSELECT_CONFIG) = (MSELECT(MSELECT_CONFIG) & (~(MSELECT_CFG_ERR_RESP_EN_GPU | MSELECT_CFG_ERR_RESP_EN_PCIE))) |\n\t\t\t\t\t\t\t  (MSELECT_CFG_WRAP_TO_INCR_GPU | MSELECT_CFG_WRAP_TO_INCR_PCIE | MSELECT_CFG_WRAP_TO_INCR_BPMP);\n\n#if LOCK_PMC_REGISTERS\n\t// Lock LP0 parameters and misc secure registers. Always happens on warmboot.\n #if CARVEOUT_NVDEC_TSEC_ENABLE\n\tpmc_scratch_lock(PMC_SEC_LOCK_CARVEOUTS_L4T | PMC_SEC_LOCK_SE_SRK);\n #else\n\tpmc_scratch_lock(PMC_SEC_LOCK_LP0_PARAMS | PMC_SEC_LOCK_MISC | PMC_SEC_LOCK_SE_SRK);\n #endif\n\n\t// Lock SE2 SRK and misc secure regs. Also lock writes on normal LP0 scratch regs.\n\tif (t210b01)\n\t\tpmc_scratch_lock(PMC_SEC_LOCK_MISC_B01 | PMC_SEC_LOCK_SE2_SRK_B01 | PMC_SEC_LOCK_LP0_PARAMS_B01);\n#endif\n}\n\nstatic void _l4t_bpmpfw_b01_config(l4t_ctxt_t *ctxt)\n{\n\tchar *ram_oc_txt  = ctxt->ram_oc_txt;\n\tu32   ram_oc_freq = ctxt->ram_oc_freq;\n\tu32   ram_oc_opt  = ctxt->ram_oc_opt;\n\tu32   ram_id      = fuse_read_dramid(false);\n\n\t// Set default parameters.\n\t*(u32 *)BPMPFW_B01_DTB_ADDR = 0;\n\t*(u8  *)BPMPFW_B01_CC_INIT_OP = OP_TRAIN;\n\t*(u32 *)BPMPFW_B01_CC_PT_TIME = 100;\n\n#if DEBUG_LOG_BPMPFW\n\t// Set default debug parameters.\n\t*(u32 *)BPMPFW_B01_LOGLEVEL = 3;\n\t*(u32 *)BPMPFW_B01_CC_DEBUG = 0x50000101;\n\n\t// Set serial debug port.\n\tif (*(u32 *)BPMPFW_B01_ADTB_BASE == DTB_MAGIC)\n\t\tBPMPFW_B01_DTB_SET_SERIAL_PORT(ctxt->serial_port);\n#endif\n\n\t// Set and copy MTC tables.\n\tu32 mtc_idx = mtc_table_idx_t210b01[ram_id];\n\tfor (u32 i = 0; i < 3; i++)\n\t{\n\t\tif (true)\n\t\t\tminerva_sdmmc_la_program(BPMPFW_B01_MTC_TABLE_OFFSET(mtc_idx, i), true);\n\t\tmemcpy(BPMPFW_B01_DTB_EMC_TBL_OFFSET(i), BPMPFW_B01_MTC_TABLE_OFFSET(mtc_idx, i), BPMPFW_B01_MTC_FREQ_TABLE_SIZE);\n\t}\n\n\t// Always use Arachne Register Cell (ARC) for setting rated frequencies if no ram_oc is defined.\n\tif (!ram_oc_freq)\n\t{\n\t\tif (ram_id >= LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AM_MGCJ &&\n\t\t\tram_id <= LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTE)\n\t\t{\n\t\t\tram_oc_txt  = \"1866000\";\n\t\t\tram_oc_freq = 1866000;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tram_oc_txt  = \"2133000\";\n\t\t\tram_oc_freq = 2133000;\n\t\t}\n\t}\n\n\t// Set DRAM voltage.\n\tif (ctxt->ram_oc_vdd2)\n\t\tmax7762x_regulator_set_voltage(REGULATOR_SD1,  ctxt->ram_oc_vdd2 * 1000);\n\tif (ctxt->ram_oc_vddq)\n\t\tmax7762x_regulator_set_voltage(REGULATOR_RAM0, ctxt->ram_oc_vddq * 1000);\n\n\t// A frequency of lower or equal with stock max will skip ARC.\n\tif (ram_oc_freq > DRAM_T210B01_TBL_MAX_FREQ)\n\t{\n\t\t// Final table.\n\t\tconst u32 tbl_idx = BPMPFW_B01_DTB_EMC_ENTRIES - 1;\n\n\t\t// Copy table and prep it for Arachne.\n\t\tmemcpy(BPMPFW_B01_DTB_EMC_TBL_OFFSET(tbl_idx), BPMPFW_B01_MTC_TABLE_OFFSET(mtc_idx, 2), BPMPFW_B01_MTC_FREQ_TABLE_SIZE);\n\n\t\tBPMPFW_B01_DTB_EMC_TBL_SET_NAME(tbl_idx, ram_oc_txt);\n\t\tBPMPFW_B01_DTB_EMC_TBL_SET_FREQ(tbl_idx, ram_oc_freq);\n\t\tBPMPFW_B01_DTB_EMC_TBL_SET_OPTC(tbl_idx, ram_oc_opt);\n\n\t\t// Enable table.\n\t\tBPMPFW_B01_DTB_EMC_TBL_ENABLE(tbl_idx);\n\n\t\tUPRINTF(\"RAM Frequency set to: %d KHz. Voltage: %d mV\\n\", ram_oc_freq, ctxt->ram_oc_vdd2);\n\t}\n\n\t// Save BPMP-FW entrypoint for TZ.\n\tPMC(APBDEV_PMC_SCRATCH39) = BPMPFW_B01_ENTRYPOINT;\n\tPMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE1_B01) |= BIT(15);\n}\n\nstatic int _l4t_sc7_exit_config(bool t210b01)\n{\n\tif (!t210b01)\n\t{\n\t\t// Apply Nintendo Switch (2017) RSA modulus to SC7-Exit firmware.\n\t\temmc_initialize(false);\n\t\tpkg1_warmboot_rsa_mod(SC7EXIT_BASE);\n\t\temmc_end();\n\n\t\t// Set SC7-Exit firmware address for bootrom to find.\n\t\tPMC(APBDEV_PMC_SCRATCH1) = SC7EXIT_BASE;\n\t}\n\telse\n\t{\n\t\t// Get latest SC7-Exit if needed and setup PA id.\n\t\tlaunch_ctxt_t hos_ctxt = {0};\n\t\tif (pkg1_warmboot_config(&hos_ctxt, 0, 0, 0))\n\t\t{\n\t\t\tgfx_con.mute = false;\n\t\t\tgfx_wputs(\"\\nFailed to match warmboot with fuses!\\nIf you continue, sleep wont work!\");\n\n\t\t\tgfx_puts(\"\\nPress POWER to continue.\\nPress VOL to go to the menu.\\n\");\n\n\t\t\tif (!(btn_wait() & BTN_POWER))\n\t\t\t\treturn 1;\n\t\t}\n\n\t\t// Copy loaded warmboot fw to address if from storage.\n\t\tif (hos_ctxt.warmboot)\n\t\t\tmemcpy((void *)SC7EXIT_B01_BASE, hos_ctxt.warmboot, hos_ctxt.warmboot_size);\n\n\t\t// Set SC7-Exit firmware address for bootrom to find.\n\t\tPMC(APBDEV_PMC_SECURE_SCRATCH119) = SC7EXIT_B01_BASE;\n\t\tPMC(APBDEV_PMC_SEC_DISABLE8) |= BIT(30);\n\t}\n\n\treturn 0;\n}\n\nstatic void _l4t_bl33_cfg_set_key(char *env, const char *key, const char *val)\n{\n\tstrcat(env, key);\n\tstrcat(env, \"=\");\n\tstrcat(env, val);\n\tstrcat(env, \"\\n\");\n}\n\nstatic void _l4t_set_config(l4t_ctxt_t *ctxt, const ini_sec_t *ini_sec, int entry_idx, int is_list, bool t210b01)\n{\n\tchar *bl33_env = (char *)BL33_ENV_BASE;\n\tbl33_env[0] = '\\0';\n\tchar val[4] = {0};\n\n\t// Set default SLD type.\n\tctxt->sld_type = true;\n\n\t// Parse ini section and prepare BL33 env.\n\tLIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)\n\t{\n\t\tif (!strcmp(\"boot_prefixes\",    kv->key))\n\t\t\tctxt->path        = kv->val;\n\t\telse if (!strcmp(\"ram_oc\",      kv->key))\n\t\t{\n\t\t\tctxt->ram_oc_txt  = kv->val;\n\t\t\tctxt->ram_oc_freq = atoi(kv->val);\n\t\t}\n\t\telse if (!strcmp(\"ram_oc_vdd2\", kv->key))\n\t\t{\n\t\t\tctxt->ram_oc_vdd2 = atoi(kv->val);\n\n\t\t\tif (t210b01 && ctxt->ram_oc_vdd2 > DRAM_VDD2_OC_MAX_VOLTAGE)\n\t\t\t\tctxt->ram_oc_vdd2 = DRAM_VDD2_OC_MAX_VOLTAGE;\n\t\t\telse if (!t210b01 && ctxt->ram_oc_vdd2 > DRAM_VDD2Q_OC_MAX_VOLTAGE)\n\t\t\t\tctxt->ram_oc_vdd2 = DRAM_VDD2Q_OC_MAX_VOLTAGE;\n\t\t\telse if (ctxt->ram_oc_vdd2 < DRAM_VDD2_OC_MIN_VOLTAGE)\n\t\t\t\tctxt->ram_oc_vdd2 = DRAM_VDD2_OC_MIN_VOLTAGE;\n\t\t}\n\t\telse if (!strcmp(\"ram_oc_vddq\", kv->key))\n\t\t{\n\t\t\tctxt->ram_oc_vddq = atoi(kv->val);\n\t\t\tif (ctxt->ram_oc_vddq > DRAM_VDDQ_OC_MAX_VOLTAGE)\n\t\t\t\tctxt->ram_oc_vddq = DRAM_VDDQ_OC_MAX_VOLTAGE;\n\t\t\telse if (ctxt->ram_oc_vddq < DRAM_VDDQ_OC_MIN_VOLTAGE)\n\t\t\t\tctxt->ram_oc_vddq = 0;\n\t\t}\n\t\telse if (!strcmp(\"ram_oc_opt\",  kv->key))\n\t\t\tctxt->ram_oc_opt  = atoi(kv->val);\n\t\telse if (!strcmp(\"uart_port\",   kv->key))\n\t\t\tctxt->serial_port = atoi(kv->val);\n\t\telse if (!strcmp(\"sld_type\",    kv->key))\n\t\t\tctxt->sld_type    = atoi(kv->val);\n\n\t\t// Set key/val to BL33 env.\n\t\t_l4t_bl33_cfg_set_key(bl33_env, kv->key, kv->val);\n\t}\n\n#ifdef DEBUG_UART_PORT\n\t// Override port if bootloader UART debug is enabled.\n\tctxt->serial_port = DEBUG_UART_PORT + 1;\n#endif\n\n\t// Set r2p parameters.\n\tif (entry_idx >= 10)\n\t{\n\t\tval[0] = '1';\n\t\tval[1] = '0' + (entry_idx % 10);\n\t}\n\telse\n\t\tval[0] = '0' + entry_idx;\n\t_l4t_bl33_cfg_set_key(bl33_env, \"autoboot\",      val);\n\n\t// NULL terminate at single char for the next env sets.\n\tval[1] = 0;\n\n\tval[0] = '0' + is_list;\n\t_l4t_bl33_cfg_set_key(bl33_env, \"autoboot_list\", val);\n\n\tval[0] = '0' + L4T_LOADER_API_REV;\n\t_l4t_bl33_cfg_set_key(bl33_env, \"loader_rev\",    val);\n\n\t// Enable BL33 memory env import.\n\t*(u32 *)(BL33_ENV_MAGIC_OFFSET) = BL33_ENV_MAGIC;\n\n\t// Set boot path.\n\tsd_path = (char *)malloc(512);\n\tsd_path_len = strlen(ctxt->path);\n\tstrcpy(sd_path, ctxt->path);\n}\n\nvoid launch_l4t(const ini_sec_t *ini_sec, int entry_idx, int is_list, bool t210b01)\n{\n\tl4t_ctxt_t *ctxt = (l4t_ctxt_t *)TZ_PARAM_BASE;\n\tmemset(ctxt, 0, TZ_PARAM_SIZE);\n\n\tgfx_con_setpos(0, 0);\n\n\t// Parse config.\n\t_l4t_set_config(ctxt, ini_sec, entry_idx, is_list, t210b01);\n\n\tif (!ctxt->path)\n\t{\n\t\t_l4t_crit_error(\"Path missing\", false);\n\t\treturn;\n\t}\n\n\t// Get MTC table.\n\tctxt->mtc_table = minerva_get_mtc_table();\n\tif (!t210b01 && !ctxt->mtc_table)\n\t{\n\t\t_l4t_crit_error(\"Minerva missing\", true);\n\t\treturn;\n\t}\n\n\t// Load BL31 (ATF/TrustZone fw).\n\tif (!_l4t_sd_load(BL31_FW))\n\t{\n\t\t_l4t_crit_error(\"BL31 missing\", false);\n\t\treturn;\n\t}\n\n\t// Load BL33 (U-BOOT/CBOOT).\n\tif (!_l4t_sd_load(BL33_FW))\n\t{\n\t\t_l4t_crit_error(\"BL33 missing\", false);\n\t\treturn;\n\t}\n\n\t// Set firmware path.\n\tstrcpy(sd_path, \"bootloader/sys/l4t/\");\n\tsd_path_len = strlen(sd_path);\n\n\tif (!t210b01)\n\t{\n\t\t// Load SC7-Entry firmware.\n\t\tctxt->sc7entry_size = _l4t_sd_load(SC7ENTRY_FW);\n\t\tif (!ctxt->sc7entry_size)\n\t\t{\n\t\t\t_l4t_crit_error(\"loading SC7-Entry\", true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Load BPMP-FW. Does power management.\n\t\tif (!_l4t_sd_load(BPMPFW_FW))\n\t\t{\n\t\t\t_l4t_crit_error(\"loading BPMP-FW\", true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Load SC7-Exit firmware.\n\t\tif (!_l4t_sd_load(SC7EXIT_FW))\n\t\t{\n\t\t\t_l4t_crit_error(\"loading SC7-Exit\", true);\n\t\t\treturn;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Load BPMP-FW. Manages SC7-Entry also.\n\t\tif (!_l4t_sd_load(BPMPFW_B01_FW))\n\t\t{\n\t\t\t_l4t_crit_error(\"loading BPMP-FW\", true);\n\t\t\treturn;\n\t\t}\n\n\t\t// Load BPMP-FW MTC table.\n\t\tif (!_l4t_sd_load(BPMPFW_B01_MTC_TBL))\n\t\t{\n\t\t\t_l4t_crit_error(\"loading BPMP-FW MTC\", true);\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// Set SC7-Exit firmware address to PMC for bootrom and do further setup.\n\tif (_l4t_sc7_exit_config(t210b01))\n\t\treturn;\n\n\t// Done loading bootloaders/firmware.\n\tsd_end();\n\n\t// We don't need AHB aperture open.\n\tmc_disable_ahb_redirect();\n\n\t// Enable debug port.\n\tif (ctxt->serial_port)\n\t{\n\t\tpinmux_config_uart(ctxt->serial_port - 1);\n\t\tclock_enable_uart(ctxt->serial_port - 1);\n\t}\n\n\t// Restore UARTB/C TX pins to SPIO.\n\tgpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);\n\tgpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);\n\n\t// Configure BL33 parameters.\n\tif (*(u32 *)BL33_DTB_BASE == DTB_MAGIC)\n\t{\n\t\t// Defaults are for UARTA.\n\t\tchar *bl33_serial_port = NULL;\n\t\tswitch (ctxt->serial_port)\n\t\t{\n\t\tcase 0: // Disable.\n\t\t\tbreak;\n\t\tcase 1: // UARTA.\n\t\t\tbl33_serial_port = \"70006000\";\n\t\t\tbreak;\n\t\tcase 2: // UARTB.\n\t\t\tbl33_serial_port = \"70006040\";\n\t\t\tbreak;\n\t\tcase 3: // UARTC.\n\t\t\tbl33_serial_port = \"70006200\";\n\t\t\tbreak;\n\t\t}\n\n\t\tif (bl33_serial_port)\n\t\t{\n\t\t\tBL33_DTB_SET_STDOUT_PATH(bl33_serial_port);\n\t\t\tBL33_DTB_SET_STDERR_PATH(bl33_serial_port);\n\t\t\tBL33_DTB_SET_UART_STATUS(ctxt->serial_port);\n\t\t}\n\t}\n\n\t// Set BL31 params.\n\tctxt->bl31_v1_params.hdr.type     = PARAM_BL31;\n\tctxt->bl31_v1_params.hdr.version  = VERSION_1;\n\tctxt->bl31_v1_params.hdr.size     = sizeof(bl31_v1_params_t);\n\tctxt->bl31_v1_params.hdr.attr     = PARAM_EP_SECURE;\n\tctxt->bl31_v1_params.bl33_ep_info = (u64)(u32)&ctxt->bl33_ep_info;\n\n\t// Set BL33 params.\n\tctxt->bl33_ep_info.hdr.type    = PARAM_EP;\n\tctxt->bl33_ep_info.hdr.version = VERSION_1;\n\tctxt->bl33_ep_info.hdr.size    = sizeof(entry_point_info_t);\n\tctxt->bl33_ep_info.hdr.attr    = PARAM_EP_NON_SECURE;\n\tctxt->bl33_ep_info.pc          = BL33_LOAD_BASE;\n\tctxt->bl33_ep_info.spsr        = SPSR_EL2T;\n\n\t// Set Platform parameters.\n\tctxt->bl31_plat_params.tzdram_base = TZDRAM_BASE;\n\tctxt->bl31_plat_params.tzdram_size = TZDRAM_SIZE;\n#if DEBUG_LOG_ATF\n\tctxt->bl31_plat_params.uart_id = ctxt->serial_port;\n#endif\n\n\tif (!t210b01)\n\t{\n\t\t// Set SC7-Entry fw parameters. For now BPMP-FW is not used on T210.\n\t\tctxt->bl31_plat_params.sc7entry_fw_base = SC7ENTRY_HDR_BASE;\n\t\tctxt->bl31_plat_params.sc7entry_fw_size = ALIGN(ctxt->sc7entry_size + SC7ENTRY_HDR_SIZE, SZ_PAGE);\n\t}\n\n\t// Enable below features.\n\tctxt->bl31_plat_params.enable_extra_features = BL31_EXTRA_FEATURES_ENABLE;\n\n\tif (!t210b01)\n\t{\n\t\t// Set R2P payload.\n\t\treloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + 0x7C);\n\t\tmemcpy((u8 *)R2P_PAYLOAD_BASE, (u8 *)reloc->start, reloc->end - reloc->start);\n\t\tmemset((u8 *)R2P_PAYLOAD_BASE + 0x94, 0, sizeof(boot_cfg_t)); // Clear Boot Config Storage.\n\n\t\t// Set R2P payload fw parameters.\n\t\tctxt->bl31_plat_params.r2p_payload_base = R2P_PAYLOAD_BASE;\n\t\tctxt->bl31_plat_params.r2p_payload_size = ALIGN(reloc->end - reloc->start, SZ_PAGE);\n\t}\n\n\t// Set PMC access security. NS is mandatory for T210B01.\n\tctxt->bl31_plat_params.flags  = FLAGS_PMC_NON_SECURE; // Unsecure it unconditionally to reduce SMC calls to a minimum.\n\t// Lift SC7 placement restrictions. Disables TZDRAM increased carveout too.\n\tctxt->bl31_plat_params.flags |= FLAGS_SC7_NO_BASE_RESTRICTION;\n\n\t// Prepare EMC table.\n\tif (ctxt->mtc_table)\n\t{\n\t\t// Set DRAM voltage.\n\t\tif (ctxt->ram_oc_vdd2)\n\t\t\tmax7762x_regulator_set_voltage(REGULATOR_SD1, ctxt->ram_oc_vdd2 * 1000);\n\n\t\t// Train the rest of the table, apply FSP WAR, set RAM to 800 MHz.\n\t\tminerva_prep_boot_l4t(ctxt->ram_oc_freq, ctxt->ram_oc_opt, true);\n\n\t\t// Set emc table parameters and copy it.\n\t\tint table_entries = minerva_get_mtc_table_entries();\n\t\tctxt->bl31_plat_params.emc_table_base = MTCTABLE_BASE;\n\t\tctxt->bl31_plat_params.emc_table_size = sizeof(emc_table_t) * table_entries;\n\t\tmemcpy((u32 *)MTCTABLE_BASE, ctxt->mtc_table, sizeof(emc_table_t) * table_entries);\n\t}\n\n\t// Set and enable IRAM based BL31 config.\n\tPMC(APBDEV_PMC_SECURE_SCRATCH112) = PMC(APBDEV_PMC_SECURE_SCRATCH108);\n\tPMC(APBDEV_PMC_SECURE_SCRATCH114) = PMC(APBDEV_PMC_SECURE_SCRATCH109);\n\tPMC(APBDEV_PMC_SECURE_SCRATCH108) = (u32)&ctxt->bl31_v1_params;\n\tPMC(APBDEV_PMC_SECURE_SCRATCH109) = (u32)&ctxt->bl31_plat_params;\n\tPMC(APBDEV_PMC_SECURE_SCRATCH110) = BL31_IRAM_PARAMS;\n\n\t// Set panel model.\n\tPMC(APBDEV_PMC_SECURE_SCRATCH113) = display_get_decoded_panel_id();\n\n\t// Set charging limit parameters.\n\tif (fuse_read_hw_type() == FUSE_NX_HW_TYPE_HOAG)\n\t{\n\t\tint in_volt_lim = 0;\n\t\tbq24193_get_property(BQ24193_ChargeVoltageLimit, &in_volt_lim);\n\n\t\tPMC(APBDEV_PMC_SECURE_SCRATCH113) |= in_volt_lim << 16;\n\t}\n\n\t// Disable writes to above registers.\n\tPMC(APBDEV_PMC_SEC_DISABLE8) |= BIT(18) | BIT(16) | BIT(12) | BIT(10) | BIT(8);\n\n\t// Set BPMP-FW parameters.\n\tif (t210b01)\n\t\t_l4t_bpmpfw_b01_config(ctxt);\n\n\t// Set carveouts and save them to PMC for SC7 Exit.\n\t_l4t_mc_config_carveout(t210b01);\n\n\t// Deinit any unneeded HW.\n\thw_deinit(ctxt->sld_type);\n\n\t// Do late hardware config.\n\t_l4t_late_hw_config(t210b01);\n\n\tif (t210b01)\n\t{\n\t\t// Launch BL31.\n\t\tccplex_boot_cpu0(TZDRAM_COLD_ENTRY, true);\n\n\t\t// For T210B01, prep reset vector for SC7 save state and start BPMP-FW.\n\t\tEXCP_VEC(EVP_COP_RESET_VECTOR) = BPMPFW_B01_ENTRYPOINT;\n\t\tvoid (*bpmp_fw_ptr)() = (void *)BPMPFW_B01_ENTRYPOINT;\n\t\t(*bpmp_fw_ptr)();\n\t}\n\telse\n\t{\n\t\t// If T210, BPMP-FW runs BL31.\n\t\tvoid (*bpmp_fw_ptr)() = (void *)BPMPFW_ENTRYPOINT;\n\t\t(*bpmp_fw_ptr)();\n\t}\n\n\t// Halt BPMP.\n\twhile (true)\n\t\tbpmp_halt();\n}\n"
  },
  {
    "path": "bootloader/l4t/l4t.h",
    "content": "/*\n * L4T Loader for Tegra X1\n *\n * Copyright (c) 2020-2022 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _L4T_H_\n#define _L4T_H_\n\nvoid launch_l4t(const ini_sec_t *ini_sec, int entry_idx, int is_list, bool t210b01);\n\n#endif\n"
  },
  {
    "path": "bootloader/l4t/l4t_config.inl",
    "content": "/*\n * L4T Loader for Tegra X1\n *\n * Copyright (c) 2020-2022 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n// Set to 1 to enable early boot debugging.\n#define DEBUG_LOG_ATF    0\n#define DEBUG_LOG_BPMPFW 0 // Do not enable if UART setup is hindered during early boot.\n\n// Set to 1 to lock PMC registers that contain LP0 parameters.\n#define LOCK_PMC_REGISTERS 0\n\n// Configurable carveout enable config. Only one can be enabled at a time.\n#define CARVEOUT_NVDEC_TSEC_ENABLE 0 // Enable for NVDEC bl/prod and full TOS/DRM.\n#define CARVEOUT_SECFW_ENABLE      1 // SECFW is always allocated even if carveout is disabled.\n\n/*\n * WPR Carveout size config.\n *\n * L4T: 2MB or 13MB. On non SecureOS env, only 0x100 bytes are used, probably also on full TOS.\n * On 4GB+ systems, it's normally placed at BANK1_TOP - SIZE;\n */\n#define CARVEOUT_GPUWPR_SIZE_CFG (SZ_8M + SZ_4M + SZ_1M) // Mandatory when CARVEOUT_NVDEC_TSEC_ENABLE is 1.\n"
  },
  {
    "path": "bootloader/libs/fatfs/diskio.c",
    "content": "/*-----------------------------------------------------------------------*/\n/* Low level disk I/O module skeleton for FatFs     (C)ChaN, 2016        */\n/*-----------------------------------------------------------------------*/\n/* If a working storage control module is available, it should be        */\n/* attached to the FatFs via a glue function rather than modifying it.   */\n/* This is an example of glue functions to attach various exsisting      */\n/* storage control modules to the FatFs module with a defined API.       */\n/*-----------------------------------------------------------------------*/\n\n#include <string.h>\n\n#include <bdk.h>\n\n#include <libs/fatfs/diskio.h>\t/* FatFs lower layer API */\n\n/*-----------------------------------------------------------------------*/\n/* Get Drive Status                                                      */\n/*-----------------------------------------------------------------------*/\nDSTATUS disk_status (\n\tBYTE pdrv\t\t/* Physical drive nmuber to identify the drive */\n)\n{\n\treturn 0;\n}\n\n/*-----------------------------------------------------------------------*/\n/* Inidialize a Drive                                                    */\n/*-----------------------------------------------------------------------*/\nDSTATUS disk_initialize (\n\tBYTE pdrv\t\t\t\t/* Physical drive nmuber to identify the drive */\n)\n{\n\treturn 0;\n}\n\n/*-----------------------------------------------------------------------*/\n/* Read Sector(s)                                                        */\n/*-----------------------------------------------------------------------*/\nDRESULT disk_read (\n\tBYTE pdrv,\t\t/* Physical drive nmuber to identify the drive */\n\tBYTE *buff,\t\t/* Data buffer to store read data */\n\tDWORD sector,\t/* Start sector in LBA */\n\tUINT count\t\t/* Number of sectors to read */\n)\n{\n\treturn sdmmc_storage_read(&sd_storage, sector, count, buff);\n}\n\n/*-----------------------------------------------------------------------*/\n/* Write Sector(s)                                                       */\n/*-----------------------------------------------------------------------*/\nDRESULT disk_write (\n\tBYTE pdrv,\t\t\t/* Physical drive nmuber to identify the drive */\n\tconst BYTE *buff,\t/* Data to be written */\n\tDWORD sector,\t\t/* Start sector in LBA */\n\tUINT count\t\t\t/* Number of sectors to write */\n)\n{\n\treturn sdmmc_storage_write(&sd_storage, sector, count, (void *)buff);\n}\n\n/*-----------------------------------------------------------------------*/\n/* Miscellaneous Functions                                               */\n/*-----------------------------------------------------------------------*/\nDRESULT disk_ioctl (\n\tBYTE pdrv,\t\t/* Physical drive nmuber (0..) */\n\tBYTE cmd,\t\t/* Control code */\n\tvoid *buff\t\t/* Buffer to send/receive control data */\n)\n{\n\treturn RES_OK;\n}\n"
  },
  {
    "path": "bootloader/libs/fatfs/ffconf.h",
    "content": "/*---------------------------------------------------------------------------/\n/  FatFs Functional Configurations\n/---------------------------------------------------------------------------*/\n\n#define FFCONF_DEF\t86604\t/* Revision ID */\n\n/*---------------------------------------------------------------------------/\n/ Function Configurations\n/---------------------------------------------------------------------------*/\n\n#define FF_FS_READONLY\t0\n/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)\n/  Read-only configuration removes writing API functions, f_write(), f_sync(),\n/  f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()\n/  and optional writing functions as well. */\n\n\n#define FF_FS_MINIMIZE\t0\n/* This option defines minimization level to remove some basic API functions.\n/\n/   0: Basic functions are fully enabled.\n/   1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()\n/      are removed.\n/   2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.\n/   3: f_lseek() function is removed in addition to 2. */\n\n\n#define FF_USE_STRFUNC\t2\n/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().\n/\n/  0: Disable string functions.\n/  1: Enable without LF-CRLF conversion.\n/  2: Enable with LF-CRLF conversion. */\n\n\n#define FF_USE_FIND\t\t1\n/* This option switches filtered directory read functions, f_findfirst() and\n/  f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */\n\n\n#define FF_USE_MKFS\t\t0\n/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */\n\n\n#if FF_USE_MKFS\n#define FF_MKFS_LABEL \"SWITCH SD  \"\n#endif\n/* This sets FAT/FAT32 label. Exactly 11 characters, all caps. */\n\n\n#define FF_USE_FASTSEEK\t0\n/* This option switches fast seek function. (0:Disable or 1:Enable) */\n\n\n#define FF_FASTFS 0\n#if FF_FASTFS\n#undef FF_USE_FASTSEEK\n#define FF_USE_FASTSEEK\t1\n#endif\n/* This option switches fast access to chained clusters. (0:Disable or 1:Enable) */\n\n\n#define FF_SIMPLE_GPT 1\n/* This option switches support for the first GPT partition. (0:Disable or 1:Enable) */\n\n\n#define FF_USE_EXPAND\t0\n/* This option switches f_expand function. (0:Disable or 1:Enable) */\n\n\n#define FF_USE_CHMOD\t1\n/* This option switches attribute manipulation functions, f_chmod() and f_utime().\n/  (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */\n\n\n#define FF_USE_LABEL\t0\n/* This option switches volume label functions, f_getlabel() and f_setlabel().\n/  (0:Disable or 1:Enable) */\n\n\n#define FF_USE_FORWARD\t0\n/* This option switches f_forward() function. (0:Disable or 1:Enable) */\n\n\n/*---------------------------------------------------------------------------/\n/ Locale and Namespace Configurations\n/---------------------------------------------------------------------------*/\n\n#define FF_CODE_PAGE\t850\n/* This option specifies the OEM code page to be used on the target system.\n/  Incorrect code page setting can cause a file open failure.\n/\n/   437 - U.S.\n/   720 - Arabic\n/   737 - Greek\n/   771 - KBL\n/   775 - Baltic\n/   850 - Latin 1\n/   852 - Latin 2\n/   855 - Cyrillic\n/   857 - Turkish\n/   860 - Portuguese\n/   861 - Icelandic\n/   862 - Hebrew\n/   863 - Canadian French\n/   864 - Arabic\n/   865 - Nordic\n/   866 - Russian\n/   869 - Greek 2\n/   932 - Japanese (DBCS)\n/   936 - Simplified Chinese (DBCS)\n/   949 - Korean (DBCS)\n/   950 - Traditional Chinese (DBCS)\n/     0 - Include all code pages above and configured by f_setcp()\n*/\n\n\n#define FF_USE_LFN\t\t3\n#define FF_MAX_LFN\t\t255\n/* The FF_USE_LFN switches the support for LFN (long file name).\n/\n/   0: Disable LFN. FF_MAX_LFN has no effect.\n/   1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.\n/   2: Enable LFN with dynamic working buffer on the STACK.\n/   3: Enable LFN with dynamic working buffer on the HEAP.\n/\n/  To enable the LFN, ffunicode.c needs to be added to the project. The LFN function\n/  requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and\n/  additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.\n/  The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can\n/  be in range of 12 to 255. It is recommended to be set 255 to fully support LFN\n/  specification.\n/  When use stack for the working buffer, take care on stack overflow. When use heap\n/  memory for the working buffer, memory management functions, ff_memalloc() and\n/  ff_memfree() in ffsystem.c, need to be added to the project. */\n\n\n#define FF_LFN_UNICODE\t0\n/* This option switches the character encoding on the API when LFN is enabled.\n/\n/   0: ANSI/OEM in current CP (TCHAR = char)\n/   1: Unicode in UTF-16 (TCHAR = WCHAR)\n/   2: Unicode in UTF-8 (TCHAR = char)\n/   3: Unicode in UTF-32 (TCHAR = DWORD)\n/\n/  Also behavior of string I/O functions will be affected by this option.\n/  When LFN is not enabled, this option has no effect. */\n\n\n#define FF_LFN_BUF\t\t255\n#define FF_SFN_BUF\t\t12\n/* This set of options defines size of file name members in the FILINFO structure\n/  which is used to read out directory items. These values should be suffcient for\n/  the file names to read. The maximum possible length of the read file name depends\n/  on character encoding. When LFN is not enabled, these options have no effect. */\n\n\n#define FF_STRF_ENCODE\t0\n/* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(),\n/  f_putc(), f_puts and f_printf() convert the character encoding in it.\n/  This option selects assumption of character encoding ON THE FILE to be\n/  read/written via those functions.\n/\n/   0: ANSI/OEM in current CP\n/   1: Unicode in UTF-16LE\n/   2: Unicode in UTF-16BE\n/   3: Unicode in UTF-8\n*/\n\n\n#define FF_FS_RPATH\t\t0\n/* This option configures support for relative path.\n/\n/   0: Disable relative path and remove related functions.\n/   1: Enable relative path. f_chdir() and f_chdrive() are available.\n/   2: f_getcwd() function is available in addition to 1.\n*/\n\n\n/*---------------------------------------------------------------------------/\n/ Drive/Volume Configurations\n/---------------------------------------------------------------------------*/\n\n#define FF_VOLUMES\t\t1\n/* Number of volumes (logical drives) to be used. (1-10) */\n\n\n#define FF_STR_VOLUME_ID\t0\n#define FF_VOLUME_STRS\t\t\"sd\"\n/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings.\n/  When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive\n/  number in the path name. FF_VOLUME_STRS defines the volume ID strings for each\n/  logical drives. Number of items must not be less than FF_VOLUMES. Valid\n/  characters for the volume ID strings are A-Z, a-z and 0-9, however, they are\n/  compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is\n/  not defined, a user defined volume string table needs to be defined as:\n/\n/  const char* VolumeStr[FF_VOLUMES] = {\"ram\",\"flash\",\"sd\",\"usb\",...\n/  Order is important! Any change to order, must also be reflected to diskio drive enum.\n*/\n\n\n#define FF_MULTI_PARTITION\t0\n/* This option switches support for multiple volumes on the physical drive.\n/  By default (0), each logical drive number is bound to the same physical drive\n/  number and only an FAT volume found on the physical drive will be mounted.\n/  When this function is enabled (1), each logical drive number can be bound to\n/  arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()\n/  funciton will be available. */\n\n\n#define FF_MIN_SS\t\t512\n#define FF_MAX_SS\t\t512\n/* This set of options configures the range of sector size to be supported. (512,\n/  1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and\n/  harddisk. But a larger value may be required for on-board flash memory and some\n/  type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured\n/  for variable sector size mode and disk_ioctl() function needs to implement\n/  GET_SECTOR_SIZE command. */\n\n\n#define FF_USE_TRIM\t\t0\n/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable)\n/  To enable Trim function, also CTRL_TRIM command should be implemented to the\n/  disk_ioctl() function. */\n\n\n#define FF_FS_NOFSINFO\t1\n/* If you need to know correct free space on the FAT32 volume, set bit 0 of this\n/  option, and f_getfree() function at first time after volume mount will force\n/  a full FAT scan. Bit 1 controls the use of last allocated cluster number.\n/\n/  bit0=0: Use free cluster count in the FSINFO if available.\n/  bit0=1: Do not trust free cluster count in the FSINFO.\n/  bit1=0: Use last allocated cluster number in the FSINFO if available.\n/  bit1=1: Do not trust last allocated cluster number in the FSINFO.\n*/\n\n\n\n/*---------------------------------------------------------------------------/\n/ System Configurations\n/---------------------------------------------------------------------------*/\n\n#define FF_FS_TINY\t\t0\n/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)\n/  At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes.\n/  Instead of private sector buffer eliminated from the file object, common sector\n/  buffer in the filesystem object (FATFS) is used for the file data transfer. */\n\n\n#define FF_FS_EXFAT\t\t1\n/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)\n/  To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)\n/  Note that enabling exFAT discards ANSI C (C89) compatibility. */\n\n\n#define FF_FS_NORTC\t\t1\n#define FF_NORTC_MON\t1\n#define FF_NORTC_MDAY\t1\n#define FF_NORTC_YEAR\t2026\n/* The option FF_FS_NORTC switches timestamp function. If the system does not have\n/  any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable\n/  the timestamp function. Every object modified by FatFs will have a fixed timestamp\n/  defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.\n/  To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be\n/  added to the project to read current time form real-time clock. FF_NORTC_MON,\n/  FF_NORTC_MDAY and FF_NORTC_YEAR have no effect.\n/  These options have no effect at read-only configuration (FF_FS_READONLY = 1). */\n\n\n#define FF_FS_LOCK\t\t0\n/* The option FF_FS_LOCK switches file lock function to control duplicated file open\n/  and illegal operation to open objects. This option must be 0 when FF_FS_READONLY\n/  is 1.\n/\n/  0:  Disable file lock function. To avoid volume corruption, application program\n/      should avoid illegal open, remove and rename to the open objects.\n/  >0: Enable file lock function. The value defines how many files/sub-directories\n/      can be opened simultaneously under file lock control. Note that the file\n/      lock control is independent of re-entrancy. */\n\n\n/* #include <somertos.h>\t// O/S definitions */\n#define FF_FS_REENTRANT\t0\n#define FF_FS_TIMEOUT\t1000\n#define FF_SYNC_t\t\tHANDLE\n/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs\n/  module itself. Note that regardless of this option, file access to different\n/  volume is always re-entrant and volume control functions, f_mount(), f_mkfs()\n/  and f_fdisk() function, are always not re-entrant. Only file/directory access\n/  to the same volume is under control of this function.\n/\n/   0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect.\n/   1: Enable re-entrancy. Also user provided synchronization handlers,\n/      ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()\n/      function, must be added to the project. Samples are available in\n/      option/syscall.c.\n/\n/  The FF_FS_TIMEOUT defines timeout period in unit of time tick.\n/  The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,\n/  SemaphoreHandle_t and etc. A header file for O/S definitions needs to be\n/  included somewhere in the scope of ff.h. */\n\n\n\n/*--- End of configuration options ---*/\n"
  },
  {
    "path": "bootloader/link.ld",
    "content": "ENTRY(_start)\n\nSECTIONS {\n\tPROVIDE(__ipl_start = IPL_LOAD_ADDR);\n\t. = __ipl_start;\n\t.text : {\n\t\t*(.text._start);\n\t\tKEEP(*(._boot_cfg));\n\t\tKEEP(*(._ipl_version));\n\t\t*(.text._irq_setup);\n\t\t*(.text*);\n\t}\n\t.data : {\n\t\t*(.data*);\n\t\t*(.rodata*);\n\t}\n\t. = ALIGN(0x10);\n\t__ipl_end = .;\n\t.bss : {\n\t\t__bss_start = .;\n\t\t*(COMMON)\n\t\t*(.bss*)\n\t\t__bss_end = .;\n\t}\n}\n"
  },
  {
    "path": "bootloader/main.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n *\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n#include <stdlib.h>\n\n#include <bdk.h>\n\n#include \"config.h\"\n#include \"gfx/logos.h\"\n#include \"gfx/tui.h\"\n#include \"hos/hos.h\"\n#include \"hos/secmon_exo.h\"\n#include \"l4t/l4t.h\"\n#include <ianos/ianos.h>\n#include <libs/compr/blz.h>\n#include <libs/fatfs/ff.h>\n#include \"storage/emummc.h\"\n\n#include \"frontend/fe_tools.h\"\n#include \"frontend/fe_info.h\"\n\nhekate_config h_cfg;\nboot_cfg_t __attribute__((section (\"._boot_cfg\"))) b_cfg;\nconst volatile ipl_ver_meta_t __attribute__((section (\"._ipl_version\"))) ipl_ver = {\n\t.magic             = BL_MAGIC,\n\t.version           = (BL_VER_MJ + '0') | ((BL_VER_MN + '0') << 8) | ((BL_VER_HF + '0') << 16) | ((BL_VER_RL) << 24),\n\t.rcfg.rsvd_flags   = 0,\n\t.rcfg.bclk_t210    = BPMP_CLK_LOWER_BOOST,\n\t.rcfg.bclk_t210b01 = BPMP_CLK_DEFAULT_BOOST\n};\n\nvolatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR;\n\nstatic void _check_power_off_from_hos()\n{\n\t// Power off on alarm wakeup from HOS shutdown. For modchips/dongles.\n\tu8 hos_wakeup = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_IRQTOP);\n\n\t// Clear RTC interrupts.\n\t(void)i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_RTCINT_REG);\n\n\t// Stop the alarm, in case we injected and powered off too fast.\n\tmax77620_rtc_stop_alarm();\n\n\t// Handle RTC wake up.\n\tif (hos_wakeup & MAX77620_IRQ_TOP_RTC_MASK)\n\t{\n\t\tif (h_cfg.autohosoff == 1)\n\t\t{\n\t\t\trender_static_bootlogo();\n\n\t\t\tif (display_get_decoded_panel_id() != PANEL_SAM_AMS699VC01)\n\t\t\t{\n\t\t\t\t// Slow fading for LCD panels.\n\t\t\t\tdisplay_backlight_brightness(10,  5000);\n\t\t\t\tdisplay_backlight_brightness(100, 25000);\n\t\t\t\tmsleep(600);\n\t\t\t\tdisplay_backlight_brightness(0,   20000);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Blink 3 times for OLED panel.\n\t\t\t\tfor (u32 i = 0; i < 3; i++)\n\t\t\t\t{\n\t\t\t\t\tmsleep(150);\n\t\t\t\t\tdisplay_backlight_brightness(100, 0);\n\t\t\t\t\tmsleep(150);\n\t\t\t\t\tdisplay_backlight_brightness(0,   0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tpower_set_state(POWER_OFF_RESET);\n\t}\n}\n\n// This is a safe and unused DRAM region for our payloads.\n#define RELOC_META_OFF      0x7C\n#define PATCHED_RELOC_SZ    0x94\n#define VERSION_RCFG_OFF    0x120\n#define PATCHED_RELOC_STACK 0x40007000\n#define PATCHED_RELOC_ENTRY 0x40010000\n#define EXT_PAYLOAD_ADDR    0xC0000000\n#define RCM_PAYLOAD_ADDR    (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))\n\nstatic void _reloc_append(u32 payload_dst, u32 payload_src, u32 payload_size)\n{\n\tmemcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ);\n\n\tvolatile reloc_meta_t *relocator = (reloc_meta_t *)(payload_src + RELOC_META_OFF);\n\n\trelocator->start = payload_dst - ALIGN(PATCHED_RELOC_SZ, 0x10);\n\trelocator->stack = PATCHED_RELOC_STACK;\n\trelocator->end   = payload_dst + payload_size;\n\trelocator->ep    = payload_dst;\n}\n\nbool is_ipl_updated(void *buf, u32 size, const char *path, bool force)\n{\n\tipl_ver_meta_t *update_ft = (ipl_ver_meta_t *)(buf + PATCHED_RELOC_SZ + sizeof(boot_cfg_t));\n\n\tbool magic_valid  = update_ft->magic == ipl_ver.magic;\n\tbool force_update = force && !magic_valid;\n\tbool is_valid_old = magic_valid && (byte_swap_32(update_ft->version) < byte_swap_32(ipl_ver.version));\n\n\t// Check if newer version.\n\tif (!force && magic_valid)\n\t{\n\t\t// Copy reserved config.\n\t\tif (size && !is_valid_old && memcmp((u8 *)(IPL_LOAD_ADDR + VERSION_RCFG_OFF), (u8 *)(buf + VERSION_RCFG_OFF), sizeof(rsvd_cfg_t)))\n\t\t{\n\t\t\tmemcpy((u8 *)(buf + VERSION_RCFG_OFF), (u8 *)(IPL_LOAD_ADDR + VERSION_RCFG_OFF), sizeof(rsvd_cfg_t));\n\t\t\tsd_save_to_file(buf, size, path);\n\t\t}\n\n\t\tif (byte_swap_32(update_ft->version) > byte_swap_32(ipl_ver.version))\n\t\t\treturn false;\n\t}\n\n\t// Update if old or broken.\n\tif (force_update || is_valid_old)\n\t{\n\t\tboot_cfg_t tmp_cfg;\n\t\treloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF);\n\n\t\t// Reset boot storage configuration.\n\t\tmemcpy(&tmp_cfg, (u8 *)(reloc->start + PATCHED_RELOC_SZ), sizeof(boot_cfg_t));\n\t\tmemset((u8 *)(reloc->start + PATCHED_RELOC_SZ), 0, sizeof(boot_cfg_t));\n\n\t\tsd_save_to_file((u8 *)reloc->start, reloc->end - reloc->start, path);\n\n\t\t// Restore boot storage configuration.\n\t\tmemcpy((u8 *)(reloc->start + PATCHED_RELOC_SZ), &tmp_cfg, sizeof(boot_cfg_t));\n\t}\n\n\treturn true;\n}\n\nstatic void _launch_payload(char *path, bool update, bool clear_screen)\n{\n\tif (clear_screen)\n\t\tgfx_clear_grey(0x1B);\n\tgfx_con_setpos(0, 0);\n\n\t// Read payload.\n\tu32 size = 0;\n\tvoid *buf = sd_file_read(path, &size);\n\tif (!buf)\n\t{\n\t\tgfx_con.mute = false;\n\t\tEPRINTFARGS(\"Payload file is missing!\\n(%s)\", path);\n\n\t\tgoto out;\n\t}\n\n\tif (update && is_ipl_updated(buf, size, path, false))\n\t\tgoto out;\n\n\t// Check if it safely fits IRAM.\n\tif (size > 0x30000)\n\t{\n\t\tgfx_con.mute = false;\n\t\tEPRINTF(\"Payload is too big!\");\n\n\t\tgoto out;\n\t}\n\n\tsd_end();\n\n\t// Copy the payload to our chosen address.\n\tmemcpy((void *)RCM_PAYLOAD_ADDR, buf, size);\n\n\t// Append relocator or set config.\n\tvoid (*payload_ptr)();\n\tif (!update)\n\t{\n\t\t_reloc_append(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10));\n\n\t\tpayload_ptr = (void *)EXT_PAYLOAD_ADDR;\n\t}\n\telse\n\t{\n\t\tmemcpy((u8 *)(RCM_PAYLOAD_ADDR + PATCHED_RELOC_SZ), &b_cfg, sizeof(boot_cfg_t)); // Transfer boot cfg.\n\n\t\t// Set updated flag to skip check on launch.\n\t\tEMC(EMC_SCRATCH0) |= EMC_HEKA_UPD;\n\n\t\tpayload_ptr = (void *)RCM_PAYLOAD_ADDR;\n\t}\n\n\thw_deinit(false);\n\n\t// Launch our payload.\n\t(*payload_ptr)();\n\nout:\n\tfree(buf);\n\tif (!update)\n\t{\n\t\tgfx_con.mute = false;\n\t\tEPRINTF(\"Failed to launch payload!\");\n\t}\n}\n\nstatic void _launch_payloads()\n{\n\tu8 max_entries = 61;\n\tment_t *ments  = NULL;\n\tchar *file_sec = NULL;\n\tchar *dir = NULL;\n\tdirlist_t *filelist = NULL;\n\n\tgfx_clear_grey(0x1B);\n\tgfx_con_setpos(0, 0);\n\n\tif (sd_mount())\n\t\tgoto failed_sd_mount;\n\n\tments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3));\n\n\tdir = (char *)malloc(256);\n\tmemcpy(dir, \"bootloader/payloads\", 20);\n\n\tfilelist = dirlist(dir, NULL, 0);\n\n\tu32 i = 0;\n\n\tif (filelist)\n\t{\n\t\t// Build configuration menu.\n\t\tments[0].type    = MENT_BACK;\n\t\tments[0].caption = \"Back\";\n\n\t\tments[1].type    = MENT_CHGLINE;\n\n\t\twhile (true)\n\t\t{\n\t\t\tif (i > max_entries || !filelist->name[i])\n\t\t\t\tbreak;\n\t\t\tments[i + 2].type    = INI_CHOICE;\n\t\t\tments[i + 2].caption = filelist->name[i];\n\t\t\tments[i + 2].data    = filelist->name[i];\n\n\t\t\ti++;\n\t\t}\n\t}\n\n\tif (i > 0)\n\t{\n\t\tmemset(&ments[i + 2], 0, sizeof(ment_t));\n\t\tmenu_t menu = { ments, \"Choose a payload\", 0, 0 };\n\n\t\tfile_sec = (char *)tui_do_menu(&menu);\n\n\t\tif (!file_sec)\n\t\t{\n\t\t\tfree(ments);\n\t\t\tfree(dir);\n\t\t\tfree(filelist);\n\t\t\tsd_end();\n\n\t\t\treturn;\n\t\t}\n\t}\n\telse\n\t\tEPRINTF(\"No payloads found.\");\n\n\tif (file_sec)\n\t{\n\t\tmemcpy(dir + strlen(dir), \"/\", 2);\n\t\tmemcpy(dir + strlen(dir), file_sec, strlen(file_sec) + 1);\n\n\t\t_launch_payload(dir, false, true);\n\t}\n\nfailed_sd_mount:\n\tfree(dir);\n\tfree(ments);\n\tfree(filelist);\n\tsd_end();\n\n\tbtn_wait();\n}\n\nstatic void _launch_ini_list()\n{\n\tu8 max_entries = 61;\n\tchar *special_path = NULL;\n\tchar *emummc_path  = NULL;\n\tment_t *ments      = NULL;\n\tini_sec_t *cfg_sec = NULL;\n\n\tLIST_INIT(ini_list_sections);\n\n\tgfx_clear_grey(0x1B);\n\tgfx_con_setpos(0, 0);\n\n\tif (sd_mount())\n\t\tgoto parse_failed;\n\n\t// Check that ini files exist and parse them.\n\tif (ini_parse(&ini_list_sections, \"bootloader/ini\", true))\n\t{\n\t\tEPRINTF(\"No .ini files in bootloader/ini!\");\n\t\tgoto parse_failed;\n\t}\n\n\t// Build configuration menu.\n\tments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3));\n\tments[0].type    = MENT_BACK;\n\tments[0].caption = \"Back\";\n\n\tments[1].type    = MENT_CHGLINE;\n\n\tu32 sec_idx = 2;\n\tLIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_list_sections, link)\n\t{\n\t\tif (ini_sec->type == INI_COMMENT ||\n\t\t\tini_sec->type == INI_NEWLINE ||\n\t\t\t!strcmp(ini_sec->name, \"config\"))\n\t\t\tcontinue;\n\n\t\tments[sec_idx].type    = ini_sec->type;\n\t\tments[sec_idx].caption = ini_sec->name;\n\t\tments[sec_idx].data    = ini_sec;\n\n\t\tif (ini_sec->type == MENT_CAPTION)\n\t\t\tments[sec_idx].color = ini_sec->color;\n\t\tsec_idx++;\n\n\t\tif ((sec_idx - 1) > max_entries)\n\t\t\tbreak;\n\t}\n\n\tif (sec_idx > 2)\n\t{\n\t\tmemset(&ments[sec_idx], 0, sizeof(ment_t));\n\t\tmenu_t menu = {\n\t\t\tments, \"Launch ini entries\", 0, 0\n\t\t};\n\n\t\tcfg_sec = (ini_sec_t *)tui_do_menu(&menu);\n\n\t\tspecial_path = ini_check_special_section(cfg_sec);\n\n\t\tif (cfg_sec && !special_path)\n\t\t{\n\t\t\tLIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link)\n\t\t\t{\n\t\t\t\tif (!strcmp(\"emummc_force_disable\", kv->key))\n\t\t\t\t\th_cfg.emummc_force_disable = atoi(kv->val);\n\t\t\t\telse if (!strcmp(\"emupath\", kv->key))\n\t\t\t\t\temummc_path = kv->val;\n\t\t\t}\n\n\t\t\tif (emummc_path && !emummc_set_path(emummc_path))\n\t\t\t{\n\t\t\t\tEPRINTF(\"emupath is wrong!\");\n\t\t\t\tgoto wrong_emupath;\n\t\t\t}\n\t\t}\n\n\t\tif (!cfg_sec)\n\t\t{\n\t\t\tfree(ments);\n\n\t\t\treturn;\n\t\t}\n\t}\n\telse\n\t\tEPRINTF(\"No extra configs found.\");\n\nparse_failed:\n\tif (!cfg_sec)\n\t\tgoto out;\n\n\tif (special_path)\n\t{\n\t\t// Try to launch Payload or L4T.\n\t\tif (special_path != (char *)-1)\n\t\t\t_launch_payload(special_path, false, true);\n\t\telse\n\t\t{\n\t\t\tu32 entry_idx = 0;\n\t\t\tfor (u32 i = 0; i < sec_idx; i++)\n\t\t\t{\n\t\t\t\tif (ments[i].data == cfg_sec)\n\t\t\t\t{\n\t\t\t\t\tentry_idx = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tlaunch_l4t(cfg_sec, entry_idx, 1, h_cfg.t210b01);\n\t\t}\n\t}\n\telse\n\t{\n\t\thos_launch(cfg_sec);\n\nwrong_emupath:\n\t\tif (emummc_path)\n\t\t{\n\t\t\tsd_mount();\n\t\t\temummc_load_cfg(); // Reload emuMMC config in case of emupath.\n\t\t}\n\t}\n\nout:\n\tfree(ments);\n\n\tbtn_wait();\n}\n\nstatic void _launch_config()\n{\n\tu8 max_entries = 61;\n\tchar *special_path = NULL;\n\tchar *emummc_path  = NULL;\n\n\tment_t *ments      = NULL;\n\tini_sec_t *cfg_sec = NULL;\n\n\tLIST_INIT(ini_sections);\n\n\tgfx_clear_grey(0x1B);\n\tgfx_con_setpos(0, 0);\n\n\tif (sd_mount())\n\t\tgoto parse_failed;\n\n\t// Load emuMMC configuration.\n\temummc_load_cfg();\n\n\t// Parse main configuration.\n\tini_parse(&ini_sections, \"bootloader/hekate_ipl.ini\", false);\n\n\t// Build configuration menu.\n\tments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 6));\n\tments[0].type    = MENT_BACK;\n\tments[0].caption = \"Back\";\n\n\tments[1].type    = MENT_CHGLINE;\n\n\tments[2].type    = MENT_HANDLER;\n\tments[2].caption = \"Payloads...\";\n\tments[2].handler = _launch_payloads;\n\n\tments[3].type    = MENT_HANDLER;\n\tments[3].caption = \"More configs...\";\n\tments[3].handler = _launch_ini_list;\n\n\tments[4].type    = MENT_CHGLINE;\n\n\tu32 sec_idx = 5;\n\tLIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)\n\t{\n\t\tif (ini_sec->type == INI_COMMENT ||\n\t\t\tini_sec->type == INI_NEWLINE ||\n\t\t\t!strcmp(ini_sec->name, \"config\"))\n\t\t\tcontinue;\n\n\t\tments[sec_idx].type    = ini_sec->type;\n\t\tments[sec_idx].caption = ini_sec->name;\n\t\tments[sec_idx].data    = ini_sec;\n\n\t\tif (ini_sec->type == MENT_CAPTION)\n\t\t\tments[sec_idx].color = ini_sec->color;\n\t\tsec_idx++;\n\n\t\tif ((sec_idx - 4) > max_entries)\n\t\t\tbreak;\n\t}\n\n\tif (sec_idx < 6)\n\t{\n\t\tments[sec_idx].type    = MENT_CAPTION;\n\t\tments[sec_idx].caption = \"No main configs found...\";\n\t\tments[sec_idx].color   = TXT_CLR_WARNING;\n\t\tsec_idx++;\n\t}\n\n\tmemset(&ments[sec_idx], 0, sizeof(ment_t));\n\tmenu_t menu = {\n\t\tments, \"Launch configurations\", 0, 0\n\t};\n\n\tcfg_sec = (ini_sec_t *)tui_do_menu(&menu);\n\n\tspecial_path = ini_check_special_section(cfg_sec);\n\n\tif (cfg_sec && !special_path)\n\t{\n\t\tLIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link)\n\t\t{\n\t\t\tif (!strcmp(\"emummc_force_disable\", kv->key))\n\t\t\t\th_cfg.emummc_force_disable = atoi(kv->val);\n\t\t\tif (!strcmp(\"emupath\", kv->key))\n\t\t\t\temummc_path = kv->val;\n\t\t}\n\n\t\tif (emummc_path && !emummc_set_path(emummc_path))\n\t\t{\n\t\t\tEPRINTF(\"emupath is wrong!\");\n\t\t\tgoto wrong_emupath;\n\t\t}\n\t}\n\n\tif (!cfg_sec)\n\t{\n\t\tfree(ments);\n\t\tsd_end();\n\t\treturn;\n\t}\n\nparse_failed:\n\tif (!cfg_sec)\n\t{\n\t\tgfx_printf(\"\\nPress any key...\\n\");\n\t\tgoto out;\n\t}\n\n\tif (special_path)\n\t{\n\t\t// Try to launch Payload or L4T.\n\t\tif (special_path != (char *)-1)\n\t\t\t_launch_payload(special_path, false, true);\n\t\telse\n\t\t{\n\t\t\tu32 entry_idx = 0;\n\t\t\tfor (u32 i = 0; i < sec_idx; i++)\n\t\t\t{\n\t\t\t\tif (ments[i].data == cfg_sec)\n\t\t\t\t{\n\t\t\t\t\tentry_idx = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tlaunch_l4t(cfg_sec, entry_idx, 0, h_cfg.t210b01);\n\t\t}\n\t}\n\telse\n\t{\n\t\thos_launch(cfg_sec);\n\nwrong_emupath:\n\t\tif (emummc_path)\n\t\t{\n\t\t\tsd_mount();\n\t\t\temummc_load_cfg(); // Reload emuMMC config in case of emupath.\n\t\t}\n\t}\n\nout:\n\tsd_end();\n\n\tfree(ments);\n\n\th_cfg.emummc_force_disable = false;\n\n\tbtn_wait();\n}\n\n#define NYX_VER_OFF 0x9C\n\nstatic void _nyx_load_run()\n{\n\tu8 *nyx = sd_file_read(\"bootloader/sys/nyx.bin\", NULL);\n\tif (!nyx)\n\t\treturn;\n\n\tsd_end();\n\n\trender_static_bootlogo();\n\tdisplay_backlight_brightness(h_cfg.backlight, 1000);\n\n\t// Check if Nyx version is old.\n\tu32 expected_nyx_ver = ((NYX_VER_MJ + '0') << 24) | ((NYX_VER_MN + '0') << 16) | ((NYX_VER_HF + '0') << 8);\n\tu32 nyx_ver = byte_swap_32(*(u32 *)(nyx + NYX_VER_OFF)) & 0xFFFFFF00;\n\tif (nyx_ver < expected_nyx_ver)\n\t{\n\t\th_cfg.errors |= ERR_SYSOLD_NYX;\n\n\t\tgfx_con_setpos(0, 0);\n\t\tWPRINTF(\"Old Nyx GUI found! There will be dragons!\\n\");\n\t\tWPRINTF(\"\\nUpdate bootloader folder!\\n\\n\");\n\t\tWPRINTF(\"Press any key...\");\n\n\t\tmsleep(1000);\n\t\tbtn_wait();\n\t}\n\n\t// Set hekate errors.\n\tnyx_str->info.errors = h_cfg.errors;\n\n\t// Set Nyx mode.\n\tnyx_str->cfg = 0;\n\tif (b_cfg.extra_cfg & EXTRA_CFG_NYX_UMS)\n\t{\n\t\tb_cfg.extra_cfg &= ~(EXTRA_CFG_NYX_UMS);\n\n\t\tnyx_str->cfg |= NYX_CFG_UMS;\n\t\tnyx_str->cfg |= b_cfg.ums << 24;\n\t}\n\n\t// Set hekate version used to boot Nyx.\n\tnyx_str->version = ipl_ver.version - 0x303030; // Convert ASCII to numbers.\n\n\t// Set [new] info validation magic.\n\tnyx_str->info.magic    = NYX_NEW_INFO;\n\tnyx_str->info_ex.magic = NYX_NEW_INFO;\n\n\t// Set [new] reserved flags.\n\tnyx_str->info_ex.rsvd_flags = ipl_ver.rcfg.rsvd_flags;\n\n\t// Set [new] SD card initialization and error info.\n\tnyx_str->info.sd_init = sd_get_mode();\n\tu16 *sd_errors = sd_get_error_count();\n\tfor (u32 i = 0; i < 3; i++)\n\t\tnyx_str->info.sd_errors[i] = sd_errors[i];\n\n\t// Set Display ID info.\n\tnyx_str->info.panel_id = display_get_verbose_panel_id();\n\n\treloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF);\n\tmemcpy((u8 *)nyx_str->hekate, (u8 *)reloc->start, reloc->end - reloc->start);\n\n\t// Do one last training.\n\tminerva_periodic_training();\n\n\tbpmp_mmu_disable();\n\tbpmp_clk_rate_set(BPMP_CLK_NORMAL);\n\n\t// Some cards (Sandisk U1), do not like a fast power cycle.\n\tsdmmc_storage_init_wait_sd();\n\n\tvoid (*nyx_ptr)() = (void *)nyx;\n\t(*nyx_ptr)();\n}\n\nvoid launch_nyx()\n{\n\tsd_mount();\n\t_nyx_load_run();\n}\n\nstatic ini_sec_t *_get_ini_sec_from_id(ini_sec_t *ini_sec, char **bootlogoCustomEntry, char **emummc_path)\n{\n\tini_sec_t *cfg_sec = NULL;\n\n\tLIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)\n\t{\n\t\tif (!strcmp(\"id\", kv->key))\n\t\t{\n\t\t\tif (b_cfg.id[0] && kv->val[0] && !strcmp(b_cfg.id, kv->val))\n\t\t\t\tcfg_sec = ini_sec;\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t\tif (!strcmp(\"emupath\", kv->key))\n\t\t\t*emummc_path = kv->val;\n\t\telse if (!strcmp(\"logopath\", kv->key))\n\t\t\t*bootlogoCustomEntry = kv->val;\n\t\telse if (!strcmp(\"emummc_force_disable\", kv->key))\n\t\t\th_cfg.emummc_force_disable = atoi(kv->val);\n\t}\n\tif (!cfg_sec)\n\t{\n\t\t*emummc_path               = NULL;\n\t\t*bootlogoCustomEntry       = NULL;\n\t\th_cfg.emummc_force_disable = false;\n\t}\n\n\treturn cfg_sec;\n}\n\nstatic void _bootloader_corruption_protect()\n{\n\tFILINFO fno;\n\tif (!f_stat(\"bootloader\", &fno))\n\t{\n\t\tif (!h_cfg.bootprotect && (fno.fattrib & AM_ARC))\n\t\t\tf_chmod(\"bootloader\", 0,      AM_ARC);\n\t\telse if (h_cfg.bootprotect && !(fno.fattrib & AM_ARC))\n\t\t\tf_chmod(\"bootloader\", AM_ARC, AM_ARC);\n\t}\n}\n\nstatic void _check_for_updated_bootloader()\n{\n\t// Check if already chainloaded update and clear flag. Otherwise check for updates.\n\tif (EMC(EMC_SCRATCH0) & EMC_HEKA_UPD)\n\t\tEMC(EMC_SCRATCH0) &= ~EMC_HEKA_UPD;\n\telse\n\t{\n\t\t// Check if update.bin exists and is newer and launch it. Otherwise create it.\n\t\tif (!f_stat(\"bootloader/update.bin\", NULL))\n\t\t\t_launch_payload(\"bootloader/update.bin\", true, false);\n\t\telse\n\t\t{\n\t\t\tu8 *buf = zalloc(0x200);\n\t\t\tis_ipl_updated(buf, 0, \"bootloader/update.bin\", true);\n\t\t\tfree(buf);\n\t\t}\n\t}\n}\n\nstatic void _auto_launch()\n{\n\tstruct _bmp_data\n\t{\n\t\tu32 size;\n\t\tu32 size_x;\n\t\tu32 size_y;\n\t\tu32 offset;\n\t\tu32 pos_x;\n\t\tu32 pos_y;\n\t};\n\n\tu32 boot_wait             = h_cfg.bootwait;\n\tu32 boot_entry_id         = 0;\n\tini_sec_t *cfg_sec        = NULL;\n\tchar *emummc_path         = NULL;\n\tchar *bootlogoCustomEntry = NULL;\n\tbool  config_entry_found  = false;\n\n\tbool boot_from_id = (b_cfg.boot_cfg & BOOT_CFG_FROM_ID) && (b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN);\n\tif (boot_from_id)\n\t\tb_cfg.id[7] = 0;\n\n\tif (!(b_cfg.boot_cfg & BOOT_CFG_FROM_LAUNCH))\n\t\tgfx_con.mute = true;\n\n\tLIST_INIT(ini_sections);\n\tLIST_INIT(ini_list_sections);\n\n\t// Load emuMMC configuration.\n\temummc_load_cfg();\n\n\t// Parse hekate main configuration.\n\tif (ini_parse(&ini_sections, \"bootloader/hekate_ipl.ini\", false))\n\t\tgoto out; // Can't load hekate_ipl.ini.\n\n\t// Load configuration.\n\tLIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)\n\t{\n\t\t// Skip other ini entries for autoboot.\n\t\tif (ini_sec->type == INI_CHOICE)\n\t\t{\n\t\t\tif (!config_entry_found && !strcmp(ini_sec->name, \"config\"))\n\t\t\t{\n\t\t\t\tconfig_entry_found = true;\n\t\t\t\tLIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)\n\t\t\t\t{\n\t\t\t\t\tif      (!strcmp(\"autoboot\",      kv->key))\n\t\t\t\t\t\th_cfg.autoboot = atoi(kv->val);\n\t\t\t\t\telse if (!strcmp(\"autoboot_list\", kv->key))\n\t\t\t\t\t\th_cfg.autoboot_list = atoi(kv->val);\n\t\t\t\t\telse if (!strcmp(\"bootwait\",      kv->key))\n\t\t\t\t\t\tboot_wait = atoi(kv->val);\n\t\t\t\t\telse if (!strcmp(\"backlight\",     kv->key))\n\t\t\t\t\t\th_cfg.backlight   = atoi(kv->val);\n\t\t\t\t\telse if (!strcmp(\"noticker\",      kv->key))\n\t\t\t\t\t\th_cfg.noticker    = atoi(kv->val);\n\t\t\t\t\telse if (!strcmp(\"autohosoff\",    kv->key))\n\t\t\t\t\t\th_cfg.autohosoff  = atoi(kv->val);\n\t\t\t\t\telse if (!strcmp(\"autonogc\",      kv->key))\n\t\t\t\t\t\th_cfg.autonogc    = atoi(kv->val);\n\t\t\t\t\telse if (!strcmp(\"updater2p\",     kv->key))\n\t\t\t\t\t\th_cfg.updater2p   = atoi(kv->val);\n\t\t\t\t\telse if (!strcmp(\"bootprotect\",   kv->key))\n\t\t\t\t\t\th_cfg.bootprotect = atoi(kv->val);\n\t\t\t\t}\n\t\t\t\tboot_entry_id++;\n\n\t\t\t\t// Override autoboot.\n\t\t\t\tif (b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN)\n\t\t\t\t{\n\t\t\t\t\th_cfg.autoboot      = b_cfg.autoboot;\n\t\t\t\t\th_cfg.autoboot_list = b_cfg.autoboot_list;\n\t\t\t\t}\n\n\t\t\t\t// Apply bootloader protection against corruption.\n\t\t\t\t_bootloader_corruption_protect();\n\n\t\t\t\t// If ini list, exit here.\n\t\t\t\tif (!boot_from_id && h_cfg.autoboot_list)\n\t\t\t\t\tbreak;\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (boot_from_id)\n\t\t\t\tcfg_sec = _get_ini_sec_from_id(ini_sec, &bootlogoCustomEntry, &emummc_path);\n\t\t\telse if (h_cfg.autoboot == boot_entry_id && config_entry_found)\n\t\t\t{\n\t\t\t\tcfg_sec = ini_sec;\n\t\t\t\tLIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link)\n\t\t\t\t{\n\t\t\t\t\tif (!strcmp(\"logopath\", kv->key))\n\t\t\t\t\t\tbootlogoCustomEntry = kv->val;\n\t\t\t\t\telse if (!strcmp(\"emupath\", kv->key))\n\t\t\t\t\t\temummc_path = kv->val;\n\t\t\t\t\telse if (!strcmp(\"emummc_force_disable\", kv->key))\n\t\t\t\t\t\th_cfg.emummc_force_disable = atoi(kv->val);\n\t\t\t\t\telse if (!strcmp(\"bootwait\", kv->key))\n\t\t\t\t\t\tboot_wait = atoi(kv->val);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (cfg_sec)\n\t\t\t\tbreak;\n\t\t\tboot_entry_id++;\n\t\t}\n\t}\n\n\tif (h_cfg.autohosoff && !(b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN))\n\t\t_check_power_off_from_hos();\n\n\tif (h_cfg.autoboot_list || (boot_from_id && !cfg_sec))\n\t{\n\t\tif (boot_from_id && cfg_sec)\n\t\t\tgoto skip_list;\n\n\t\tcfg_sec = NULL;\n\t\tboot_entry_id = 1;\n\t\tbootlogoCustomEntry = NULL;\n\n\t\tif (ini_parse(&ini_list_sections, \"bootloader/ini\", true))\n\t\t\tgoto skip_list;\n\n\t\tLIST_FOREACH_ENTRY(ini_sec_t, ini_sec_list, &ini_list_sections, link)\n\t\t{\n\t\t\tif (ini_sec_list->type != INI_CHOICE)\n\t\t\t\tcontinue;\n\n\t\t\tif (!strcmp(ini_sec_list->name, \"config\"))\n\t\t\t\tcontinue;\n\n\t\t\tif (boot_from_id)\n\t\t\t\tcfg_sec = _get_ini_sec_from_id(ini_sec_list, &bootlogoCustomEntry, &emummc_path);\n\t\t\telse if (h_cfg.autoboot == boot_entry_id)\n\t\t\t{\n\t\t\t\th_cfg.emummc_force_disable = false;\n\t\t\t\tcfg_sec = ini_sec_list;\n\t\t\t\tLIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link)\n\t\t\t\t{\n\t\t\t\t\tif (!strcmp(\"logopath\", kv->key))\n\t\t\t\t\t\tbootlogoCustomEntry = kv->val;\n\t\t\t\t\telse if (!strcmp(\"emupath\", kv->key))\n\t\t\t\t\t\temummc_path = kv->val;\n\t\t\t\t\telse if (!strcmp(\"emummc_force_disable\", kv->key))\n\t\t\t\t\t\th_cfg.emummc_force_disable = atoi(kv->val);\n\t\t\t\t\telse if (!strcmp(\"bootwait\", kv->key))\n\t\t\t\t\t\tboot_wait = atoi(kv->val);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (cfg_sec)\n\t\t\t\tbreak;\n\t\t\tboot_entry_id++;\n\t\t}\n\t}\n\nskip_list:\n\tif (!cfg_sec)\n\t\tgoto out; // No configurations or auto boot is disabled.\n\n\t// Check if entry is payload or l4t special case.\n\tchar *special_path = ini_check_special_section(cfg_sec);\n\n\tif ((!(b_cfg.boot_cfg & BOOT_CFG_FROM_LAUNCH) && boot_wait) || // Conditional for HOS/Payload.\n\t\t(special_path && special_path == (char *)-1))              // Always show for L4T.\n\t{\n\t\tu32 fsize;\n\t\tu8 *logo_buf = NULL;\n\t\tu8 *bitmap = NULL;\n\t\tstruct _bmp_data bmpData;\n\t\tbool bootlogoFound = false;\n\n\t\t// Check if user set custom logo path at the boot entry.\n\t\tif (bootlogoCustomEntry)\n\t\t\tbitmap = (u8 *)sd_file_read(bootlogoCustomEntry, &fsize);\n\n\t\t// Custom entry bootlogo not found, trying default custom one.\n\t\tif (!bitmap)\n\t\t\tbitmap = (u8 *)sd_file_read(\"bootloader/bootlogo.bmp\", &fsize);\n\n\t\tif (bitmap)\n\t\t{\n\t\t\t// Get values manually to avoid unaligned access.\n\t\t\tbmpData.size = bitmap[2] | bitmap[3] << 8 |\n\t\t\t\tbitmap[4] << 16 | bitmap[5] << 24;\n\t\t\tbmpData.offset = bitmap[10] | bitmap[11] << 8 |\n\t\t\t\tbitmap[12] << 16 | bitmap[13] << 24;\n\t\t\tbmpData.size_x = bitmap[18] | bitmap[19] << 8 |\n\t\t\t\tbitmap[20] << 16 | bitmap[21] << 24;\n\t\t\tbmpData.size_y = bitmap[22] | bitmap[23] << 8 |\n\t\t\t\tbitmap[24] << 16 | bitmap[25] << 24;\n\t\t\t// Sanity check.\n\t\t\tif (bitmap[0] == 'B' &&\n\t\t\t\tbitmap[1] == 'M' &&\n\t\t\t\tbitmap[28] == 32 && // Only 32 bit BMPs allowed.\n\t\t\t\tbmpData.size_x <= 720 &&\n\t\t\t\tbmpData.size_y <= 1280)\n\t\t\t{\n\t\t\t\tif (bmpData.size <= fsize && ((bmpData.size - bmpData.offset) < SZ_4M))\n\t\t\t\t{\n\t\t\t\t\t// Avoid unaligned access from BM 2-byte MAGIC and remove header.\n\t\t\t\t\tlogo_buf = (u8 *)malloc(SZ_4M);\n\t\t\t\t\tmemcpy(logo_buf, bitmap + bmpData.offset, bmpData.size - bmpData.offset);\n\t\t\t\t\tfree(bitmap);\n\t\t\t\t\t// Center logo if res < 720x1280.\n\t\t\t\t\tbmpData.pos_x = (720  - bmpData.size_x) >> 1;\n\t\t\t\t\tbmpData.pos_y = (1280 - bmpData.size_y) >> 1;\n\t\t\t\t\t// Get background color from 1st pixel.\n\t\t\t\t\tif (bmpData.size_x < 720 || bmpData.size_y < 1280)\n\t\t\t\t\t\tgfx_clear_color(*(u32 *)logo_buf);\n\n\t\t\t\t\tbootlogoFound = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\tfree(bitmap);\n\t\t}\n\n\t\t// Clamp value to default if it exceeds 20s to protect against corruption.\n\t\tif (boot_wait > 20)\n\t\t\tboot_wait = 3;\n\n\t\t// Render boot logo.\n\t\tif (bootlogoFound)\n\t\t{\n\t\t\tgfx_render_bmp_argb((u32 *)logo_buf, bmpData.size_x, bmpData.size_y,\n\t\t\t\tbmpData.pos_x, bmpData.pos_y);\n\t\t\tfree(logo_buf);\n\n\t\t\t// Do animated waiting before booting. If VOL- is pressed go into bootloader menu.\n\t\t\tif (render_ticker(boot_wait, h_cfg.backlight, h_cfg.noticker))\n\t\t\t\tgoto out;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Do animated waiting before booting. If VOL- is pressed go into bootloader menu.\n\t\t\tif (render_ticker_logo(boot_wait, h_cfg.backlight))\n\t\t\t\tgoto out;\n\t\t}\n\t}\n\n\tif (b_cfg.boot_cfg & BOOT_CFG_FROM_LAUNCH)\n\t\tdisplay_backlight_brightness(h_cfg.backlight, 0);\n\telse if (btn_read_vol() == BTN_VOL_DOWN) // 0s bootwait VOL- check.\n\t\tgoto out;\n\n\tif (special_path)\n\t{\n\t\t// Try to launch Payload or L4T.\n\t\tif (special_path != (char *)-1)\n\t\t\t_launch_payload(special_path, false, false);\n\t\telse\n\t\t\tlaunch_l4t(cfg_sec, h_cfg.autoboot, h_cfg.autoboot_list, h_cfg.t210b01);\n\t\tgoto error;\n\t}\n\telse\n\t{\n\t\tif (b_cfg.boot_cfg & BOOT_CFG_TO_EMUMMC)\n\t\t\temummc_set_path(b_cfg.emummc_path);\n\t\telse if (emummc_path && !emummc_set_path(emummc_path))\n\t\t{\n\t\t\tgfx_con.mute = false;\n\t\t\tEPRINTF(\"emupath is wrong!\");\n\t\t\tgoto wrong_emupath;\n\t\t}\n\n\t\thos_launch(cfg_sec);\n\nwrong_emupath:\n\t\tif (emummc_path || b_cfg.boot_cfg & BOOT_CFG_TO_EMUMMC)\n\t\t{\n\t\t\tsd_mount();\n\t\t\temummc_load_cfg(); // Reload emuMMC config in case of emupath.\n\t\t}\n\nerror:\n\t\tgfx_con.mute = false;\n\t\tgfx_printf(\"\\nPress any key...\\n\");\n\t\tdisplay_backlight_brightness(h_cfg.backlight, 1000);\n\t\tmsleep(500);\n\t\tbtn_wait();\n\t}\n\nout:\n\tgfx_con.mute = false;\n\n\t// Clear boot reasons from binary.\n\tif (b_cfg.boot_cfg & (BOOT_CFG_FROM_ID | BOOT_CFG_TO_EMUMMC))\n\t\tmemset(b_cfg.xt_str, 0, sizeof(b_cfg.xt_str));\n\th_cfg.emummc_force_disable = false;\n\n\t// L4T: Clear custom boot mode flags from PMC_SCRATCH0.\n\tPMC(APBDEV_PMC_SCRATCH0) &= ~PMC_SCRATCH0_MODE_CUSTOM_ALL;\n\n\t_nyx_load_run();\n}\n\n#define EXCP_EN_ADDR   0x4003FF1C\n#define  EXCP_MAGIC       0x30505645 // \"EVP0\".\n#define EXCP_TYPE_ADDR 0x4003FF18\n#define  EXCP_TYPE_RESET  0x545352   // \"RST\".\n#define  EXCP_TYPE_UNDEF  0x464455   // \"UDF\".\n#define  EXCP_TYPE_PABRT  0x54424150 // \"PABT\".\n#define  EXCP_TYPE_DABRT  0x54424144 // \"DABT\".\n#define  EXCP_TYPE_WDT    0x544457   // \"WDT\".\n#define EXCP_LR_ADDR   0x4003FF14\n\n#define PSTORE_LOG_OFFSET 0x180000\n#define PSTORE_RAM_SIG    0x43474244 // \"DBGC\".\n\ntypedef struct _pstore_buf {\n\tu32 sig;\n\tu32 start;\n\tu32 size;\n} pstore_buf_t;\n\nstatic void _show_errors()\n{\n\tu32 *excp_lr = (u32 *)EXCP_LR_ADDR;\n\tu32 *excp_type = (u32 *)EXCP_TYPE_ADDR;\n\tu32 *excp_enabled = (u32 *)EXCP_EN_ADDR;\n\n\tu32 panic_status = hw_rst_status & 0xFFFFF;\n\n\t// Check for exception error.\n\tif (*excp_enabled == EXCP_MAGIC)\n\t\th_cfg.errors |= ERR_EXCEPTION;\n\n\t// Check for L4T kernel panic.\n\tif (PMC(APBDEV_PMC_SCRATCH37) == PMC_SCRATCH37_KERNEL_PANIC_MAGIC)\n\t{\n\t\t// Set error and clear flag.\n\t\th_cfg.errors |= ERR_L4T_KERNEL;\n\t\tPMC(APBDEV_PMC_SCRATCH37) = 0;\n\t}\n\n\t// Check for watchdog panic.\n\tif (hw_rst_reason == PMC_RST_STATUS_WATCHDOG && panic_status &&\n\t\tpanic_status <= 0xFF && panic_status != 0x20 && panic_status != 0x21)\n\t{\n\t\th_cfg.errors |= ERR_PANIC_CODE;\n\t}\n\n\t// Check if we had a panic while in CFW.\n\tsecmon_exo_check_panic();\n\n\t// Handle errors.\n\tif (h_cfg.errors)\n\t{\n\t\tgfx_clear_grey(0x1B);\n\t\tgfx_con_setpos(0, 0);\n\t\tdisplay_backlight_brightness(150, 1000);\n\n\t\tif (h_cfg.errors & ERR_SD_BOOT_EN)\n\t\t{\n\t\t\tWPRINTF(\"Failed to init or mount SD!\\n\");\n\n\t\t\t// Clear the module bits as to not cram the error screen.\n\t\t\th_cfg.errors &= ~(ERR_LIBSYS_LP0 | ERR_LIBSYS_MTC);\n\t\t}\n\n\t\tif (h_cfg.errors & ERR_LIBSYS_LP0)\n\t\t\tWPRINTF(\"Missing LP0 (sleep) lib!\\n\");\n\t\tif (h_cfg.errors & ERR_LIBSYS_MTC)\n\t\t\tWPRINTF(\"Missing Minerva lib!\\n\");\n\n\t\tif (h_cfg.errors & (ERR_LIBSYS_LP0 | ERR_LIBSYS_MTC))\n\t\t\tWPRINTF(\"\\nUpdate bootloader folder!\\n\\n\");\n\n\t\tif (h_cfg.errors & ERR_EXCEPTION)\n\t\t{\n\t\t\tWPRINTFARGS(\"hekate exception occurred (LR %08X):\\n\", *excp_lr);\n\t\t\tswitch (*excp_type)\n\t\t\t{\n\t\t\tcase EXCP_TYPE_WDT:\n\t\t\t\tWPRINTF(\"Hang detected in LP0/Minerva!\");\n\t\t\t\tbreak;\n\t\t\tcase EXCP_TYPE_RESET:\n\t\t\t\tWPRINTF(\"RESET\");\n\t\t\t\tbreak;\n\t\t\tcase EXCP_TYPE_UNDEF:\n\t\t\t\tWPRINTF(\"UNDEF\");\n\t\t\t\tbreak;\n\t\t\tcase EXCP_TYPE_PABRT:\n\t\t\t\tWPRINTF(\"PABRT\");\n\t\t\t\tbreak;\n\t\t\tcase EXCP_TYPE_DABRT:\n\t\t\t\tWPRINTF(\"DABRT\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tgfx_puts(\"\\n\");\n\n\t\t\t// Clear the exception.\n\t\t\t*excp_enabled = 0;\n\t\t\t*excp_type = 0;\n\t\t}\n\n\t\tif (h_cfg.errors & ERR_L4T_KERNEL)\n\t\t{\n\t\t\tWPRINTF(\"L4T Kernel panic occurred!\\n\");\n\t\t\tif (!(h_cfg.errors & ERR_SD_BOOT_EN))\n\t\t\t{\n\t\t\t\tif (!sd_save_to_file((void *)PSTORE_ADDR, PSTORE_SZ, \"L4T_panic.bin\"))\n\t\t\t\t\tWPRINTF(\"PSTORE saved to L4T_panic.bin\");\n\t\t\t\tpstore_buf_t *buf = (pstore_buf_t *)(PSTORE_ADDR + PSTORE_LOG_OFFSET);\n\t\t\t\tif (buf->sig == PSTORE_RAM_SIG && buf->size && buf->size < 0x80000)\n\t\t\t\t{\n\t\t\t\t\tu32 log_offset = PSTORE_ADDR + PSTORE_LOG_OFFSET + sizeof(pstore_buf_t);\n\t\t\t\t\tif (!sd_save_to_file((void *)log_offset, buf->size, \"L4T_panic.txt\"))\n\t\t\t\t\t\tWPRINTF(\"Log saved to L4T_panic.txt\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tgfx_puts(\"\\n\");\n\t\t}\n\n\t\tif (h_cfg.errors & ERR_PANIC_CODE)\n\t\t{\n\t\t\tu32 r = (hw_rst_status >> 20) & 0xF;\n\t\t\tu32 g = (hw_rst_status >> 24) & 0xF;\n\t\t\tu32 b = (hw_rst_status >> 28) & 0xF;\n\t\t\tr = (r << 16) | (r << 20);\n\t\t\tg = (g << 8)  | (g << 12);\n\t\t\tb = (b << 0)  | (b << 4);\n\t\t\tu32 color = r | g | b;\n\n\t\t\tWPRINTF(\"HOS panic occurred!\\n\");\n\t\t\tgfx_printf(\"Color: %k####%k, Code: %02X\\n\\n\", color, TXT_CLR_DEFAULT, panic_status);\n\t\t}\n\n\t\tWPRINTF(\"Press any key...\");\n\n\t\tmsleep(1000); // Guard against injection VOL+.\n\t\tbtn_wait();\n\t\tmsleep(500);  // Guard against force menu VOL-.\n\t}\n}\n\nstatic void _check_low_battery()\n{\n\tif (h_cfg.devmode)\n\t\tgoto out;\n\n\tint enough_battery;\n\tint batt_volt = 0;\n\tint charge_status = 0;\n\n\t// Enable charger in case it's disabled.\n\tbq24193_enable_charger();\n\n\tbq24193_get_property(BQ24193_ChargeStatus, &charge_status);\n\tmax17050_get_property(MAX17050_AvgVCELL,   &batt_volt);\n\n\tenough_battery = charge_status ? 3300 : 3100;\n\n\t// If battery voltage is enough, exit.\n\tif (batt_volt > enough_battery || !batt_volt)\n\t\tgoto out;\n\n\t// Prepare battery icon resources.\n\tu8 *battery_res = malloc(ALIGN(BATTERY_EMPTY_SIZE, SZ_4K));\n\tblz_uncompress_srcdest(battery_icons_blz, BATTERY_EMPTY_BLZ_SIZE, battery_res, BATTERY_EMPTY_SIZE);\n\n\tu8 *battery_icon     = malloc(0x95A); // 21x38x3\n\tu8 *charging_icon    = malloc(0x2F4); // 21x12x3\n\tu8 *no_charging_icon = zalloc(0x2F4);\n\n\tmemcpy(charging_icon, battery_res, 0x2F4);\n\tmemcpy(battery_icon, battery_res + 0x2F4, 0x95A);\n\n\tu32 battery_icon_y_pos  = 1280 - 16 - BATTERY_EMPTY_BATT_HEIGHT;\n\tu32 charging_icon_y_pos = 1280 - 16 - BATTERY_EMPTY_BATT_HEIGHT - 12 - BATTERY_EMPTY_CHRG_HEIGHT;\n\tfree(battery_res);\n\n\tcharge_status = !charge_status;\n\n\tu32 timer = 0;\n\tbool screen_on = false;\n\twhile (true)\n\t{\n\t\tbpmp_msleep(250);\n\n\t\t// Refresh battery stats.\n\t\tint current_charge_status = 0;\n\t\tbq24193_get_property(BQ24193_ChargeStatus, &current_charge_status);\n\t\tmax17050_get_property(MAX17050_AvgVCELL, &batt_volt);\n\t\tenough_battery = current_charge_status ? 3300 : 3100;\n\n\t\t// If battery voltage is enough, exit.\n\t\tif (batt_volt > enough_battery)\n\t\t\tbreak;\n\n\t\t// Refresh charging icon.\n\t\tif (screen_on && (charge_status != current_charge_status))\n\t\t{\n\t\t\tif (current_charge_status)\n\t\t\t\tgfx_set_rect_rgb(charging_icon,    BATTERY_EMPTY_WIDTH, BATTERY_EMPTY_CHRG_HEIGHT, 16, charging_icon_y_pos);\n\t\t\telse\n\t\t\t\tgfx_set_rect_rgb(no_charging_icon, BATTERY_EMPTY_WIDTH, BATTERY_EMPTY_CHRG_HEIGHT, 16, charging_icon_y_pos);\n\t\t}\n\n\t\t// Check if it's time to turn off display.\n\t\tif (screen_on && timer < get_tmr_ms())\n\t\t{\n\t\t\t// If battery is not charging, power off.\n\t\t\tif (!current_charge_status)\n\t\t\t{\n\t\t\t\tmax77620_low_battery_monitor_config(true);\n\n\t\t\t\t// Handle full hw deinit and power off.\n\t\t\t\tpower_set_state(POWER_OFF_RESET);\n\t\t\t}\n\n\t\t\t// If charging, just disable display.\n\t\t\tdisplay_end();\n\t\t\tscreen_on = false;\n\t\t}\n\n\t\t// Check if charging status changed or Power button was pressed and enable display.\n\t\tif ((charge_status != current_charge_status) || (btn_wait_timeout_single(0, BTN_POWER) & BTN_POWER))\n\t\t{\n\t\t\tif (!screen_on)\n\t\t\t{\n\t\t\t\tdisplay_init();\n\t\t\t\tu32 *fb = display_init_window_a_pitch();\n\t\t\t\tgfx_init_ctxt(fb, 720, 1280, 720);\n\n\t\t\t\tgfx_set_rect_rgb(battery_icon,         BATTERY_EMPTY_WIDTH, BATTERY_EMPTY_BATT_HEIGHT, 16, battery_icon_y_pos);\n\t\t\t\tif (current_charge_status)\n\t\t\t\t\tgfx_set_rect_rgb(charging_icon,    BATTERY_EMPTY_WIDTH, BATTERY_EMPTY_CHRG_HEIGHT, 16, charging_icon_y_pos);\n\t\t\t\telse\n\t\t\t\t\tgfx_set_rect_rgb(no_charging_icon, BATTERY_EMPTY_WIDTH, BATTERY_EMPTY_CHRG_HEIGHT, 16, charging_icon_y_pos);\n\n\t\t\t\tdisplay_backlight_pwm_init();\n\t\t\t\tdisplay_backlight_brightness(100, 1000);\n\n\t\t\t\tscreen_on = true;\n\t\t\t}\n\n\t\t\ttimer = get_tmr_ms() + 15000;\n\t\t}\n\n\t\t// Check if forcefully continuing.\n\t\tif (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))\n\t\t\tbreak;\n\n\t\tcharge_status = current_charge_status;\n\t}\n\n\tif (screen_on)\n\t\tdisplay_end();\n\n\tfree(battery_icon);\n\tfree(charging_icon);\n\tfree(no_charging_icon);\n\nout:\n\t// Re enable Low Battery Monitor shutdown.\n\tmax77620_low_battery_monitor_config(true);\n}\n\nstatic void _r2c_get_config_t210b01()\n{\n\trtc_reboot_reason_t rr;\n\tif (!max77620_rtc_get_reboot_reason(&rr))\n\t\treturn;\n\n\t// Check if reason is actually set.\n\tif (rr.dec.reason != REBOOT_REASON_NOP)\n\t{\n\t\t// Clear boot storage.\n\t\tmemset(&b_cfg, 0, sizeof(boot_cfg_t));\n\n\t\t// Enable boot storage.\n\t\tb_cfg.boot_cfg |= BOOT_CFG_AUTOBOOT_EN;\n\t}\n\n\tswitch (rr.dec.reason)\n\t{\n\tcase REBOOT_REASON_NOP:\n\t\tbreak;\n\tcase REBOOT_REASON_REC:\n\t\tPMC(APBDEV_PMC_SCRATCH0) |= PMC_SCRATCH0_MODE_RECOVERY;\n\tcase REBOOT_REASON_SELF:\n\t\tb_cfg.autoboot      = rr.dec.autoboot_idx;\n\t\tb_cfg.autoboot_list = rr.dec.autoboot_list;\n\t\tbreak;\n\tcase REBOOT_REASON_MENU:\n\t\tbreak;\n\tcase REBOOT_REASON_UMS:\n\t\tb_cfg.extra_cfg |= EXTRA_CFG_NYX_UMS;\n\t\tb_cfg.ums = rr.dec.ums_idx;\n\t\tbreak;\n\tcase REBOOT_REASON_PANIC:\n\t\tPMC(APBDEV_PMC_SCRATCH37) = PMC_SCRATCH37_KERNEL_PANIC_MAGIC;\n\t\tbreak;\n\t}\n}\n\nstatic void _ipl_reload()\n{\n\thw_deinit(false);\n\n\t// Reload hekate.\n\tvoid (*ipl_ptr)() = (void *)IPL_LOAD_ADDR;\n\t(*ipl_ptr)();\n}\n\nstatic void _about()\n{\n\tstatic const char credits[] =\n\t\t\"\\nhekate   (c) 2018,      naehrwert, st4rk\\n\\n\"\n\t\t\"         (c) 2018-2026, CTCaer\\n\\n\"\n\t\t\" ___________________________________________\\n\\n\"\n\t\t\"Thanks to: %kderrek, nedwill, plutoo,\\n\"\n\t\t\"           shuffle2, smea, thexyz, yellows8%k\\n\"\n\t\t\" ___________________________________________\\n\\n\"\n\t\t\"Greetings to: fincs, hexkyz, SciresM,\\n\"\n\t\t\"              Shiny Quagsire, WinterMute\\n\"\n\t\t\" ___________________________________________\\n\\n\"\n\t\t\"Open source and free packages used:\\n\\n\"\n\t\t\" - FatFs R0.13c\\n\"\n\t\t\"   (c) 2006-2018, ChaN\\n\"\n\t\t\"   (c) 2018-2022, CTCaer\\n\\n\"\n\t\t\" - bcl-1.2.0\\n\"\n\t\t\"   (c) 2003-2006, Marcus Geelnard\\n\\n\"\n\t\t\" - blz\\n\"\n\t\t\"   (c) 2018, SciresM\\n\\n\"\n\t\t\" - elfload\\n\"\n\t\t\"   (c) 2014, Owen Shepherd\\n\"\n\t\t\"   (c) 2018, M4xw\\n\"\n\t\t\" ___________________________________________\\n\\n\";\n\tstatic const char octopus[] =\n\t\t\"                         %k___\\n\"\n\t\t\"                      .-'   `'.\\n\"\n\t\t\"                     /         \\\\\\n\"\n\t\t\"                     |         ;\\n\"\n\t\t\"                     |         |           ___.--,\\n\"\n\t\t\"            _.._     |0) = (0) |    _.---'`__.-( (_.\\n\"\n\t\t\"     __.--'`_.. '.__.\\\\    '--. \\\\_.-' ,.--'`     `\\\"\\\"`\\n\"\n\t\t\"    ( ,.--'`   ',__ /./;   ;, '.__.'`    __\\n\"\n\t\t\"    _`) )  .---.__.' / |   |\\\\   \\\\__..--\\\"\\\"  \\\"\\\"\\\"--.,_\\n\"\n\t\t\"   `---' .'.''-._.-'`_./  /\\\\ '.  \\\\ _.--''````'''--._`-.__.'\\n\"\n\t\t\"         | |  .' _.-' |  |  \\\\  \\\\  '.               `----`\\n\"\n\t\t\"          \\\\ \\\\/ .'     \\\\  \\\\   '. '-._)\\n\"\n\t\t\"           \\\\/ /        \\\\  \\\\    `=.__`'-.\\n\"\n\t\t\"           / /\\\\         `) )    / / `\\\"\\\".`\\\\\\n\"\n\t\t\"     , _.-'.'\\\\ \\\\        / /    ( (     / /\\n\"\n\t\t\"      `--'`   ) )    .-'.'      '.'.  | (\\n\"\n\t\t\"             (/`    ( (`          ) )  '-;   %k[switchbrew]%k\\n\"\n\t\t\"              `      '-;         (-'%k\";\n\n\tgfx_clear_grey(0x1B);\n\tgfx_con_setpos(0, 0);\n\n\tgfx_printf(credits, TXT_CLR_CYAN_L, TXT_CLR_DEFAULT);\n\tgfx_con.fntsz = 8;\n\tgfx_printf(octopus, TXT_CLR_CYAN_L, TXT_CLR_TURQUOISE, TXT_CLR_CYAN_L, TXT_CLR_DEFAULT);\n\n\tbtn_wait();\n}\n\nment_t ment_cinfo[] = {\n\tMDEF_BACK(),\n\tMDEF_CHGLINE(),\n\tMDEF_CAPTION(\"---- SoC Info ----\", TXT_CLR_CYAN_L),\n\tMDEF_HANDLER(\"Fuses\", print_fuseinfo),\n\tMDEF_CHGLINE(),\n\tMDEF_CAPTION(\"-- Storage Info --\", TXT_CLR_CYAN_L),\n\tMDEF_HANDLER(\"eMMC\",    print_mmc_info),\n\tMDEF_HANDLER(\"SD Card\", print_sdcard_info),\n\tMDEF_CHGLINE(),\n\tMDEF_CAPTION(\"------ Misc ------\", TXT_CLR_CYAN_L),\n\tMDEF_HANDLER(\"Battery\", print_battery_info),\n\tMDEF_END()\n};\n\nmenu_t menu_cinfo = { ment_cinfo, \"Console Info\", 0, 0 };\n\nment_t ment_tools[] = {\n\tMDEF_BACK(),\n\tMDEF_CHGLINE(),\n\tMDEF_CAPTION(\"-------- Other -------\", TXT_CLR_WARNING),\n\tMDEF_HANDLER(\"AutoRCM\", menu_autorcm),\n\tMDEF_END()\n};\n\nmenu_t menu_tools = { ment_tools, \"Tools\", 0, 0 };\n\npower_state_t STATE_POWER_OFF           = POWER_OFF_RESET;\npower_state_t STATE_REBOOT_RCM          = REBOOT_RCM;\npower_state_t STATE_REBOOT_BYPASS_FUSES = REBOOT_BYPASS_FUSES;\n\nment_t ment_top[] = {\n\tMDEF_HANDLER(\"Launch\", _launch_config),\n\tMDEF_CAPTION(\"---------------\", TXT_CLR_GREY_DM),\n\tMDEF_MENU(\"Tools\",        &menu_tools),\n\tMDEF_MENU(\"Console info\", &menu_cinfo),\n\tMDEF_CAPTION(\"---------------\", TXT_CLR_GREY_DM),\n\tMDEF_HANDLER(\"Reload\", _ipl_reload),\n\tMDEF_HANDLER(\"Load Nyx\", launch_nyx),\n\tMDEF_HANDLER_EX(\"Reboot (OFW)\", &STATE_REBOOT_BYPASS_FUSES, power_set_state_ex),\n\tMDEF_HANDLER_EX(\"Reboot (RCM)\", &STATE_REBOOT_RCM,          power_set_state_ex),\n\tMDEF_HANDLER_EX(\"Power off\",    &STATE_POWER_OFF,           power_set_state_ex),\n\tMDEF_CAPTION(\"---------------\", TXT_CLR_GREY_DM),\n\tMDEF_HANDLER(\"About\", _about),\n\tMDEF_END()\n};\n\nmenu_t menu_top = { ment_top, \"hekate v6.5.2\", 0, 0 };\n\nextern void pivot_stack(u32 stack_top);\n\nvoid ipl_main()\n{\n\t// Override DRAM ID if needed.\n\tif (ipl_ver.rcfg.rsvd_flags & RSVD_FLAG_DRAM_8GB)\n\t\tfuse_force_8gb_dramid();\n\n\t// Do initial HW configuration. This is compatible with consecutive reruns without a reset.\n\thw_init();\n\n\t// Pivot the stack under IPL. (Only max 4KB is needed).\n\tpivot_stack(IPL_LOAD_ADDR);\n\n\t// Place heap at a place outside of L4T/HOS configuration and binaries.\n\theap_init((void *)IPL_HEAP_START);\n\n#ifdef DEBUG_UART_PORT\n\tuart_send(DEBUG_UART_PORT, (u8 *)\"hekate: Hello!\\n\", 15);\n\tuart_wait_xfer(DEBUG_UART_PORT, UART_TX_IDLE);\n#endif\n\n\t// Set bootloader's default configuration.\n\tset_default_configuration();\n\n\t// Check if battery is enough.\n\t_check_low_battery();\n\n\t// Prep RTC regs for read. Needed for T210B01 R2C.\n\tmax77620_rtc_prep_read();\n\n\t// Initialize display.\n\tdisplay_init();\n\n\t// Overclock BPMP.\n\tbpmp_clk_rate_set(h_cfg.t210b01 ? ipl_ver.rcfg.bclk_t210b01 : ipl_ver.rcfg.bclk_t210);\n\n\t// Mount SD Card.\n\tif (sd_mount())\n\t\th_cfg.errors |= ERR_SD_BOOT_EN;\n\n\t// Check if watchdog was fired previously.\n\tif (watchdog_fired())\n\t\tgoto skip_lp0_minerva_config;\n\n\t// Enable watchdog protection to avoid SD corruption based hanging in LP0/Minerva config.\n\twatchdog_start(5000000 / 2, TIMER_FIQENABL_EN); // 5 seconds.\n\n\t// Save sdram lp0 config.\n\tvoid *sdram_params = h_cfg.t210b01 ? sdram_get_params_t210b01() : sdram_get_params_patched();\n\tif (!ianos_static_module(\"bootloader/sys/libsys_lp0.bso\", sdram_params))\n\t\th_cfg.errors |= ERR_LIBSYS_LP0;\n\n\t// Train DRAM and switch to max frequency.\n\tif (minerva_init((minerva_str_t *)&nyx_str->minerva))\n\t\th_cfg.errors |= ERR_LIBSYS_MTC;\n\n\t// Disable watchdog protection.\n\twatchdog_end();\n\nskip_lp0_minerva_config:\n\t// Initialize display window, backlight and gfx console.\n\tu32 *fb = display_init_window_a_pitch();\n\tgfx_init_ctxt(fb, 720, 1280, 720);\n\tgfx_con_init();\n\n\t// Initialize backlight PWM.\n\tdisplay_backlight_pwm_init();\n\t//display_backlight_brightness(h_cfg.backlight, 1000);\n\n\t// Show exceptions, HOS errors, library errors and L4T kernel panics.\n\t_show_errors();\n\n\t// Get R2C config from RTC.\n\tif (h_cfg.t210b01)\n\t\t_r2c_get_config_t210b01();\n\n\t// Load saved configuration and auto boot if enabled.\n\tif (!(h_cfg.errors & ERR_SD_BOOT_EN))\n\t{\n\t\t_check_for_updated_bootloader();\n\t\t_auto_launch();\n\t}\n\n\t// Failed to launch Nyx, unmount SD Card.\n\tsd_end();\n\n\t// Set ram to a freq that doesn't need periodic training.\n\tminerva_change_freq(FREQ_800);\n\n\twhile (true)\n\t\ttui_do_menu(&menu_top);\n\n\t// Halt BPMP if we managed to get out of execution.\n\twhile (true)\n\t\tbpmp_halt();\n}\n"
  },
  {
    "path": "bootloader/start.S",
    "content": "/*\n* Copyright (c) 2018 naehrwert\n*\n* This program is free software; you can redistribute it and/or modify it\n* under the terms and conditions of the GNU General Public License,\n* version 2, as published by the Free Software Foundation.\n*\n* This program is distributed in the hope it will be useful, but WITHOUT\n* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n* more details.\n*\n* You should have received a copy of the GNU General Public License\n* along with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n.section .text._start\n.arm\n\n.extern _reloc_ipl\n.type _reloc_ipl, %function\n\n.extern memset\n.type memset, %function\n\n.extern _irq_setup\n.type _irq_setup, %function\n\n.globl _start\n.type _start, %function\n_start:\n\tADR R0, _start\n\tLDR R1, =__ipl_start\n\tCMP R0, R1\n\tBEQ _real_start\n\n\t/* If we are not in the right location already, copy a relocator to upper IRAM. */\n\tADR R2, _reloc_ipl\n\tLDR R3, =0x4003FF00\n\tMOV R4, #(_real_start - _reloc_ipl)\n_copy_loop:\n\tLDMIA R2!, {R5}\n\tSTMIA R3!, {R5}\n\tSUBS R4, #4\n\tBNE _copy_loop\n\n\t/* Use the relocator to copy ourselves into the right place. */\n\tLDR R2, =__ipl_end\n\tSUB R2, R2, R1\n\tLDR R3, =_real_start\n\tLDR R4, =0x4003FF00\n\tBX R4\n\n_reloc_ipl:\n\tLDMIA R0!, {R4-R7}\n\tSTMIA R1!, {R4-R7}\n\tSUBS R2, #0x10\n\tBNE _reloc_ipl\n\t/* Jump to the relocated entry. */\n\tBX R3\n\n_real_start:\n\t/* Initially, we place our stack under relocator but will move it to under the payload. */\n\t/* This depends on application scope. */\n\tLDR SP, =0x4003FF00\n\tLDR R0, =__bss_start\n\tEOR R1, R1, R1\n\tLDR R2, =__bss_end\n\tSUB R2, R2, R0\n\tBL memset\n\tBL _irq_setup\n\tB .\n\n.globl pivot_stack\n.type pivot_stack, %function\npivot_stack:\n\tMOV SP, R0\n\tBX LR\n"
  },
  {
    "path": "bootloader/storage/emummc.c",
    "content": "/*\n * Copyright (c) 2019-2022 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n#include <stdlib.h>\n\n#include <bdk.h>\n\n#include \"emummc.h\"\n#include \"../config.h\"\n#include <libs/fatfs/ff.h>\n\nemummc_cfg_t emu_cfg = { 0 };\n\nvoid emummc_load_cfg()\n{\n\temu_cfg.enabled = 0;\n\temu_cfg.path = NULL;\n\temu_cfg.sector = 0;\n\temu_cfg.id = 0;\n\temu_cfg.file_based_part_size = 0;\n\temu_cfg.active_part = 0;\n\temu_cfg.fs_ver = 0;\n\tif (!emu_cfg.nintendo_path)\n\t\temu_cfg.nintendo_path = (char *)malloc(0x200);\n\tif (!emu_cfg.emummc_file_based_path)\n\t\temu_cfg.emummc_file_based_path = (char *)malloc(0x200);\n\n\temu_cfg.nintendo_path[0] = 0;\n\temu_cfg.emummc_file_based_path[0] = 0;\n\n\tLIST_INIT(ini_sections);\n\tif (!ini_parse(&ini_sections, \"emuMMC/emummc.ini\", false))\n\t{\n\t\tLIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)\n\t\t{\n\t\t\tif (ini_sec->type == INI_CHOICE)\n\t\t\t{\n\t\t\t\tif (strcmp(ini_sec->name, \"emummc\"))\n\t\t\t\t\tcontinue;\n\n\t\t\t\tLIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)\n\t\t\t\t{\n\t\t\t\t\tif (!strcmp(\"enabled\",            kv->key))\n\t\t\t\t\t\temu_cfg.enabled = atoi(kv->val);\n\t\t\t\t\telse if (!strcmp(\"sector\",        kv->key))\n\t\t\t\t\t\temu_cfg.sector  = strtol(kv->val, NULL, 16);\n\t\t\t\t\telse if (!strcmp(\"id\",            kv->key))\n\t\t\t\t\t\temu_cfg.id      = strtol(kv->val, NULL, 16);\n\t\t\t\t\telse if (!strcmp(\"path\",          kv->key))\n\t\t\t\t\t\temu_cfg.path   = kv->val;\n\t\t\t\t\telse if (!strcmp(\"nintendo_path\", kv->key))\n\t\t\t\t\t\tstrcpy(emu_cfg.nintendo_path, kv->val);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\nbool emummc_set_path(char *path)\n{\n\tFIL fp;\n\tbool found = false;\n\n\tstrcpy(emu_cfg.emummc_file_based_path, path);\n\tstrcat(emu_cfg.emummc_file_based_path, \"/raw_based\");\n\n\tif (!f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ))\n\t{\n\t\tif (!f_read(&fp, &emu_cfg.sector, 4, NULL))\n\t\t\tif (emu_cfg.sector)\n\t\t\t\tfound = true;\n\t}\n\telse\n\t{\n\t\tstrcpy(emu_cfg.emummc_file_based_path, path);\n\t\tstrcat(emu_cfg.emummc_file_based_path, \"/file_based\");\n\n\t\tif (!f_stat(emu_cfg.emummc_file_based_path, NULL))\n\t\t{\n\t\t\temu_cfg.sector = 0;\n\t\t\temu_cfg.path = path;\n\n\t\t\tfound = true;\n\t\t}\n\t}\n\n\tif (found)\n\t{\n\t\temu_cfg.enabled = 1;\n\n\t\t// Get ID from path.\n\t\tu32 id_from_path = 0;\n\t\tu32 path_size = strlen(path);\n\t\tif (path_size >= 4)\n\t\t\tmemcpy(&id_from_path, path + path_size - 4, 4);\n\t\temu_cfg.id = id_from_path;\n\n\t\tstrcpy(emu_cfg.nintendo_path, path);\n\t\tstrcat(emu_cfg.nintendo_path, \"/Nintendo\");\n\t}\n\n\treturn found;\n}\n\nstatic int emummc_raw_get_part_off(int part_idx)\n{\n\tswitch (part_idx)\n\t{\n\tcase 0:\n\t\treturn 2;\n\tcase 1:\n\t\treturn 0;\n\tcase 2:\n\t\treturn 1;\n\t}\n\treturn 2;\n}\n\nint emummc_storage_init_mmc()\n{\n\tFILINFO fno;\n\temu_cfg.active_part = 0;\n\n\t// Always init eMMC even when in emuMMC. eMMC is needed from the emuMMC driver anyway.\n\tif (emmc_initialize(false))\n\t\treturn 2;\n\n\tif (!emu_cfg.enabled || h_cfg.emummc_force_disable)\n\t\treturn 0;\n\n\tif (sd_mount())\n\t\tgoto out;\n\n\tif (!emu_cfg.sector)\n\t{\n\t\tstrcpy(emu_cfg.emummc_file_based_path, emu_cfg.path);\n\t\tstrcat(emu_cfg.emummc_file_based_path, \"/eMMC\");\n\n\t\tif (f_stat(emu_cfg.emummc_file_based_path, &fno))\n\t\t{\n\t\t\tEPRINTF(\"Failed to open eMMC folder.\");\n\t\t\tgoto out;\n\t\t}\n\t\tf_chmod(emu_cfg.emummc_file_based_path, AM_ARC, AM_ARC);\n\n\t\tstrcat(emu_cfg.emummc_file_based_path, \"/00\");\n\t\tif (f_stat(emu_cfg.emummc_file_based_path, &fno))\n\t\t{\n\t\t\tEPRINTF(\"Failed to open emuMMC rawnand.\");\n\t\t\tgoto out;\n\t\t}\n\t\temu_cfg.file_based_part_size = fno.fsize >> 9;\n\t}\n\n\treturn 0;\n\nout:\n\treturn 1;\n}\n\nint emummc_storage_end()\n{\n\tif (!emu_cfg.enabled || h_cfg.emummc_force_disable)\n\t\temmc_end();\n\telse\n\t\tsd_end();\n\n\treturn 0;\n}\n\nint emummc_storage_read(u32 sector, u32 num_sectors, void *buf)\n{\n\tFIL fp;\n\tif (!emu_cfg.enabled || h_cfg.emummc_force_disable)\n\t\treturn sdmmc_storage_read(&emmc_storage, sector, num_sectors, buf);\n\telse if (emu_cfg.sector)\n\t{\n\t\tsector += emu_cfg.sector;\n\t\tsector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000;\n\t\treturn sdmmc_storage_read(&sd_storage, sector, num_sectors, buf);\n\t}\n\telse\n\t{\n\t\tif (!emu_cfg.active_part)\n\t\t{\n\t\t\tu32 file_part = sector / emu_cfg.file_based_part_size;\n\t\t\tsector = sector % emu_cfg.file_based_part_size;\n\t\t\tif (file_part >= 10)\n\t\t\t\titoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10);\n\t\t\telse\n\t\t\t{\n\t\t\t\temu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0';\n\t\t\t\titoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10);\n\t\t\t}\n\t\t}\n\t\tif (f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ))\n\t\t{\n\t\t\tEPRINTF(\"Failed to open emuMMC image.\");\n\t\t\treturn 1;\n\t\t}\n\t\tf_lseek(&fp, (u64)sector << 9);\n\t\tif (f_read(&fp, buf, (u64)num_sectors << 9, NULL))\n\t\t{\n\t\t\tEPRINTF(\"Failed to read emuMMC image.\");\n\t\t\tf_close(&fp);\n\t\t\treturn 1;\n\t\t}\n\n\t\tf_close(&fp);\n\t\treturn 0;\n\t}\n}\n\nint emummc_storage_write(u32 sector, u32 num_sectors, void *buf)\n{\n\tFIL fp;\n\tif (!emu_cfg.enabled || h_cfg.emummc_force_disable)\n\t\treturn sdmmc_storage_write(&emmc_storage, sector, num_sectors, buf);\n\telse if (emu_cfg.sector)\n\t{\n\t\tsector += emu_cfg.sector;\n\t\tsector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000;\n\t\treturn sdmmc_storage_write(&sd_storage, sector, num_sectors, buf);\n\t}\n\telse\n\t{\n\t\tif (!emu_cfg.active_part)\n\t\t{\n\t\t\tu32 file_part = sector / emu_cfg.file_based_part_size;\n\t\t\tsector = sector % emu_cfg.file_based_part_size;\n\t\t\tif (file_part >= 10)\n\t\t\t\titoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10);\n\t\t\telse\n\t\t\t{\n\t\t\t\temu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0';\n\t\t\t\titoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10);\n\t\t\t}\n\t\t}\n\n\t\tif (f_open(&fp, emu_cfg.emummc_file_based_path, FA_WRITE))\n\t\t\treturn 1;\n\n\t\tf_lseek(&fp, (u64)sector << 9);\n\t\tif (f_write(&fp, buf, (u64)num_sectors << 9, NULL))\n\t\t{\n\t\t\tf_close(&fp);\n\t\t\treturn 1;\n\t\t}\n\n\t\tf_close(&fp);\n\t\treturn 0;\n\t}\n}\n\nint emummc_storage_set_mmc_partition(u32 partition)\n{\n\temu_cfg.active_part = partition;\n\temmc_set_partition(partition);\n\n\tif (!emu_cfg.enabled || h_cfg.emummc_force_disable || emu_cfg.sector)\n\t\treturn 0;\n\telse\n\t{\n\t\tstrcpy(emu_cfg.emummc_file_based_path, emu_cfg.path);\n\t\tstrcat(emu_cfg.emummc_file_based_path, \"/eMMC\");\n\n\t\tswitch (partition)\n\t\t{\n\t\tcase 0:\n\t\t\tstrcat(emu_cfg.emummc_file_based_path, \"/00\");\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tstrcat(emu_cfg.emummc_file_based_path, \"/BOOT0\");\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tstrcat(emu_cfg.emummc_file_based_path, \"/BOOT1\");\n\t\t\tbreak;\n\t\t}\n\n\t\treturn 0;\n\t}\n}\n"
  },
  {
    "path": "bootloader/storage/emummc.h",
    "content": "/*\n * Copyright (c) 2019-2021 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef EMUMMC_H\n#define EMUMMC_H\n\n#include <bdk.h>\n\ntypedef enum\n{\n\tEMUMMC_TYPE_NONE      = 0,\n\tEMUMMC_TYPE_PARTITION = 1,\n\tEMUMMC_TYPE_FILES     = 2,\n} emummc_type_t;\n\ntypedef enum {\n\tEMUMMC_MMC_NAND = 0,\n\tEMUMMC_MMC_SD   = 1,\n\tEMUMMC_MMC_GC   = 2,\n} emummc_mmc_t;\n\ntypedef struct _emummc_cfg_t\n{\n\tint   enabled;\n\tu64   sector;\n\tu32   id;\n\tchar *path;\n\tchar *nintendo_path;\n\t// Internal.\n\tchar *emummc_file_based_path;\n\tu32 file_based_part_size;\n\tu32 active_part;\n\tint fs_ver;\n} emummc_cfg_t;\n\nextern emummc_cfg_t emu_cfg;\n\nvoid emummc_load_cfg();\nbool emummc_set_path(char *path);\nint  emummc_storage_init_mmc();\nint  emummc_storage_end();\nint  emummc_storage_read(u32 sector, u32 num_sectors, void *buf);\nint  emummc_storage_write(u32 sector, u32 num_sectors, void *buf);\nint  emummc_storage_set_mmc_partition(u32 partition);\n\n#endif"
  },
  {
    "path": "loader/Makefile",
    "content": "ifeq ($(strip $(DEVKITARM)),)\n$(error \"Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM\")\nendif\n\ninclude $(DEVKITARM)/base_rules\n\n################################################################################\n\nLDR_LOAD_ADDR := 0x40007000\nIPL_MAGIC := 0x43544349 #\"ICTC\"\ninclude ../Versions.inc\n\n################################################################################\n\nTARGET := loader\nBUILDDIR := ../build/$(TARGET)\nOUTPUTDIR := ../output\nBDKDIR := bdk\nBDKINC := -I../$(BDKDIR)\nVPATH += $(dir $(wildcard ../$(BDKDIR)/*/)) $(dir $(wildcard ../$(BDKDIR)/*/*/))\n\n# Main and graphics.\nOBJS = $(addprefix $(BUILDDIR)/, \\\n\tstart.o loader.o lz.o \\\n)\n\n################################################################################\n\nCUSTOMDEFINES := -DBL_MAGIC=$(IPL_MAGIC)\nCUSTOMDEFINES += -DBL_VER_MJ=$(BLVERSION_MAJOR) -DBL_VER_MN=$(BLVERSION_MINOR) -DBL_VER_HF=$(BLVERSION_HOTFX) -DBL_VER_RL=$(BLVERSION_REL)\n\n#TODO: Considering reinstating some of these when pointer warnings have been fixed.\nWARNINGS := -Wall -Wsign-compare -Wno-array-bounds -Wno-stringop-overflow\n\nARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork\nCFLAGS = $(ARCH) -O2 -g -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 $(WARNINGS) $(CUSTOMDEFINES)\nLDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=LDR_LOAD_ADDR=$(LDR_LOAD_ADDR)\n\n################################################################################\n\n.PHONY: all clean\n\nall: $(TARGET).bin $(TOOLSLZ) $(TOOLSB2C)\n\nclean:\n\t@rm -f payload_00.h\n\t@rm -f payload_01.h\n\n$(TARGET).bin: $(BUILDDIR)/$(TARGET).elf\n\t@$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$(PAYLOAD_NAME).bin\n\n$(BUILDDIR)/$(TARGET).elf: $(OBJS)\n\t@$(CC) $(LDFLAGS) -T link.ld $^ -o $@\n\n$(BUILDDIR)/%.o: %.c\n\t@$(CC) $(CFLAGS) $(BDKINC) -c $< -o $@\n\n$(BUILDDIR)/%.o: %.S\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n$(OBJS): $(BUILDDIR)\n\n$(BUILDDIR):\n\t@mkdir -p \"$(BUILDDIR)\"\n\t@mkdir -p \"$(OUTPUTDIR)\"\n"
  },
  {
    "path": "loader/link.ld",
    "content": "ENTRY(_start)\n\nSECTIONS {\n\tPROVIDE(__ipl_start = LDR_LOAD_ADDR);\n\t. = __ipl_start;\n\t.text : {\n\t\t*(.text._start);\n\t\tKEEP(*(._boot_cfg));\n\t\tKEEP(*(._ipl_version));\n\t\tKEEP(*(._octopus));\n\t\t*(.text*);\n\t}\n\t.data : {\n\t\t*(.data*);\n\t\t*(.rodata*);\n\t\t*(._payload_00);\n\t\t*(._payload_01);\n\n\t\t/*\n\t\t * To mitigate bad injectors/chainloaders,\n\t\t * miss-align binary size to account for version info.\n\t\t * !If version text is not appended, then use \". = ALIGN(4)\"!\n\t\t */\n\t\t data_end_ua = .;\n\t\t . = ((data_end_ua + 0x6 + 4 - 1) & ~(4 - 1)) - 6;\n\t}\n\t__ldr_end = .;\n\t. = ALIGN(0x10);\n\t__ipl_end = .;\n}\n"
  },
  {
    "path": "loader/loader.c",
    "content": "/*\n * Copyright (c) 2019-2024 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n#include <stdlib.h>\n\n#include \"payload_00.h\"\n#include \"payload_01.h\"\n\n#include <memory_map.h>\n#include <libs/compr/lz.h>\n#include <soc/bpmp.h>\n#include <soc/clock.h>\n#include <soc/t210.h>\n\n// 0x4003D000: Safe for panic preserving, 0x40038000: Safe for debugging needs.\n#define IPL_RELOC_TOP        0x40038000\n#define IPL_PATCHED_RELOC_SZ 0x94\n#define IPL_VERSION_RCFG_OFF 0x120\n\nboot_cfg_t __attribute__((section (\"._boot_cfg\"))) b_cfg;\nconst volatile ipl_ver_meta_t __attribute__((section (\"._ipl_version\"))) ipl_ver = {\n\t.magic             = BL_MAGIC,\n\t.version           = (BL_VER_MJ + '0') | ((BL_VER_MN + '0') << 8) | ((BL_VER_HF + '0') << 16) | ((BL_VER_RL) << 24),\n\t.rcfg.rsvd_flags   = 0,\n\t.rcfg.bclk_t210    = BPMP_CLK_LOWER_BOOST,\n\t.rcfg.bclk_t210b01 = BPMP_CLK_DEFAULT_BOOST\n};\n\nconst char __attribute__((section (\"._octopus\"))) octopus[] =\n\t\"\\n\"\n\t\"                         ___\\n\"\n\t\"                      .-'   `'.\\n\"\n\t\"                     /         \\\\\\n\"\n\t\"                     |         ;\\n\"\n\t\"                     |         |           ___.--,\\n\"\n\t\"            _.._     |0) = (0) |    _.---'`__.-( (_.\\n\"\n\t\"     __.--'`_.. '.__.\\\\    '--. \\\\_.-' ,.--'`     `\\\"\\\"`\\n\"\n\t\"    ( ,.--'`   ',__ /./;   ;, '.__.'`    __\\n\"\n\t\"    _`) )  .---.__.' / |   |\\\\   \\\\__..--\\\"\\\"  \\\"\\\"\\\"--.,_\\n\"\n\t\"   `---' .'.''-._.-'`_./  /\\\\ '.  \\\\ _.--''````'''--._`-.__.'\\n\"\n\t\"         | |  .' _.-' |  |  \\\\  \\\\  '.               `----`\\n\"\n\t\"          \\\\ \\\\/ .'     \\\\  \\\\   '. '-._)\\n\"\n\t\"           \\\\/ /        \\\\  \\\\    `=.__`'-.\\n\"\n\t\"           / /\\\\         `) )    / / `\\\"\\\".`\\\\\\n\"\n\t\"     , _.-'.'\\\\ \\\\        / /    ( (     / /\\n\"\n\t\"      `--'`   ) )    .-'.'      '.'.  | (\\n\"\n\t\"             (/`    ( (`          ) )  '-;   [switchbrew]\\n\";\n\nvoid loader_main()\n{\n\t// Preliminary BPMP clocks init.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE)    = 0x10;       // Set HCLK div to 2 and PCLK div to 1.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SYS)     = 0;          // Set SCLK div to 1.\n\tCLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY)  = 0x20004444; // Set clk source to Run and PLLP_OUT2 (204MHz).\n\tCLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000; // Enable SUPER_SDIV to 1.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE)    = 2;          // Set HCLK div to 1 and PCLK div to 3.\n\tCLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY)  = 0x20003333; // Set SCLK to PLLP_OUT (408MHz).\n\n\t// Set arbiter.\n\tARB_PRI(ARB_PRIO_CPU_PRIORITY) = 0x12412D1;\n\tARB_PRI(ARB_PRIO_COP_PRIORITY) = 0x0000000;\n\tARB_PRI(ARB_PRIO_VCP_PRIORITY) = 0x220244A;\n\tARB_PRI(ARB_PRIO_DMA_PRIORITY) = 0x320369B;\n\n\t// Get Payload size.\n\tu32 payload_size  = sizeof(payload_00) + sizeof(payload_01);                // Actual payload size.\n\tpayload_size     += (u32)payload_01 - (u32)payload_00 - sizeof(payload_00); // Add compiler alignment.\n\tpayload_size      = ALIGN(payload_size, 4);                                 // Align size to 4 bytes.\n\tu32 *payload_addr = (u32 *)payload_00;\n\n\t// Relocate payload to a safer place.\n\tu32 words = payload_size >> 2;\n\tu32 *src  = payload_addr + words - 1;\n\tu32 *dst  = (u32 *)(IPL_RELOC_TOP - 4);\n\twhile (words)\n\t{\n\t\t*dst = *src;\n\t\tsrc--;\n\t\tdst--;\n\t\twords--;\n\t}\n\n\t// Set source address of the first part.\n\tu8 *src_addr = (void *)(IPL_RELOC_TOP - payload_size);\n\t// Uncompress first part.\n\tu32 dst_pos = LZ_Uncompress((const u8 *)src_addr, (u8 *)IPL_LOAD_ADDR, sizeof(payload_00));\n\n\t// Set source address of the second part. Includes compiler alignment.\n\tsrc_addr += (u32)payload_01 - (u32)payload_00;\n\t// Uncompress second part.\n\tLZ_Uncompress((const u8 *)src_addr, (u8 *)IPL_LOAD_ADDR + dst_pos, sizeof(payload_01));\n\n\t// Copy over boot configuration storage.\n\tmemcpy((u8 *)(IPL_LOAD_ADDR + IPL_PATCHED_RELOC_SZ), &b_cfg, sizeof(boot_cfg_t));\n\n\t// Copy new reserved configuration.\n\tmemcpy((u8 *)(IPL_LOAD_ADDR + IPL_VERSION_RCFG_OFF), (rsvd_cfg_t *)&ipl_ver.rcfg, sizeof(rsvd_cfg_t));\n\n\t// Chainload into uncompressed payload.\n\tvoid (*ipl_ptr)() = (void *)IPL_LOAD_ADDR;\n\t(*ipl_ptr)();\n\n\t// Halt if we managed to get out of execution.\n\twhile (true)\n\t\t;\n}\n"
  },
  {
    "path": "loader/start.S",
    "content": "/*\n* Copyright (c) 2018 naehrwert\n*\n* This program is free software; you can redistribute it and/or modify it\n* under the terms and conditions of the GNU General Public License,\n* version 2, as published by the Free Software Foundation.\n*\n* This program is distributed in the hope it will be useful, but WITHOUT\n* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n* more details.\n*\n* You should have received a copy of the GNU General Public License\n* along with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n.section .text._start\n.arm\n\n.extern _reloc_ipl\n.type _reloc_ipl, %function\n\n.extern memset\n.type memset, %function\n\n.extern loader_main\n.type loader_main, %function\n\n.globl _start\n.type _start, %function\n_start:\n\tADR R0, _start\n\tLDR R1, =__ipl_start\n\tCMP R0, R1\n\tBEQ _real_start\n\n\t/* If we are not in the right location already, copy a relocator to upper IRAM. */\n\tADR R2, _reloc_ipl\n\tLDR R3, =0x4003FF00\n\tMOV R4, #(_real_start - _reloc_ipl)\n_copy_loop:\n\tLDMIA R2!, {R5}\n\tSTMIA R3!, {R5}\n\tSUBS R4, #4\n\tBNE _copy_loop\n\n\t/* Use the relocator to copy ourselves into the right place. */\n\tLDR R2, =__ipl_end\n\tSUB R2, R2, R1\n\tLDR R3, =_real_start\n\tLDR R4, =0x4003FF00\n\tBX R4\n\n_reloc_ipl:\n\tLDMIA R0!, {R4-R7}\n\tSTMIA R1!, {R4-R7}\n\tSUBS R2, #0x10\n\tBNE _reloc_ipl\n\t/* Jump to the relocated entry. */\n\tBX R3\n\n_real_start:\n\t/* Initially, we place our stack in IRAM but will move it to SDRAM later. */\n\tLDR SP, =0x40007000\n\tLDR R0, =__ldr_end\n\tBL loader_main\n\tB .\n\t.word 0\n\t.word 0\n\t.word 0\n\t.word 0\n\t.word 0\n\t.word 0\n"
  },
  {
    "path": "modules/hekate_libsys_lp0/Makefile",
    "content": "ifeq ($(strip $(DEVKITARM)),)\n$(error \"Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM\")\nendif\n\ninclude $(DEVKITARM)/base_rules\n\nTARGET := libsys_lp0\nBUILDDIR := ../../build/$(TARGET)\nOUTPUTDIR := ../../output\nBDKDIR := bdk\nBDKINC := -I../../$(BDKDIR)\n\n# Track compiler flags\nTRACK_CFLAGS = $(BUILDDIR)/.cflags\nTRACK_LDFLAGS = $(BUILDDIR)/.ldflags\n\nOBJS = $(addprefix $(BUILDDIR)/,\\\n\tsys_sdramlp0.o \\\n)\n\nARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork\nCFLAGS = $(ARCH) -O2 -nostdlib -fpie -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 -Wall -Wsign-compare $(CUSTOMDEFINES)\nLDFLAGS = $(ARCH) -fpie -pie -nostartfiles -lgcc -Wl,-z,max-page-size=256\n\n.PHONY: all\n\nall: $(TARGET).bso\n$(BUILDDIR)/%.o: ./%.c $(TRACK_CFLAGS)\n\t@$(CC) $(CFLAGS) $(BDKINC) -MMD -MP -c $< -o $@\n\n$(TARGET).bso: $(OBJS) $(TRACK_LDFLAGS)\n\t@$(CC) $(LDFLAGS) -e sdram_lp0_entry $(OBJS) -o $(OUTPUTDIR)/$(TARGET).bso\n\t@$(STRIP) -g $(OUTPUTDIR)/$(TARGET).bso\n\t@echo \"Built module: \"$(TARGET)\".bso\"\n\n$(BUILDDIR):\n\t@mkdir -p \"$(BUILDDIR)\"\n\n# Non objects change detectors.\n$(TRACK_CFLAGS): $(BUILDDIR)\n\t@echo '$(CFLAGS)' | cmp -s - $@ || echo '$(CFLAGS)' > $@\n$(TRACK_LDFLAGS): $(BUILDDIR)\n\t@echo '$(LDFLAGS)' | cmp -s - $@ || echo '$(LDFLAGS)' > $@\n-include $(OBJS:.o=.d)\n"
  },
  {
    "path": "modules/hekate_libsys_lp0/pmc_t210.h",
    "content": "/*\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n */\n\n#ifndef _PMC_T210_H_\n#define _PMC_T210_H_\n\n#include \"types.h\"\n\ntypedef struct _pmc_regs_t210_t  {\n/* 0x000 */\tu32 pmc_cntrl;\n/* 0x004 */\tu32 pmc_sec_disable;\n/* 0x008 */\tu32 pmc_pmc_swrst;\n/* 0x00c */\tu32 pmc_wake_mask;\n/* 0x010 */\tu32 pmc_wake_lvl;\n/* 0x014 */\tu32 pmc_wake_status;\n/* 0x018 */\tu32 pmc_sw_wake_status;\n/* 0x01c */\tu32 pmc_dpd_pads_oride;\n/* 0x020 */\tu32 pmc_dpd_sample;\n/* 0x024 */\tu32 pmc_dpd_enable;\n/* 0x028 */\tu32 pmc_pwrgate_timer_off;\n/* 0x02c */\tu32 pmc_clamp_status;\n/* 0x030 */\tu32 pmc_pwrgate_toggle;\n/* 0x034 */\tu32 pmc_remove_clamping_cmd;\n/* 0x038 */\tu32 pmc_pwrgate_status;\n/* 0x03c */\tu32 pmc_pwrgood_timer;\n/* 0x040 */\tu32 pmc_blink_timer;\n/* 0x044 */\tu32 pmc_no_iopower;\n/* 0x048 */\tu32 pmc_pwr_det;\n/* 0x04c */\tu32 pmc_pwr_det_latch;\n/* 0x050 */\tu32 pmc_scratch0;\n/* 0x054 */\tu32 pmc_scratch1;\n/* 0x058 */\tu32 pmc_scratch2;\n/* 0x05c */\tu32 pmc_scratch3;\n/* 0x060 */\tu32 pmc_scratch4;\n/* 0x064 */\tu32 pmc_scratch5;\n/* 0x068 */\tu32 pmc_scratch6;\n/* 0x06c */\tu32 pmc_scratch7;\n/* 0x070 */\tu32 pmc_scratch8;\n/* 0x074 */\tu32 pmc_scratch9;\n/* 0x078 */\tu32 pmc_scratch10;\n/* 0x07c */\tu32 pmc_scratch11;\n/* 0x080 */\tu32 pmc_scratch12;\n/* 0x084 */\tu32 pmc_scratch13;\n/* 0x088 */\tu32 pmc_scratch14;\n/* 0x08c */\tu32 pmc_scratch15;\n/* 0x090 */\tu32 pmc_scratch16;\n/* 0x094 */\tu32 pmc_scratch17;\n/* 0x098 */\tu32 pmc_scratch18;\n/* 0x09c */\tu32 pmc_scratch19;\n/* 0x0a0 */\tu32 pmc_scratch20; // ODM data/config scratch.\n/* 0x0a4 */\tu32 pmc_scratch21;\n/* 0x0a8 */\tu32 pmc_scratch22;\n/* 0x0ac */\tu32 pmc_scratch23;\n/* 0x0b0 */\tu32 pmc_secure_scratch0;\n/* 0x0b4 */\tu32 pmc_secure_scratch1;\n/* 0x0b8 */\tu32 pmc_secure_scratch2;\n/* 0x0bc */\tu32 pmc_secure_scratch3;\n/* 0x0c0 */\tu32 pmc_secure_scratch4;\n/* 0x0c4 */\tu32 pmc_secure_scratch5;\n/* 0x0c8 */\tu32 pmc_cpupwrgood_timer;\n/* 0x0cc */\tu32 pmc_cpupwroff_timer;\n/* 0x0d0 */\tu32 pmc_pg_mask;\n/* 0x0d4 */\tu32 pmc_pg_mask_1;\n/* 0x0d8 */\tu32 pmc_auto_wake_lvl;\n/* 0x0dc */\tu32 pmc_auto_wake_lvl_mask;\n/* 0x0e0 */\tu32 pmc_wake_delay;\n/* 0x0e4 */\tu32 pmc_pwr_det_val;\n/* 0x0e8 */\tu32 pmc_ddr_pwr;\n/* 0x0ec */\tu32 pmc_usb_debounce_del;\n/* 0x0f0 */\tu32 pmc_usb_ao;\n/* 0x0f4 */\tu32 pmc_crypto_op;\n/* 0x0f8 */\tu32 pmc_pllp_wb0_override;\n/* 0x0fc */\tu32 pmc_scratch24;\n/* 0x100 */\tu32 pmc_scratch25;\n/* 0x104 */\tu32 pmc_scratch26;\n/* 0x108 */\tu32 pmc_scratch27;\n/* 0x10c */\tu32 pmc_scratch28;\n/* 0x110 */\tu32 pmc_scratch29;\n/* 0x114 */\tu32 pmc_scratch30;\n/* 0x118 */\tu32 pmc_scratch31;\n/* 0x11c */\tu32 pmc_scratch32;\n/* 0x120 */\tu32 pmc_scratch33;\n/* 0x124 */\tu32 pmc_scratch34;\n/* 0x128 */\tu32 pmc_scratch35;\n/* 0x12c */\tu32 pmc_scratch36;\n/* 0x130 */\tu32 pmc_scratch37;\n/* 0x134 */\tu32 pmc_scratch38;\n/* 0x138 */\tu32 pmc_scratch39;\n/* 0x13c */\tu32 pmc_scratch40;\n/* 0x140 */\tu32 pmc_scratch41;\n/* 0x144 */\tu32 pmc_scratch42;\n/* 0x148 */\tu32 pmc_bondout_mirror0;\n/* 0x14c */\tu32 pmc_bondout_mirror1;\n/* 0x150 */\tu32 pmc_bondout_mirror2;\n/* 0x154 */\tu32 pmc_sys_33v_en;\n/* 0x158 */\tu32 pmc_bondout_mirror_access;\n/* 0x15c */\tu32 pmc_gate;\n/* 0x160 */\tu32 pmc_wake2_mask;\n/* 0x164 */\tu32 pmc_wake2_lvl;\n/* 0x168 */\tu32 pmc_wake2_status;\n/* 0x16c */\tu32 pmc_sw_wake2_status;\n/* 0x170 */\tu32 pmc_auto_wake2_lvl_mask;\n/* 0x174 */\tu32 pmc_pg_mask_2;\n/* 0x178 */\tu32 pmc_pg_mask_ce1;\n/* 0x17c */\tu32 pmc_pg_mask_ce2;\n/* 0x180 */\tu32 pmc_pg_mask_ce3;\n/* 0x184 */\tu32 pmc_pwrgate_timer_ce_0;\n/* 0x188 */\tu32 pmc_pwrgate_timer_ce_1;\n/* 0x18c */\tu32 pmc_pwrgate_timer_ce_2;\n/* 0x190 */\tu32 pmc_pwrgate_timer_ce_3;\n/* 0x194 */\tu32 pmc_pwrgate_timer_ce_4;\n/* 0x198 */\tu32 pmc_pwrgate_timer_ce_5;\n/* 0x19c */\tu32 pmc_pwrgate_timer_ce_6;\n/* 0x1a0 */\tu32 pmc_pcx_edpd_cntrl;\n/* 0x1a4 */\tu32 pmc_osc_edpd_over;\n/* 0x1a8 */\tu32 pmc_clk_out_cntrl;\n/* 0x1ac */\tu32 pmc_sata_pwrgt;\n/* 0x1b0 */\tu32 pmc_sensor_ctrl;\n/* 0x1b4 */\tu32 pmc_rst_status;\n/* 0x1b8 */\tu32 pmc_io_dpd_req;\n/* 0x1bc */\tu32 pmc_io_dpd_status;\n/* 0x1c0 */\tu32 pmc_io_dpd2_req;\n/* 0x1c4 */\tu32 pmc_io_dpd2_status;\n/* 0x1c8 */\tu32 pmc_sel_dpd_tim;\n/* 0x1cc */\tu32 pmc_vddp_sel;\n/* 0x1d0 */\tu32 pmc_ddr_cfg;\n/* 0x1d4 */\tu32 pmc_e_no_vttgen;\n/* 0x1d8 */\tu32 rsvd_1d8;\n/* 0x1dc */\tu32 pmc_pllm_wb0_override_freq;\n/* 0x1e0 */\tu32 pmc_test_pwrgate;\n/* 0x1e4 */\tu32 pmc_pwrgate_timer_mult;\n/* 0x1e8 */\tu32 pmc_dsi_sel_dpd;\n/* 0x1ec */\tu32 pmc_utmip_uhsic_triggers;\n/* 0x1f0 */\tu32 pmc_utmip_uhsic_saved_state;\n/* 0x1f4 */\tu32 rsvd_1f4;\n/* 0x1f8 */\tu32 pmc_utmip_term_pad_cfg;\n/* 0x1fc */\tu32 pmc_utmip_uhsic_sleep_cfg;\n/* 0x200 */\tu32 pmc_utmip_uhsic_sleepwalk_cfg;\n/* 0x204 */\tu32 pmc_utmip_sleepwalk_p0;\n/* 0x208 */\tu32 pmc_utmip_sleepwalk_p1;\n/* 0x20c */\tu32 pmc_utmip_sleepwalk_p2;\n/* 0x210 */\tu32 pmc_uhsic_sleepwalk_p0;\n/* 0x214 */\tu32 pmc_utmip_uhsic_status;\n/* 0x218 */\tu32 pmc_utmip_uhsic_fake;\n/* 0x21c */\tu32 pmc_bondout_mirror3;\n/* 0x220 */\tu32 pmc_bondout_mirror4;\n/* 0x224 */\tu32 pmc_secure_scratch6;\n/* 0x228 */\tu32 pmc_secure_scratch7;\n/* 0x22c */\tu32 pmc_scratch43;\n/* 0x230 */\tu32 pmc_scratch44;\n/* 0x234 */\tu32 pmc_scratch45;\n/* 0x238 */\tu32 pmc_scratch46;\n/* 0x23c */\tu32 pmc_scratch47;\n/* 0x240 */\tu32 pmc_scratch48;\n/* 0x244 */\tu32 pmc_scratch49;\n/* 0x248 */\tu32 pmc_scratch50;\n/* 0x24c */\tu32 pmc_scratch51;\n/* 0x250 */\tu32 pmc_scratch52;\n/* 0x254 */\tu32 pmc_scratch53;\n/* 0x258 */\tu32 pmc_scratch54;\n/* 0x25c */\tu32 pmc_scratch55;\n/* 0x260 */\tu32 pmc_scratch0_eco;\n/* 0x264 */\tu32 pmc_por_dpd_ctrl;\n/* 0x268 */\tu32 pmc_scratch2_eco;\n/* 0x26c */\tu32 pmc_utmip_uhsic_line_wakeup;\n/* 0x270 */\tu32 pmc_utmip_bias_master_cntrl;\n/* 0x274 */\tu32 pmc_utmip_master_config;\n/* 0x278 */\tu32 pmc_td_pwrgate_inter_part_timer;\n/* 0x27c */\tu32 pmc_utmip_uhsic2_triggers;\n/* 0x280 */\tu32 pmc_utmip_uhsic2_saved_state;\n/* 0x284 */\tu32 pmc_utmip_uhsic2_sleep_cfg;\n/* 0x288 */\tu32 pmc_utmip_uhsic2_sleepwalk_cfg;\n/* 0x28c */\tu32 pmc_uhsic2_sleepwalk_p1;\n/* 0x290 */\tu32 pmc_utmip_uhsic2_status;\n/* 0x294 */\tu32 pmc_utmip_uhsic2_fake;\n/* 0x298 */\tu32 pmc_utmip_uhsic2_line_wakeup;\n/* 0x29c */\tu32 pmc_utmip_master2_config;\n/* 0x2a0 */\tu32 pmc_utmip_uhsic_rpd_cfg;\n/* 0x2a4 */\tu32 pmc_pg_mask_ce0;\n/* 0x2a8 */\tu32 pmc_pg_mask_3;\n/* 0x2ac */\tu32 pmc_pg_mask_4;\n/* 0x2b0 */\tu32 pmc_pllm_wb0_override2;\n/* 0x2b4 */\tu32 pmc_tsc_mult;\n/* 0x2b8 */\tu32 pmc_cpu_vsense_override;\n/* 0x2bc */\tu32 pmc_glb_amap_cfg;\n/* 0x2c0 */\tu32 pmc_sticky_bits;\n/* 0x2c4 */\tu32 pmc_sec_disable2;\n/* 0x2c8 */\tu32 pmc_weak_bias;\n/* 0x2cc */\tu32 pmc_reg_short;\n/* 0x2d0 */\tu32 pmc_pg_mask_andor;\n/* 0x2d4 */\tu32 pmc_gpu_rg_cntrl;\n/* 0x2d8 */\tu32 pmc_sec_disable3;\n/* 0x2dc */\tu32 pmc_pg_mask_5;\n/* 0x2e0 */\tu32 pmc_pg_mask_6;\n/* 0x2e4 */\tu32 rsvd_2e4[7];\n/* 0x300 */\tu32 pmc_secure_scratch8;\n/* 0x304 */\tu32 pmc_secure_scratch9;\n/* 0x308 */\tu32 pmc_secure_scratch10;\n/* 0x30c */\tu32 pmc_secure_scratch11;\n/* 0x310 */\tu32 pmc_secure_scratch12;\n/* 0x314 */\tu32 pmc_secure_scratch13;\n/* 0x318 */\tu32 pmc_secure_scratch14;\n/* 0x31c */\tu32 pmc_secure_scratch15;\n/* 0x320 */\tu32 pmc_secure_scratch16;\n/* 0x324 */\tu32 pmc_secure_scratch17;\n/* 0x328 */\tu32 pmc_secure_scratch18;\n/* 0x32c */\tu32 pmc_secure_scratch19;\n/* 0x330 */\tu32 pmc_secure_scratch20;\n/* 0x334 */\tu32 pmc_secure_scratch21;\n/* 0x338 */\tu32 pmc_secure_scratch22; // AArch32 reset address.\n/* 0x33c */\tu32 pmc_secure_scratch23;\n/* 0x340 */\tu32 pmc_secure_scratch24;\n/* 0x344 */\tu32 pmc_secure_scratch25;\n/* 0x348 */\tu32 pmc_secure_scratch26;\n/* 0x34c */\tu32 pmc_secure_scratch27;\n/* 0x350 */\tu32 pmc_secure_scratch28;\n/* 0x354 */\tu32 pmc_secure_scratch29;\n/* 0x358 */\tu32 pmc_secure_scratch30;\n/* 0x35c */\tu32 pmc_secure_scratch31;\n/* 0x360 */\tu32 pmc_secure_scratch32;\n/* 0x364 */\tu32 pmc_secure_scratch33;\n/* 0x368 */\tu32 pmc_secure_scratch34; // AArch64 reset address.\n/* 0x36c */\tu32 pmc_secure_scratch35; // AArch64 reset hi-address.\n/* 0x370 */\tu32 pmc_secure_scratch36;\n/* 0x374 */\tu32 pmc_secure_scratch37;\n/* 0x378 */\tu32 pmc_secure_scratch38;\n/* 0x37c */\tu32 pmc_secure_scratch39;\n/* 0x380 */\tu32 pmc_secure_scratch40;\n/* 0x384 */\tu32 pmc_secure_scratch41;\n/* 0x388 */\tu32 pmc_secure_scratch42;\n/* 0x38c */\tu32 pmc_secure_scratch43;\n/* 0x390 */\tu32 pmc_secure_scratch44;\n/* 0x394 */\tu32 pmc_secure_scratch45;\n/* 0x398 */\tu32 pmc_secure_scratch46;\n/* 0x39c */\tu32 pmc_secure_scratch47;\n/* 0x3a0 */\tu32 pmc_secure_scratch48;\n/* 0x3a4 */\tu32 pmc_secure_scratch49;\n/* 0x3a8 */\tu32 pmc_secure_scratch50;\n/* 0x3ac */\tu32 pmc_secure_scratch51;\n/* 0x3b0 */\tu32 pmc_secure_scratch52;\n/* 0x3b4 */\tu32 pmc_secure_scratch53;\n/* 0x3b8 */\tu32 pmc_secure_scratch54;\n/* 0x3bc */\tu32 pmc_secure_scratch55;\n/* 0x3c0 */\tu32 pmc_secure_scratch56;\n/* 0x3c4 */\tu32 pmc_secure_scratch57;\n/* 0x3c8 */\tu32 pmc_secure_scratch58;\n/* 0x3cc */\tu32 pmc_secure_scratch59;\n/* 0x3d0 */\tu32 pmc_secure_scratch60;\n/* 0x3d4 */\tu32 pmc_secure_scratch61;\n/* 0x3d8 */\tu32 pmc_secure_scratch62;\n/* 0x3dc */\tu32 pmc_secure_scratch63;\n/* 0x3e0 */\tu32 pmc_secure_scratch64;\n/* 0x3e4 */\tu32 pmc_secure_scratch65;\n/* 0x3e8 */\tu32 pmc_secure_scratch66;\n/* 0x3ec */\tu32 pmc_secure_scratch67;\n/* 0x3f0 */\tu32 pmc_secure_scratch68;\n/* 0x3f4 */\tu32 pmc_secure_scratch69;\n/* 0x3f8 */\tu32 pmc_secure_scratch70;\n/* 0x3fc */\tu32 pmc_secure_scratch71;\n/* 0x400 */\tu32 pmc_secure_scratch72;\n/* 0x404 */\tu32 pmc_secure_scratch73;\n/* 0x408 */\tu32 pmc_secure_scratch74;\n/* 0x40c */\tu32 pmc_secure_scratch75;\n/* 0x410 */\tu32 pmc_secure_scratch76;\n/* 0x414 */\tu32 pmc_secure_scratch77;\n/* 0x418 */\tu32 pmc_secure_scratch78;\n/* 0x41c */\tu32 pmc_secure_scratch79;\n/* 0x420 */\tu32 rsvd_420[8];\n/* 0x440 */\tu32 pmc_cntrl2;\n/* 0x444 */\tu32 pmc_io_dpd_off_mask;\n/* 0x448 */\tu32 pmc_io_dpd2_off_mask;\n/* 0x44c */\tu32 pmc_event_counter;\n/* 0x450 */\tu32 pmc_fuse_control;\n/* 0x454 */\tu32 pmc_scratch1_eco;\n/* 0x458 */\tu32 rsvd_458;\n/* 0x45c */\tu32 pmc_io_dpd3_req;\n/* 0x460 */\tu32 pmc_io_dpd3_status;\n/* 0x464 */\tu32 pmc_io_dpd4_req;\n/* 0x468 */\tu32 pmc_io_dpd4_status;\n/* 0x46c */\tu32 rsvd_46c[2];\n/* 0x474 */\tu32 pmc_direct_thermtrip_cfg;\n/* 0x478 */\tu32 pmc_tsosc_delay;\n/* 0x47c */\tu32 pmc_set_sw_clamp;\n/* 0x480 */\tu32 pmc_debug_authentication;\n/* 0x484 */\tu32 pmc_aotag_cfg;\n/* 0x488 */\tu32 pmc_aotag_thresh1_cfg;\n/* 0x48c */\tu32 pmc_aotag_thresh2_cfg;\n/* 0x490 */\tu32 pmc_aotag_thresh3_cfg;\n/* 0x494 */\tu32 pmc_aotag_status;\n/* 0x498 */\tu32 pmc_aotag_security;\n/* 0x49c */\tu32 pmc_tsensor_config0;\n/* 0x4a0 */\tu32 pmc_tsensor_config1;\n/* 0x4a4 */\tu32 pmc_tsensor_config2;\n/* 0x4a8 */\tu32 pmc_tsensor_status0;\n/* 0x4ac */\tu32 pmc_tsensor_status1;\n/* 0x4b0 */\tu32 pmc_tsensor_status2;\n/* 0x4b4 */\tu32 pmc_tsensor_pdiv;\n/* 0x4b8 */\tu32 pmc_aotag_intr_en;\n/* 0x4bc */\tu32 pmc_aotag_intr_dis;\n/* 0x4c0 */\tu32 pmc_utmip_pad_cfg0;\n/* 0x4c4 */\tu32 pmc_utmip_pad_cfg1;\n/* 0x4c8 */\tu32 pmc_utmip_pad_cfg2;\n/* 0x4cc */\tu32 pmc_utmip_pad_cfg3;\n/* 0x4d0 */\tu32 pmc_utmip_uhsic_sleep_cfg1;\n/* 0x4d4 */\tu32 pmc_cc4_hvc_control;\n/* 0x4d8 */\tu32 pmc_wake_debounce_en;\n/* 0x4dc */\tu32 pmc_ramdump_ctl_status;\n/* 0x4e0 */\tu32 pmc_utmip_sleepwalk_p3;\n/* 0x4e4 */\tu32 pmc_ddr_cntrl;\n/* 0x4e8 */\tu32 rsvd_4e8[50];\n/* 0x5b0 */\tu32 pmc_sec_disable4;\n/* 0x5b4 */\tu32 pmc_sec_disable5;\n/* 0x5b8 */\tu32 pmc_sec_disable6;\n/* 0x5bc */\tu32 pmc_sec_disable7;\n/* 0x5c0 */\tu32 pmc_sec_disable8;\n/* 0x5c4 */\tu32 pmc_sec_disable9_b01;\n/* 0x5c8 */\tu32 pmc_sec_disable10_b01;\n/* 0x5cc */\tu32 rsvd_5cc[13];\n/* 0x600 */\tu32 pmc_scratch56;\n/* 0x604 */\tu32 pmc_scratch57;\n/* 0x608 */\tu32 pmc_scratch58;\n/* 0x60c */\tu32 pmc_scratch59;\n/* 0x610 */\tu32 pmc_scratch60;\n/* 0x614 */\tu32 pmc_scratch61;\n/* 0x618 */\tu32 pmc_scratch62;\n/* 0x61c */\tu32 pmc_scratch63;\n/* 0x620 */\tu32 pmc_scratch64;\n/* 0x624 */\tu32 pmc_scratch65;\n/* 0x628 */\tu32 pmc_scratch66;\n/* 0x62c */\tu32 pmc_scratch67;\n/* 0x630 */\tu32 pmc_scratch68;\n/* 0x634 */\tu32 pmc_scratch69;\n/* 0x638 */\tu32 pmc_scratch70;\n/* 0x63c */\tu32 pmc_scratch71;\n/* 0x640 */\tu32 pmc_scratch72;\n/* 0x644 */\tu32 pmc_scratch73;\n/* 0x648 */\tu32 pmc_scratch74;\n/* 0x64c */\tu32 pmc_scratch75;\n/* 0x650 */\tu32 pmc_scratch76;\n/* 0x654 */\tu32 pmc_scratch77;\n/* 0x658 */\tu32 pmc_scratch78;\n/* 0x65c */\tu32 pmc_scratch79;\n/* 0x660 */\tu32 pmc_scratch80;\n/* 0x664 */\tu32 pmc_scratch81;\n/* 0x668 */\tu32 pmc_scratch82;\n/* 0x66c */\tu32 pmc_scratch83;\n/* 0x670 */\tu32 pmc_scratch84;\n/* 0x674 */\tu32 pmc_scratch85;\n/* 0x678 */\tu32 pmc_scratch86;\n/* 0x67c */\tu32 pmc_scratch87;\n/* 0x680 */\tu32 pmc_scratch88;\n/* 0x684 */\tu32 pmc_scratch89;\n/* 0x688 */\tu32 pmc_scratch90;\n/* 0x68c */\tu32 pmc_scratch91;\n/* 0x690 */\tu32 pmc_scratch92;\n/* 0x694 */\tu32 pmc_scratch93;\n/* 0x698 */\tu32 pmc_scratch94;\n/* 0x69c */\tu32 pmc_scratch95;\n/* 0x6a0 */\tu32 pmc_scratch96;\n/* 0x6a4 */\tu32 pmc_scratch97;\n/* 0x6a8 */\tu32 pmc_scratch98;\n/* 0x6ac */\tu32 pmc_scratch99;\n/* 0x6b0 */\tu32 pmc_scratch100;\n/* 0x6b4 */\tu32 pmc_scratch101;\n/* 0x6b8 */\tu32 pmc_scratch102;\n/* 0x6bc */\tu32 pmc_scratch103;\n/* 0x6c0 */\tu32 pmc_scratch104;\n/* 0x6c4 */\tu32 pmc_scratch105;\n/* 0x6c8 */\tu32 pmc_scratch106;\n/* 0x6cc */\tu32 pmc_scratch107;\n/* 0x6d0 */\tu32 pmc_scratch108;\n/* 0x6d4 */\tu32 pmc_scratch109;\n/* 0x6d8 */\tu32 pmc_scratch110;\n/* 0x6dc */\tu32 pmc_scratch111;\n/* 0x6e0 */\tu32 pmc_scratch112;\n/* 0x6e4 */\tu32 pmc_scratch113;\n/* 0x6e8 */\tu32 pmc_scratch114;\n/* 0x6ec */\tu32 pmc_scratch115;\n/* 0x6f0 */\tu32 pmc_scratch116;\n/* 0x6f4 */\tu32 pmc_scratch117;\n/* 0x6f8 */\tu32 pmc_scratch118;\n/* 0x6fc */\tu32 pmc_scratch119;\n/* 0x700 */\tu32 pmc_scratch120;\n/* 0x704 */\tu32 pmc_scratch121;\n/* 0x708 */\tu32 pmc_scratch122;\n/* 0x70c */\tu32 pmc_scratch123;\n/* 0x710 */\tu32 pmc_scratch124;\n/* 0x714 */\tu32 pmc_scratch125;\n/* 0x718 */\tu32 pmc_scratch126;\n/* 0x71c */\tu32 pmc_scratch127;\n/* 0x720 */\tu32 pmc_scratch128;\n/* 0x724 */\tu32 pmc_scratch129;\n/* 0x728 */\tu32 pmc_scratch130;\n/* 0x72c */\tu32 pmc_scratch131;\n/* 0x730 */\tu32 pmc_scratch132;\n/* 0x734 */\tu32 pmc_scratch133;\n/* 0x738 */\tu32 pmc_scratch134;\n/* 0x73c */\tu32 pmc_scratch135;\n/* 0x740 */\tu32 pmc_scratch136;\n/* 0x744 */\tu32 pmc_scratch137;\n/* 0x748 */\tu32 pmc_scratch138;\n/* 0x74c */\tu32 pmc_scratch139;\n/* 0x750 */\tu32 pmc_scratch140;\n/* 0x754 */\tu32 pmc_scratch141;\n/* 0x758 */\tu32 pmc_scratch142;\n/* 0x75c */\tu32 pmc_scratch143;\n/* 0x760 */\tu32 pmc_scratch144;\n/* 0x764 */\tu32 pmc_scratch145;\n/* 0x768 */\tu32 pmc_scratch146;\n/* 0x76c */\tu32 pmc_scratch147;\n/* 0x770 */\tu32 pmc_scratch148;\n/* 0x774 */\tu32 pmc_scratch149;\n/* 0x778 */\tu32 pmc_scratch150;\n/* 0x77c */\tu32 pmc_scratch151;\n/* 0x780 */\tu32 pmc_scratch152;\n/* 0x784 */\tu32 pmc_scratch153;\n/* 0x788 */\tu32 pmc_scratch154;\n/* 0x78c */\tu32 pmc_scratch155;\n/* 0x790 */\tu32 pmc_scratch156;\n/* 0x794 */\tu32 pmc_scratch157;\n/* 0x798 */\tu32 pmc_scratch158;\n/* 0x79c */\tu32 pmc_scratch159;\n/* 0x7a0 */\tu32 pmc_scratch160;\n/* 0x7a4 */\tu32 pmc_scratch161;\n/* 0x7a8 */\tu32 pmc_scratch162;\n/* 0x7ac */\tu32 pmc_scratch163;\n/* 0x7b0 */\tu32 pmc_scratch164;\n/* 0x7b4 */\tu32 pmc_scratch165;\n/* 0x7b8 */\tu32 pmc_scratch166;\n/* 0x7bc */\tu32 pmc_scratch167;\n/* 0x7c0 */\tu32 pmc_scratch168;\n/* 0x7c4 */\tu32 pmc_scratch169;\n/* 0x7c8 */\tu32 pmc_scratch170;\n/* 0x7cc */\tu32 pmc_scratch171;\n/* 0x7d0 */\tu32 pmc_scratch172;\n/* 0x7d4 */\tu32 pmc_scratch173;\n/* 0x7d8 */\tu32 pmc_scratch174;\n/* 0x7dc */\tu32 pmc_scratch175;\n/* 0x7e0 */\tu32 pmc_scratch176;\n/* 0x7e4 */\tu32 pmc_scratch177;\n/* 0x7e8 */\tu32 pmc_scratch178;\n/* 0x7ec */\tu32 pmc_scratch179;\n/* 0x7f0 */\tu32 pmc_scratch180;\n/* 0x7f4 */\tu32 pmc_scratch181;\n/* 0x7f8 */\tu32 pmc_scratch182;\n/* 0x7fc */\tu32 pmc_scratch183;\n/* 0x800 */\tu32 pmc_scratch184;\n/* 0x804 */\tu32 pmc_scratch185;\n/* 0x808 */\tu32 pmc_scratch186;\n/* 0x80c */\tu32 pmc_scratch187;\n/* 0x810 */\tu32 pmc_scratch188;\n/* 0x814 */\tu32 pmc_scratch189;\n/* 0x818 */\tu32 pmc_scratch190;\n/* 0x81c */\tu32 pmc_scratch191;\n/* 0x820 */\tu32 pmc_scratch192;\n/* 0x824 */\tu32 pmc_scratch193;\n/* 0x828 */\tu32 pmc_scratch194;\n/* 0x82c */\tu32 pmc_scratch195;\n/* 0x830 */\tu32 pmc_scratch196;\n/* 0x834 */\tu32 pmc_scratch197;\n/* 0x838 */\tu32 pmc_scratch198;\n/* 0x83c */\tu32 pmc_scratch199;\n/* 0x840 */\tu32 pmc_scratch200;\n/* 0x844 */\tu32 pmc_scratch201;\n/* 0x848 */\tu32 pmc_scratch202;\n/* 0x84c */\tu32 pmc_scratch203;\n/* 0x850 */\tu32 pmc_scratch204;\n/* 0x854 */\tu32 pmc_scratch205;\n/* 0x858 */\tu32 pmc_scratch206;\n/* 0x85c */\tu32 pmc_scratch207;\n/* 0x860 */\tu32 pmc_scratch208;\n/* 0x864 */\tu32 pmc_scratch209;\n/* 0x868 */\tu32 pmc_scratch210;\n/* 0x86c */\tu32 pmc_scratch211;\n/* 0x870 */\tu32 pmc_scratch212;\n/* 0x874 */\tu32 pmc_scratch213;\n/* 0x878 */\tu32 pmc_scratch214;\n/* 0x87c */\tu32 pmc_scratch215;\n/* 0x880 */\tu32 pmc_scratch216;\n/* 0x884 */\tu32 pmc_scratch217;\n/* 0x888 */\tu32 pmc_scratch218;\n/* 0x88c */\tu32 pmc_scratch219;\n/* 0x890 */\tu32 pmc_scratch220;\n/* 0x894 */\tu32 pmc_scratch221;\n/* 0x898 */\tu32 pmc_scratch222;\n/* 0x89c */\tu32 pmc_scratch223;\n/* 0x8a0 */\tu32 pmc_scratch224;\n/* 0x8a4 */\tu32 pmc_scratch225;\n/* 0x8a8 */\tu32 pmc_scratch226;\n/* 0x8ac */\tu32 pmc_scratch227;\n/* 0x8b0 */\tu32 pmc_scratch228;\n/* 0x8b4 */\tu32 pmc_scratch229;\n/* 0x8b8 */\tu32 pmc_scratch230;\n/* 0x8bc */\tu32 pmc_scratch231;\n/* 0x8c0 */\tu32 pmc_scratch232;\n/* 0x8c4 */\tu32 pmc_scratch233;\n/* 0x8c8 */\tu32 pmc_scratch234;\n/* 0x8cc */\tu32 pmc_scratch235;\n/* 0x8d0 */\tu32 pmc_scratch236;\n/* 0x8d4 */\tu32 pmc_scratch237;\n/* 0x8d8 */\tu32 pmc_scratch238;\n/* 0x8dc */\tu32 pmc_scratch239;\n/* 0x8e0 */\tu32 pmc_scratch240;\n/* 0x8e4 */\tu32 pmc_scratch241;\n/* 0x8e8 */\tu32 pmc_scratch242;\n/* 0x8ec */\tu32 pmc_scratch243;\n/* 0x8f0 */\tu32 pmc_scratch244;\n/* 0x8f4 */\tu32 pmc_scratch245;\n/* 0x8f8 */\tu32 pmc_scratch246;\n/* 0x8fc */\tu32 pmc_scratch247;\n/* 0x900 */\tu32 pmc_scratch248;\n/* 0x904 */\tu32 pmc_scratch249;\n/* 0x908 */\tu32 pmc_scratch250;\n/* 0x90c */\tu32 pmc_scratch251;\n/* 0x910 */\tu32 pmc_scratch252;\n/* 0x914 */\tu32 pmc_scratch253;\n/* 0x918 */\tu32 pmc_scratch254;\n/* 0x91c */\tu32 pmc_scratch255;\n/* 0x920 */\tu32 pmc_scratch256;\n/* 0x924 */\tu32 pmc_scratch257;\n/* 0x928 */\tu32 pmc_scratch258;\n/* 0x92c */\tu32 pmc_scratch259;\n/* 0x930 */\tu32 pmc_scratch260;\n/* 0x934 */\tu32 pmc_scratch261;\n/* 0x938 */\tu32 pmc_scratch262;\n/* 0x93c */\tu32 pmc_scratch263;\n/* 0x940 */\tu32 pmc_scratch264;\n/* 0x944 */\tu32 pmc_scratch265;\n/* 0x948 */\tu32 pmc_scratch266;\n/* 0x94c */\tu32 pmc_scratch267;\n/* 0x950 */\tu32 pmc_scratch268;\n/* 0x954 */\tu32 pmc_scratch269;\n/* 0x958 */\tu32 pmc_scratch270;\n/* 0x95c */\tu32 pmc_scratch271;\n/* 0x960 */\tu32 pmc_scratch272;\n/* 0x964 */\tu32 pmc_scratch273;\n/* 0x968 */\tu32 pmc_scratch274;\n/* 0x96c */\tu32 pmc_scratch275;\n/* 0x970 */\tu32 pmc_scratch276;\n/* 0x974 */\tu32 pmc_scratch277;\n/* 0x978 */\tu32 pmc_scratch278;\n/* 0x97c */\tu32 pmc_scratch279;\n/* 0x980 */\tu32 pmc_scratch280;\n/* 0x984 */\tu32 pmc_scratch281;\n/* 0x988 */\tu32 pmc_scratch282;\n/* 0x98c */\tu32 pmc_scratch283;\n/* 0x990 */\tu32 pmc_scratch284;\n/* 0x994 */\tu32 pmc_scratch285;\n/* 0x998 */\tu32 pmc_scratch286;\n/* 0x99c */\tu32 pmc_scratch287;\n/* 0x9a0 */\tu32 pmc_scratch288;\n/* 0x9a4 */\tu32 pmc_scratch289;\n/* 0x9a8 */\tu32 pmc_scratch290;\n/* 0x9ac */\tu32 pmc_scratch291;\n/* 0x9b0 */\tu32 pmc_scratch292;\n/* 0x9b4 */\tu32 pmc_scratch293;\n/* 0x9b8 */\tu32 pmc_scratch294;\n/* 0x9bc */\tu32 pmc_scratch295;\n/* 0x9c0 */\tu32 pmc_scratch296;\n/* 0x9c4 */\tu32 pmc_scratch297;\n/* 0x9c8 */\tu32 pmc_scratch298;\n/* 0x9cc */\tu32 pmc_scratch299;\n/* 0x9d0 */\tu32 rsvd_9d0[30];\n/* 0xa48 */\tu32 pmc_scratch_write_disable0_b01;\n/* 0xa4c */\tu32 pmc_scratch_write_disable1_b01;\n/* 0xa50 */\tu32 pmc_scratch_write_disable2_b01;\n/* 0xa54 */\tu32 pmc_scratch_write_disable3_b01;\n/* 0xa58 */\tu32 pmc_scratch_write_disable4_b01;\n/* 0xa5c */\tu32 pmc_scratch_write_disable5_b01;\n/* 0xa60 */\tu32 pmc_scratch_write_disable6_b01;\n/* 0xa64 */\tu32 pmc_scratch_write_disable7_b01;\n/* 0xa68 */\tu32 pmc_scratch_write_disable8_b01;\n/* 0xa6c */\tu32 pmc_scratch_write_disable9_b01;\n/* 0xa70 */\tu32 pmc_scratch_write_disable10_b01;\n/* 0xa74 */\tu32 pmc_scratch_write_lock_disable_sticky_b01;\n/* 0xa78 */\tu32 rsvd_a78[8];\n/* 0xa98 */\tu32 pmc_secure_scratch80;\n/* 0xa9c */\tu32 pmc_secure_scratch81;\n/* 0xaa0 */\tu32 pmc_secure_scratch82;\n/* 0xaa4 */\tu32 pmc_secure_scratch83;\n/* 0xaa8 */\tu32 pmc_secure_scratch84;\n/* 0xaac */\tu32 pmc_secure_scratch85;\n/* 0xab0 */\tu32 pmc_secure_scratch86;\n/* 0xab4 */\tu32 pmc_secure_scratch87;\n/* 0xab8 */\tu32 pmc_secure_scratch88;\n/* 0xabc */\tu32 pmc_secure_scratch89;\n/* 0xac0 */\tu32 pmc_secure_scratch90;\n/* 0xac4 */\tu32 pmc_secure_scratch91;\n/* 0xac8 */\tu32 pmc_secure_scratch92;\n/* 0xacc */\tu32 pmc_secure_scratch93;\n/* 0xad0 */\tu32 pmc_secure_scratch94;\n/* 0xad4 */\tu32 pmc_secure_scratch95;\n/* 0xad8 */\tu32 pmc_secure_scratch96;\n/* 0xadc */\tu32 pmc_secure_scratch97;\n/* 0xae0 */\tu32 pmc_secure_scratch98;\n/* 0xae4 */\tu32 pmc_secure_scratch99;\n/* 0xae8 */\tu32 pmc_secure_scratch100;\n/* 0xaec */\tu32 pmc_secure_scratch101;\n/* 0xaf0 */\tu32 pmc_secure_scratch102;\n/* 0xaf4 */\tu32 pmc_secure_scratch103;\n/* 0xaf8 */\tu32 pmc_secure_scratch104;\n/* 0xafc */\tu32 pmc_secure_scratch105;\n/* 0xb00 */\tu32 pmc_secure_scratch106;\n/* 0xb04 */\tu32 pmc_secure_scratch107;\n/* 0xb08 */\tu32 pmc_secure_scratch108;\n/* 0xb0c */\tu32 pmc_secure_scratch109;\n/* 0xb10 */\tu32 pmc_secure_scratch110;\n/* 0xb14 */\tu32 pmc_secure_scratch111;\n/* 0xb18 */\tu32 pmc_secure_scratch112;\n/* 0xb1c */\tu32 pmc_secure_scratch113;\n/* 0xb20 */\tu32 pmc_secure_scratch114;\n/* 0xb24 */\tu32 pmc_secure_scratch115;\n/* 0xb28 */\tu32 pmc_secure_scratch116;\n/* 0xb2c */\tu32 pmc_secure_scratch117;\n/* 0xb30 */\tu32 pmc_secure_scratch118;\n/* 0xb34 */\tu32 pmc_secure_scratch119;\n/* 0xb38 */\tu32 pmc_secure_scratch120_b01;\n/* 0xb3c */\tu32 pmc_secure_scratch121_b01;\n/* 0xb40 */\tu32 pmc_secure_scratch122_b01;\n/* 0xb44 */\tu32 pmc_secure_scratch123_b01;\n/* 0xb48 */\tu32 pmc_led_breathing_ctrl_b01;\n/* 0xb4c */\tu32 pmc_led_breathing_counter0_b01; // Slope Steps.\n/* 0xb50 */\tu32 pmc_led_breathing_counter1_b01; // ON counter.\n/* 0xb54 */\tu32 pmc_led_breathing_counter2_b01; // OFF counter1.\n/* 0xb58 */\tu32 pmc_led_breathing_counter3_b01; // OFF counter0.\n/* 0xb5c */\tu32 pmc_led_breathing_status_b01;\n/* 0xb60 */\tu32 rsvd_b60[2];\n/* 0xb68 */\tu32 pmc_secure_scratch124_b01;\n/* 0xb6c */\tu32 pmc_secure_scratch125_b01;\n/* 0xb70 */\tu32 pmc_secure_scratch126_b01;\n/* 0xb74 */\tu32 pmc_secure_scratch127_b01;\n/* 0xb78 */\tu32 pmc_secure_scratch128_b01;\n/* 0xb7c */\tu32 pmc_secure_scratch129_b01;\n/* 0xb80 */\tu32 pmc_secure_scratch130_b01;\n/* 0xb84 */\tu32 pmc_secure_scratch131_b01;\n/* 0xb88 */\tu32 pmc_secure_scratch132_b01;\n/* 0xb8c */\tu32 pmc_secure_scratch133_b01;\n/* 0xb90 */\tu32 pmc_secure_scratch134_b01;\n/* 0xb94 */\tu32 pmc_secure_scratch135_b01;\n/* 0xb98 */\tu32 pmc_secure_scratch136_b01;\n/* 0xb9c */\tu32 pmc_secure_scratch137_b01;\n/* 0xba0 */\tu32 pmc_secure_scratch138_b01;\n/* 0xba4 */\tu32 pmc_secure_scratch139_b01;\n/* 0xba8 */\tu32 rsvd_ba8[2];\n/* 0xbb0 */\tu32 pmc_sec_disable_ns_b01;\n/* 0xbb4 */\tu32 pmc_sec_disable2_ns_b01;\n/* 0xbb8 */\tu32 pmc_sec_disable3_ns_b01;\n/* 0xbbc */\tu32 pmc_sec_disable4_ns_b01;\n/* 0xbc0 */\tu32 pmc_sec_disable5_ns_b01;\n/* 0xbc4 */\tu32 pmc_sec_disable6_ns_b01;\n/* 0xbc8 */\tu32 pmc_sec_disable7_ns_b01;\n/* 0xbcc */\tu32 pmc_sec_disable8_ns_b01;\n/* 0xbd0 */\tu32 pmc_sec_disable9_ns_b01;\n/* 0xbd4 */\tu32 pmc_sec_disable10_ns_b01;\n/* 0xbd8 */\tu32 rsvd_bd8[4];\n/* 0xbe8 */\tu32 pmc_tzram_pwr_cntrl_b01;\n/* 0xbec */\tu32 pmc_tzram_sec_disable_b01;\n/* 0xbf0 */\tu32 pmc_tzram_non_sec_disable_b01;\n} pmc_regs_t210_t;\n\n#endif\t/* _PMC_T210_H_ */\n"
  },
  {
    "path": "modules/hekate_libsys_lp0/sdram_lp0_param_t210.h",
    "content": "/*\n * Copyright (c) 2013-2015, NVIDIA CORPORATION.  All rights reserved.\n * Copyright 2014 Google Inc.\n * Copyright (c) 2018 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n */\n\n/**\n * Defines the SDRAM parameter structure.\n *\n * Note that PLLM is used by EMC. The field names are in camel case to ease\n * directly converting BCT config files (*.cfg) into C structure.\n */\n\n#ifndef __TEGRA210_SDRAM_PARAM_H__\n#define __TEGRA210_SDRAM_PARAM_H__\n\n#include \"types.h\"\n\nenum\n{\n\t/* Specifies the memory type to be undefined */\n\tNvBootMemoryType_None = 0,\n\n\t/* Specifies the memory type to be DDR SDRAM */\n\tNvBootMemoryType_Ddr = 0,\n\n\t/* Specifies the memory type to be LPDDR SDRAM */\n\tNvBootMemoryType_LpDdr = 0,\n\n\t/* Specifies the memory type to be DDR2 SDRAM */\n\tNvBootMemoryType_Ddr2 = 0,\n\n\t/* Specifies the memory type to be LPDDR2 SDRAM */\n\tNvBootMemoryType_LpDdr2,\n\n\t/* Specifies the memory type to be DDR3 SDRAM */\n\tNvBootMemoryType_Ddr3,\n\n\t/* Specifies the memory type to be LPDDR4 SDRAM */\n\tNvBootMemoryType_LpDdr4,\n\n\tNvBootMemoryType_Num,\n\n\t/* Specifies an entry in the ram_code table that's not in use */\n\tNvBootMemoryType_Unused = 0X7FFFFFF,\n};\n\n/**\n * Defines the SDRAM parameter structure\n */\ntypedef struct _sdram_params_t210_t\n{\n\n\t/* Specifies the type of memory device */\n\tu32 MemoryType;\n\n\t/* MC/EMC clock source configuration */\n\n\t/* Specifies the M value for PllM */\n\tu32 PllMInputDivider;\n\t/* Specifies the N value for PllM */\n\tu32 PllMFeedbackDivider;\n\t/* Specifies the time to wait for PLLM to lock (in microseconds) */\n\tu32 PllMStableTime;\n\t/* Specifies misc. control bits */\n\tu32 PllMSetupControl;\n\t/* Specifies the P value for PLLM */\n\tu32 PllMPostDivider;\n\t/* Specifies value for Charge Pump Gain Control */\n\tu32 PllMKCP;\n\t/* Specifies VCO gain */\n\tu32 PllMKVCO;\n\t/* Spare BCT param */\n\tu32 EmcBctSpare0;\n\t/* Spare BCT param */\n\tu32 EmcBctSpare1;\n\t/* Spare BCT param */\n\tu32 EmcBctSpare2;\n\t/* Spare BCT param */\n\tu32 EmcBctSpare3;\n\t/* Spare BCT param */\n\tu32 EmcBctSpare4;\n\t/* Spare BCT param */\n\tu32 EmcBctSpare5;\n\t/* Spare BCT param */\n\tu32 EmcBctSpare6;\n\t/* Spare BCT param */\n\tu32 EmcBctSpare7;\n\t/* Spare BCT param */\n\tu32 EmcBctSpare8;\n\t/* Spare BCT param */\n\tu32 EmcBctSpare9;\n\t/* Spare BCT param */\n\tu32 EmcBctSpare10;\n\t/* Spare BCT param */\n\tu32 EmcBctSpare11;\n\t/* Spare BCT param */\n\tu32 EmcBctSpare12;\n\t/* Spare BCT param */\n\tu32 EmcBctSpare13;\n\n\t/* Defines EMC_2X_CLK_SRC, EMC_2X_CLK_DIVISOR, EMC_INVERT_DCD */\n\tu32 EmcClockSource;\n\tu32 EmcClockSourceDll;\n\n\t/* Defines possible override for PLLLM_MISC2 */\n\tu32 ClkRstControllerPllmMisc2Override;\n\t/* enables override for PLLLM_MISC2 */\n\tu32 ClkRstControllerPllmMisc2OverrideEnable;\n\t/* defines CLK_ENB_MC1 in register clk_rst_controller_clk_enb_w_clr */\n\tu32 ClearClk2Mc1;\n\n\t/* Auto-calibration of EMC pads */\n\n\t/* Specifies the value for EMC_AUTO_CAL_INTERVAL */\n\tu32 EmcAutoCalInterval;\n\t/*\n\t * Specifies the value for EMC_AUTO_CAL_CONFIG\n\t * Note: Trigger bits are set by the SDRAM code.\n\t */\n\tu32 EmcAutoCalConfig;\n\n\t/* Specifies the value for EMC_AUTO_CAL_CONFIG2 */\n\tu32 EmcAutoCalConfig2;\n\n\t/* Specifies the value for EMC_AUTO_CAL_CONFIG3 */\n\tu32 EmcAutoCalConfig3;\n\n\t/* Specifies the values for EMC_AUTO_CAL_CONFIG4-8 */\n\tu32 EmcAutoCalConfig4;\n\tu32 EmcAutoCalConfig5;\n\tu32 EmcAutoCalConfig6;\n\tu32 EmcAutoCalConfig7;\n\tu32 EmcAutoCalConfig8;\n\n\t/* Specifies the value for EMC_AUTO_CAL_VREF_SEL_0 */\n\tu32 EmcAutoCalVrefSel0;\n\tu32 EmcAutoCalVrefSel1;\n\n\t/* Specifies the value for EMC_AUTO_CAL_CHANNEL */\n\tu32 EmcAutoCalChannel;\n\n\t/* Specifies the value for EMC_PMACRO_AUTOCAL_CFG_0 */\n\tu32 EmcPmacroAutocalCfg0;\n\tu32 EmcPmacroAutocalCfg1;\n\tu32 EmcPmacroAutocalCfg2;\n\tu32 EmcPmacroRxTerm;\n\tu32 EmcPmacroDqTxDrv;\n\tu32 EmcPmacroCaTxDrv;\n\tu32 EmcPmacroCmdTxDrv;\n\tu32 EmcPmacroAutocalCfgCommon;\n\tu32 EmcPmacroZctrl;\n\n\t/*\n\t * Specifies the time for the calibration\n\t * to stabilize (in microseconds)\n\t */\n\tu32 EmcAutoCalWait;\n\n\tu32 EmcXm2CompPadCtrl;\n\tu32 EmcXm2CompPadCtrl2;\n\tu32 EmcXm2CompPadCtrl3;\n\n\t/*\n\t * DRAM size information\n\t * Specifies the value for EMC_ADR_CFG\n\t */\n\tu32 EmcAdrCfg;\n\n\t/*\n\t * Specifies the time to wait after asserting pin\n\t * CKE (in microseconds)\n\t */\n\tu32 EmcPinProgramWait;\n\t/* Specifies the extra delay before/after pin RESET/CKE command */\n\tu32 EmcPinExtraWait;\n\n\tu32 EmcPinGpioEn;\n\tu32 EmcPinGpio;\n\n\t/*\n\t * Specifies the extra delay after the first writing\n\t * of EMC_TIMING_CONTROL\n\t */\n\tu32 EmcTimingControlWait;\n\n\t/* Timing parameters required for the SDRAM */\n\n\t/* Specifies the value for EMC_RC */\n\tu32 EmcRc;\n\t/* Specifies the value for EMC_RFC */\n\tu32 EmcRfc;\n\t/* Specifies the value for EMC_RFC_PB */\n\tu32 EmcRfcPb;\n\t/* Specifies the value for EMC_RFC_CTRL2 */\n\tu32 EmcRefctrl2;\n\t/* Specifies the value for EMC_RFC_SLR */\n\tu32 EmcRfcSlr;\n\t/* Specifies the value for EMC_RAS */\n\tu32 EmcRas;\n\t/* Specifies the value for EMC_RP */\n\tu32 EmcRp;\n\t/* Specifies the value for EMC_R2R */\n\tu32 EmcR2r;\n\t/* Specifies the value for EMC_W2W */\n\tu32 EmcW2w;\n\t/* Specifies the value for EMC_R2W */\n\tu32 EmcR2w;\n\t/* Specifies the value for EMC_W2R */\n\tu32 EmcW2r;\n\t/* Specifies the value for EMC_R2P */\n\tu32 EmcR2p;\n\t/* Specifies the value for EMC_W2P */\n\tu32 EmcW2p;\n\n\tu32 EmcTppd;\n\tu32 EmcCcdmw;\n\n\t/* Specifies the value for EMC_RD_RCD */\n\tu32 EmcRdRcd;\n\t/* Specifies the value for EMC_WR_RCD */\n\tu32 EmcWrRcd;\n\t/* Specifies the value for EMC_RRD */\n\tu32 EmcRrd;\n\t/* Specifies the value for EMC_REXT */\n\tu32 EmcRext;\n\t/* Specifies the value for EMC_WEXT */\n\tu32 EmcWext;\n\t/* Specifies the value for EMC_WDV */\n\tu32 EmcWdv;\n\n\tu32 EmcWdvChk;\n\tu32 EmcWsv;\n\tu32 EmcWev;\n\n\t/* Specifies the value for EMC_WDV_MASK */\n\tu32 EmcWdvMask;\n\n\tu32 EmcWsDuration;\n\tu32 EmcWeDuration;\n\n\t/* Specifies the value for EMC_QUSE */\n\tu32 EmcQUse;\n\t/* Specifies the value for EMC_QUSE_WIDTH */\n\tu32 EmcQuseWidth;\n\t/* Specifies the value for EMC_IBDLY */\n\tu32 EmcIbdly;\n\t/* Specifies the value for EMC_OBDLY */\n\tu32 EmcObdly;\n\t/* Specifies the value for EMC_EINPUT */\n\tu32 EmcEInput;\n\t/* Specifies the value for EMC_EINPUT_DURATION */\n\tu32 EmcEInputDuration;\n\t/* Specifies the value for EMC_PUTERM_EXTRA */\n\tu32 EmcPutermExtra;\n\t/* Specifies the value for EMC_PUTERM_WIDTH */\n\tu32 EmcPutermWidth;\n\t/* Specifies the value for EMC_PUTERM_ADJ */\n\t////u32 EmcPutermAdj;\n\n\t/* Specifies the value for EMC_QRST */\n\tu32 EmcQRst;\n\t/* Specifies the value for EMC_QSAFE */\n\tu32 EmcQSafe;\n\t/* Specifies the value for EMC_RDV */\n\tu32 EmcRdv;\n\t/* Specifies the value for EMC_RDV_MASK */\n\tu32 EmcRdvMask;\n\t/* Specifies the value for EMC_RDV_EARLY */\n\tu32 EmcRdvEarly;\n\t/* Specifies the value for EMC_RDV_EARLY_MASK */\n\tu32 EmcRdvEarlyMask;\n\t/* Specifies the value for EMC_QPOP */\n\tu32 EmcQpop;\n\n\t/* Specifies the value for EMC_REFRESH */\n\tu32 EmcRefresh;\n\t/* Specifies the value for EMC_BURST_REFRESH_NUM */\n\tu32 EmcBurstRefreshNum;\n\t/* Specifies the value for EMC_PRE_REFRESH_REQ_CNT */\n\tu32 EmcPreRefreshReqCnt;\n\t/* Specifies the value for EMC_PDEX2WR */\n\tu32 EmcPdEx2Wr;\n\t/* Specifies the value for EMC_PDEX2RD */\n\tu32 EmcPdEx2Rd;\n\t/* Specifies the value for EMC_PCHG2PDEN */\n\tu32 EmcPChg2Pden;\n\t/* Specifies the value for EMC_ACT2PDEN */\n\tu32 EmcAct2Pden;\n\t/* Specifies the value for EMC_AR2PDEN */\n\tu32 EmcAr2Pden;\n\t/* Specifies the value for EMC_RW2PDEN */\n\tu32 EmcRw2Pden;\n\t/* Specifies the value for EMC_CKE2PDEN */\n\tu32 EmcCke2Pden;\n\t/* Specifies the value for EMC_PDEX2CKE */\n\tu32 EmcPdex2Cke;\n\t/* Specifies the value for EMC_PDEX2MRR */\n\tu32 EmcPdex2Mrr;\n\t/* Specifies the value for EMC_TXSR */\n\tu32 EmcTxsr;\n\t/* Specifies the value for EMC_TXSRDLL */\n\tu32 EmcTxsrDll;\n\t/* Specifies the value for EMC_TCKE */\n\tu32 EmcTcke;\n\t/* Specifies the value for EMC_TCKESR */\n\tu32 EmcTckesr;\n\t/* Specifies the value for EMC_TPD */\n\tu32 EmcTpd;\n\t/* Specifies the value for EMC_TFAW */\n\tu32 EmcTfaw;\n\t/* Specifies the value for EMC_TRPAB */\n\tu32 EmcTrpab;\n\t/* Specifies the value for EMC_TCLKSTABLE */\n\tu32 EmcTClkStable;\n\t/* Specifies the value for EMC_TCLKSTOP */\n\tu32 EmcTClkStop;\n\t/* Specifies the value for EMC_TREFBW */\n\tu32 EmcTRefBw;\n\n\t/* FBIO configuration values */\n\n\t/* Specifies the value for EMC_FBIO_CFG5 */\n\tu32 EmcFbioCfg5;\n\t/* Specifies the value for EMC_FBIO_CFG7 */\n\tu32 EmcFbioCfg7;\n\t/* Specifies the value for EMC_FBIO_CFG8 */\n\tu32 EmcFbioCfg8;\n\n\t/* Command mapping for CMD brick 0 */\n\tu32 EmcCmdMappingCmd0_0;\n\tu32 EmcCmdMappingCmd0_1;\n\tu32 EmcCmdMappingCmd0_2;\n\tu32 EmcCmdMappingCmd1_0;\n\tu32 EmcCmdMappingCmd1_1;\n\tu32 EmcCmdMappingCmd1_2;\n\tu32 EmcCmdMappingCmd2_0;\n\tu32 EmcCmdMappingCmd2_1;\n\tu32 EmcCmdMappingCmd2_2;\n\tu32 EmcCmdMappingCmd3_0;\n\tu32 EmcCmdMappingCmd3_1;\n\tu32 EmcCmdMappingCmd3_2;\n\tu32 EmcCmdMappingByte;\n\n\t/* Specifies the value for EMC_FBIO_SPARE */\n\tu32 EmcFbioSpare;\n\n\t/* Specifies the value for EMC_CFG_RSV */\n\tu32 EmcCfgRsv;\n\n\t/* MRS command values */\n\n\t/* Specifies the value for EMC_MRS */\n\tu32 EmcMrs;\n\t/* Specifies the MP0 command to initialize mode registers */\n\tu32 EmcEmrs;\n\t/* Specifies the MP2 command to initialize mode registers */\n\tu32 EmcEmrs2;\n\t/* Specifies the MP3 command to initialize mode registers */\n\tu32 EmcEmrs3;\n\t/* Specifies the programming to LPDDR2 Mode Register 1 at cold boot */\n\tu32 EmcMrw1;\n\t/* Specifies the programming to LPDDR2 Mode Register 2 at cold boot */\n\tu32 EmcMrw2;\n\t/* Specifies the programming to LPDDR2 Mode Register 3 at cold boot */\n\tu32 EmcMrw3;\n\t/* Specifies the programming to LPDDR2 Mode Register 11 at cold boot */\n\tu32 EmcMrw4;\n\t/* Specifies the programming to LPDDR2 Mode Register 3? at cold boot */\n\tu32 EmcMrw6;\n\t/* Specifies the programming to LPDDR2 Mode Register 11 at cold boot */\n\tu32 EmcMrw8;\n\t/* Specifies the programming to LPDDR2 Mode Register 11? at cold boot */\n\tu32 EmcMrw9;\n\t/* Specifies the programming to LPDDR2 Mode Register 12 at cold boot */\n\tu32 EmcMrw10;\n\t/* Specifies the programming to LPDDR2 Mode Register 14 at cold boot */\n\tu32 EmcMrw12;\n\t/* Specifies the programming to LPDDR2 Mode Register 14? at cold boot */\n\tu32 EmcMrw13;\n\t/* Specifies the programming to LPDDR2 Mode Register 22 at cold boot */\n\tu32 EmcMrw14;\n\t/*\n\t * Specifies the programming to extra LPDDR2 Mode Register\n\t * at cold boot\n\t */\n\tu32 EmcMrwExtra;\n\t/*\n\t * Specifies the programming to extra LPDDR2 Mode Register\n\t * at warm boot\n\t */\n\tu32 EmcWarmBootMrwExtra;\n\t/*\n\t * Specify the enable of extra Mode Register programming at\n\t * warm boot\n\t */\n\tu32 EmcWarmBootExtraModeRegWriteEnable;\n\t/*\n\t * Specify the enable of extra Mode Register programming at\n\t * cold boot\n\t */\n\tu32 EmcExtraModeRegWriteEnable;\n\n\t/* Specifies the EMC_MRW reset command value */\n\tu32 EmcMrwResetCommand;\n\t/* Specifies the EMC Reset wait time (in microseconds) */\n\tu32 EmcMrwResetNInitWait;\n\t/* Specifies the value for EMC_MRS_WAIT_CNT */\n\tu32 EmcMrsWaitCnt;\n\t/* Specifies the value for EMC_MRS_WAIT_CNT2 */\n\tu32 EmcMrsWaitCnt2;\n\n\t/* EMC miscellaneous configurations */\n\n\t/* Specifies the value for EMC_CFG */\n\tu32 EmcCfg;\n\t/* Specifies the value for EMC_CFG_2 */\n\tu32 EmcCfg2;\n\t/* Specifies the pipe bypass controls */\n\tu32 EmcCfgPipe;\n\tu32 EmcCfgPipeClk;\n\tu32 EmcFdpdCtrlCmdNoRamp;\n\tu32 EmcCfgUpdate;\n\n\t/* Specifies the value for EMC_DBG */\n\tu32 EmcDbg;\n\tu32 EmcDbgWriteMux;\n\n\t/* Specifies the value for EMC_CMDQ */\n\tu32 EmcCmdQ;\n\t/* Specifies the value for EMC_MC2EMCQ */\n\tu32 EmcMc2EmcQ;\n\t/* Specifies the value for EMC_DYN_SELF_REF_CONTROL */\n\tu32 EmcDynSelfRefControl;\n\n\t/* Specifies the value for MEM_INIT_DONE */\n\tu32 AhbArbitrationXbarCtrlMemInitDone;\n\n\t/* Specifies the value for EMC_CFG_DIG_DLL */\n\tu32 EmcCfgDigDll;\n\tu32 EmcCfgDigDll_1;\n\t/* Specifies the value for EMC_CFG_DIG_DLL_PERIOD */\n\tu32 EmcCfgDigDllPeriod;\n\t/* Specifies the value of *DEV_SELECTN of various EMC registers */\n\tu32 EmcDevSelect;\n\n\t/* Specifies the value for EMC_SEL_DPD_CTRL */\n\tu32 EmcSelDpdCtrl;\n\n\t/* Pads trimmer delays */\n\tu32 EmcFdpdCtrlDq;\n\tu32 EmcFdpdCtrlCmd;\n\tu32 EmcPmacroIbVrefDq_0;\n\tu32 EmcPmacroIbVrefDq_1;\n\tu32 EmcPmacroIbVrefDqs_0;\n\tu32 EmcPmacroIbVrefDqs_1;\n\tu32 EmcPmacroIbRxrt;\n\tu32 EmcCfgPipe1;\n\tu32 EmcCfgPipe2;\n\n\t/* Specifies the value for EMC_PMACRO_QUSE_DDLL_RANK0_0 */\n\tu32 EmcPmacroQuseDdllRank0_0;\n\tu32 EmcPmacroQuseDdllRank0_1;\n\tu32 EmcPmacroQuseDdllRank0_2;\n\tu32 EmcPmacroQuseDdllRank0_3;\n\tu32 EmcPmacroQuseDdllRank0_4;\n\tu32 EmcPmacroQuseDdllRank0_5;\n\tu32 EmcPmacroQuseDdllRank1_0;\n\tu32 EmcPmacroQuseDdllRank1_1;\n\tu32 EmcPmacroQuseDdllRank1_2;\n\tu32 EmcPmacroQuseDdllRank1_3;\n\tu32 EmcPmacroQuseDdllRank1_4;\n\tu32 EmcPmacroQuseDdllRank1_5;\n\n\tu32 EmcPmacroObDdllLongDqRank0_0;\n\tu32 EmcPmacroObDdllLongDqRank0_1;\n\tu32 EmcPmacroObDdllLongDqRank0_2;\n\tu32 EmcPmacroObDdllLongDqRank0_3;\n\tu32 EmcPmacroObDdllLongDqRank0_4;\n\tu32 EmcPmacroObDdllLongDqRank0_5;\n\tu32 EmcPmacroObDdllLongDqRank1_0;\n\tu32 EmcPmacroObDdllLongDqRank1_1;\n\tu32 EmcPmacroObDdllLongDqRank1_2;\n\tu32 EmcPmacroObDdllLongDqRank1_3;\n\tu32 EmcPmacroObDdllLongDqRank1_4;\n\tu32 EmcPmacroObDdllLongDqRank1_5;\n\n\tu32 EmcPmacroObDdllLongDqsRank0_0;\n\tu32 EmcPmacroObDdllLongDqsRank0_1;\n\tu32 EmcPmacroObDdllLongDqsRank0_2;\n\tu32 EmcPmacroObDdllLongDqsRank0_3;\n\tu32 EmcPmacroObDdllLongDqsRank0_4;\n\tu32 EmcPmacroObDdllLongDqsRank0_5;\n\tu32 EmcPmacroObDdllLongDqsRank1_0;\n\tu32 EmcPmacroObDdllLongDqsRank1_1;\n\tu32 EmcPmacroObDdllLongDqsRank1_2;\n\tu32 EmcPmacroObDdllLongDqsRank1_3;\n\tu32 EmcPmacroObDdllLongDqsRank1_4;\n\tu32 EmcPmacroObDdllLongDqsRank1_5;\n\n\tu32 EmcPmacroIbDdllLongDqsRank0_0;\n\tu32 EmcPmacroIbDdllLongDqsRank0_1;\n\tu32 EmcPmacroIbDdllLongDqsRank0_2;\n\tu32 EmcPmacroIbDdllLongDqsRank0_3;\n\tu32 EmcPmacroIbDdllLongDqsRank1_0;\n\tu32 EmcPmacroIbDdllLongDqsRank1_1;\n\tu32 EmcPmacroIbDdllLongDqsRank1_2;\n\tu32 EmcPmacroIbDdllLongDqsRank1_3;\n\n\tu32 EmcPmacroDdllLongCmd_0;\n\tu32 EmcPmacroDdllLongCmd_1;\n\tu32 EmcPmacroDdllLongCmd_2;\n\tu32 EmcPmacroDdllLongCmd_3;\n\tu32 EmcPmacroDdllLongCmd_4;\n\tu32 EmcPmacroDdllShortCmd_0;\n\tu32 EmcPmacroDdllShortCmd_1;\n\tu32 EmcPmacroDdllShortCmd_2;\n\n\t/*\n\t * Specifies the delay after asserting CKE pin during a WarmBoot0\n\t * sequence (in microseconds)\n\t */\n\tu32 WarmBootWait;\n\n\t/* Specifies the value for EMC_ODT_WRITE */\n\tu32 EmcOdtWrite;\n\n\t/* Periodic ZQ calibration */\n\n\t/*\n\t * Specifies the value for EMC_ZCAL_INTERVAL\n\t * Value 0 disables ZQ calibration\n\t */\n\tu32 EmcZcalInterval;\n\t/* Specifies the value for EMC_ZCAL_WAIT_CNT */\n\tu32 EmcZcalWaitCnt;\n\t/* Specifies the value for EMC_ZCAL_MRW_CMD */\n\tu32 EmcZcalMrwCmd;\n\n\t/* DRAM initialization sequence flow control */\n\n\t/* Specifies the MRS command value for resetting DLL */\n\tu32 EmcMrsResetDll;\n\t/* Specifies the command for ZQ initialization of device 0 */\n\tu32 EmcZcalInitDev0;\n\t/* Specifies the command for ZQ initialization of device 1 */\n\tu32 EmcZcalInitDev1;\n\t/*\n\t * Specifies the wait time after programming a ZQ initialization\n\t * command (in microseconds)\n\t */\n\tu32 EmcZcalInitWait;\n\t/*\n\t * Specifies the enable for ZQ calibration at cold boot [bit 0]\n\t * and warm boot [bit 1]\n\t */\n\tu32 EmcZcalWarmColdBootEnables;\n\n\t/*\n\t * Specifies the MRW command to LPDDR2 for ZQ calibration\n\t * on warmboot\n\t */\n\t/* Is issued to both devices separately */\n\tu32 EmcMrwLpddr2ZcalWarmBoot;\n\t/*\n\t * Specifies the ZQ command to DDR3 for ZQ calibration on warmboot\n\t * Is issued to both devices separately\n\t */\n\tu32 EmcZqCalDdr3WarmBoot;\n\tu32 EmcZqCalLpDdr4WarmBoot;\n\t/*\n\t * Specifies the wait time for ZQ calibration on warmboot\n\t * (in microseconds)\n\t */\n\tu32 EmcZcalWarmBootWait;\n\t/*\n\t * Specifies the enable for DRAM Mode Register programming\n\t * at warm boot\n\t */\n\tu32 EmcMrsWarmBootEnable;\n\t/*\n\t * Specifies the wait time after sending an MRS DLL reset command\n\t * in microseconds)\n\t */\n\tu32 EmcMrsResetDllWait;\n\t/* Specifies the extra MRS command to initialize mode registers */\n\tu32 EmcMrsExtra;\n\t/* Specifies the extra MRS command at warm boot */\n\tu32 EmcWarmBootMrsExtra;\n\t/* Specifies the EMRS command to enable the DDR2 DLL */\n\tu32 EmcEmrsDdr2DllEnable;\n\t/* Specifies the MRS command to reset the DDR2 DLL */\n\tu32 EmcMrsDdr2DllReset;\n\t/* Specifies the EMRS command to set OCD calibration */\n\tu32 EmcEmrsDdr2OcdCalib;\n\t/*\n\t * Specifies the wait between initializing DDR and setting OCD\n\t * calibration (in microseconds)\n\t */\n\tu32 EmcDdr2Wait;\n\t/* Specifies the value for EMC_CLKEN_OVERRIDE */\n\tu32 EmcClkenOverride;\n\n\t/*\n\t * Specifies LOG2 of the extra refresh numbers after booting\n\t * Program 0 to disable\n\t */\n\tu32 EmcExtraRefreshNum;\n\t/* Specifies the master override for all EMC clocks */\n\tu32 EmcClkenOverrideAllWarmBoot;\n\t/* Specifies the master override for all MC clocks */\n\tu32 McClkenOverrideAllWarmBoot;\n\t/* Specifies digital dll period, choosing between 4 to 64 ms */\n\tu32 EmcCfgDigDllPeriodWarmBoot;\n\n\t/* Pad controls */\n\n\t/* Specifies the value for PMC_VDDP_SEL */\n\tu32 PmcVddpSel;\n\t/* Specifies the wait time after programming PMC_VDDP_SEL */\n\tu32 PmcVddpSelWait;\n\t/* Specifies the value for PMC_DDR_PWR */\n\tu32 PmcDdrPwr;\n\t/* Specifies the value for PMC_DDR_CFG */\n\tu32 PmcDdrCfg;\n\t/* Specifies the value for PMC_IO_DPD3_REQ */\n\tu32 PmcIoDpd3Req;\n\t/* Specifies the wait time after programming PMC_IO_DPD3_REQ */\n\tu32 PmcIoDpd3ReqWait;\n\tu32 PmcIoDpd4ReqWait;\n\n\t/* Specifies the value for PMC_REG_SHORT */\n\tu32 PmcRegShort;\n\t/* Specifies the value for PMC_NO_IOPOWER */\n\tu32 PmcNoIoPower;\n\n\tu32 PmcDdrCntrlWait;\n\tu32 PmcDdrCntrl;\n\n\t/* Specifies the value for EMC_ACPD_CONTROL */\n\tu32 EmcAcpdControl;\n\n\t/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE_CFG */\n\t////u32 EmcSwizzleRank0ByteCfg;\n\t/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE0 */\n\tu32 EmcSwizzleRank0Byte0;\n\t/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE1 */\n\tu32 EmcSwizzleRank0Byte1;\n\t/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE2 */\n\tu32 EmcSwizzleRank0Byte2;\n\t/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE3 */\n\tu32 EmcSwizzleRank0Byte3;\n\t/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE_CFG */\n\t////u32 EmcSwizzleRank1ByteCfg;\n\t/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE0 */\n\tu32 EmcSwizzleRank1Byte0;\n\t/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE1 */\n\tu32 EmcSwizzleRank1Byte1;\n\t/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE2 */\n\tu32 EmcSwizzleRank1Byte2;\n\t/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE3 */\n\tu32 EmcSwizzleRank1Byte3;\n\n\t/* Specifies the value for EMC_TXDSRVTTGEN */\n\tu32 EmcTxdsrvttgen;\n\n\t/* Specifies the value for EMC_DATA_BRLSHFT_0 */\n\tu32 EmcDataBrlshft0;\n\tu32 EmcDataBrlshft1;\n\n\tu32 EmcDqsBrlshft0;\n\tu32 EmcDqsBrlshft1;\n\n\tu32 EmcCmdBrlshft0;\n\tu32 EmcCmdBrlshft1;\n\tu32 EmcCmdBrlshft2;\n\tu32 EmcCmdBrlshft3;\n\n\tu32 EmcQuseBrlshft0;\n\tu32 EmcQuseBrlshft1;\n\tu32 EmcQuseBrlshft2;\n\tu32 EmcQuseBrlshft3;\n\n\tu32 EmcDllCfg0;\n\tu32 EmcDllCfg1;\n\n\tu32 EmcPmcScratch1;\n\tu32 EmcPmcScratch2;\n\tu32 EmcPmcScratch3;\n\n\tu32 EmcPmacroPadCfgCtrl;\n\n\tu32 EmcPmacroVttgenCtrl0;\n\tu32 EmcPmacroVttgenCtrl1;\n\tu32 EmcPmacroVttgenCtrl2;\n\n\tu32 EmcPmacroBrickCtrlRfu1;\n\tu32 EmcPmacroCmdBrickCtrlFdpd;\n\tu32 EmcPmacroBrickCtrlRfu2;\n\tu32 EmcPmacroDataBrickCtrlFdpd;\n\tu32 EmcPmacroBgBiasCtrl0;\n\tu32 EmcPmacroDataPadRxCtrl;\n\tu32 EmcPmacroCmdPadRxCtrl;\n\tu32 EmcPmacroDataRxTermMode;\n\tu32 EmcPmacroCmdRxTermMode;\n\tu32 EmcPmacroDataPadTxCtrl;\n\tu32 EmcPmacroCommonPadTxCtrl;\n\tu32 EmcPmacroCmdPadTxCtrl;\n\tu32 EmcCfg3;\n\n\tu32 EmcPmacroTxPwrd0;\n\tu32 EmcPmacroTxPwrd1;\n\tu32 EmcPmacroTxPwrd2;\n\tu32 EmcPmacroTxPwrd3;\n\tu32 EmcPmacroTxPwrd4;\n\tu32 EmcPmacroTxPwrd5;\n\n\tu32 EmcConfigSampleDelay;\n\n\tu32 EmcPmacroBrickMapping0;\n\tu32 EmcPmacroBrickMapping1;\n\tu32 EmcPmacroBrickMapping2;\n\n\tu32 EmcPmacroTxSelClkSrc0;\n\tu32 EmcPmacroTxSelClkSrc1;\n\tu32 EmcPmacroTxSelClkSrc2;\n\tu32 EmcPmacroTxSelClkSrc3;\n\tu32 EmcPmacroTxSelClkSrc4;\n\tu32 EmcPmacroTxSelClkSrc5;\n\n\tu32 EmcPmacroDdllBypass;\n\n\tu32 EmcPmacroDdllPwrd0;\n\tu32 EmcPmacroDdllPwrd1;\n\tu32 EmcPmacroDdllPwrd2;\n\n\tu32 EmcPmacroCmdCtrl0;\n\tu32 EmcPmacroCmdCtrl1;\n\tu32 EmcPmacroCmdCtrl2;\n\n\t/* DRAM size information */\n\n\t/* Specifies the value for MC_EMEM_ADR_CFG */\n\tu32 McEmemAdrCfg;\n\t/* Specifies the value for MC_EMEM_ADR_CFG_DEV0 */\n\tu32 McEmemAdrCfgDev0;\n\t/* Specifies the value for MC_EMEM_ADR_CFG_DEV1 */\n\tu32 McEmemAdrCfgDev1;\n\tu32 McEmemAdrCfgChannelMask;\n\n\t/* Specifies the value for MC_EMEM_BANK_SWIZZLECfg0 */\n\tu32 McEmemAdrCfgBankMask0;\n\t/* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG1 */\n\tu32 McEmemAdrCfgBankMask1;\n\t/* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG2 */\n\tu32 McEmemAdrCfgBankMask2;\n\n\t/*\n\t * Specifies the value for MC_EMEM_CFG which holds the external memory\n\t * size (in KBytes)\n\t */\n\tu32 McEmemCfg;\n\n\t/* MC arbitration configuration */\n\n\t/* Specifies the value for MC_EMEM_ARB_CFG */\n\tu32 McEmemArbCfg;\n\t/* Specifies the value for MC_EMEM_ARB_OUTSTANDING_REQ */\n\tu32 McEmemArbOutstandingReq;\n\n\tu32 McEmemArbRefpbHpCtrl;\n\tu32 McEmemArbRefpbBankCtrl;\n\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RCD */\n\tu32 McEmemArbTimingRcd;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RP */\n\tu32 McEmemArbTimingRp;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RC */\n\tu32 McEmemArbTimingRc;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RAS */\n\tu32 McEmemArbTimingRas;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_FAW */\n\tu32 McEmemArbTimingFaw;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RRD */\n\tu32 McEmemArbTimingRrd;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RAP2PRE */\n\tu32 McEmemArbTimingRap2Pre;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_WAP2PRE */\n\tu32 McEmemArbTimingWap2Pre;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_R2R */\n\tu32 McEmemArbTimingR2R;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_W2W */\n\tu32 McEmemArbTimingW2W;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_R2W */\n\tu32 McEmemArbTimingR2W;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_W2R */\n\tu32 McEmemArbTimingW2R;\n\n\tu32 McEmemArbTimingRFCPB;\n\n\t/* Specifies the value for MC_EMEM_ARB_DA_TURNS */\n\tu32 McEmemArbDaTurns;\n\t/* Specifies the value for MC_EMEM_ARB_DA_COVERS */\n\tu32 McEmemArbDaCovers;\n\t/* Specifies the value for MC_EMEM_ARB_MISC0 */\n\tu32 McEmemArbMisc0;\n\t/* Specifies the value for MC_EMEM_ARB_MISC1 */\n\tu32 McEmemArbMisc1;\n\tu32 McEmemArbMisc2;\n\n\t/* Specifies the value for MC_EMEM_ARB_RING1_THROTTLE */\n\tu32 McEmemArbRing1Throttle;\n\t/* Specifies the value for MC_EMEM_ARB_OVERRIDE */\n\tu32 McEmemArbOverride;\n\t/* Specifies the value for MC_EMEM_ARB_OVERRIDE_1 */\n\tu32 McEmemArbOverride1;\n\t/* Specifies the value for MC_EMEM_ARB_RSV */\n\tu32 McEmemArbRsv;\n\n\tu32 McDaCfg0;\n\tu32 McEmemArbTimingCcdmw;\n\n\t/* Specifies the value for MC_CLKEN_OVERRIDE */\n\tu32 McClkenOverride;\n\n\t/* Specifies the value for MC_STAT_CONTROL */\n\tu32 McStatControl;\n\n\t/* Specifies the value for MC_VIDEO_PROTECT_BOM */\n\tu32 McVideoProtectBom;\n\t/* Specifies the value for MC_VIDEO_PROTECT_BOM_ADR_HI */\n\tu32 McVideoProtectBomAdrHi;\n\t/* Specifies the value for MC_VIDEO_PROTECT_SIZE_MB */\n\tu32 McVideoProtectSizeMb;\n\t/* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE */\n\tu32 McVideoProtectVprOverride;\n\t/* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE1 */\n\tu32 McVideoProtectVprOverride1;\n\t/* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_0 */\n\tu32 McVideoProtectGpuOverride0;\n\t/* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_1 */\n\tu32 McVideoProtectGpuOverride1;\n\t/* Specifies the value for MC_SEC_CARVEOUT_BOM */\n\tu32 McSecCarveoutBom;\n\t/* Specifies the value for MC_SEC_CARVEOUT_ADR_HI */\n\tu32 McSecCarveoutAdrHi;\n\t/* Specifies the value for MC_SEC_CARVEOUT_SIZE_MB */\n\tu32 McSecCarveoutSizeMb;\n\t/* Specifies the value for MC_VIDEO_PROTECT_REG_CTRL.\n\t   VIDEO_PROTECT_WRITEAccess */\n\tu32 McVideoProtectWriteAccess;\n\t/* Specifies the value for MC_SEC_CARVEOUT_REG_CTRL.\n\t   SEC_CARVEOUT_WRITEAccess */\n\tu32 McSecCarveoutProtectWriteAccess;\n\n\t/* Write-Protect Regions (WPR) */\n\tu32 McGeneralizedCarveout1Bom;\n\tu32 McGeneralizedCarveout1BomHi;\n\tu32 McGeneralizedCarveout1Size128kb;\n\tu32 McGeneralizedCarveout1Access0;\n\tu32 McGeneralizedCarveout1Access1;\n\tu32 McGeneralizedCarveout1Access2;\n\tu32 McGeneralizedCarveout1Access3;\n\tu32 McGeneralizedCarveout1Access4;\n\tu32 McGeneralizedCarveout1ForceInternalAccess0;\n\tu32 McGeneralizedCarveout1ForceInternalAccess1;\n\tu32 McGeneralizedCarveout1ForceInternalAccess2;\n\tu32 McGeneralizedCarveout1ForceInternalAccess3;\n\tu32 McGeneralizedCarveout1ForceInternalAccess4;\n\tu32 McGeneralizedCarveout1Cfg0;\n\n\tu32 McGeneralizedCarveout2Bom;\n\tu32 McGeneralizedCarveout2BomHi;\n\tu32 McGeneralizedCarveout2Size128kb;\n\tu32 McGeneralizedCarveout2Access0;\n\tu32 McGeneralizedCarveout2Access1;\n\tu32 McGeneralizedCarveout2Access2;\n\tu32 McGeneralizedCarveout2Access3;\n\tu32 McGeneralizedCarveout2Access4;\n\tu32 McGeneralizedCarveout2ForceInternalAccess0;\n\tu32 McGeneralizedCarveout2ForceInternalAccess1;\n\tu32 McGeneralizedCarveout2ForceInternalAccess2;\n\tu32 McGeneralizedCarveout2ForceInternalAccess3;\n\tu32 McGeneralizedCarveout2ForceInternalAccess4;\n\tu32 McGeneralizedCarveout2Cfg0;\n\n\tu32 McGeneralizedCarveout3Bom;\n\tu32 McGeneralizedCarveout3BomHi;\n\tu32 McGeneralizedCarveout3Size128kb;\n\tu32 McGeneralizedCarveout3Access0;\n\tu32 McGeneralizedCarveout3Access1;\n\tu32 McGeneralizedCarveout3Access2;\n\tu32 McGeneralizedCarveout3Access3;\n\tu32 McGeneralizedCarveout3Access4;\n\tu32 McGeneralizedCarveout3ForceInternalAccess0;\n\tu32 McGeneralizedCarveout3ForceInternalAccess1;\n\tu32 McGeneralizedCarveout3ForceInternalAccess2;\n\tu32 McGeneralizedCarveout3ForceInternalAccess3;\n\tu32 McGeneralizedCarveout3ForceInternalAccess4;\n\tu32 McGeneralizedCarveout3Cfg0;\n\n\tu32 McGeneralizedCarveout4Bom;\n\tu32 McGeneralizedCarveout4BomHi;\n\tu32 McGeneralizedCarveout4Size128kb;\n\tu32 McGeneralizedCarveout4Access0;\n\tu32 McGeneralizedCarveout4Access1;\n\tu32 McGeneralizedCarveout4Access2;\n\tu32 McGeneralizedCarveout4Access3;\n\tu32 McGeneralizedCarveout4Access4;\n\tu32 McGeneralizedCarveout4ForceInternalAccess0;\n\tu32 McGeneralizedCarveout4ForceInternalAccess1;\n\tu32 McGeneralizedCarveout4ForceInternalAccess2;\n\tu32 McGeneralizedCarveout4ForceInternalAccess3;\n\tu32 McGeneralizedCarveout4ForceInternalAccess4;\n\tu32 McGeneralizedCarveout4Cfg0;\n\n\tu32 McGeneralizedCarveout5Bom;\n\tu32 McGeneralizedCarveout5BomHi;\n\tu32 McGeneralizedCarveout5Size128kb;\n\tu32 McGeneralizedCarveout5Access0;\n\tu32 McGeneralizedCarveout5Access1;\n\tu32 McGeneralizedCarveout5Access2;\n\tu32 McGeneralizedCarveout5Access3;\n\tu32 McGeneralizedCarveout5Access4;\n\tu32 McGeneralizedCarveout5ForceInternalAccess0;\n\tu32 McGeneralizedCarveout5ForceInternalAccess1;\n\tu32 McGeneralizedCarveout5ForceInternalAccess2;\n\tu32 McGeneralizedCarveout5ForceInternalAccess3;\n\tu32 McGeneralizedCarveout5ForceInternalAccess4;\n\tu32 McGeneralizedCarveout5Cfg0;\n\n\t/* Specifies enable for CA training */\n\tu32 EmcCaTrainingEnable;\n\n\t/* Set if bit 6 select is greater than bit 7 select; uses aremc.\n\t   spec packet SWIZZLE_BIT6_GT_BIT7 */\n\tu32 SwizzleRankByteEncode;\n\t/* Specifies enable and offset for patched boot ROM write */\n\tu32 BootRomPatchControl;\n\t/* Specifies data for patched boot ROM write */\n\tu32 BootRomPatchData;\n\n\t/* Specifies the value for MC_MTS_CARVEOUT_BOM */\n\tu32 McMtsCarveoutBom;\n\t/* Specifies the value for MC_MTS_CARVEOUT_ADR_HI */\n\tu32 McMtsCarveoutAdrHi;\n\t/* Specifies the value for MC_MTS_CARVEOUT_SIZE_MB */\n\tu32 McMtsCarveoutSizeMb;\n\t/* Specifies the value for MC_MTS_CARVEOUT_REG_CTRL */\n\tu32 McMtsCarveoutRegCtrl;\n\n\t/* End */\n} sdram_params_t210_t;\n\n#endif /* __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__ */\n"
  },
  {
    "path": "modules/hekate_libsys_lp0/sdram_lp0_param_t210b01.h",
    "content": "/*\n * Copyright (c) 2020 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n */\n\n#ifndef __TEGRA210B01_SDRAM_PARAM_H__\n#define __TEGRA210B01_SDRAM_PARAM_H__\n\n#include \"types.h\"\n\ntypedef struct _sdram_params_t210b01_t\n{\n\t/* Specifies the type of memory device */\n\tu32 memory_type;\n\n\t/* MC/EMC clock source configuration */\n\n\t/* Specifies the M value for PllM */\n\tu32 pllm_input_divider;\n\t/* Specifies the N value for PllM */\n\tu32 pllm_feedback_divider;\n\t/* Specifies the time to wait for PLLM to lock (in microseconds) */\n\tu32 pllm_stable_time;\n\t/* Specifies misc. control bits */\n\tu32 pllm_setup_control;\n\t/* Specifies the P value for PLLM */\n\tu32 pllm_post_divider;\n\t/* Specifies value for Charge Pump Gain Control */\n\tu32 pllm_kcp;\n\t/* Specifies VCO gain */\n\tu32 pllm_kvco;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare0;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare1;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare2;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare3;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare4;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare5;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare6;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare7;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare8;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare9;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare10;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare11;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare12;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare13;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure0;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure1;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure2;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure3;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure4;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure5;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure6;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure7;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure8;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure9;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure10;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure11;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure12;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure13;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure14;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure15;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure16;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure17;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure18;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure19;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure20;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure21;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure22;\n\t/* Spare BCT param */\n\tu32 emc_bct_spare_secure23;\n\n\t/* Defines EMC_2X_CLK_SRC, EMC_2X_CLK_DIVISOR, EMC_INVERT_DCD */\n\tu32 emc_clock_source;\n\tu32 emc_clock_source_dll;\n\n\t/* Defines possible override for PLLLM_MISC2 */\n\tu32 clk_rst_pllm_misc20_override;\n\t/* enables override for PLLLM_MISC2 */\n\tu32 clk_rst_pllm_misc20_override_enable;\n\t/* defines CLK_ENB_MC1 in register clk_rst_controller_clk_enb_w_clr */\n\tu32 clear_clock2_mc1;\n\n\t/* Auto-calibration of EMC pads */\n\n\t/* Specifies the value for EMC_AUTO_CAL_INTERVAL */\n\tu32 emc_auto_cal_interval;\n\t/*\n\t * Specifies the value for EMC_AUTO_CAL_CONFIG\n\t * Note: Trigger bits are set by the SDRAM code.\n\t */\n\tu32 emc_auto_cal_config;\n\n\t/* Specifies the value for EMC_AUTO_CAL_CONFIG2 */\n\tu32 emc_auto_cal_config2;\n\n\t/* Specifies the value for EMC_AUTO_CAL_CONFIG3 */\n\tu32 emc_auto_cal_config3;\n\tu32 emc_auto_cal_config4;\n\tu32 emc_auto_cal_config5;\n\tu32 emc_auto_cal_config6;\n\tu32 emc_auto_cal_config7;\n\tu32 emc_auto_cal_config8;\n\tu32 emc_auto_cal_config9;\n\n\t/* Specifies the value for EMC_AUTO_CAL_VREF_SEL_0 */\n\tu32 emc_auto_cal_vref_sel0;\n\tu32 emc_auto_cal_vref_sel1;\n\n\t/* Specifies the value for EMC_AUTO_CAL_CHANNEL */\n\tu32 emc_auto_cal_channel;\n\n\t/* Specifies the value for EMC_PMACRO_AUTOCAL_CFG_0 */\n\tu32 emc_pmacro_auto_cal_cfg0;\n\tu32 emc_pmacro_auto_cal_cfg1;\n\tu32 emc_pmacro_auto_cal_cfg2;\n\n\tu32 emc_pmacro_rx_term;\n\tu32 emc_pmacro_dq_tx_drive;\n\tu32 emc_pmacro_ca_tx_drive;\n\tu32 emc_pmacro_cmd_tx_drive;\n\tu32 emc_pmacro_auto_cal_common;\n\tu32 emc_pmacro_zcrtl;\n\n\t/*\n\t * Specifies the time for the calibration\n\t * to stabilize (in microseconds)\n\t */\n\tu32 emc_auto_cal_wait;\n\n\tu32 emc_xm2_comp_pad_ctrl;\n\tu32 emc_xm2_comp_pad_ctrl2;\n\tu32 emc_xm2_comp_pad_ctrl3;\n\n\t/*\n\t * DRAM size information\n\t * Specifies the value for EMC_ADR_CFG\n\t */\n\tu32 emc_adr_cfg;\n\n\t/*\n\t * Specifies the time to wait after asserting pin\n\t * CKE (in microseconds)\n\t */\n\tu32 emc_pin_program_wait;\n\t/* Specifies the extra delay before/after pin RESET/CKE command */\n\tu32 emc_pin_extra_wait;\n\n\tu32 emc_pin_gpio_enable;\n\tu32 emc_pin_gpio;\n\n\t/*\n\t * Specifies the extra delay after the first writing\n\t * of EMC_TIMING_CONTROL\n\t */\n\tu32 emc_timing_control_wait;\n\n\t/* Timing parameters required for the SDRAM */\n\n\t/* Specifies the value for EMC_RC */\n\tu32 emc_rc;\n\t/* Specifies the value for EMC_RFC */\n\tu32 emc_rfc;\n\n\tu32 emc_rfc_pb;\n\tu32 emc_ref_ctrl2;\n\n\t/* Specifies the value for EMC_RFC_SLR */\n\tu32 emc_rfc_slr;\n\t/* Specifies the value for EMC_RAS */\n\tu32 emc_ras;\n\t/* Specifies the value for EMC_RP */\n\tu32 emc_rp;\n\t/* Specifies the value for EMC_R2R */\n\tu32 emc_r2r;\n\t/* Specifies the value for EMC_W2W */\n\tu32 emc_w2w;\n\t/* Specifies the value for EMC_R2W */\n\tu32 emc_r2w;\n\t/* Specifies the value for EMC_W2R */\n\tu32 emc_w2r;\n\t/* Specifies the value for EMC_R2P */\n\tu32 emc_r2p;\n\t/* Specifies the value for EMC_W2P */\n\tu32 emc_w2p;\n\n\tu32 emc_tppd;\n\tu32 emc_trtm;\n\tu32 emc_twtm;\n\tu32 emc_tratm;\n\tu32 emc_twatm;\n\tu32 emc_tr2ref;\n\tu32 emc_ccdmw;\n\n\t/* Specifies the value for EMC_RD_RCD */\n\tu32 emc_rd_rcd;\n\t/* Specifies the value for EMC_WR_RCD */\n\tu32 emc_wr_rcd;\n\t/* Specifies the value for EMC_RRD */\n\tu32 emc_rrd;\n\t/* Specifies the value for EMC_REXT */\n\tu32 emc_rext;\n\t/* Specifies the value for EMC_WEXT */\n\tu32 emc_wext;\n\t/* Specifies the value for EMC_WDV */\n\tu32 emc_wdv;\n\n\tu32 emc_wdv_chk;\n\tu32 emc_wsv;\n\tu32 emc_wev;\n\n\t/* Specifies the value for EMC_WDV_MASK */\n\tu32 emc_wdv_mask;\n\n\tu32 emc_ws_duration;\n\tu32 emc_we_duration;\n\n\t/* Specifies the value for EMC_QUSE */\n\tu32 emc_quse;\n\t/* Specifies the value for EMC_QUSE_WIDTH */\n\tu32 emc_quse_width;\n\t/* Specifies the value for EMC_IBDLY */\n\tu32 emc_ibdly;\n\n\tu32 emc_obdly;\n\n\t/* Specifies the value for EMC_EINPUT */\n\tu32 emc_einput;\n\t/* Specifies the value for EMC_EINPUT_DURATION */\n\tu32 emc_einput_duration;\n\t/* Specifies the value for EMC_PUTERM_EXTRA */\n\tu32 emc_puterm_extra;\n\t/* Specifies the value for EMC_PUTERM_WIDTH */\n\tu32 emc_puterm_width;\n\n\tu32 emc_qrst;\n\tu32 emc_qsafe;\n\tu32 emc_rdv;\n\tu32 emc_rdv_mask;\n\n\tu32 emc_rdv_early;\n\tu32 emc_rdv_early_mask;\n\n\t/* Specifies the value for EMC_QPOP */\n\tu32 emc_qpop;\n\n\t/* Specifies the value for EMC_REFRESH */\n\tu32 emc_refresh;\n\t/* Specifies the value for EMC_BURST_REFRESH_NUM */\n\tu32 emc_burst_refresh_num;\n\t/* Specifies the value for EMC_PRE_REFRESH_REQ_CNT */\n\tu32 emc_prerefresh_req_cnt;\n\t/* Specifies the value for EMC_PDEX2WR */\n\tu32 emc_pdex2wr;\n\t/* Specifies the value for EMC_PDEX2RD */\n\tu32 emc_pdex2rd;\n\t/* Specifies the value for EMC_PCHG2PDEN */\n\tu32 emc_pchg2pden;\n\t/* Specifies the value for EMC_ACT2PDEN */\n\tu32 emc_act2pden;\n\t/* Specifies the value for EMC_AR2PDEN */\n\tu32 emc_ar2pden;\n\t/* Specifies the value for EMC_RW2PDEN */\n\tu32 emc_rw2pden;\n\n\tu32 emc_cke2pden;\n\tu32 emc_pdex2che;\n\tu32 emc_pdex2mrr;\n\n\t/* Specifies the value for EMC_TXSR */\n\tu32 emc_txsr;\n\t/* Specifies the value for EMC_TXSRDLL */\n\tu32 emc_txsr_dll;\n\t/* Specifies the value for EMC_TCKE */\n\tu32 emc_tcke;\n\t/* Specifies the value for EMC_TCKESR */\n\tu32 emc_tckesr;\n\t/* Specifies the value for EMC_TPD */\n\tu32 emc_tpd;\n\t/* Specifies the value for EMC_TFAW */\n\tu32 emc_tfaw;\n\t/* Specifies the value for EMC_TRPAB */\n\tu32 emc_trpab;\n\t/* Specifies the value for EMC_TCLKSTABLE */\n\tu32 emc_tclkstable;\n\t/* Specifies the value for EMC_TCLKSTOP */\n\tu32 emc_tclkstop;\n\t/* Specifies the value for EMC_TREFBW */\n\tu32 emc_trefbw;\n\n\t/* FBIO configuration values */\n\n\t/* Specifies the value for EMC_FBIO_CFG5 */\n\tu32 emc_fbio_cfg5;\n\t/* Specifies the value for EMC_FBIO_CFG7 */\n\tu32 emc_fbio_cfg7;\n\tu32 emc_fbio_cfg8;\n\n\t/* Command mapping for CMD brick 0 */\n\tu32 emc_cmd_mapping_cmd0_0;\n\tu32 emc_cmd_mapping_cmd0_1;\n\tu32 emc_cmd_mapping_cmd0_2;\n\tu32 emc_cmd_mapping_cmd1_0;\n\tu32 emc_cmd_mapping_cmd1_1;\n\tu32 emc_cmd_mapping_cmd1_2;\n\tu32 emc_cmd_mapping_cmd2_0;\n\tu32 emc_cmd_mapping_cmd2_1;\n\tu32 emc_cmd_mapping_cmd2_2;\n\tu32 emc_cmd_mapping_cmd3_0;\n\tu32 emc_cmd_mapping_cmd3_1;\n\tu32 emc_cmd_mapping_cmd3_2;\n\tu32 emc_cmd_mapping_byte;\n\n\t/* Specifies the value for EMC_FBIO_SPARE */\n\tu32 emc_fbio_spare;\n\n\t/* Specifies the value for EMC_CFG_RSV */\n\tu32 emc_cfg_rsv;\n\n\t/* MRS command values */\n\n\t/* Specifies the value for EMC_MRS */\n\tu32 emc_mrs;\n\t/* Specifies the MP0 command to initialize mode registers */\n\tu32 emc_emrs;\n\t/* Specifies the MP2 command to initialize mode registers */\n\tu32 emc_emrs2;\n\t/* Specifies the MP3 command to initialize mode registers */\n\tu32 emc_emrs3;\n\t/* Specifies the programming to LPDDR2 Mode Register 1 at cold boot */\n\tu32 emc_mrw1;\n\t/* Specifies the programming to LPDDR2 Mode Register 2 at cold boot */\n\tu32 emc_mrw2;\n\t/* Specifies the programming to LPDDR2 Mode Register 3 at cold boot */\n\tu32 emc_mrw3;\n\t/* Specifies the programming to LPDDR2 Mode Register 11 at cold boot */\n\tu32 emc_mrw4;\n\n\t/* Specifies the programming to LPDDR4 Mode Register 3 at cold boot */\n\tu32 emc_mrw6;\n\t/* Specifies the programming to LPDDR4 Mode Register 11 at cold boot */\n\tu32 emc_mrw8;\n\t/* Specifies the programming to LPDDR4 Mode Register 11 at cold boot */\n\tu32 emc_mrw9;\n\t/* Specifies the programming to LPDDR4 Mode Register 12 at cold boot */\n\tu32 emc_mrw10;\n\t/* Specifies the programming to LPDDR4 Mode Register 14 at cold boot */\n\tu32 emc_mrw12;\n\t/* Specifies the programming to LPDDR4 Mode Register 14 at cold boot */\n\tu32 emc_mrw13;\n\t/* Specifies the programming to LPDDR4 Mode Register 22 at cold boot */\n\tu32 emc_mrw14;\n\n\t/*\n\t * Specifies the programming to extra LPDDR2 Mode Register\n\t * at cold boot\n\t */\n\tu32 emc_mrw_extra;\n\t/*\n\t * Specifies the programming to extra LPDDR2 Mode Register\n\t * at warm boot\n\t */\n\tu32 emc_warm_boot_mrw_extra;\n\t/*\n\t * Specify the enable of extra Mode Register programming at\n\t * warm boot\n\t */\n\tu32 emc_warm_boot_extramode_reg_write_enable;\n\t/*\n\t * Specify the enable of extra Mode Register programming at\n\t * cold boot\n\t */\n\tu32 emc_extramode_reg_write_enable;\n\n\t/* Specifies the EMC_MRW reset command value */\n\tu32 emc_mrw_reset_command;\n\t/* Specifies the EMC Reset wait time (in microseconds) */\n\tu32 emc_mrw_reset_ninit_wait;\n\t/* Specifies the value for EMC_MRS_WAIT_CNT */\n\tu32 emc_mrs_wait_cnt;\n\t/* Specifies the value for EMC_MRS_WAIT_CNT2 */\n\tu32 emc_mrs_wait_cnt2;\n\n\t/* EMC miscellaneous configurations */\n\n\t/* Specifies the value for EMC_CFG */\n\tu32 emc_cfg;\n\t/* Specifies the value for EMC_CFG_2 */\n\tu32 emc_cfg2;\n\t/* Specifies the pipe bypass controls */\n\tu32 emc_cfg_pipe;\n\n\tu32 emc_cfg_pipe_clk;\n\tu32 emc_fdpd_ctrl_cmd_no_ramp;\n\tu32 emc_cfg_update;\n\n\t/* Specifies the value for EMC_DBG */\n\tu32 emc_dbg;\n\n\tu32 emc_dbg_write_mux;\n\n\t/* Specifies the value for EMC_CMDQ */\n\tu32 emc_cmd_q;\n\t/* Specifies the value for EMC_MC2EMCQ */\n\tu32 emc_mc2emc_q;\n\t/* Specifies the value for EMC_DYN_SELF_REF_CONTROL */\n\tu32 emc_dyn_self_ref_control;\n\n\t/* Specifies the value for MEM_INIT_DONE */\n\tu32 ahb_arbitration_xbar_ctrl_meminit_done;\n\n\t/* Specifies the value for EMC_CFG_DIG_DLL */\n\tu32 emc_cfg_dig_dll;\n\tu32 emc_cfg_dig_dll_1;\n\n\t/* Specifies the value for EMC_CFG_DIG_DLL_PERIOD */\n\tu32 emc_cfg_dig_dll_period;\n\t/* Specifies the value of *DEV_SELECTN of various EMC registers */\n\tu32 emc_dev_select;\n\n\t/* Specifies the value for EMC_SEL_DPD_CTRL */\n\tu32 emc_sel_dpd_ctrl;\n\n\t/* Pads trimmer delays */\n\tu32 emc_fdpd_ctrl_dq;\n\tu32 emc_fdpd_ctrl_cmd;\n\tu32 emc_pmacro_ib_vref_dq_0;\n\tu32 emc_pmacro_ib_vref_dq_1;\n\tu32 emc_pmacro_ib_vref_dqs_0;\n\tu32 emc_pmacro_ib_vref_dqs_1;\n\tu32 emc_pmacro_ib_rxrt;\n\tu32 emc_cfg_pipe1;\n\tu32 emc_cfg_pipe2;\n\n\t/* Specifies the value for EMC_PMACRO_QUSE_DDLL_RANK0_0 */\n\tu32 emc_pmacro_quse_ddll_rank0_0;\n\tu32 emc_pmacro_quse_ddll_rank0_1;\n\tu32 emc_pmacro_quse_ddll_rank0_2;\n\tu32 emc_pmacro_quse_ddll_rank0_3;\n\tu32 emc_pmacro_quse_ddll_rank0_4;\n\tu32 emc_pmacro_quse_ddll_rank0_5;\n\tu32 emc_pmacro_quse_ddll_rank1_0;\n\tu32 emc_pmacro_quse_ddll_rank1_1;\n\tu32 emc_pmacro_quse_ddll_rank1_2;\n\tu32 emc_pmacro_quse_ddll_rank1_3;\n\tu32 emc_pmacro_quse_ddll_rank1_4;\n\tu32 emc_pmacro_quse_ddll_rank1_5;\n\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_0;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_1;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_2;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_3;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_4;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_5;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_0;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_1;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_2;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_3;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_4;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_5;\n\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_0;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_1;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_2;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_3;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_4;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_5;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_0;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_1;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_2;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_3;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_4;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_5;\n\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_0;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_1;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_2;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_3;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_0;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_1;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_2;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_3;\n\n\tu32 emc_pmacro_ddll_long_cmd_0;\n\tu32 emc_pmacro_ddll_long_cmd_1;\n\tu32 emc_pmacro_ddll_long_cmd_2;\n\tu32 emc_pmacro_ddll_long_cmd_3;\n\tu32 emc_pmacro_ddll_long_cmd_4;\n\tu32 emc_pmacro_ddll_short_cmd_0;\n\tu32 emc_pmacro_ddll_short_cmd_1;\n\tu32 emc_pmacro_ddll_short_cmd_2;\n\n\tu32 emc_pmacro_ddll_periodic_offset;\n\n\t/*\n\t * Specifies the delay after asserting CKE pin during a WarmBoot0\n\t * sequence (in microseconds)\n\t */\n\tu32 warm_boot_wait;\n\n\t/* Specifies the value for EMC_ODT_WRITE */\n\tu32 emc_odt_write;\n\n\t/* Periodic ZQ calibration */\n\n\t/*\n\t * Specifies the value for EMC_ZCAL_INTERVAL\n\t * Value 0 disables ZQ calibration\n\t */\n\tu32 emc_zcal_interval;\n\t/* Specifies the value for EMC_ZCAL_WAIT_CNT */\n\tu32 emc_zcal_wait_cnt;\n\t/* Specifies the value for EMC_ZCAL_MRW_CMD */\n\tu32 emc_zcal_mrw_cmd;\n\n\t/* DRAM initialization sequence flow control */\n\n\t/* Specifies the MRS command value for resetting DLL */\n\tu32 emc_mrs_reset_dll;\n\t/* Specifies the command for ZQ initialization of device 0 */\n\tu32 emc_zcal_init_dev0;\n\t/* Specifies the command for ZQ initialization of device 1 */\n\tu32 emc_zcal_init_dev1;\n\t/*\n\t * Specifies the wait time after programming a ZQ initialization\n\t * command (in microseconds)\n\t */\n\tu32 emc_zcal_init_wait;\n\t/*\n\t * Specifies the enable for ZQ calibration at cold boot [bit 0]\n\t * and warm boot [bit 1]\n\t */\n\tu32 emc_zcal_warm_cold_boot_enables;\n\n\t/*\n\t * Specifies the MRW command to LPDDR2 for ZQ calibration\n\t * on warmboot\n\t */\n\t/* Is issued to both devices separately */\n\tu32 emc_mrw_lpddr2zcal_warm_boot;\n\t/*\n\t * Specifies the ZQ command to DDR3 for ZQ calibration on warmboot\n\t * Is issued to both devices separately\n\t */\n\tu32 emc_zqcal_ddr3_warm_boot;\n\n\tu32 emc_zqcal_lpddr4_warm_boot;\n\n\t/*\n\t * Specifies the wait time for ZQ calibration on warmboot\n\t * (in microseconds)\n\t */\n\tu32 emc_zcal_warm_boot_wait;\n\t/*\n\t * Specifies the enable for DRAM Mode Register programming\n\t * at warm boot\n\t */\n\tu32 emc_mrs_warm_boot_enable;\n\t/*\n\t * Specifies the wait time after sending an MRS DLL reset command\n\t * in microseconds)\n\t */\n\tu32 emc_mrs_reset_dll_wait;\n\t/* Specifies the extra MRS command to initialize mode registers */\n\tu32 emc_mrs_extra;\n\t/* Specifies the extra MRS command at warm boot */\n\tu32 emc_warm_boot_mrs_extra;\n\t/* Specifies the EMRS command to enable the DDR2 DLL */\n\tu32 emc_emrs_ddr2_dll_enable;\n\t/* Specifies the MRS command to reset the DDR2 DLL */\n\tu32 emc_mrs_ddr2_dll_reset;\n\t/* Specifies the EMRS command to set OCD calibration */\n\tu32 emc_emrs_ddr2_ocd_calib;\n\t/*\n\t * Specifies the wait between initializing DDR and setting OCD\n\t * calibration (in microseconds)\n\t */\n\tu32 emc_ddr2_wait;\n\t/* Specifies the value for EMC_CLKEN_OVERRIDE */\n\tu32 emc_clken_override;\n\t/*\n\t * Specifies LOG2 of the extra refresh numbers after booting\n\t * Program 0 to disable\n\t */\n\tu32 emc_extra_refresh_num;\n\t/* Specifies the master override for all EMC clocks */\n\tu32 emc_clken_override_allwarm_boot;\n\t/* Specifies the master override for all MC clocks */\n\tu32 mc_clken_override_allwarm_boot;\n\t/* Specifies digital dll period, choosing between 4 to 64 ms */\n\tu32 emc_cfg_dig_dll_period_warm_boot;\n\n\t/* Pad controls */\n\n\t/* Specifies the value for PMC_VDDP_SEL */\n\tu32 pmc_vddp_sel;\n\t/* Specifies the wait time after programming PMC_VDDP_SEL */\n\tu32 pmc_vddp_sel_wait;\n\t/* Specifies the value for PMC_DDR_CFG */\n\tu32 pmc_ddr_cfg;\n\t/* Specifies the value for PMC_IO_DPD3_REQ */\n\tu32 pmc_io_dpd3_req;\n\t/* Specifies the wait time after programming PMC_IO_DPD3_REQ */\n\tu32 pmc_io_dpd3_req_wait;\n\n\tu32 pmc_io_dpd4_req_wait;\n\n\t/* Specifies the value for PMC_REG_SHORT */\n\tu32 pmc_reg_short;\n\t/* Specifies the value for PMC_NO_IOPOWER */\n\tu32 pmc_no_io_power;\n\n\tu32 pmc_ddr_ctrl_wait;\n\tu32 pmc_ddr_ctrl;\n\n\t/* Specifies the value for EMC_ACPD_CONTROL */\n\tu32 emc_acpd_control;\n\n\t/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE0 */\n\tu32 emc_swizzle_rank0_byte0;\n\t/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE1 */\n\tu32 emc_swizzle_rank0_byte1;\n\t/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE2 */\n\tu32 emc_swizzle_rank0_byte2;\n\t/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE3 */\n\tu32 emc_swizzle_rank0_byte3;\n\t/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE0 */\n\tu32 emc_swizzle_rank1_byte0;\n\t/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE1 */\n\tu32 emc_swizzle_rank1_byte1;\n\t/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE2 */\n\tu32 emc_swizzle_rank1_byte2;\n\t/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE3 */\n\tu32 emc_swizzle_rank1_byte3;\n\n\t/* Specifies the value for EMC_TXDSRVTTGEN */\n\tu32 emc_txdsrvttgen;\n\n\t/* Specifies the value for EMC_DATA_BRLSHFT_0 */\n\tu32 emc_data_brlshft0;\n\tu32 emc_data_brlshft1;\n\n\tu32 emc_dqs_brlshft0;\n\tu32 emc_dqs_brlshft1;\n\n\tu32 emc_cmd_brlshft0;\n\tu32 emc_cmd_brlshft1;\n\tu32 emc_cmd_brlshft2;\n\tu32 emc_cmd_brlshft3;\n\n\tu32 emc_quse_brlshft0;\n\tu32 emc_quse_brlshft1;\n\tu32 emc_quse_brlshft2;\n\tu32 emc_quse_brlshft3;\n\n\tu32 emc_dll_cfg0;\n\tu32 emc_dll_cfg1;\n\n\tu32 emc_pmc_scratch1;\n\tu32 emc_pmc_scratch2;\n\tu32 emc_pmc_scratch3;\n\n\tu32 emc_pmacro_pad_cfg_ctrl;\n\n\tu32 emc_pmacro_vttgen_ctrl0;\n\tu32 emc_pmacro_vttgen_ctrl1;\n\tu32 emc_pmacro_vttgen_ctrl2;\n\tu32 emc_pmacro_dsr_vttgen_ctrl0;\n\tu32 emc_pmacro_brick_ctrl_rfu1;\n\tu32 emc_pmacro_cmd_brick_ctrl_fdpd;\n\tu32 emc_pmacro_brick_ctrl_rfu2;\n\tu32 emc_pmacro_data_brick_ctrl_fdpd;\n\tu32 emc_pmacro_bg_bias_ctrl0;\n\tu32 emc_pmacro_data_pad_rx_ctrl;\n\tu32 emc_pmacro_cmd_pad_rx_ctrl;\n\tu32 emc_pmacro_data_rx_term_mode;\n\tu32 emc_pmacro_cmd_rx_term_mode;\n\tu32 emc_pmacro_data_pad_tx_ctrl;\n\tu32 emc_pmacro_cmd_pad_tx_ctrl;\n\tu32 emc_cfg3;\n\n\tu32 emc_pmacro_tx_pwrd0;\n\tu32 emc_pmacro_tx_pwrd1;\n\tu32 emc_pmacro_tx_pwrd2;\n\tu32 emc_pmacro_tx_pwrd3;\n\tu32 emc_pmacro_tx_pwrd4;\n\tu32 emc_pmacro_tx_pwrd5;\n\n\tu32 emc_config_sample_delay;\n\n\tu32 emc_pmacro_brick_mapping0;\n\tu32 emc_pmacro_brick_mapping1;\n\tu32 emc_pmacro_brick_mapping2;\n\n\tu32 emc_pmacro_tx_sel_clk_src0;\n\tu32 emc_pmacro_tx_sel_clk_src1;\n\tu32 emc_pmacro_tx_sel_clk_src2;\n\tu32 emc_pmacro_tx_sel_clk_src3;\n\tu32 emc_pmacro_tx_sel_clk_src4;\n\tu32 emc_pmacro_tx_sel_clk_src5;\n\n\tu32 emc_pmacro_perbit_fgcg_ctrl0;\n\tu32 emc_pmacro_perbit_fgcg_ctrl1;\n\tu32 emc_pmacro_perbit_fgcg_ctrl2;\n\tu32 emc_pmacro_perbit_fgcg_ctrl3;\n\tu32 emc_pmacro_perbit_fgcg_ctrl4;\n\tu32 emc_pmacro_perbit_fgcg_ctrl5;\n\tu32 emc_pmacro_perbit_rfu_ctrl0;\n\tu32 emc_pmacro_perbit_rfu_ctrl1;\n\tu32 emc_pmacro_perbit_rfu_ctrl2;\n\tu32 emc_pmacro_perbit_rfu_ctrl3;\n\tu32 emc_pmacro_perbit_rfu_ctrl4;\n\tu32 emc_pmacro_perbit_rfu_ctrl5;\n\tu32 emc_pmacro_perbit_rfu1_ctrl0;\n\tu32 emc_pmacro_perbit_rfu1_ctrl1;\n\tu32 emc_pmacro_perbit_rfu1_ctrl2;\n\tu32 emc_pmacro_perbit_rfu1_ctrl3;\n\tu32 emc_pmacro_perbit_rfu1_ctrl4;\n\tu32 emc_pmacro_perbit_rfu1_ctrl5;\n\n\tu32 emc_pmacro_data_pi_ctrl;\n\tu32 emc_pmacro_cmd_pi_ctrl;\n\n\tu32 emc_pmacro_ddll_bypass;\n\n\tu32 emc_pmacro_ddll_pwrd0;\n\tu32 emc_pmacro_ddll_pwrd1;\n\tu32 emc_pmacro_ddll_pwrd2;\n\n\tu32 emc_pmacro_cmd_ctrl0;\n\tu32 emc_pmacro_cmd_ctrl1;\n\tu32 emc_pmacro_cmd_ctrl2;\n\n\t/* DRAM size information */\n\n\t/* Specifies the value for MC_EMEM_ADR_CFG */\n\tu32 mc_emem_adr_cfg;\n\t/* Specifies the value for MC_EMEM_ADR_CFG_DEV0 */\n\tu32 mc_emem_adr_cfg_dev0;\n\t/* Specifies the value for MC_EMEM_ADR_CFG_DEV1 */\n\tu32 mc_emem_adr_cfg_dev1;\n\n\tu32 mc_emem_adr_cfg_channel_mask;\n\n\t/* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG0 */\n\tu32 mc_emem_adr_cfg_bank_mask0;\n\t/* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG1 */\n\tu32 mc_emem_adr_cfg_bank_mask1;\n\t/* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG2 */\n\tu32 mc_emem_adr_cfg_bank_mask2;\n\n\t/*\n\t * Specifies the value for MC_EMEM_CFG which holds the external memory\n\t * size (in KBytes)\n\t */\n\tu32 mc_emem_cfg;\n\n\t/* MC arbitration configuration */\n\n\t/* Specifies the value for MC_EMEM_ARB_CFG */\n\tu32 mc_emem_arb_cfg;\n\t/* Specifies the value for MC_EMEM_ARB_OUTSTANDING_REQ */\n\tu32 mc_emem_arb_outstanding_req;\n\n\tu32 emc_emem_arb_refpb_hp_ctrl;\n\tu32 emc_emem_arb_refpb_bank_ctrl;\n\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RCD */\n\tu32 mc_emem_arb_timing_rcd;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RP */\n\tu32 mc_emem_arb_timing_rp;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RC */\n\tu32 mc_emem_arb_timing_rc;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RAS */\n\tu32 mc_emem_arb_timing_ras;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_FAW */\n\tu32 mc_emem_arb_timing_faw;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RRD */\n\tu32 mc_emem_arb_timing_rrd;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_RAP2PRE */\n\tu32 mc_emem_arb_timing_rap2pre;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_WAP2PRE */\n\tu32 mc_emem_arb_timing_wap2pre;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_R2R */\n\tu32 mc_emem_arb_timing_r2r;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_W2W */\n\tu32 mc_emem_arb_timing_w2w;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_R2W */\n\tu32 mc_emem_arb_timing_r2w;\n\t/* Specifies the value for MC_EMEM_ARB_TIMING_W2R */\n\tu32 mc_emem_arb_timing_w2r;\n\n\tu32 mc_emem_arb_timing_rfcpb;\n\n\t/* Specifies the value for MC_EMEM_ARB_DA_TURNS */\n\tu32 mc_emem_arb_da_turns;\n\t/* Specifies the value for MC_EMEM_ARB_DA_COVERS */\n\tu32 mc_emem_arb_da_covers;\n\t/* Specifies the value for MC_EMEM_ARB_MISC0 */\n\tu32 mc_emem_arb_misc0;\n\t/* Specifies the value for MC_EMEM_ARB_MISC1 */\n\tu32 mc_emem_arb_misc1;\n\tu32 mc_emem_arb_misc2;\n\n\t/* Specifies the value for MC_EMEM_ARB_RING1_THROTTLE */\n\tu32 mc_emem_arb_ring1_throttle;\n\t/* Specifies the value for MC_EMEM_ARB_OVERRIDE */\n\tu32 mc_emem_arb_override;\n\t/* Specifies the value for MC_EMEM_ARB_OVERRIDE_1 */\n\tu32 mc_emem_arb_override1;\n\t/* Specifies the value for MC_EMEM_ARB_RSV */\n\tu32 mc_emem_arb_rsv;\n\n\tu32 mc_da_cfg0;\n\tu32 mc_emem_arb_timing_ccdmw;\n\n\t/* Specifies the value for MC_CLKEN_OVERRIDE */\n\tu32 mc_clken_override;\n\n\t/* Specifies the value for MC_STAT_CONTROL */\n\tu32 mc_stat_control;\n\t/* Specifies the value for MC_VIDEO_PROTECT_BOM */\n\tu32 mc_video_protect_bom;\n\t/* Specifies the value for MC_VIDEO_PROTECT_BOM_ADR_HI */\n\tu32 mc_video_protect_bom_adr_hi;\n\t/* Specifies the value for MC_VIDEO_PROTECT_SIZE_MB */\n\tu32 mc_video_protect_size_mb;\n\t/* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE */\n\tu32 mc_video_protect_vpr_override;\n\t/* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE1 */\n\tu32 mc_video_protect_vpr_override1;\n\t/* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_0 */\n\tu32 mc_video_protect_gpu_override0;\n\t/* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_1 */\n\tu32 mc_video_protect_gpu_override1;\n\t/* Specifies the value for MC_SEC_CARVEOUT_BOM */\n\tu32 mc_sec_carveout_bom;\n\t/* Specifies the value for MC_SEC_CARVEOUT_ADR_HI */\n\tu32 mc_sec_carveout_adr_hi;\n\t/* Specifies the value for MC_SEC_CARVEOUT_SIZE_MB */\n\tu32 mc_sec_carveout_size_mb;\n\t/* Specifies the value for MC_VIDEO_PROTECT_REG_CTRL.VIDEO_PROTECT_WRITE_ACCESS */\n\tu32 mc_video_protect_write_access;\n\t/* Specifies the value for MC_SEC_CARVEOUT_REG_CTRL.SEC_CARVEOUT_WRITE_ACCESS */\n\tu32 mc_sec_carveout_protect_write_access;\n\n\tu32 mc_generalized_carveout1_bom;\n\tu32 mc_generalized_carveout1_bom_hi;\n\tu32 mc_generalized_carveout1_size_128kb;\n\tu32 mc_generalized_carveout1_access0;\n\tu32 mc_generalized_carveout1_access1;\n\tu32 mc_generalized_carveout1_access2;\n\tu32 mc_generalized_carveout1_access3;\n\tu32 mc_generalized_carveout1_access4;\n\tu32 mc_generalized_carveout1_force_internal_access0;\n\tu32 mc_generalized_carveout1_force_internal_access1;\n\tu32 mc_generalized_carveout1_force_internal_access2;\n\tu32 mc_generalized_carveout1_force_internal_access3;\n\tu32 mc_generalized_carveout1_force_internal_access4;\n\tu32 mc_generalized_carveout1_cfg0;\n\n\tu32 mc_generalized_carveout2_bom;\n\tu32 mc_generalized_carveout2_bom_hi;\n\tu32 mc_generalized_carveout2_size_128kb;\n\tu32 mc_generalized_carveout2_access0;\n\tu32 mc_generalized_carveout2_access1;\n\tu32 mc_generalized_carveout2_access2;\n\tu32 mc_generalized_carveout2_access3;\n\tu32 mc_generalized_carveout2_access4;\n\tu32 mc_generalized_carveout2_force_internal_access0;\n\tu32 mc_generalized_carveout2_force_internal_access1;\n\tu32 mc_generalized_carveout2_force_internal_access2;\n\tu32 mc_generalized_carveout2_force_internal_access3;\n\tu32 mc_generalized_carveout2_force_internal_access4;\n\tu32 mc_generalized_carveout2_cfg0;\n\n\tu32 mc_generalized_carveout3_bom;\n\tu32 mc_generalized_carveout3_bom_hi;\n\tu32 mc_generalized_carveout3_size_128kb;\n\tu32 mc_generalized_carveout3_access0;\n\tu32 mc_generalized_carveout3_access1;\n\tu32 mc_generalized_carveout3_access2;\n\tu32 mc_generalized_carveout3_access3;\n\tu32 mc_generalized_carveout3_access4;\n\tu32 mc_generalized_carveout3_force_internal_access0;\n\tu32 mc_generalized_carveout3_force_internal_access1;\n\tu32 mc_generalized_carveout3_force_internal_access2;\n\tu32 mc_generalized_carveout3_force_internal_access3;\n\tu32 mc_generalized_carveout3_force_internal_access4;\n\tu32 mc_generalized_carveout3_cfg0;\n\n\tu32 mc_generalized_carveout4_bom;\n\tu32 mc_generalized_carveout4_bom_hi;\n\tu32 mc_generalized_carveout4_size_128kb;\n\tu32 mc_generalized_carveout4_access0;\n\tu32 mc_generalized_carveout4_access1;\n\tu32 mc_generalized_carveout4_access2;\n\tu32 mc_generalized_carveout4_access3;\n\tu32 mc_generalized_carveout4_access4;\n\tu32 mc_generalized_carveout4_force_internal_access0;\n\tu32 mc_generalized_carveout4_force_internal_access1;\n\tu32 mc_generalized_carveout4_force_internal_access2;\n\tu32 mc_generalized_carveout4_force_internal_access3;\n\tu32 mc_generalized_carveout4_force_internal_access4;\n\tu32 mc_generalized_carveout4_cfg0;\n\n\tu32 mc_generalized_carveout5_bom;\n\tu32 mc_generalized_carveout5_bom_hi;\n\tu32 mc_generalized_carveout5_size_128kb;\n\tu32 mc_generalized_carveout5_access0;\n\tu32 mc_generalized_carveout5_access1;\n\tu32 mc_generalized_carveout5_access2;\n\tu32 mc_generalized_carveout5_access3;\n\tu32 mc_generalized_carveout5_access4;\n\tu32 mc_generalized_carveout5_force_internal_access0;\n\tu32 mc_generalized_carveout5_force_internal_access1;\n\tu32 mc_generalized_carveout5_force_internal_access2;\n\tu32 mc_generalized_carveout5_force_internal_access3;\n\tu32 mc_generalized_carveout5_force_internal_access4;\n\tu32 mc_generalized_carveout5_cfg0;\n\n\t/* Specifies enable for CA training */\n\tu32 emc_ca_training_enable;\n\t/* Set if bit 6 select is greater than bit 7 select; uses aremc.spec packet SWIZZLE_BIT6_GT_BIT7 */\n\tu32 swizzle_rank_byte_encode;\n\t/* Specifies enable and offset for patched boot rom write */\n\tu32 boot_rom_patch_control;\n\t/* Specifies data for patched boot rom write */\n\tu32 boot_rom_patch_data;\n\n\t/* Specifies the value for MC_MTS_CARVEOUT_BOM */\n\tu32 mc_mts_carveout_bom;\n\t/* Specifies the value for MC_MTS_CARVEOUT_ADR_HI */\n\tu32 mc_mts_carveout_adr_hi;\n\t/* Specifies the value for MC_MTS_CARVEOUT_SIZE_MB */\n\tu32 mc_mts_carveout_size_mb;\n\t/* Specifies the value for MC_MTS_CARVEOUT_REG_CTRL */\n\tu32 mc_mts_carveout_reg_ctrl;\n\n\t/* Specifies the clients that are allowed to access untranslated memory */\n\tu32 mc_untranslated_region_check;\n\n\t/* Just a place holder for special usage when there is no BCT for certain registers */\n\tu32 bct_na;\n} sdram_params_t210b01_t;\n\n#endif\n"
  },
  {
    "path": "modules/hekate_libsys_lp0/sys_sdramlp0.c",
    "content": "/*\n * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.\n * Copyright 2014 Google Inc.\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n */\n\n#include \"t210.h\"\n#include \"pmc_t210.h\"\n#include \"sdram_lp0_param_t210.h\"\n#include \"sdram_lp0_param_t210b01.h\"\n#include <module.h>\n\n#define pack(src, src_bits, dst, dst_bits) { \\\n\tu32 mask = 0xFFFFFFFF >> (31 - ((1 ? src_bits) - (0 ? src_bits))); \\\n\tdst &= ~(mask << (0 ? dst_bits)); \\\n\tdst |= ((src >> (0 ? src_bits)) & mask) << (0 ? dst_bits); \\\n}\n\n#define s(param, src_bits, pmcreg, dst_bits) \\\n\tpack(sdram->param, src_bits, pmc->pmc_ ## pmcreg, dst_bits)\n\n#define c(value, pmcreg, dst_bits) \\\n\tpack(value, (1 ? dst_bits) - (0 ? dst_bits) : 0, pmc->pmc_ ## pmcreg, dst_bits)\n\n/* 32 bits version of s macro */\n#define s32(param, pmcreg) pmc->pmc_ ## pmcreg = sdram->param\n\n/* 32 bits version c macro */\n#define c32(value, pmcreg) pmc->pmc_ ## pmcreg = value\n\n/*\n * This function reads SDRAM parameters from the common BCT format and\n * writes them into PMC scratch registers (where the BootROM expects them\n * on LP0 resume).\n */\nstatic void _sdram_lp0_save_params_t210(sdram_params_t210_t *sdram)\n{\n\tpmc_regs_t210_t *pmc = (pmc_regs_t210_t *)PMC_BASE;\n\n\t// Patch full access to carveout parameters and unprotect their regions.\n\tsdram->McGeneralizedCarveout1Cfg0 = 0;\n\tsdram->McGeneralizedCarveout2Cfg0 = 0;\n\tsdram->McGeneralizedCarveout3Cfg0 = 0;\n\tsdram->McGeneralizedCarveout4Cfg0 = 0;\n\tsdram->McGeneralizedCarveout5Cfg0 = 0;\n\n\t// Patch SDRAM parameters.\n\tu32 t0 = (sdram->EmcSwizzleRank0Byte0 << 5 >> 29) > (sdram->EmcSwizzleRank0Byte0 << 1 >> 29);\n\tu32 t1 = (t0 & 0xFFFFFFEF) | (((sdram->EmcSwizzleRank1Byte0 << 5 >> 29) > (sdram->EmcSwizzleRank1Byte0 << 1 >> 29)) << 4);\n\tu32 t2 = (t1 & 0xFFFFFFFD) | (((sdram->EmcSwizzleRank0Byte1 << 5 >> 29) > (sdram->EmcSwizzleRank0Byte1 << 1 >> 29)) << 1);\n\tu32 t3 = (t2 & 0xFFFFFFDF) | (((sdram->EmcSwizzleRank1Byte1 << 5 >> 29) > (sdram->EmcSwizzleRank1Byte1 << 1 >> 29)) << 5);\n\tu32 t4 = (t3 & 0xFFFFFFFB) | (((sdram->EmcSwizzleRank0Byte2 << 5 >> 29) > (sdram->EmcSwizzleRank0Byte2 << 1 >> 29)) << 2);\n\tu32 t5 = (t4 & 0xFFFFFFBF) | (((sdram->EmcSwizzleRank1Byte2 << 5 >> 29) > (sdram->EmcSwizzleRank1Byte2 << 1 >> 29)) << 6);\n\tu32 t6 = (t5 & 0xFFFFFFF7) | (((sdram->EmcSwizzleRank0Byte3 << 5 >> 29) > (sdram->EmcSwizzleRank0Byte3 << 1 >> 29)) << 3);\n\tu32 t7 = (t6 & 0xFFFFFF7F) | (((sdram->EmcSwizzleRank1Byte3 << 5 >> 29) > (sdram->EmcSwizzleRank1Byte3 << 1 >> 29)) << 7);\n\tsdram->SwizzleRankByteEncode = t7;\n\tsdram->EmcBctSpare2 = 0x40000DD8;\n\tsdram->EmcBctSpare3 = t7;\n\n\ts(EmcClockSource, 7:0, scratch6, 15:8);\n\ts(EmcClockSourceDll, 7:0, scratch6, 23:16);\n\ts(EmcClockSource, 31:29, scratch6, 26:24);\n\ts(EmcClockSourceDll, 31:29, scratch6, 29:27);\n\ts(EmcClockSourceDll, 11:10, scratch6, 31:30);\n\ts(ClkRstControllerPllmMisc2Override, 9:8, scratch7, 1:0);\n\ts(ClkRstControllerPllmMisc2Override, 2:1, scratch7, 3:2);\n\ts(EmcZqCalLpDdr4WarmBoot, 31:30, scratch7, 5:4);\n\ts(EmcClockSource, 15:15, scratch7, 6:6);\n\ts(EmcClockSource, 26:26, scratch7, 7:7);\n\ts(EmcClockSource, 20:20, scratch7, 8:8);\n\ts(EmcClockSource, 19:19, scratch7, 9:9);\n\ts(ClkRstControllerPllmMisc2Override, 13:13, scratch7, 10:10);\n\ts(ClkRstControllerPllmMisc2Override, 12:12, scratch7, 11:11);\n\ts(ClkRstControllerPllmMisc2Override, 11:11, scratch7, 12:12);\n\ts(ClkRstControllerPllmMisc2Override, 10:10, scratch7, 13:13);\n\ts(ClkRstControllerPllmMisc2Override, 5:5, scratch7, 14:14);\n\ts(ClkRstControllerPllmMisc2Override, 4:4, scratch7, 15:15);\n\ts(ClkRstControllerPllmMisc2Override, 3:3, scratch7, 16:16);\n\ts(ClkRstControllerPllmMisc2Override, 0:0, scratch7, 17:17);\n\ts(EmcZqCalLpDdr4WarmBoot, 1:0, scratch7, 19:18);\n\ts(EmcZqCalLpDdr4WarmBoot, 4:4, scratch7, 20:20);\n\ts(EmcOdtWrite, 5:0, scratch7, 26:21);\n\ts(EmcOdtWrite, 11:8, scratch7, 30:27);\n\ts(EmcOdtWrite, 31:31, scratch7, 31:31);\n\ts(EmcFdpdCtrlCmdNoRamp, 0:0, scratch13, 30:30);\n\ts(EmcCfgPipeClk, 0:0, scratch13, 31:31);\n\ts(McEmemArbMisc2, 0:0, scratch14, 30:30);\n\ts(McDaCfg0, 0:0, scratch14, 31:31);\n\ts(EmcQRst, 6:0, scratch15, 26:20);\n\ts(EmcQRst, 20:16, scratch15, 31:27);\n\ts(EmcPmacroCmdTxDrv, 5:0, scratch16, 25:20);\n\ts(EmcPmacroCmdTxDrv, 13:8, scratch16, 31:26);\n\ts(EmcPmacroAutocalCfg0, 2:0, scratch17, 22:20);\n\ts(EmcPmacroAutocalCfg0, 10:8, scratch17, 25:23);\n\ts(EmcPmacroAutocalCfg0, 18:16, scratch17, 28:26);\n\ts(EmcPmacroAutocalCfg0, 26:24, scratch17, 31:29);\n\ts(EmcPmacroAutocalCfg1, 2:0, scratch18, 22:20);\n\ts(EmcPmacroAutocalCfg1, 10:8, scratch18, 25:23);\n\ts(EmcPmacroAutocalCfg1, 18:16, scratch18, 28:26);\n\ts(EmcPmacroAutocalCfg1, 26:24, scratch18, 31:29);\n\ts(EmcPmacroAutocalCfg2, 2:0, scratch19, 22:20);\n\ts(EmcPmacroAutocalCfg2, 10:8, scratch19, 25:23);\n\ts(EmcPmacroAutocalCfg2, 18:16, scratch19, 28:26);\n\ts(EmcPmacroAutocalCfg2, 26:24, scratch19, 31:29);\n\ts32(EmcCfgRsv,scratch22);\n\ts32(EmcAutoCalConfig, scratch23);\n\ts32(EmcAutoCalVrefSel0, scratch24);\n\ts32(EmcPmacroBrickCtrlRfu1, scratch25);\n\ts32(EmcPmacroBrickCtrlRfu2, scratch26);\n\ts32(EmcPmcScratch1, scratch27);\n\ts32(EmcPmcScratch2, scratch28);\n\ts32(EmcPmcScratch3, scratch29);\n\ts32(McEmemArbDaTurns, scratch30);\n\ts(EmcFbioSpare, 31:24, scratch58, 7:0);\n\ts(EmcFbioSpare, 23:16, scratch58, 15:8);\n\ts(EmcFbioSpare, 15:8, scratch58, 23:16);\n\ts(EmcFbioSpare, 7:2, scratch58, 29:24);\n\ts(EmcFbioSpare, 0:0, scratch58, 30:30);\n\ts(EmcDllCfg0, 29:0, scratch59, 29:0);\n\ts(EmcPmacroDdllBypass, 11:0, scratch60, 11:0);\n\ts(EmcPmacroDdllBypass, 27:13, scratch60, 26:12);\n\ts(EmcPmacroDdllBypass, 31:29, scratch60, 29:27);\n\ts(McEmemArbMisc0, 14:0, scratch61, 14:0);\n\ts(McEmemArbMisc0, 30:16, scratch61, 29:15);\n\ts(EmcFdpdCtrlCmd, 16:0, scratch62, 16:0);\n\ts(EmcFdpdCtrlCmd, 31:20, scratch62, 28:17);\n\ts(EmcAutoCalConfig2, 27:0, scratch63, 27:0);\n\ts(EmcBurstRefreshNum, 3:0, scratch63, 31:28);\n\ts(EmcPmacroZctrl, 27:0, scratch64, 27:0);\n\ts(EmcTppd, 3:0, scratch64, 31:28);\n\ts(EmcCfgDigDll, 10:0, scratch65, 10:0);\n\ts(EmcCfgDigDll, 25:12, scratch65, 24:11);\n\ts(EmcCfgDigDll, 27:27, scratch65, 25:25);\n\ts(EmcCfgDigDll, 31:30, scratch65, 27:26);\n\ts(EmcR2r, 3:0, scratch65, 31:28);\n\ts(EmcFdpdCtrlDq, 16:0, scratch66, 16:0);\n\ts(EmcFdpdCtrlDq, 28:20, scratch66, 25:17);\n\ts(EmcFdpdCtrlDq, 31:30, scratch66, 27:26);\n\ts(EmcW2w, 3:0, scratch66, 31:28);\n\ts(EmcPmacroTxPwrd4, 13:0, scratch67, 13:0);\n\ts(EmcPmacroTxPwrd4, 29:16, scratch67, 27:14);\n\ts(EmcPmacroCommonPadTxCtrl, 3:0, scratch67, 31:28);\n\ts(EmcPmacroTxPwrd5, 13:0, scratch68, 13:0);\n\ts(EmcPmacroTxPwrd5, 29:16, scratch68, 27:14);\n\ts(EmcPmacroDdllPwrd0, 4:0, scratch69, 4:0);\n\ts(EmcPmacroDdllPwrd0, 12:6, scratch69, 11:5);\n\ts(EmcPmacroDdllPwrd0, 20:14, scratch69, 18:12);\n\ts(EmcPmacroDdllPwrd0, 28:22, scratch69, 25:19);\n\ts(EmcPmacroDdllPwrd0, 31:30, scratch69, 27:26);\n\ts(EmcCfg, 4:4, scratch69, 31:31);\n\ts(EmcPmacroDdllPwrd1, 4:0, scratch70, 4:0);\n\ts(EmcPmacroDdllPwrd1, 12:6, scratch70, 11:5);\n\ts(EmcPmacroDdllPwrd1, 20:14, scratch70, 18:12);\n\ts(EmcPmacroDdllPwrd1, 28:22, scratch70, 25:19);\n\ts(EmcPmacroDdllPwrd1, 31:30, scratch70, 27:26);\n\ts(EmcCfg, 5:5, scratch70, 31:31);\n\ts(EmcPmacroDdllPwrd2, 4:0, scratch71, 4:0);\n\ts(EmcPmacroDdllPwrd2, 12:6, scratch71, 11:5);\n\ts(EmcPmacroDdllPwrd2, 20:14, scratch71, 18:12);\n\ts(EmcPmacroDdllPwrd2, 28:22, scratch71, 25:19);\n\ts(EmcPmacroDdllPwrd2, 31:30, scratch71, 27:26);\n\ts(EmcFbioCfg5, 23:20, scratch71, 31:28);\n\ts(EmcPmacroIbVrefDq_0, 6:0, scratch72, 6:0);\n\ts(EmcPmacroIbVrefDq_0, 14:8, scratch72, 13:7);\n\ts(EmcPmacroIbVrefDq_0, 22:16, scratch72, 20:14);\n\ts(EmcPmacroIbVrefDq_0, 30:24, scratch72, 27:21);\n\ts(EmcFbioCfg5, 15:13, scratch72, 30:28);\n\ts(EmcCfg, 6:6, scratch72, 31:31);\n\ts(EmcPmacroIbVrefDq_1, 6:0, scratch73, 6:0);\n\ts(EmcPmacroIbVrefDq_1, 14:8, scratch73, 13:7);\n\ts(EmcPmacroIbVrefDq_1, 22:16, scratch73, 20:14);\n\ts(EmcPmacroIbVrefDq_1, 30:24, scratch73, 27:21);\n\ts(EmcCfg2, 5:3, scratch73, 30:28);\n\ts(EmcCfg, 7:7, scratch73, 31:31);\n\ts(EmcPmacroIbVrefDqs_0, 6:0, scratch74, 6:0);\n\ts(EmcPmacroIbVrefDqs_0, 14:8, scratch74, 13:7);\n\ts(EmcPmacroIbVrefDqs_0, 22:16, scratch74, 20:14);\n\ts(EmcPmacroIbVrefDqs_0, 30:24, scratch74, 27:21);\n\ts(EmcCfg, 17:16, scratch74, 29:28);\n\ts(EmcFbioCfg5, 1:0, scratch74, 31:30);\n\ts(EmcPmacroIbVrefDqs_1, 6:0, scratch75, 6:0);\n\ts(EmcPmacroIbVrefDqs_1, 14:8, scratch75, 13:7);\n\ts(EmcPmacroIbVrefDqs_1, 22:16, scratch75, 20:14);\n\ts(EmcPmacroIbVrefDqs_1, 30:24, scratch75, 27:21);\n\ts(EmcFbioCfg5, 3:2, scratch75, 29:28);\n\ts(EmcCfg2, 27:26, scratch75, 31:30);\n\ts(EmcPmacroDdllShortCmd_0, 6:0, scratch76, 6:0);\n\ts(EmcPmacroDdllShortCmd_0, 14:8, scratch76, 13:7);\n\ts(EmcPmacroDdllShortCmd_0, 22:16, scratch76, 20:14);\n\ts(EmcPmacroDdllShortCmd_0, 30:24, scratch76, 27:21);\n\ts(EmcPmacroCmdPadTxCtrl, 3:2, scratch76, 29:28);\n\ts(EmcPmacroCmdPadTxCtrl, 7:6, scratch76, 31:30);\n\ts(EmcPmacroDdllShortCmd_1, 6:0, scratch77, 6:0);\n\ts(EmcPmacroDdllShortCmd_1, 14:8, scratch77, 13:7);\n\ts(EmcPmacroDdllShortCmd_1, 22:16, scratch77, 20:14);\n\ts(EmcPmacroDdllShortCmd_1, 30:24, scratch77, 27:21);\n\ts(EmcPmacroCmdPadTxCtrl, 11:10, scratch77, 29:28);\n\ts(EmcPmacroCmdPadTxCtrl, 15:14, scratch77, 31:30);\n\ts(EmcAutoCalChannel, 5:0, scratch78, 5:0);\n\ts(EmcAutoCalChannel, 11:8, scratch78, 9:6);\n\ts(EmcAutoCalChannel, 27:16, scratch78, 21:10);\n\ts(EmcAutoCalChannel, 31:29, scratch78, 24:22);\n\ts(EmcConfigSampleDelay, 6:0, scratch78, 31:25);\n\ts(EmcPmacroRxTerm, 5:0, scratch79, 5:0);\n\ts(EmcPmacroRxTerm, 13:8, scratch79, 11:6);\n\ts(EmcPmacroRxTerm, 21:16, scratch79, 17:12);\n\ts(EmcPmacroRxTerm, 29:24, scratch79, 23:18);\n\ts(EmcRc, 7:0, scratch79, 31:24);\n\ts(EmcPmacroDqTxDrv, 5:0, scratch80, 5:0);\n\ts(EmcPmacroDqTxDrv, 13:8, scratch80, 11:6);\n\ts(EmcPmacroDqTxDrv, 21:16, scratch80, 17:12);\n\ts(EmcPmacroDqTxDrv, 29:24, scratch80, 23:18);\n\ts(EmcSelDpdCtrl, 5:2, scratch80, 27:24);\n\ts(EmcSelDpdCtrl, 8:8, scratch80, 28:28);\n\ts(EmcSelDpdCtrl, 18:16, scratch80, 31:29);\n\ts(EmcPmacroCaTxDrv, 5:0, scratch81, 5:0);\n\ts(EmcPmacroCaTxDrv, 13:8, scratch81, 11:6);\n\ts(EmcPmacroCaTxDrv, 21:16, scratch81, 17:12);\n\ts(EmcPmacroCaTxDrv, 29:24, scratch81, 23:18);\n\ts(EmcObdly, 5:0, scratch81, 29:24);\n\ts(EmcObdly, 29:28, scratch81, 31:30);\n\ts(EmcZcalInterval, 23:10, scratch82, 13:0);\n\ts(EmcZcalInterval, 9:0, scratch82, 23:14);\n\ts(EmcPmacroCmdRxTermMode, 1:0, scratch82, 25:24);\n\ts(EmcPmacroCmdRxTermMode, 5:4, scratch82, 27:26);\n\ts(EmcPmacroCmdRxTermMode, 9:8, scratch82, 29:28);\n\ts(EmcPmacroCmdRxTermMode, 13:12, scratch82, 31:30);\n\ts(EmcDataBrlshft0, 23:0, scratch83, 23:0);\n\ts(EmcPmacroDataRxTermMode, 1:0, scratch83, 25:24);\n\ts(EmcPmacroDataRxTermMode, 5:4, scratch83, 27:26);\n\ts(EmcPmacroDataRxTermMode, 9:8, scratch83, 29:28);\n\ts(EmcPmacroDataRxTermMode, 13:12, scratch83, 31:30);\n\ts(EmcDataBrlshft1, 23:0, scratch84, 23:0);\n\ts(McEmemArbTimingRc, 7:0, scratch84, 31:24);\n\ts(EmcDqsBrlshft0, 23:0, scratch85, 23:0);\n\ts(McEmemArbRsv, 7:0, scratch85, 31:24);\n\ts(EmcDqsBrlshft1, 23:0, scratch86, 23:0);\n\ts(EmcCfgPipe2, 11:0, scratch87, 11:0);\n\ts(EmcCfgPipe2, 27:16, scratch87, 23:12);\n\ts(EmcCfgPipe1, 11:0, scratch88, 11:0);\n\ts(EmcCfgPipe1, 27:16, scratch88, 23:12);\n\ts(EmcPmacroCmdCtrl0, 5:0, scratch89, 5:0);\n\ts(EmcPmacroCmdCtrl0, 13:8, scratch89, 11:6);\n\ts(EmcPmacroCmdCtrl0, 21:16, scratch89, 17:12);\n\ts(EmcPmacroCmdCtrl0, 29:24, scratch89, 23:18);\n\ts(EmcPmacroCmdCtrl1, 5:0, scratch90, 5:0);\n\ts(EmcPmacroCmdCtrl1, 13:8, scratch90, 11:6);\n\ts(EmcPmacroCmdCtrl1, 21:16, scratch90, 17:12);\n\ts(EmcPmacroCmdCtrl1, 29:24, scratch90, 23:18);\n\ts(EmcRas, 6:0, scratch90, 30:24);\n\ts(EmcCfg, 8:8, scratch90, 31:31);\n\ts(EmcPmacroVttgenCtrl2, 23:0, scratch91, 23:0);\n\ts(EmcW2p, 6:0, scratch91, 30:24);\n\ts(EmcCfg, 9:9, scratch91, 31:31);\n\ts(EmcPmacroCmdPadRxCtrl, 2:0, scratch92, 2:0);\n\ts(EmcPmacroCmdPadRxCtrl, 5:4, scratch92, 4:3);\n\ts(EmcPmacroCmdPadRxCtrl, 10:8, scratch92, 7:5);\n\ts(EmcPmacroCmdPadRxCtrl, 22:12, scratch92, 18:8);\n\ts(EmcPmacroCmdPadRxCtrl, 28:24, scratch92, 23:19);\n\ts(EmcQSafe, 6:0, scratch92, 30:24);\n\ts(EmcCfg, 18:18, scratch92, 31:31);\n\ts(EmcPmacroDataPadRxCtrl, 2:0, scratch93, 2:0);\n\ts(EmcPmacroDataPadRxCtrl, 5:4, scratch93, 4:3);\n\ts(EmcPmacroDataPadRxCtrl, 10:8, scratch93, 7:5);\n\ts(EmcPmacroDataPadRxCtrl, 22:12, scratch93, 18:8);\n\ts(EmcPmacroDataPadRxCtrl, 28:24, scratch93, 23:19);\n\ts(EmcRdv, 6:0, scratch93, 30:24);\n\ts(EmcCfg, 21:21, scratch93, 31:31);\n\ts(McEmemArbDaCovers, 23:0, scratch94, 23:0);\n\ts(EmcRw2Pden, 6:0, scratch94, 30:24);\n\ts(EmcCfg, 22:22, scratch94, 31:31);\n\ts(EmcPmacroCmdCtrl2, 5:0, scratch95, 5:0);\n\ts(EmcPmacroCmdCtrl2, 13:9, scratch95, 10:6);\n\ts(EmcPmacroCmdCtrl2, 21:16, scratch95, 16:11);\n\ts(EmcPmacroCmdCtrl2, 29:24, scratch95, 22:17);\n\ts(EmcRfcPb, 8:0, scratch95, 31:23);\n\ts(EmcPmacroQuseDdllRank0_0, 10:0, scratch96, 10:0);\n\ts(EmcPmacroQuseDdllRank0_0, 26:16, scratch96, 21:11);\n\ts(EmcCfgUpdate, 2:0, scratch96, 24:22);\n\ts(EmcCfgUpdate, 10:8, scratch96, 27:25);\n\ts(EmcCfgUpdate, 31:28, scratch96, 31:28);\n\ts(EmcPmacroQuseDdllRank0_1, 10:0, scratch97, 10:0);\n\ts(EmcPmacroQuseDdllRank0_1, 26:16, scratch97, 21:11);\n\ts(EmcRfc, 9:0, scratch97, 31:22);\n\ts(EmcPmacroQuseDdllRank0_2, 10:0, scratch98, 10:0);\n\ts(EmcPmacroQuseDdllRank0_2, 26:16, scratch98, 21:11);\n\ts(EmcTxsr, 9:0, scratch98, 31:22);\n\ts(EmcPmacroQuseDdllRank0_3, 10:0, scratch99, 10:0);\n\ts(EmcPmacroQuseDdllRank0_3, 26:16, scratch99, 21:11);\n\ts(EmcMc2EmcQ, 2:0, scratch99, 24:22);\n\ts(EmcMc2EmcQ, 10:8, scratch99, 27:25);\n\ts(EmcMc2EmcQ, 27:24, scratch99, 31:28);\n\ts(EmcPmacroQuseDdllRank0_4, 10:0, scratch100, 10:0);\n\ts(EmcPmacroQuseDdllRank0_4, 26:16, scratch100, 21:11);\n\ts(McEmemArbRing1Throttle, 4:0, scratch100, 26:22);\n\ts(McEmemArbRing1Throttle, 20:16, scratch100, 31:27);\n\ts(EmcPmacroQuseDdllRank0_5, 10:0, scratch101, 10:0);\n\ts(EmcPmacroQuseDdllRank0_5, 26:16, scratch101, 21:11);\n\ts(EmcPmacroQuseDdllRank1_0, 10:0, scratch102, 10:0);\n\ts(EmcPmacroQuseDdllRank1_0, 26:16, scratch102, 21:11);\n\ts(EmcAr2Pden, 8:0, scratch102, 30:22);\n\ts(EmcCfg, 23:23, scratch102, 31:31);\n\ts(EmcPmacroQuseDdllRank1_1, 10:0, scratch103, 10:0);\n\ts(EmcPmacroQuseDdllRank1_1, 26:16, scratch103, 21:11);\n\ts(EmcRfcSlr, 8:0, scratch103, 30:22);\n\ts(EmcCfg, 24:24, scratch103, 31:31);\n\ts(EmcPmacroQuseDdllRank1_2, 10:0, scratch104, 10:0);\n\ts(EmcPmacroQuseDdllRank1_2, 26:16, scratch104, 21:11);\n\ts(EmcIbdly, 6:0, scratch104, 28:22);\n\ts(EmcIbdly, 29:28, scratch104, 30:29);\n\ts(EmcCfg, 25:25, scratch104, 31:31);\n\ts(EmcPmacroQuseDdllRank1_3, 10:0, scratch105, 10:0);\n\ts(EmcPmacroQuseDdllRank1_3, 26:16, scratch105, 21:11);\n\ts(McEmemArbTimingRFCPB, 8:0, scratch105, 30:22);\n\ts(EmcCfg, 26:26, scratch105, 31:31);\n\ts(EmcPmacroQuseDdllRank1_4, 10:0, scratch106, 10:0);\n\ts(EmcPmacroQuseDdllRank1_4, 26:16, scratch106, 21:11);\n\ts(EmcTfaw, 6:0, scratch106, 28:22);\n\ts(EmcPmacroDataPadTxCtrl, 3:2, scratch106, 30:29);\n\ts(EmcCfg, 28:28, scratch106, 31:31);\n\ts(EmcPmacroQuseDdllRank1_5, 10:0, scratch107, 10:0);\n\ts(EmcPmacroQuseDdllRank1_5, 26:16, scratch107, 21:11);\n\ts(EmcTClkStable, 6:0, scratch107, 28:22);\n\ts(EmcPmacroDataPadTxCtrl, 7:6, scratch107, 30:29);\n\ts(EmcCfg, 29:29, scratch107, 31:31);\n\ts(EmcPmacroObDdllLongDqRank0_0, 10:0, scratch108, 10:0);\n\ts(EmcPmacroObDdllLongDqRank0_0, 26:16, scratch108, 21:11);\n\ts(EmcPdex2Mrr, 6:0, scratch108, 28:22);\n\ts(EmcPmacroDataPadTxCtrl, 11:10, scratch108, 30:29);\n\ts(EmcCfg, 30:30, scratch108, 31:31);\n\ts(EmcPmacroObDdllLongDqRank0_1, 10:0, scratch109, 10:0);\n\ts(EmcPmacroObDdllLongDqRank0_1, 26:16, scratch109, 21:11);\n\ts(EmcRdvMask, 6:0, scratch109, 28:22);\n\ts(EmcPmacroDataPadTxCtrl, 15:14, scratch109, 30:29);\n\ts(EmcCfg, 31:31, scratch109, 31:31);\n\ts(EmcPmacroObDdllLongDqRank0_2, 10:0, scratch110, 10:0);\n\ts(EmcPmacroObDdllLongDqRank0_2, 26:16, scratch110, 21:11);\n\ts(EmcRdvEarlyMask, 6:0, scratch110, 28:22);\n\ts(EmcFbioCfg5, 4:4, scratch110, 29:29);\n\ts(EmcFbioCfg5, 8:8, scratch110, 30:30);\n\ts(EmcFbioCfg5, 10:10, scratch110, 31:31);\n\ts(EmcPmacroObDdllLongDqRank0_3, 10:0, scratch111, 10:0);\n\ts(EmcPmacroObDdllLongDqRank0_3, 26:16, scratch111, 21:11);\n\ts(EmcRdvEarly, 6:0, scratch111, 28:22);\n\ts(EmcFbioCfg5, 12:12, scratch111, 29:29);\n\ts(EmcFbioCfg5, 25:24, scratch111, 31:30);\n\ts(EmcPmacroObDdllLongDqRank0_4, 10:0, scratch112, 10:0);\n\ts(EmcPmacroObDdllLongDqRank0_4, 26:16, scratch112, 21:11);\n\ts(EmcPmacroDdllShortCmd_2, 6:0, scratch112, 28:22);\n\ts(EmcFbioCfg5, 28:26, scratch112, 31:29);\n\ts(EmcPmacroObDdllLongDqRank0_5, 10:0, scratch113, 10:0);\n\ts(EmcPmacroObDdllLongDqRank0_5, 26:16, scratch113, 21:11);\n\ts(McEmemArbTimingRp, 6:0, scratch113, 28:22);\n\ts(EmcFbioCfg5, 31:30, scratch113, 30:29);\n\ts(EmcCfg2, 0:0, scratch113, 31:31);\n\ts(EmcPmacroObDdllLongDqRank1_0, 10:0, scratch114, 10:0);\n\ts(EmcPmacroObDdllLongDqRank1_0, 26:16, scratch114, 21:11);\n\ts(McEmemArbTimingRas, 6:0, scratch114, 28:22);\n\ts(EmcCfg2, 2:1, scratch114, 30:29);\n\ts(EmcCfg2, 7:7, scratch114, 31:31);\n\ts(EmcPmacroObDdllLongDqRank1_1, 10:0, scratch115, 10:0);\n\ts(EmcPmacroObDdllLongDqRank1_1, 26:16, scratch115, 21:11);\n\ts(McEmemArbTimingFaw, 6:0, scratch115, 28:22);\n\ts(EmcCfg2, 11:10, scratch115, 30:29);\n\ts(EmcCfg2, 14:14, scratch115, 31:31);\n\ts(EmcPmacroObDdllLongDqRank1_2, 10:0, scratch123, 10:0);\n\ts(EmcPmacroObDdllLongDqRank1_2, 26:16, scratch123, 21:11);\n\ts(McEmemArbTimingRap2Pre, 6:0, scratch123, 28:22);\n\ts(EmcCfg2, 16:15, scratch123, 30:29);\n\ts(EmcCfg2, 20:20, scratch123, 31:31);\n\ts(EmcPmacroObDdllLongDqRank1_3, 10:0, scratch124, 10:0);\n\ts(EmcPmacroObDdllLongDqRank1_3, 26:16, scratch124, 21:11);\n\ts(McEmemArbTimingWap2Pre, 6:0, scratch124, 28:22);\n\ts(EmcCfg2, 24:22, scratch124, 31:29);\n\ts(EmcPmacroObDdllLongDqRank1_4, 10:0, scratch125, 10:0);\n\ts(EmcPmacroObDdllLongDqRank1_4, 26:16, scratch125, 21:11);\n\ts(McEmemArbTimingR2W, 6:0, scratch125, 28:22);\n\ts(EmcCfg2, 25:25, scratch125, 29:29);\n\ts(EmcCfg2, 29:28, scratch125, 31:30);\n\ts(EmcPmacroObDdllLongDqRank1_5, 10:0, scratch126, 10:0);\n\ts(EmcPmacroObDdllLongDqRank1_5, 26:16, scratch126, 21:11);\n\ts(McEmemArbTimingW2R, 6:0, scratch126, 28:22);\n\ts(EmcCfg2, 31:30, scratch126, 30:29);\n\ts(EmcCfgPipe, 0:0, scratch126, 31:31);\n\ts(EmcPmacroObDdllLongDqsRank0_0, 10:0, scratch127, 10:0);\n\ts(EmcPmacroObDdllLongDqsRank0_0, 26:16, scratch127, 21:11);\n\ts(EmcRp, 5:0, scratch127, 27:22);\n\ts(EmcCfgPipe, 4:1, scratch127, 31:28);\n\ts(EmcPmacroObDdllLongDqsRank0_1, 10:0, scratch128, 10:0);\n\ts(EmcPmacroObDdllLongDqsRank0_1, 26:16, scratch128, 21:11);\n\ts(EmcR2w, 5:0, scratch128, 27:22);\n\ts(EmcCfgPipe, 8:5, scratch128, 31:28);\n\ts(EmcPmacroObDdllLongDqsRank0_2, 10:0, scratch129, 10:0);\n\ts(EmcPmacroObDdllLongDqsRank0_2, 26:16, scratch129, 21:11);\n\ts(EmcW2r, 5:0, scratch129, 27:22);\n\ts(EmcCfgPipe, 11:9, scratch129, 30:28);\n\ts(EmcCfgPipe, 16:16, scratch129, 31:31);\n\ts(EmcPmacroObDdllLongDqsRank0_3, 10:0, scratch130, 10:0);\n\ts(EmcPmacroObDdllLongDqsRank0_3, 26:16, scratch130, 21:11);\n\ts(EmcR2p, 5:0, scratch130, 27:22);\n\ts(EmcCfgPipe, 20:17, scratch130, 31:28);\n\ts(EmcPmacroObDdllLongDqsRank0_4, 10:0, scratch131, 10:0);\n\ts(EmcPmacroObDdllLongDqsRank0_4, 26:16, scratch131, 21:11);\n\ts(EmcCcdmw, 5:0, scratch131, 27:22);\n\ts(EmcCfgPipe, 24:21, scratch131, 31:28);\n\ts(EmcPmacroObDdllLongDqsRank0_5, 10:0, scratch132, 10:0);\n\ts(EmcPmacroObDdllLongDqsRank0_5, 26:16, scratch132, 21:11);\n\ts(EmcRdRcd, 5:0, scratch132, 27:22);\n\ts(EmcCfgPipe, 27:25, scratch132, 30:28);\n\ts(EmcPmacroTxPwrd0, 0:0, scratch132, 31:31);\n\ts(EmcPmacroObDdllLongDqsRank1_0, 10:0, scratch133, 10:0);\n\ts(EmcPmacroObDdllLongDqsRank1_0, 26:16, scratch133, 21:11);\n\ts(EmcWrRcd, 5:0, scratch133, 27:22);\n\ts(EmcPmacroTxPwrd0, 4:1, scratch133, 31:28);\n\ts(EmcPmacroObDdllLongDqsRank1_1, 10:0, scratch134, 10:0);\n\ts(EmcPmacroObDdllLongDqsRank1_1, 26:16, scratch134, 21:11);\n\ts(EmcWdv, 5:0, scratch134, 27:22);\n\ts(EmcPmacroTxPwrd0, 8:5, scratch134, 31:28);\n\ts(EmcPmacroObDdllLongDqsRank1_2, 10:0, scratch135, 10:0);\n\ts(EmcPmacroObDdllLongDqsRank1_2, 26:16, scratch135, 21:11);\n\ts(EmcQUse, 5:0, scratch135, 27:22);\n\ts(EmcPmacroTxPwrd0, 12:9, scratch135, 31:28);\n\ts(EmcPmacroObDdllLongDqsRank1_3, 10:0, scratch136, 10:0);\n\ts(EmcPmacroObDdllLongDqsRank1_3, 26:16, scratch136, 21:11);\n\ts(EmcPdEx2Wr, 5:0, scratch136, 27:22);\n\ts(EmcPmacroTxPwrd0, 13:13, scratch136, 28:28);\n\ts(EmcPmacroTxPwrd0, 18:16, scratch136, 31:29);\n\ts(EmcPmacroObDdllLongDqsRank1_4, 10:0, scratch137, 10:0);\n\ts(EmcPmacroObDdllLongDqsRank1_4, 26:16, scratch137, 21:11);\n\ts(EmcPdEx2Rd, 5:0, scratch137, 27:22);\n\ts(EmcPmacroTxPwrd0, 22:19, scratch137, 31:28);\n\ts(EmcPmacroObDdllLongDqsRank1_5, 10:0, scratch138, 10:0);\n\ts(EmcPmacroObDdllLongDqsRank1_5, 26:16, scratch138, 21:11);\n\ts(EmcPdex2Cke, 5:0, scratch138, 27:22);\n\ts(EmcPmacroTxPwrd0, 26:23, scratch138, 31:28);\n\ts(EmcPmacroIbDdllLongDqsRank0_0, 10:0, scratch139, 10:0);\n\ts(EmcPmacroIbDdllLongDqsRank0_0, 26:16, scratch139, 21:11);\n\ts(EmcPChg2Pden, 5:0, scratch139, 27:22);\n\ts(EmcPmacroTxPwrd0, 29:27, scratch139, 30:28);\n\ts(EmcPmacroTxPwrd1, 0:0, scratch139, 31:31);\n\ts(EmcPmacroIbDdllLongDqsRank0_1, 10:0, scratch140, 10:0);\n\ts(EmcPmacroIbDdllLongDqsRank0_1, 26:16, scratch140, 21:11);\n\ts(EmcAct2Pden, 5:0, scratch140, 27:22);\n\ts(EmcPmacroTxPwrd1, 4:1, scratch140, 31:28);\n\ts(EmcPmacroIbDdllLongDqsRank0_2, 10:0, scratch141, 10:0);\n\ts(EmcPmacroIbDdllLongDqsRank0_2, 26:16, scratch141, 21:11);\n\ts(EmcCke2Pden, 5:0, scratch141, 27:22);\n\ts(EmcPmacroTxPwrd1, 8:5, scratch141, 31:28);\n\ts(EmcPmacroIbDdllLongDqsRank0_3, 10:0, scratch142, 10:0);\n\ts(EmcPmacroIbDdllLongDqsRank0_3, 26:16, scratch142, 21:11);\n\ts(EmcTcke, 5:0, scratch142, 27:22);\n\ts(EmcPmacroTxPwrd1, 12:9, scratch142, 31:28);\n\ts(EmcPmacroIbDdllLongDqsRank1_0, 10:0, scratch143, 10:0);\n\ts(EmcPmacroIbDdllLongDqsRank1_0, 26:16, scratch143, 21:11);\n\ts(EmcTrpab, 5:0, scratch143, 27:22);\n\ts(EmcPmacroTxPwrd1, 13:13, scratch143, 28:28);\n\ts(EmcPmacroTxPwrd1, 18:16, scratch143, 31:29);\n\ts(EmcPmacroIbDdllLongDqsRank1_1, 10:0, scratch144, 10:0);\n\ts(EmcPmacroIbDdllLongDqsRank1_1, 26:16, scratch144, 21:11);\n\ts(EmcClkenOverride, 3:1, scratch144, 24:22);\n\ts(EmcClkenOverride, 8:6, scratch144, 27:25);\n\ts(EmcPmacroTxPwrd1, 22:19, scratch144, 31:28);\n\ts(EmcPmacroIbDdllLongDqsRank1_2, 10:0, scratch145, 10:0);\n\ts(EmcPmacroIbDdllLongDqsRank1_2, 26:16, scratch145, 21:11);\n\ts(EmcEInput, 5:0, scratch145, 27:22);\n\ts(EmcPmacroTxPwrd1, 26:23, scratch145, 31:28);\n\ts(EmcPmacroIbDdllLongDqsRank1_3, 10:0, scratch146, 10:0);\n\ts(EmcPmacroIbDdllLongDqsRank1_3, 26:16, scratch146, 21:11);\n\ts(EmcEInputDuration, 5:0, scratch146, 27:22);\n\ts(EmcPmacroTxPwrd1, 29:27, scratch146, 30:28);\n\ts(EmcPmacroTxPwrd2, 0:0, scratch146, 31:31);\n\ts(EmcPmacroDdllLongCmd_0, 10:0, scratch147, 10:0);\n\ts(EmcPmacroDdllLongCmd_0, 26:16, scratch147, 21:11);\n\ts(EmcPutermExtra, 5:0, scratch147, 27:22);\n\ts(EmcPmacroTxPwrd2, 4:1, scratch147, 31:28);\n\ts(EmcPmacroDdllLongCmd_1, 10:0, scratch148, 10:0);\n\ts(EmcPmacroDdllLongCmd_1, 26:16, scratch148, 21:11);\n\ts(EmcTckesr, 5:0, scratch148, 27:22);\n\ts(EmcPmacroTxPwrd2, 8:5, scratch148, 31:28);\n\ts(EmcPmacroDdllLongCmd_2, 10:0, scratch149, 10:0);\n\ts(EmcPmacroDdllLongCmd_2, 26:16, scratch149, 21:11);\n\ts(EmcTpd, 5:0, scratch149, 27:22);\n\ts(EmcPmacroTxPwrd2, 12:9, scratch149, 31:28);\n\ts(EmcPmacroDdllLongCmd_3, 10:0, scratch150, 10:0);\n\ts(EmcPmacroDdllLongCmd_3, 26:16, scratch150, 21:11);\n\ts(EmcWdvMask, 5:0, scratch150, 27:22);\n\ts(EmcPmacroTxPwrd2, 13:13, scratch150, 28:28);\n\ts(EmcPmacroTxPwrd2, 18:16, scratch150, 31:29);\n\ts(McEmemArbCfg, 8:0, scratch151, 8:0);\n\ts(McEmemArbCfg, 20:16, scratch151, 13:9);\n\ts(McEmemArbCfg, 31:24, scratch151, 21:14);\n\ts(EmcWdvChk, 5:0, scratch151, 27:22);\n\ts(EmcPmacroTxPwrd2, 22:19, scratch151, 31:28);\n\ts(McEmemArbMisc1, 12:0, scratch152, 12:0);\n\ts(McEmemArbMisc1, 25:21, scratch152, 17:13);\n\ts(McEmemArbMisc1, 31:28, scratch152, 21:18);\n\ts(EmcCmdBrlshft0, 5:0, scratch152, 27:22);\n\ts(EmcPmacroTxPwrd2, 26:23, scratch152, 31:28);\n\ts(EmcMrsWaitCnt2, 9:0, scratch153, 9:0);\n\ts(EmcMrsWaitCnt2, 26:16, scratch153, 20:10);\n\ts(EmcPmacroIbRxrt, 10:0, scratch153, 31:21);\n\ts(EmcMrsWaitCnt, 9:0, scratch154, 9:0);\n\ts(EmcMrsWaitCnt, 26:16, scratch154, 20:10);\n\ts(EmcPmacroDdllLongCmd_4, 10:0, scratch154, 31:21);\n\ts(EmcAutoCalInterval, 20:0, scratch155, 20:0);\n\ts(McEmemArbOutstandingReq, 8:0, scratch155, 29:21);\n\ts(McEmemArbOutstandingReq, 31:30, scratch155, 31:30);\n\ts(McEmemArbRefpbHpCtrl, 6:0, scratch156, 6:0);\n\ts(McEmemArbRefpbHpCtrl, 14:8, scratch156, 13:7);\n\ts(McEmemArbRefpbHpCtrl, 22:16, scratch156, 20:14);\n\ts(EmcCmdBrlshft1, 5:0, scratch156, 26:21);\n\ts(EmcRrd, 4:0, scratch156, 31:27);\n\ts(EmcQuseBrlshft0, 19:0, scratch157, 19:0);\n\ts(EmcFbioCfg8, 27:16, scratch157, 31:20);\n\ts(EmcQuseBrlshft1, 19:0, scratch158, 19:0);\n\ts(EmcTxsrDll, 11:0, scratch158, 31:20);\n\ts(EmcQuseBrlshft2, 19:0, scratch159, 19:0);\n\ts(EmcTxdsrvttgen, 11:0, scratch159, 31:20);\n\ts(EmcQuseBrlshft3, 19:0, scratch160, 19:0);\n\ts(EmcPmacroVttgenCtrl0, 3:0, scratch160, 23:20);\n\ts(EmcPmacroVttgenCtrl0, 11:8, scratch160, 27:24);\n\ts(EmcPmacroVttgenCtrl0, 19:16, scratch160, 31:28);\n\ts(EmcPmacroVttgenCtrl1, 19:0, scratch161, 19:0);\n\ts(EmcCmdBrlshft2, 5:0, scratch161, 25:20);\n\ts(EmcCmdBrlshft3, 5:0, scratch161, 31:26);\n\ts(EmcAutoCalConfig3, 5:0, scratch162, 5:0);\n\ts(EmcAutoCalConfig3, 13:8, scratch162, 11:6);\n\ts(EmcAutoCalConfig3, 18:16, scratch162, 14:12);\n\ts(EmcAutoCalConfig3, 22:20, scratch162, 17:15);\n\ts(EmcTRefBw, 13:0, scratch162, 31:18);\n\ts(EmcAutoCalConfig4, 5:0, scratch163, 5:0);\n\ts(EmcAutoCalConfig4, 13:8, scratch163, 11:6);\n\ts(EmcAutoCalConfig4, 18:16, scratch163, 14:12);\n\ts(EmcAutoCalConfig4, 22:20, scratch163, 17:15);\n\ts(EmcQpop, 6:0, scratch163, 24:18);\n\ts(EmcQpop, 22:16, scratch163, 31:25);\n\ts(EmcAutoCalConfig5, 5:0, scratch164, 5:0);\n\ts(EmcAutoCalConfig5, 13:8, scratch164, 11:6);\n\ts(EmcAutoCalConfig5, 18:16, scratch164, 14:12);\n\ts(EmcAutoCalConfig5, 22:20, scratch164, 17:15);\n\ts(EmcPmacroAutocalCfgCommon, 5:0, scratch164, 23:18);\n\ts(EmcPmacroAutocalCfgCommon, 13:8, scratch164, 29:24);\n\ts(EmcPmacroAutocalCfgCommon, 16:16, scratch164, 30:30);\n\ts(EmcPmacroTxPwrd2, 27:27, scratch164, 31:31);\n\ts(EmcAutoCalConfig6, 5:0, scratch165, 5:0);\n\ts(EmcAutoCalConfig6, 13:8, scratch165, 11:6);\n\ts(EmcAutoCalConfig6, 18:16, scratch165, 14:12);\n\ts(EmcAutoCalConfig6, 22:20, scratch165, 17:15);\n\ts(EmcWev, 5:0, scratch165, 23:18);\n\ts(EmcWsv, 5:0, scratch165, 29:24);\n\ts(EmcPmacroTxPwrd2, 29:28, scratch165, 31:30);\n\ts(EmcAutoCalConfig7, 5:0, scratch166, 5:0);\n\ts(EmcAutoCalConfig7, 13:8, scratch166, 11:6);\n\ts(EmcAutoCalConfig7, 18:16, scratch166, 14:12);\n\ts(EmcAutoCalConfig7, 22:20, scratch166, 17:15);\n\ts(EmcCfg3, 2:0, scratch166, 20:18);\n\ts(EmcCfg3, 6:4, scratch166, 23:21);\n\ts(EmcQuseWidth, 3:0, scratch166, 27:24);\n\ts(EmcQuseWidth, 29:28, scratch166, 29:28);\n\ts(EmcPmacroTxPwrd3, 1:0, scratch166, 31:30);\n\ts(EmcAutoCalConfig8, 5:0, scratch167, 5:0);\n\ts(EmcAutoCalConfig8, 13:8, scratch167, 11:6);\n\ts(EmcAutoCalConfig8, 18:16, scratch167, 14:12);\n\ts(EmcAutoCalConfig8, 22:20, scratch167, 17:15);\n\ts(EmcPmacroBgBiasCtrl0, 2:0, scratch167, 20:18);\n\ts(EmcPmacroBgBiasCtrl0, 6:4, scratch167, 23:21);\n\ts(McEmemArbTimingRcd, 5:0, scratch167, 29:24);\n\ts(EmcPmacroTxPwrd3, 3:2, scratch167, 31:30);\n\ts(EmcXm2CompPadCtrl2, 17:0, scratch168, 17:0);\n\ts(McEmemArbTimingCcdmw, 5:0, scratch168, 23:18);\n\ts(McEmemArbOverride, 27:27, scratch168, 24:24);\n\ts(McEmemArbOverride, 26:26, scratch168, 25:25);\n\ts(McEmemArbOverride, 16:16, scratch168, 26:26);\n\ts(McEmemArbOverride, 10:10, scratch168, 27:27);\n\ts(McEmemArbOverride, 4:4, scratch168, 28:28);\n\ts(McEmemArbOverride, 3:3, scratch168, 29:29);\n\ts(EmcPmacroTxPwrd3, 5:4, scratch168, 31:30);\n\ts(EmcXm2CompPadCtrl3, 17:0, scratch169, 17:0);\n\ts(EmcRext, 4:0, scratch169, 22:18);\n\ts(EmcTClkStop, 4:0, scratch169, 27:23);\n\ts(EmcPmacroTxPwrd3, 9:6, scratch169, 31:28);\n\ts(EmcZcalWaitCnt, 10:0, scratch170, 10:0);\n\ts(EmcZcalWaitCnt, 21:16, scratch170, 16:11);\n\ts(EmcZcalWaitCnt, 31:31, scratch170, 17:17);\n\ts(EmcWext, 4:0, scratch170, 22:18);\n\ts(EmcRefctrl2, 0:0, scratch170, 23:23);\n\ts(EmcRefctrl2, 26:24, scratch170, 26:24);\n\ts(EmcRefctrl2, 31:31, scratch170, 27:27);\n\ts(EmcPmacroTxPwrd3, 13:10, scratch170, 31:28);\n\ts(EmcZcalMrwCmd, 7:0, scratch171, 7:0);\n\ts(EmcZcalMrwCmd, 23:16, scratch171, 15:8);\n\ts(EmcZcalMrwCmd, 31:30, scratch171, 17:16);\n\ts(EmcWeDuration, 4:0, scratch171, 22:18);\n\ts(EmcWsDuration, 4:0, scratch171, 27:23);\n\ts(EmcPmacroTxPwrd3, 19:16, scratch171, 31:28);\n\ts(EmcSwizzleRank0Byte0, 2:0, scratch172, 2:0);\n\ts(EmcSwizzleRank0Byte0, 6:4, scratch172, 5:3);\n\ts(EmcSwizzleRank0Byte0, 10:8, scratch172, 8:6);\n\ts(EmcSwizzleRank0Byte0, 14:12, scratch172, 11:9);\n\ts(EmcSwizzleRank0Byte0, 18:16, scratch172, 14:12);\n\ts(EmcSwizzleRank0Byte0, 22:20, scratch172, 17:15);\n\ts(EmcPutermWidth, 31:31, scratch172, 18:18);\n\ts(EmcPutermWidth, 3:0, scratch172, 22:19);\n\ts(McEmemArbTimingRrd, 4:0, scratch172, 27:23);\n\ts(EmcPmacroTxPwrd3, 23:20, scratch172, 31:28);\n\ts(EmcSwizzleRank0Byte1, 2:0, scratch173, 2:0);\n\ts(EmcSwizzleRank0Byte1, 6:4, scratch173, 5:3);\n\ts(EmcSwizzleRank0Byte1, 10:8, scratch173, 8:6);\n\ts(EmcSwizzleRank0Byte1, 14:12, scratch173, 11:9);\n\ts(EmcSwizzleRank0Byte1, 18:16, scratch173, 14:12);\n\ts(EmcSwizzleRank0Byte1, 22:20, scratch173, 17:15);\n\ts(McEmemArbTimingR2R, 4:0, scratch173, 22:18);\n\ts(McEmemArbTimingW2W, 4:0, scratch173, 27:23);\n\ts(EmcPmacroTxPwrd3, 27:24, scratch173, 31:28);\n\ts(EmcSwizzleRank0Byte2, 2:0, scratch174, 2:0);\n\ts(EmcSwizzleRank0Byte2, 6:4, scratch174, 5:3);\n\ts(EmcSwizzleRank0Byte2, 10:8, scratch174, 8:6);\n\ts(EmcSwizzleRank0Byte2, 14:12, scratch174, 11:9);\n\ts(EmcSwizzleRank0Byte2, 18:16, scratch174, 14:12);\n\ts(EmcSwizzleRank0Byte2, 22:20, scratch174, 17:15);\n\ts(EmcPmacroTxPwrd3, 29:28, scratch174, 19:18);\n\ts(EmcPmacroTxSelClkSrc0, 11:0, scratch174, 31:20);\n\ts(EmcSwizzleRank0Byte3, 2:0, scratch175, 2:0);\n\ts(EmcSwizzleRank0Byte3, 6:4, scratch175, 5:3);\n\ts(EmcSwizzleRank0Byte3, 10:8, scratch175, 8:6);\n\ts(EmcSwizzleRank0Byte3, 14:12, scratch175, 11:9);\n\ts(EmcSwizzleRank0Byte3, 18:16, scratch175, 14:12);\n\ts(EmcSwizzleRank0Byte3, 22:20, scratch175, 17:15);\n\ts(EmcPmacroTxSelClkSrc0, 27:16, scratch175, 29:18);\n\ts(EmcPmacroTxSelClkSrc1, 1:0, scratch175, 31:30);\n\ts(EmcSwizzleRank1Byte0, 2:0, scratch176, 2:0);\n\ts(EmcSwizzleRank1Byte0, 6:4, scratch176, 5:3);\n\ts(EmcSwizzleRank1Byte0, 10:8, scratch176, 8:6);\n\ts(EmcSwizzleRank1Byte0, 14:12, scratch176, 11:9);\n\ts(EmcSwizzleRank1Byte0, 18:16, scratch176, 14:12);\n\ts(EmcSwizzleRank1Byte0, 22:20, scratch176, 17:15);\n\ts(EmcPmacroTxSelClkSrc1, 11:2, scratch176, 27:18);\n\ts(EmcPmacroTxSelClkSrc1, 19:16, scratch176, 31:28);\n\ts(EmcSwizzleRank1Byte1, 2:0, scratch177, 2:0);\n\ts(EmcSwizzleRank1Byte1, 6:4, scratch177, 5:3);\n\ts(EmcSwizzleRank1Byte1, 10:8, scratch177, 8:6);\n\ts(EmcSwizzleRank1Byte1, 14:12, scratch177, 11:9);\n\ts(EmcSwizzleRank1Byte1, 18:16, scratch177, 14:12);\n\ts(EmcSwizzleRank1Byte1, 22:20, scratch177, 17:15);\n\ts(EmcPmacroTxSelClkSrc1, 27:20, scratch177, 25:18);\n\ts(EmcPmacroTxSelClkSrc3, 5:0, scratch177, 31:26);\n\ts(EmcSwizzleRank1Byte2, 2:0, scratch178, 2:0);\n\ts(EmcSwizzleRank1Byte2, 6:4, scratch178, 5:3);\n\ts(EmcSwizzleRank1Byte2, 10:8, scratch178, 8:6);\n\ts(EmcSwizzleRank1Byte2, 14:12, scratch178, 11:9);\n\ts(EmcSwizzleRank1Byte2, 18:16, scratch178, 14:12);\n\ts(EmcSwizzleRank1Byte2, 22:20, scratch178, 17:15);\n\ts(EmcPmacroTxSelClkSrc3, 11:6, scratch178, 23:18);\n\ts(EmcPmacroTxSelClkSrc3, 23:16, scratch178, 31:24);\n\ts(EmcSwizzleRank1Byte3, 2:0, scratch179, 2:0);\n\ts(EmcSwizzleRank1Byte3, 6:4, scratch179, 5:3);\n\ts(EmcSwizzleRank1Byte3, 10:8, scratch179, 8:6);\n\ts(EmcSwizzleRank1Byte3, 14:12, scratch179, 11:9);\n\ts(EmcSwizzleRank1Byte3, 18:16, scratch179, 14:12);\n\ts(EmcSwizzleRank1Byte3, 22:20, scratch179, 17:15);\n\ts(EmcPmacroTxSelClkSrc3, 27:24, scratch179, 21:18);\n\ts(EmcPmacroTxSelClkSrc2, 9:0, scratch179, 31:22);\n\ts(EmcPmacroCmdBrickCtrlFdpd, 17:0, scratch180, 17:0);\n\ts(EmcPmacroTxSelClkSrc2, 11:10, scratch180, 19:18);\n\ts(EmcPmacroTxSelClkSrc2, 27:16, scratch180, 31:20);\n\ts(EmcPmacroDataBrickCtrlFdpd, 17:0, scratch181, 17:0);\n\ts(EmcPmacroTxSelClkSrc4, 11:0, scratch181, 29:18);\n\ts(EmcPmacroTxSelClkSrc4, 17:16, scratch181, 31:30);\n\ts(EmcFbioCfg7, 16:0, scratch182, 16:0);\n\ts(McEmemArbRefpbBankCtrl, 6:0, scratch182, 23:17);\n\ts(McEmemArbRefpbBankCtrl, 14:8, scratch182, 30:24);\n\ts(McEmemArbRefpbBankCtrl, 31:31, scratch182, 31:31);\n\ts(EmcDynSelfRefControl, 15:0, scratch183, 15:0);\n\ts(EmcDynSelfRefControl, 31:31, scratch183, 16:16);\n\ts(EmcPmacroTxSelClkSrc4, 27:18, scratch183, 26:17);\n\ts(EmcPmacroTxSelClkSrc5, 4:0, scratch183, 31:27);\n\ts(EmcDllCfg1, 16:0, scratch184, 16:0);\n\ts(EmcPmacroTxSelClkSrc5, 11:5, scratch184, 23:17);\n\ts(EmcPmacroTxSelClkSrc5, 23:16, scratch184, 31:24);\n\ts(EmcPmacroPadCfgCtrl, 1:0, scratch185, 1:0);\n\ts(EmcPmacroPadCfgCtrl, 6:5, scratch185, 3:2);\n\ts(EmcPmacroPadCfgCtrl, 11:9, scratch185, 6:4);\n\ts(EmcPmacroPadCfgCtrl, 13:13, scratch185, 7:7);\n\ts(EmcPmacroPadCfgCtrl, 17:16, scratch185, 9:8);\n\ts(EmcPmacroPadCfgCtrl, 21:20, scratch185, 11:10);\n\ts(EmcPmacroPadCfgCtrl, 25:24, scratch185, 13:12);\n\ts(EmcPmacroPadCfgCtrl, 30:28, scratch185, 16:14);\n\ts(EmcPmacroTxSelClkSrc5, 27:24, scratch185, 20:17);\n\ts(EmcPmacroCmdPadTxCtrl, 1:0, scratch185, 22:21);\n\ts(EmcPmacroCmdPadTxCtrl, 5:4, scratch185, 24:23);\n\ts(EmcPmacroCmdPadTxCtrl, 9:8, scratch185, 26:25);\n\ts(EmcPmacroCmdPadTxCtrl, 13:12, scratch185, 28:27);\n\ts(EmcPmacroCmdPadTxCtrl, 16:16, scratch185, 29:29);\n\ts(EmcPmacroCmdPadTxCtrl, 21:20, scratch185, 31:30);\n\ts(EmcRefresh, 15:0, scratch186, 15:0);\n\ts(EmcCmdQ, 4:0, scratch186, 20:16);\n\ts(EmcCmdQ, 10:8, scratch186, 23:21);\n\ts(EmcCmdQ, 14:12, scratch186, 26:24);\n\ts(EmcCmdQ, 28:24, scratch186, 31:27);\n\ts(EmcAcpdControl, 15:0, scratch187, 15:0);\n\ts(EmcAutoCalVrefSel1, 15:0, scratch187, 31:16);\n\ts(EmcXm2CompPadCtrl, 1:0, scratch188, 1:0);\n\ts(EmcXm2CompPadCtrl, 6:3, scratch188, 5:2);\n\ts(EmcXm2CompPadCtrl, 9:9, scratch188, 6:6);\n\ts(EmcXm2CompPadCtrl, 19:11, scratch188, 15:7);\n\ts(EmcCfgDigDllPeriod, 15:0, scratch188, 31:16);\n\ts(EmcCfgDigDll_1, 15:0, scratch189, 15:0);\n\ts(EmcPreRefreshReqCnt, 15:0, scratch189, 31:16);\n\ts(EmcPmacroCmdPadTxCtrl, 27:24, scratch190, 19:16);\n\ts(EmcPmacroDataPadTxCtrl, 1:0, scratch190, 21:20);\n\ts(EmcPmacroDataPadTxCtrl, 5:4, scratch190, 23:22);\n\ts(EmcPmacroDataPadTxCtrl, 9:8, scratch190, 25:24);\n\ts(EmcPmacroDataPadTxCtrl, 13:12, scratch190, 27:26);\n\ts(EmcPmacroDataPadTxCtrl, 16:16, scratch190, 28:28);\n\ts(EmcPmacroDataPadTxCtrl, 21:20, scratch190, 30:29);\n\ts(EmcPmacroDataPadTxCtrl, 24:24, scratch190, 31:31);\n\ts(EmcPmacroDataPadTxCtrl, 27:25, scratch191, 2:0);\n\n\ts(EmcPinGpio, 1:0, scratch8, 31:30);\n\ts(EmcPinGpioEn, 1:0, scratch9, 31:30);\n\ts(EmcDevSelect, 1:0, scratch10, 31:30);\n\ts(EmcZcalWarmColdBootEnables, 1:0, scratch11, 31:30);\n\ts(EmcCfgDigDllPeriodWarmBoot, 1:0, scratch12, 31:30);\n\ts32(EmcBctSpare13, scratch31);\n\ts32(EmcBctSpare12, scratch32);\n\ts32(EmcBctSpare7, scratch33);\n\ts32(EmcBctSpare6, scratch40);\n\ts32(EmcBctSpare5, scratch42);\n\ts32(EmcBctSpare4, scratch44);\n\ts32(EmcBctSpare3, scratch45);\n\ts32(EmcBctSpare2, scratch46);\n\ts32(EmcBctSpare1, scratch47);\n\ts32(EmcBctSpare0, scratch48);\n\ts32(EmcBctSpare9, scratch50);\n\ts32(EmcBctSpare8, scratch51);\n\ts32(BootRomPatchData, scratch56);\n\ts32(BootRomPatchControl, scratch57);\n\ts(McClkenOverrideAllWarmBoot, 0:0, scratch58, 31:31);\n\ts(EmcClkenOverrideAllWarmBoot, 0:0, scratch59, 30:30);\n\ts(EmcMrsWarmBootEnable, 0:0, scratch59, 31:31);\n\ts(ClearClk2Mc1, 0:0, scratch60, 30:30);\n\ts(EmcWarmBootExtraModeRegWriteEnable, 0:0, scratch60, 31:31);\n\ts(ClkRstControllerPllmMisc2OverrideEnable, 0:0, scratch61, 30:30);\n\ts(EmcDbgWriteMux, 0:0, scratch61, 31:31);\n\ts(EmcExtraRefreshNum, 2:0, scratch62, 31:29);\n\ts(PmcIoDpd3ReqWait, 2:0, scratch68, 30:28);\n\ts(AhbArbitrationXbarCtrlMemInitDone, 0:0, scratch68, 31:31);\n\ts(MemoryType, 2:0, scratch69, 30:28);\n\ts(PmcIoDpd4ReqWait, 2:0, scratch70, 30:28);\n\ts(EmcTimingControlWait, 7:0, scratch86, 31:24);\n\ts(EmcZcalWarmBootWait, 7:0, scratch87, 31:24);\n\ts(WarmBootWait, 7:0, scratch88, 31:24);\n\ts(EmcPinProgramWait, 7:0, scratch89, 31:24);\n\ts(EmcAutoCalWait, 9:0, scratch101, 31:22);\n\ts(SwizzleRankByteEncode, 15:0, scratch190, 15:0);\n\n\t// LPDDR4 MRW.\n\ts(EmcMrwLpddr2ZcalWarmBoot, 23:16, scratch5, 7:0);\n\ts(EmcMrwLpddr2ZcalWarmBoot, 7:0, scratch5, 15:8);\n\ts(EmcWarmBootMrwExtra, 23:16, scratch5, 23:16);\n\ts(EmcWarmBootMrwExtra, 7:0, scratch5, 31:24);\n\ts(EmcMrwLpddr2ZcalWarmBoot, 31:30, scratch6, 1:0);\n\ts(EmcWarmBootMrwExtra, 31:30, scratch6, 3:2);\n\ts(EmcMrwLpddr2ZcalWarmBoot, 27:26, scratch6, 5:4);\n\ts(EmcWarmBootMrwExtra, 27:26, scratch6, 7:6);\n\ts(EmcMrw6, 27:0, scratch8, 27:0);\n\ts(EmcMrw6, 31:30, scratch8, 29:28);\n\ts(EmcMrw8, 27:0, scratch9, 27:0);\n\ts(EmcMrw8, 31:30, scratch9, 29:28);\n\ts(EmcMrw9, 27:0, scratch10, 27:0);\n\ts(EmcMrw9, 31:30, scratch10, 29:28);\n\ts(EmcMrw10, 27:0, scratch11, 27:0);\n\ts(EmcMrw10, 31:30, scratch11, 29:28);\n\ts(EmcMrw12, 27:0, scratch12, 27:0);\n\ts(EmcMrw12, 31:30, scratch12, 29:28);\n\ts(EmcMrw13, 27:0, scratch13, 27:0);\n\ts(EmcMrw13, 31:30, scratch13, 29:28);\n\ts(EmcMrw14, 27:0, scratch14, 27:0);\n\ts(EmcMrw14, 31:30, scratch14, 29:28);\n\ts(EmcMrw1, 7:0, scratch15, 7:0);\n\ts(EmcMrw1, 23:16, scratch15, 15:8);\n\ts(EmcMrw1, 27:26, scratch15, 17:16);\n\ts(EmcMrw1, 31:30, scratch15, 19:18);\n\ts(EmcWarmBootMrwExtra, 7:0, scratch16, 7:0);\n\ts(EmcWarmBootMrwExtra, 23:16, scratch16, 15:8);\n\ts(EmcWarmBootMrwExtra, 27:26, scratch16, 17:16);\n\ts(EmcWarmBootMrwExtra, 31:30, scratch16, 19:18);\n\ts(EmcMrw2, 7:0, scratch17, 7:0);\n\ts(EmcMrw2, 23:16, scratch17, 15:8);\n\ts(EmcMrw2, 27:26, scratch17, 17:16);\n\ts(EmcMrw2, 31:30, scratch17, 19:18);\n\ts(EmcMrw3, 7:0, scratch18, 7:0);\n\ts(EmcMrw3, 23:16, scratch18, 15:8);\n\ts(EmcMrw3, 27:26, scratch18, 17:16);\n\ts(EmcMrw3, 31:30, scratch18, 19:18);\n\ts(EmcMrw4, 7:0, scratch19, 7:0);\n\ts(EmcMrw4, 23:16, scratch19, 15:8);\n\ts(EmcMrw4, 27:26, scratch19, 17:16);\n\ts(EmcMrw4, 31:30, scratch19, 19:18);\n\n\ts32(EmcCmdMappingByte, secure_scratch8);\n\ts32(EmcPmacroBrickMapping0, secure_scratch9);\n\ts32(EmcPmacroBrickMapping1, secure_scratch10);\n\ts32(EmcPmacroBrickMapping2, secure_scratch11);\n\ts32(McVideoProtectGpuOverride0, secure_scratch12);\n\ts(EmcCmdMappingCmd0_0, 6:0, secure_scratch13, 6:0);\n\ts(EmcCmdMappingCmd0_0, 14:8, secure_scratch13, 13:7);\n\ts(EmcCmdMappingCmd0_0, 22:16, secure_scratch13, 20:14);\n\ts(EmcCmdMappingCmd0_0, 30:24, secure_scratch13, 27:21);\n\ts(McVideoProtectBomAdrHi, 1:0, secure_scratch13, 29:28);\n\ts(McVideoProtectWriteAccess, 1:0, secure_scratch13, 31:30);\n\ts(EmcCmdMappingCmd0_1, 6:0, secure_scratch14, 6:0);\n\ts(EmcCmdMappingCmd0_1, 14:8, secure_scratch14, 13:7);\n\ts(EmcCmdMappingCmd0_1, 22:16, secure_scratch14, 20:14);\n\ts(EmcCmdMappingCmd0_1, 30:24, secure_scratch14, 27:21);\n\ts(McSecCarveoutAdrHi, 1:0, secure_scratch14, 29:28);\n\ts(McMtsCarveoutAdrHi, 1:0, secure_scratch14, 31:30);\n\ts(EmcCmdMappingCmd1_0, 6:0, secure_scratch15, 6:0);\n\ts(EmcCmdMappingCmd1_0, 14:8, secure_scratch15, 13:7);\n\ts(EmcCmdMappingCmd1_0, 22:16, secure_scratch15, 20:14);\n\ts(EmcCmdMappingCmd1_0, 30:24, secure_scratch15, 27:21);\n\ts(McGeneralizedCarveout5BomHi, 1:0, secure_scratch15, 29:28);\n\ts(McGeneralizedCarveout3BomHi, 1:0, secure_scratch15, 31:30);\n\ts(EmcCmdMappingCmd1_1, 6:0, secure_scratch16, 6:0);\n\ts(EmcCmdMappingCmd1_1, 14:8, secure_scratch16, 13:7);\n\ts(EmcCmdMappingCmd1_1, 22:16, secure_scratch16, 20:14);\n\ts(EmcCmdMappingCmd1_1, 30:24, secure_scratch16, 27:21);\n\ts(McGeneralizedCarveout2BomHi, 1:0, secure_scratch16, 29:28);\n\ts(McGeneralizedCarveout4BomHi, 1:0, secure_scratch16, 31:30);\n\ts(EmcCmdMappingCmd2_0, 6:0, secure_scratch17, 6:0);\n\ts(EmcCmdMappingCmd2_0, 14:8, secure_scratch17, 13:7);\n\ts(EmcCmdMappingCmd2_0, 22:16, secure_scratch17, 20:14);\n\ts(EmcCmdMappingCmd2_0, 30:24, secure_scratch17, 27:21);\n\ts(McGeneralizedCarveout1BomHi, 1:0, secure_scratch17, 29:28);\n\ts(EmcAdrCfg, 0:0, secure_scratch17, 30:30);\n\ts(EmcFbioSpare, 1:1, secure_scratch17, 31:31);\n\ts(EmcCmdMappingCmd2_1, 6:0, secure_scratch18, 6:0);\n\ts(EmcCmdMappingCmd2_1, 14:8, secure_scratch18, 13:7);\n\ts(EmcCmdMappingCmd2_1, 22:16, secure_scratch18, 20:14);\n\ts(EmcCmdMappingCmd2_1, 30:24, secure_scratch18, 27:21);\n\ts(EmcFbioCfg8, 15:15, secure_scratch18, 28:28);\n\ts(McEmemAdrCfg, 0:0, secure_scratch18, 29:29);\n\ts(McSecCarveoutProtectWriteAccess, 0:0, secure_scratch18, 30:30);\n\ts(McMtsCarveoutRegCtrl, 0:0, secure_scratch18, 31:31);\n\ts(EmcCmdMappingCmd3_0, 6:0, secure_scratch19, 6:0);\n\ts(EmcCmdMappingCmd3_0, 14:8, secure_scratch19, 13:7);\n\ts(EmcCmdMappingCmd3_0, 22:16, secure_scratch19, 20:14);\n\ts(EmcCmdMappingCmd3_0, 30:24, secure_scratch19, 27:21);\n\ts(McGeneralizedCarveout2Cfg0, 6:3, secure_scratch19, 31:28);\n\ts(EmcCmdMappingCmd3_1, 6:0, secure_scratch20, 6:0);\n\ts(EmcCmdMappingCmd3_1, 14:8, secure_scratch20, 13:7);\n\ts(EmcCmdMappingCmd3_1, 22:16, secure_scratch20, 20:14);\n\ts(EmcCmdMappingCmd3_1, 30:24, secure_scratch20, 27:21);\n\ts(McGeneralizedCarveout2Cfg0, 10:7, secure_scratch20, 31:28);\n\ts(McGeneralizedCarveout4Cfg0, 26:0, secure_scratch39, 26:0);\n\ts(McGeneralizedCarveout2Cfg0, 17:14, secure_scratch39, 30:27);\n\ts(McVideoProtectVprOverride, 0:0, secure_scratch39, 31:31);\n\ts(McGeneralizedCarveout5Cfg0, 26:0, secure_scratch40, 26:0);\n\ts(McGeneralizedCarveout2Cfg0, 21:18, secure_scratch40, 30:27);\n\ts(McVideoProtectVprOverride, 1:1, secure_scratch40, 31:31);\n\ts(EmcCmdMappingCmd0_2, 6:0, secure_scratch41, 6:0);\n\ts(EmcCmdMappingCmd0_2, 14:8, secure_scratch41, 13:7);\n\ts(EmcCmdMappingCmd0_2, 22:16, secure_scratch41, 20:14);\n\ts(EmcCmdMappingCmd0_2, 27:24, secure_scratch41, 24:21);\n\ts(McGeneralizedCarveout1Cfg0, 6:3, secure_scratch41, 28:25);\n\ts(McGeneralizedCarveout2Cfg0, 13:11, secure_scratch41, 31:29);\n\ts(EmcCmdMappingCmd1_2, 6:0, secure_scratch42, 6:0);\n\ts(EmcCmdMappingCmd1_2, 14:8, secure_scratch42, 13:7);\n\ts(EmcCmdMappingCmd1_2, 22:16, secure_scratch42, 20:14);\n\ts(EmcCmdMappingCmd1_2, 27:24, secure_scratch42, 24:21);\n\ts(McGeneralizedCarveout1Cfg0, 13:7, secure_scratch42, 31:25);\n\ts(EmcCmdMappingCmd2_2, 6:0, secure_scratch43, 6:0);\n\ts(EmcCmdMappingCmd2_2, 14:8, secure_scratch43, 13:7);\n\ts(EmcCmdMappingCmd2_2, 22:16, secure_scratch43, 20:14);\n\ts(EmcCmdMappingCmd2_2, 27:24, secure_scratch43, 24:21);\n\ts(McGeneralizedCarveout1Cfg0, 17:14, secure_scratch43, 28:25);\n\ts(McGeneralizedCarveout3Cfg0, 13:11, secure_scratch43, 31:29);\n\ts(EmcCmdMappingCmd3_2, 6:0, secure_scratch44, 6:0);\n\ts(EmcCmdMappingCmd3_2, 14:8, secure_scratch44, 13:7);\n\ts(EmcCmdMappingCmd3_2, 22:16, secure_scratch44, 20:14);\n\ts(EmcCmdMappingCmd3_2, 27:24, secure_scratch44, 24:21);\n\ts(McGeneralizedCarveout1Cfg0, 21:18, secure_scratch44, 28:25);\n\ts(McVideoProtectVprOverride, 3:2, secure_scratch44, 30:29);\n\ts(McVideoProtectVprOverride, 6:6, secure_scratch44, 31:31);\n\ts(McEmemAdrCfgChannelMask, 31:9, secure_scratch45, 22:0);\n\ts(McEmemAdrCfgDev0, 2:0, secure_scratch45, 25:23);\n\ts(McEmemAdrCfgDev0, 9:8, secure_scratch45, 27:26);\n\ts(McEmemAdrCfgDev0, 19:16, secure_scratch45, 31:28);\n\ts(McEmemAdrCfgBankMask0, 31:10, secure_scratch46, 21:0);\n\ts(McEmemAdrCfgDev1, 2:0, secure_scratch46, 24:22);\n\ts(McEmemAdrCfgDev1, 9:8, secure_scratch46, 26:25);\n\ts(McEmemAdrCfgDev1, 19:16, secure_scratch46, 30:27);\n\ts(McVideoProtectVprOverride, 7:7, secure_scratch46, 31:31);\n\ts(McEmemAdrCfgBankMask1, 31:10, secure_scratch47, 21:0);\n\ts(McGeneralizedCarveout3Cfg0, 10:3, secure_scratch47, 29:22);\n\ts(McVideoProtectVprOverride, 9:8, secure_scratch47, 31:30);\n\ts(McEmemAdrCfgBankMask2, 31:10, secure_scratch48, 21:0);\n\ts(McGeneralizedCarveout3Cfg0, 21:14, secure_scratch48, 29:22);\n\ts(McVideoProtectVprOverride, 11:11, secure_scratch48, 30:30);\n\ts(McVideoProtectVprOverride, 14:14, secure_scratch48, 31:31);\n\ts(McVideoProtectGpuOverride1, 15:0, secure_scratch49, 15:0);\n\ts(McEmemCfg, 13:0, secure_scratch49, 29:16);\n\ts(McEmemCfg, 31:31, secure_scratch49, 30:30);\n\ts(McVideoProtectVprOverride, 15:15, secure_scratch49, 31:31);\n\ts(McGeneralizedCarveout3Bom, 31:17, secure_scratch50, 14:0);\n\ts(McGeneralizedCarveout1Bom, 31:17, secure_scratch50, 29:15);\n\ts(McVideoProtectVprOverride, 18:17, secure_scratch50, 31:30);\n\ts(McGeneralizedCarveout4Bom, 31:17, secure_scratch51, 14:0);\n\ts(McGeneralizedCarveout2Bom, 31:17, secure_scratch51, 29:15);\n\ts(McVideoProtectVprOverride, 20:19, secure_scratch51, 31:30);\n\ts(McGeneralizedCarveout5Bom, 31:17, secure_scratch52, 14:0);\n\ts(McVideoProtectBom, 31:20, secure_scratch52, 26:15);\n\ts(McVideoProtectVprOverride, 23:21, secure_scratch52, 29:27);\n\ts(McVideoProtectVprOverride, 26:26, secure_scratch52, 30:30);\n\ts(McVideoProtectVprOverride, 29:29, secure_scratch52, 31:31);\n\ts(McVideoProtectSizeMb, 11:0, secure_scratch53, 11:0);\n\ts(McSecCarveoutBom, 31:20, secure_scratch53, 23:12);\n\ts(McVideoProtectVprOverride, 31:30, secure_scratch53, 25:24);\n\ts(McVideoProtectVprOverride1, 1:0, secure_scratch53, 27:26);\n\ts(McVideoProtectVprOverride1, 7:4, secure_scratch53, 31:28);\n\ts(McSecCarveoutSizeMb, 11:0, secure_scratch54, 11:0);\n\ts(McMtsCarveoutBom, 31:20, secure_scratch54, 23:12);\n\ts(McVideoProtectVprOverride1, 15:8, secure_scratch54, 31:24);\n\ts(McMtsCarveoutSizeMb, 11:0, secure_scratch55, 11:0);\n\ts(McGeneralizedCarveout4Size128kb, 11:0, secure_scratch55, 23:12);\n\ts(McVideoProtectVprOverride1, 16:16, secure_scratch55, 24:24);\n\ts(McGeneralizedCarveout2Cfg0, 2:0, secure_scratch55, 27:25);\n\ts(McGeneralizedCarveout2Cfg0, 25:22, secure_scratch55, 31:28);\n\ts(McGeneralizedCarveout3Size128kb, 11:0, secure_scratch56, 11:0);\n\ts(McGeneralizedCarveout2Size128kb, 11:0, secure_scratch56, 23:12);\n\ts(McGeneralizedCarveout2Cfg0, 26:26, secure_scratch56, 24:24);\n\ts(McGeneralizedCarveout1Cfg0, 2:0, secure_scratch56, 27:25);\n\ts(McGeneralizedCarveout1Cfg0, 25:22, secure_scratch56, 31:28);\n\ts(McGeneralizedCarveout1Size128kb, 11:0, secure_scratch57, 11:0);\n\ts(McGeneralizedCarveout5Size128kb, 11:0, secure_scratch57, 23:12);\n\ts(McGeneralizedCarveout1Cfg0, 26:26, secure_scratch57, 24:24);\n\ts(McGeneralizedCarveout3Cfg0, 2:0, secure_scratch57, 27:25);\n\ts(McGeneralizedCarveout3Cfg0, 25:22, secure_scratch57, 31:28);\n\ts(McGeneralizedCarveout3Cfg0, 26:26, secure_scratch58, 0:0);\n\n\ts32(McGeneralizedCarveout1Access0, secure_scratch59);\n\ts32(McGeneralizedCarveout1Access1, secure_scratch60);\n\ts32(McGeneralizedCarveout1Access2, secure_scratch61);\n\ts32(McGeneralizedCarveout1Access3, secure_scratch62);\n\ts32(McGeneralizedCarveout1Access4, secure_scratch63);\n\ts32(McGeneralizedCarveout2Access0, secure_scratch64);\n\ts32(McGeneralizedCarveout2Access1, secure_scratch65);\n\ts32(McGeneralizedCarveout2Access2, secure_scratch66);\n\ts32(McGeneralizedCarveout2Access3, secure_scratch67);\n\ts32(McGeneralizedCarveout2Access4, secure_scratch68);\n\ts32(McGeneralizedCarveout3Access0, secure_scratch69);\n\ts32(McGeneralizedCarveout3Access1, secure_scratch70);\n\ts32(McGeneralizedCarveout3Access2, secure_scratch71);\n\ts32(McGeneralizedCarveout3Access3, secure_scratch72);\n\ts32(McGeneralizedCarveout3Access4, secure_scratch73);\n\ts32(McGeneralizedCarveout4Access0, secure_scratch74);\n\ts32(McGeneralizedCarveout4Access1, secure_scratch75);\n\ts32(McGeneralizedCarveout4Access2, secure_scratch76);\n\ts32(McGeneralizedCarveout4Access3, secure_scratch77);\n\ts32(McGeneralizedCarveout4Access4, secure_scratch78);\n\ts32(McGeneralizedCarveout5Access0, secure_scratch79);\n\ts32(McGeneralizedCarveout5Access1, secure_scratch80);\n\ts32(McGeneralizedCarveout5Access2, secure_scratch81);\n\ts32(McGeneralizedCarveout5Access3, secure_scratch82);\n\ts32(McGeneralizedCarveout1ForceInternalAccess0, secure_scratch84);\n\ts32(McGeneralizedCarveout1ForceInternalAccess1, secure_scratch85);\n\ts32(McGeneralizedCarveout1ForceInternalAccess2, secure_scratch86);\n\ts32(McGeneralizedCarveout1ForceInternalAccess3, secure_scratch87);\n\ts32(McGeneralizedCarveout1ForceInternalAccess4, secure_scratch88);\n\ts32(McGeneralizedCarveout2ForceInternalAccess0, secure_scratch89);\n\ts32(McGeneralizedCarveout2ForceInternalAccess1, secure_scratch90);\n\ts32(McGeneralizedCarveout2ForceInternalAccess2, secure_scratch91);\n\ts32(McGeneralizedCarveout2ForceInternalAccess3, secure_scratch92);\n\ts32(McGeneralizedCarveout2ForceInternalAccess4, secure_scratch93);\n\ts32(McGeneralizedCarveout3ForceInternalAccess0, secure_scratch94);\n\ts32(McGeneralizedCarveout3ForceInternalAccess1, secure_scratch95);\n\ts32(McGeneralizedCarveout3ForceInternalAccess2, secure_scratch96);\n\ts32(McGeneralizedCarveout3ForceInternalAccess3, secure_scratch97);\n\ts32(McGeneralizedCarveout3ForceInternalAccess4, secure_scratch98);\n\ts32(McGeneralizedCarveout4ForceInternalAccess0, secure_scratch99);\n\ts32(McGeneralizedCarveout4ForceInternalAccess1, secure_scratch100);\n\ts32(McGeneralizedCarveout4ForceInternalAccess2, secure_scratch101);\n\ts32(McGeneralizedCarveout4ForceInternalAccess3, secure_scratch102);\n\ts32(McGeneralizedCarveout4ForceInternalAccess4, secure_scratch103);\n\ts32(McGeneralizedCarveout5ForceInternalAccess0, secure_scratch104);\n\ts32(McGeneralizedCarveout5ForceInternalAccess1, secure_scratch105);\n\ts32(McGeneralizedCarveout5ForceInternalAccess2, secure_scratch106);\n\ts32(McGeneralizedCarveout5ForceInternalAccess3, secure_scratch107);\n\n\t// PLLM.\n\tc32(0, scratch2);\n\ts(PllMInputDivider, 7:0, scratch2, 7:0);\n\ts(PllMFeedbackDivider, 7:0, scratch2, 15:8);\n\ts(PllMPostDivider, 4:0, scratch2, 20:16);\n\ts(PllMKVCO, 0:0, scratch2, 21:21);\n\ts(PllMKCP, 1:0, scratch2, 23:22);\n\n\tc32(0, scratch35);\n\ts(PllMSetupControl, 15:0, scratch35, 15:0);\n\n\t// PLLX.\n\tc32(0, scratch3);\n\ts(PllMInputDivider, 7:0, scratch3, 7:0);\n\tc(62, scratch3, 15:8); // 62 divn.\n\tc(0, scratch3, 20:16); // 0  divp.\n\ts(PllMKVCO, 0:0, scratch3, 21:21);\n\ts(PllMKCP, 1:0, scratch3, 23:22);\n\n\tc32(0, scratch36);\n\ts(PllMSetupControl, 23:0, scratch36, 23:0);\n\n\t// PLLM/PLLX.\n\tc32(0, scratch4);\n\ts(PllMStableTime, 9:0, scratch4, 9:0);\n\ts(PllMStableTime, 9:0, scratch4, 19:10);\n}\n\n/*\n * This function reads SDRAM parameters from the common BCT format and\n * writes them into PMC scratch registers (where the BootROM expects them\n * on LP0 resume).\n */\nstatic void _sdram_lp0_save_params_t210b01(sdram_params_t210b01_t *sdram)\n{\n\tpmc_regs_t210_t *pmc = (pmc_regs_t210_t *)PMC_BASE;\n\n\t// Patch full access to carveout parameters and unprotect their regions.\n\tsdram->mc_generalized_carveout1_cfg0 = 0;\n\tsdram->mc_generalized_carveout2_cfg0 = 0;\n\tsdram->mc_generalized_carveout3_cfg0 = 0;\n\tsdram->mc_generalized_carveout4_cfg0 = 0;\n\tsdram->mc_generalized_carveout5_cfg0 = 0;\n\n\t// Patch SDRAM parameters.\n\tu32 t0 = (sdram->emc_swizzle_rank0_byte0 << 5 >> 29) > (sdram->emc_swizzle_rank0_byte0 << 1 >> 29);\n\tu32 t1 = (t0 & 0xFFFFFFEF) | (((sdram->emc_swizzle_rank1_byte0 << 5 >> 29) > (sdram->emc_swizzle_rank1_byte0 << 1 >> 29)) << 4);\n\tu32 t2 = (t1 & 0xFFFFFFFD) | (((sdram->emc_swizzle_rank0_byte1 << 5 >> 29) > (sdram->emc_swizzle_rank0_byte1 << 1 >> 29)) << 1);\n\tu32 t3 = (t2 & 0xFFFFFFDF) | (((sdram->emc_swizzle_rank1_byte1 << 5 >> 29) > (sdram->emc_swizzle_rank1_byte1 << 1 >> 29)) << 5);\n\tu32 t4 = (t3 & 0xFFFFFFFB) | (((sdram->emc_swizzle_rank0_byte2 << 5 >> 29) > (sdram->emc_swizzle_rank0_byte2 << 1 >> 29)) << 2);\n\tu32 t5 = (t4 & 0xFFFFFFBF) | (((sdram->emc_swizzle_rank1_byte2 << 5 >> 29) > (sdram->emc_swizzle_rank1_byte2 << 1 >> 29)) << 6);\n\tu32 t6 = (t5 & 0xFFFFFFF7) | (((sdram->emc_swizzle_rank0_byte3 << 5 >> 29) > (sdram->emc_swizzle_rank0_byte3 << 1 >> 29)) << 3);\n\tu32 t7 = (t6 & 0xFFFFFF7F) | (((sdram->emc_swizzle_rank1_byte3 << 5 >> 29) > (sdram->emc_swizzle_rank1_byte3 << 1 >> 29)) << 7);\n\tsdram->swizzle_rank_byte_encode = t7;\n\tsdram->emc_bct_spare2 = 0x40000DD8;\n\tsdram->emc_bct_spare3 = t7;\n\n\ts(emc_clock_source, 7:0, scratch6, 15:8);\n\ts(emc_clock_source_dll, 7:0, scratch6, 23:16);\n\ts(emc_clock_source, 31:29, scratch6, 26:24);\n\ts(emc_clock_source_dll, 31:29, scratch6, 29:27);\n\ts(emc_clock_source_dll, 11:10, scratch6, 31:30);\n\ts(clk_rst_pllm_misc20_override, 9:8, scratch7, 1:0);\n\ts(clk_rst_pllm_misc20_override, 2:1, scratch7, 3:2);\n\ts(emc_zqcal_lpddr4_warm_boot, 31:30, scratch7, 5:4);\n\ts(emc_clock_source, 27:27, scratch7, 6:6);\n\ts(emc_clock_source, 26:26, scratch7, 7:7);\n\ts(emc_clock_source, 15:15, scratch7, 8:8);\n\ts(emc_clock_source, 25:25, scratch7, 9:9);\n\ts(emc_clock_source, 20:19, scratch7, 11:10);\n\ts(emc_clock_source, 16:16, scratch7, 12:12);\n\ts(clk_rst_pllm_misc20_override, 13:13, scratch7, 13:13);\n\ts(clk_rst_pllm_misc20_override, 12:12, scratch7, 14:14);\n\ts(clk_rst_pllm_misc20_override, 11:11, scratch7, 15:15);\n\ts(clk_rst_pllm_misc20_override, 10:10, scratch7, 16:16);\n\ts(clk_rst_pllm_misc20_override, 5:5, scratch7, 17:17);\n\ts(clk_rst_pllm_misc20_override, 4:4, scratch7, 18:18);\n\ts(clk_rst_pllm_misc20_override, 3:3, scratch7, 19:19);\n\ts(clk_rst_pllm_misc20_override, 0:0, scratch7, 20:20);\n\ts(emc_zqcal_lpddr4_warm_boot, 1:0, scratch7, 22:21);\n\ts(emc_zqcal_lpddr4_warm_boot, 4:4, scratch7, 23:23);\n\ts(emc_rc, 7:0, scratch7, 31:24);\n\ts(emc_pmacro_bg_bias_ctrl0, 13:12, scratch8, 31:30);\n\ts(emc_fdpd_ctrl_cmd_no_ramp, 0:0, scratch14, 30:30);\n\ts(emc_cfg_pipe_clk, 0:0, scratch14, 31:31);\n\ts(emc_qrst, 6:0, scratch15, 26:20);\n\ts(emc_qrst, 20:16, scratch15, 31:27);\n\ts(emc_pmacro_cmd_tx_drive, 5:0, scratch16, 25:20);\n\ts(emc_pmacro_cmd_tx_drive, 13:8, scratch16, 31:26);\n\ts(emc_fbio_cfg8, 27:16, scratch17, 31:20);\n\ts(emc_txsr_dll, 11:0, scratch18, 31:20);\n\ts(emc_txdsrvttgen, 11:0, scratch19, 31:20);\n\ts32(emc_cfg_rsv, scratch22);\n\ts32(emc_auto_cal_config, scratch23);\n\ts32(emc_auto_cal_vref_sel0, scratch24);\n\ts32(emc_pmacro_brick_ctrl_rfu1, scratch25);\n\ts32(emc_pmacro_brick_ctrl_rfu2, scratch26);\n\ts32(emc_pmc_scratch1, scratch27);\n\ts32(emc_pmc_scratch2, scratch28);\n\ts32(emc_pmc_scratch3, scratch29);\n\ts32(emc_pmacro_perbit_rfu_ctrl0, scratch30);\n\ts32(emc_pmacro_perbit_rfu_ctrl1, scratch31);\n\ts32(emc_pmacro_perbit_rfu_ctrl2, scratch32);\n\ts32(emc_pmacro_perbit_rfu_ctrl3, scratch33);\n\ts32(emc_pmacro_perbit_rfu_ctrl4, scratch40);\n\ts32(emc_pmacro_perbit_rfu_ctrl5, scratch42);\n\ts32(mc_emem_arb_da_turns, scratch44);\n\ts(emc_fbio_spare, 31:24, scratch64, 7:0);\n\ts(emc_fbio_spare, 23:16, scratch64, 15:8);\n\ts(emc_fbio_spare, 15:8, scratch64, 23:16);\n\ts(emc_fbio_spare, 7:2, scratch64, 29:24);\n\ts(emc_fbio_spare, 0:0, scratch64, 30:30);\n\ts(mc_emem_arb_misc2, 0:0, scratch64, 31:31);\n\ts(mc_emem_arb_misc0, 14:0, scratch65, 14:0);\n\ts(mc_emem_arb_misc0, 30:16, scratch65, 29:15);\n\ts(mc_da_cfg0, 0:0, scratch65, 30:30);\n\ts(emc_fdpd_ctrl_cmd, 16:0, scratch66, 16:0);\n\ts(emc_fdpd_ctrl_cmd, 31:20, scratch66, 28:17);\n\ts(emc_auto_cal_config2, 27:0, scratch67, 27:0);\n\ts(emc_burst_refresh_num, 3:0, scratch67, 31:28);\n\ts(emc_cfg_dig_dll, 10:0, scratch68, 10:0);\n\ts(emc_cfg_dig_dll, 25:12, scratch68, 24:11);\n\ts(emc_cfg_dig_dll, 27:27, scratch68, 25:25);\n\ts(emc_cfg_dig_dll, 31:30, scratch68, 27:26);\n\ts(emc_tppd, 3:0, scratch68, 31:28);\n\ts(emc_fdpd_ctrl_dq, 16:0, scratch69, 16:0);\n\ts(emc_fdpd_ctrl_dq, 28:20, scratch69, 25:17);\n\ts(emc_fdpd_ctrl_dq, 31:30, scratch69, 27:26);\n\ts(emc_r2r, 3:0, scratch69, 31:28);\n\ts(emc_pmacro_ib_vref_dq_0, 6:0, scratch70, 6:0);\n\ts(emc_pmacro_ib_vref_dq_0, 14:8, scratch70, 13:7);\n\ts(emc_pmacro_ib_vref_dq_0, 22:16, scratch70, 20:14);\n\ts(emc_pmacro_ib_vref_dq_0, 30:24, scratch70, 27:21);\n\ts(emc_w2w, 3:0, scratch70, 31:28);\n\ts(emc_pmacro_ib_vref_dq_1, 6:0, scratch71, 6:0);\n\ts(emc_pmacro_ib_vref_dq_1, 14:8, scratch71, 13:7);\n\ts(emc_pmacro_ib_vref_dq_1, 22:16, scratch71, 20:14);\n\ts(emc_pmacro_ib_vref_dq_1, 30:24, scratch71, 27:21);\n\ts(emc_pmacro_vttgen_ctrl0, 19:16, scratch71, 31:28);\n\ts(emc_pmacro_ib_vref_dqs_0, 6:0, scratch72, 6:0);\n\ts(emc_pmacro_ib_vref_dqs_0, 14:8, scratch72, 13:7);\n\ts(emc_pmacro_ib_vref_dqs_0, 22:16, scratch72, 20:14);\n\ts(emc_pmacro_ib_vref_dqs_0, 30:24, scratch72, 27:21);\n\ts(emc_pmacro_ib_vref_dqs_1, 6:0, scratch73, 6:0);\n\ts(emc_pmacro_ib_vref_dqs_1, 14:8, scratch73, 13:7);\n\ts(emc_pmacro_ib_vref_dqs_1, 22:16, scratch73, 20:14);\n\ts(emc_pmacro_ib_vref_dqs_1, 30:24, scratch73, 27:21);\n\ts(emc_pmacro_ddll_short_cmd_0, 6:0, scratch74, 6:0);\n\ts(emc_pmacro_ddll_short_cmd_0, 14:8, scratch74, 13:7);\n\ts(emc_pmacro_ddll_short_cmd_0, 22:16, scratch74, 20:14);\n\ts(emc_pmacro_ddll_short_cmd_0, 30:24, scratch74, 27:21);\n\ts(emc_pmacro_ddll_short_cmd_1, 6:0, scratch75, 6:0);\n\ts(emc_pmacro_ddll_short_cmd_1, 14:8, scratch75, 13:7);\n\ts(emc_pmacro_ddll_short_cmd_1, 22:16, scratch75, 20:14);\n\ts(emc_pmacro_ddll_short_cmd_1, 30:24, scratch75, 27:21);\n\ts(emc_dll_cfg0, 29:4, scratch76, 25:0);\n\ts(emc_rp, 5:0, scratch76, 31:26);\n\ts(emc_pmacro_tx_pwrd0, 10:0, scratch77, 10:0);\n\ts(emc_pmacro_tx_pwrd0, 13:12, scratch77, 12:11);\n\ts(emc_pmacro_tx_pwrd0, 26:16, scratch77, 23:13);\n\ts(emc_pmacro_tx_pwrd0, 29:28, scratch77, 25:24);\n\ts(emc_r2w, 5:0, scratch77, 31:26);\n\ts(emc_pmacro_tx_pwrd1, 10:0, scratch78, 10:0);\n\ts(emc_pmacro_tx_pwrd1, 13:12, scratch78, 12:11);\n\ts(emc_pmacro_tx_pwrd1, 26:16, scratch78, 23:13);\n\ts(emc_pmacro_tx_pwrd1, 29:28, scratch78, 25:24);\n\ts(emc_w2r, 5:0, scratch78, 31:26);\n\ts(emc_pmacro_tx_pwrd2, 10:0, scratch79, 10:0);\n\ts(emc_pmacro_tx_pwrd2, 13:12, scratch79, 12:11);\n\ts(emc_pmacro_tx_pwrd2, 26:16, scratch79, 23:13);\n\ts(emc_pmacro_tx_pwrd2, 29:28, scratch79, 25:24);\n\ts(emc_r2p, 5:0, scratch79, 31:26);\n\ts(emc_pmacro_tx_pwrd3, 10:0, scratch80, 10:0);\n\ts(emc_pmacro_tx_pwrd3, 13:12, scratch80, 12:11);\n\ts(emc_pmacro_tx_pwrd3, 26:16, scratch80, 23:13);\n\ts(emc_pmacro_tx_pwrd3, 29:28, scratch80, 25:24);\n\ts(emc_ccdmw, 5:0, scratch80, 31:26);\n\ts(emc_pmacro_tx_pwrd4, 10:0, scratch81, 10:0);\n\ts(emc_pmacro_tx_pwrd4, 13:12, scratch81, 12:11);\n\ts(emc_pmacro_tx_pwrd4, 26:16, scratch81, 23:13);\n\ts(emc_pmacro_tx_pwrd4, 29:28, scratch81, 25:24);\n\ts(emc_rd_rcd, 5:0, scratch81, 31:26);\n\ts(emc_pmacro_tx_pwrd5, 10:0, scratch82, 10:0);\n\ts(emc_pmacro_tx_pwrd5, 13:12, scratch82, 12:11);\n\ts(emc_pmacro_tx_pwrd5, 26:16, scratch82, 23:13);\n\ts(emc_pmacro_tx_pwrd5, 29:28, scratch82, 25:24);\n\ts(emc_wr_rcd, 5:0, scratch82, 31:26);\n\ts(emc_auto_cal_channel, 5:0, scratch83, 5:0);\n\ts(emc_auto_cal_channel, 11:8, scratch83, 9:6);\n\ts(emc_auto_cal_channel, 27:16, scratch83, 21:10);\n\ts(emc_auto_cal_channel, 31:29, scratch83, 24:22);\n\ts(emc_config_sample_delay, 6:0, scratch83, 31:25);\n\ts(emc_pmacro_rx_term, 5:0, scratch84, 5:0);\n\ts(emc_pmacro_rx_term, 13:8, scratch84, 11:6);\n\ts(emc_pmacro_rx_term, 21:16, scratch84, 17:12);\n\ts(emc_pmacro_rx_term, 29:24, scratch84, 23:18);\n\ts(emc_sel_dpd_ctrl, 5:2, scratch84, 27:24);\n\ts(emc_sel_dpd_ctrl, 8:8, scratch84, 28:28);\n\ts(emc_sel_dpd_ctrl, 18:16, scratch84, 31:29);\n\ts(emc_pmacro_dq_tx_drive, 5:0, scratch85, 5:0);\n\ts(emc_pmacro_dq_tx_drive, 13:8, scratch85, 11:6);\n\ts(emc_pmacro_dq_tx_drive, 21:16, scratch85, 17:12);\n\ts(emc_pmacro_dq_tx_drive, 29:24, scratch85, 23:18);\n\ts(emc_obdly, 5:0, scratch85, 29:24);\n\ts(emc_obdly, 29:28, scratch85, 31:30);\n\ts(emc_pmacro_ca_tx_drive, 5:0, scratch86, 5:0);\n\ts(emc_pmacro_ca_tx_drive, 13:8, scratch86, 11:6);\n\ts(emc_pmacro_ca_tx_drive, 21:16, scratch86, 17:12);\n\ts(emc_pmacro_ca_tx_drive, 29:24, scratch86, 23:18);\n\ts(emc_pmacro_vttgen_ctrl1, 15:10, scratch86, 29:24);\n\ts(emc_pmacro_vttgen_ctrl1, 21:20, scratch86, 31:30);\n\ts(emc_pmacro_zcrtl, 27:4, scratch87, 23:0);\n\ts(emc_pmacro_vttgen_ctrl2, 23:16, scratch87, 31:24);\n\ts(emc_zcal_interval, 23:10, scratch88, 13:0);\n\ts(emc_zcal_interval, 9:0, scratch88, 23:14);\n\ts(mc_emem_arb_timing_rc, 7:0, scratch88, 31:24);\n\ts(emc_data_brlshft0, 23:0, scratch89, 23:0);\n\ts(mc_emem_arb_rsv, 7:0, scratch89, 31:24);\n\ts(emc_data_brlshft1, 23:0, scratch90, 23:0);\n\ts(emc_dqs_brlshft0, 23:0, scratch91, 23:0);\n\ts(emc_dqs_brlshft1, 23:0, scratch92, 23:0);\n\ts(emc_swizzle_rank0_byte0, 2:0, scratch93, 2:0);\n\ts(emc_swizzle_rank0_byte0, 6:4, scratch93, 5:3);\n\ts(emc_swizzle_rank0_byte0, 10:8, scratch93, 8:6);\n\ts(emc_swizzle_rank0_byte0, 14:12, scratch93, 11:9);\n\ts(emc_swizzle_rank0_byte0, 18:16, scratch93, 14:12);\n\ts(emc_swizzle_rank0_byte0, 22:20, scratch93, 17:15);\n\ts(emc_swizzle_rank0_byte0, 26:24, scratch93, 20:18);\n\ts(emc_swizzle_rank0_byte0, 30:28, scratch93, 23:21);\n\ts(emc_swizzle_rank0_byte1, 2:0, scratch94, 2:0);\n\ts(emc_swizzle_rank0_byte1, 6:4, scratch94, 5:3);\n\ts(emc_swizzle_rank0_byte1, 10:8, scratch94, 8:6);\n\ts(emc_swizzle_rank0_byte1, 14:12, scratch94, 11:9);\n\ts(emc_swizzle_rank0_byte1, 18:16, scratch94, 14:12);\n\ts(emc_swizzle_rank0_byte1, 22:20, scratch94, 17:15);\n\ts(emc_swizzle_rank0_byte1, 26:24, scratch94, 20:18);\n\ts(emc_swizzle_rank0_byte1, 30:28, scratch94, 23:21);\n\ts(emc_ras, 6:0, scratch94, 30:24);\n\ts(emc_cfg, 4:4, scratch94, 31:31);\n\ts(emc_swizzle_rank0_byte2, 2:0, scratch95, 2:0);\n\ts(emc_swizzle_rank0_byte2, 6:4, scratch95, 5:3);\n\ts(emc_swizzle_rank0_byte2, 10:8, scratch95, 8:6);\n\ts(emc_swizzle_rank0_byte2, 14:12, scratch95, 11:9);\n\ts(emc_swizzle_rank0_byte2, 18:16, scratch95, 14:12);\n\ts(emc_swizzle_rank0_byte2, 22:20, scratch95, 17:15);\n\ts(emc_swizzle_rank0_byte2, 26:24, scratch95, 20:18);\n\ts(emc_swizzle_rank0_byte2, 30:28, scratch95, 23:21);\n\ts(emc_w2p, 6:0, scratch95, 30:24);\n\ts(emc_cfg, 5:5, scratch95, 31:31);\n\ts(emc_swizzle_rank0_byte3, 2:0, scratch96, 2:0);\n\ts(emc_swizzle_rank0_byte3, 6:4, scratch96, 5:3);\n\ts(emc_swizzle_rank0_byte3, 10:8, scratch96, 8:6);\n\ts(emc_swizzle_rank0_byte3, 14:12, scratch96, 11:9);\n\ts(emc_swizzle_rank0_byte3, 18:16, scratch96, 14:12);\n\ts(emc_swizzle_rank0_byte3, 22:20, scratch96, 17:15);\n\ts(emc_swizzle_rank0_byte3, 26:24, scratch96, 20:18);\n\ts(emc_swizzle_rank0_byte3, 30:28, scratch96, 23:21);\n\ts(emc_qsafe, 6:0, scratch96, 30:24);\n\ts(emc_cfg, 6:6, scratch96, 31:31);\n\ts(emc_swizzle_rank1_byte0, 2:0, scratch97, 2:0);\n\ts(emc_swizzle_rank1_byte0, 6:4, scratch97, 5:3);\n\ts(emc_swizzle_rank1_byte0, 10:8, scratch97, 8:6);\n\ts(emc_swizzle_rank1_byte0, 14:12, scratch97, 11:9);\n\ts(emc_swizzle_rank1_byte0, 18:16, scratch97, 14:12);\n\ts(emc_swizzle_rank1_byte0, 22:20, scratch97, 17:15);\n\ts(emc_swizzle_rank1_byte0, 26:24, scratch97, 20:18);\n\ts(emc_swizzle_rank1_byte0, 30:28, scratch97, 23:21);\n\ts(emc_rdv, 6:0, scratch97, 30:24);\n\ts(emc_cfg, 7:7, scratch97, 31:31);\n\ts(emc_swizzle_rank1_byte1, 2:0, scratch98, 2:0);\n\ts(emc_swizzle_rank1_byte1, 6:4, scratch98, 5:3);\n\ts(emc_swizzle_rank1_byte1, 10:8, scratch98, 8:6);\n\ts(emc_swizzle_rank1_byte1, 14:12, scratch98, 11:9);\n\ts(emc_swizzle_rank1_byte1, 18:16, scratch98, 14:12);\n\ts(emc_swizzle_rank1_byte1, 22:20, scratch98, 17:15);\n\ts(emc_swizzle_rank1_byte1, 26:24, scratch98, 20:18);\n\ts(emc_swizzle_rank1_byte1, 30:28, scratch98, 23:21);\n\ts(emc_rw2pden, 6:0, scratch98, 30:24);\n\ts(emc_cfg, 8:8, scratch98, 31:31);\n\ts(emc_swizzle_rank1_byte2, 2:0, scratch99, 2:0);\n\ts(emc_swizzle_rank1_byte2, 6:4, scratch99, 5:3);\n\ts(emc_swizzle_rank1_byte2, 10:8, scratch99, 8:6);\n\ts(emc_swizzle_rank1_byte2, 14:12, scratch99, 11:9);\n\ts(emc_swizzle_rank1_byte2, 18:16, scratch99, 14:12);\n\ts(emc_swizzle_rank1_byte2, 22:20, scratch99, 17:15);\n\ts(emc_swizzle_rank1_byte2, 26:24, scratch99, 20:18);\n\ts(emc_swizzle_rank1_byte2, 30:28, scratch99, 23:21);\n\ts(emc_tfaw, 6:0, scratch99, 30:24);\n\ts(emc_cfg, 9:9, scratch99, 31:31);\n\ts(emc_swizzle_rank1_byte3, 2:0, scratch100, 2:0);\n\ts(emc_swizzle_rank1_byte3, 6:4, scratch100, 5:3);\n\ts(emc_swizzle_rank1_byte3, 10:8, scratch100, 8:6);\n\ts(emc_swizzle_rank1_byte3, 14:12, scratch100, 11:9);\n\ts(emc_swizzle_rank1_byte3, 18:16, scratch100, 14:12);\n\ts(emc_swizzle_rank1_byte3, 22:20, scratch100, 17:15);\n\ts(emc_swizzle_rank1_byte3, 26:24, scratch100, 20:18);\n\ts(emc_swizzle_rank1_byte3, 30:28, scratch100, 23:21);\n\ts(emc_tclkstable, 6:0, scratch100, 30:24);\n\ts(emc_cfg, 18:18, scratch100, 31:31);\n\ts(emc_cfg_pipe2, 11:0, scratch101, 11:0);\n\ts(emc_cfg_pipe2, 27:16, scratch101, 23:12);\n\ts(emc_trtm, 6:0, scratch101, 30:24);\n\ts(emc_cfg, 21:21, scratch101, 31:31);\n\ts(emc_cfg_pipe1, 11:0, scratch102, 11:0);\n\ts(emc_cfg_pipe1, 27:16, scratch102, 23:12);\n\ts(emc_twtm, 6:0, scratch102, 30:24);\n\ts(emc_cfg, 22:22, scratch102, 31:31);\n\ts(emc_pmacro_ddll_pwrd0, 4:1, scratch103, 3:0);\n\ts(emc_pmacro_ddll_pwrd0, 7:6, scratch103, 5:4);\n\ts(emc_pmacro_ddll_pwrd0, 12:9, scratch103, 9:6);\n\ts(emc_pmacro_ddll_pwrd0, 15:14, scratch103, 11:10);\n\ts(emc_pmacro_ddll_pwrd0, 20:17, scratch103, 15:12);\n\ts(emc_pmacro_ddll_pwrd0, 23:22, scratch103, 17:16);\n\ts(emc_pmacro_ddll_pwrd0, 28:25, scratch103, 21:18);\n\ts(emc_pmacro_ddll_pwrd0, 31:30, scratch103, 23:22);\n\ts(emc_tratm, 6:0, scratch103, 30:24);\n\ts(emc_cfg, 23:23, scratch103, 31:31);\n\ts(emc_pmacro_ddll_pwrd1, 4:1, scratch104, 3:0);\n\ts(emc_pmacro_ddll_pwrd1, 7:6, scratch104, 5:4);\n\ts(emc_pmacro_ddll_pwrd1, 12:9, scratch104, 9:6);\n\ts(emc_pmacro_ddll_pwrd1, 15:14, scratch104, 11:10);\n\ts(emc_pmacro_ddll_pwrd1, 20:17, scratch104, 15:12);\n\ts(emc_pmacro_ddll_pwrd1, 23:22, scratch104, 17:16);\n\ts(emc_pmacro_ddll_pwrd1, 28:25, scratch104, 21:18);\n\ts(emc_pmacro_ddll_pwrd1, 31:30, scratch104, 23:22);\n\ts(emc_twatm, 6:0, scratch104, 30:24);\n\ts(emc_cfg, 24:24, scratch104, 31:31);\n\ts(emc_pmacro_ddll_pwrd2, 4:1, scratch105, 3:0);\n\ts(emc_pmacro_ddll_pwrd2, 7:6, scratch105, 5:4);\n\ts(emc_pmacro_ddll_pwrd2, 12:9, scratch105, 9:6);\n\ts(emc_pmacro_ddll_pwrd2, 15:14, scratch105, 11:10);\n\ts(emc_pmacro_ddll_pwrd2, 20:17, scratch105, 15:12);\n\ts(emc_pmacro_ddll_pwrd2, 23:22, scratch105, 17:16);\n\ts(emc_pmacro_ddll_pwrd2, 28:25, scratch105, 21:18);\n\ts(emc_pmacro_ddll_pwrd2, 31:30, scratch105, 23:22);\n\ts(emc_tr2ref, 6:0, scratch105, 30:24);\n\ts(emc_cfg, 25:25, scratch105, 31:31);\n\ts(emc_pmacro_ddll_periodic_offset, 5:0, scratch106, 5:0);\n\ts(emc_pmacro_ddll_periodic_offset, 16:8, scratch106, 14:6);\n\ts(emc_pmacro_ddll_periodic_offset, 28:20, scratch106, 23:15);\n\ts(emc_pdex2mrr, 6:0, scratch106, 30:24);\n\ts(emc_cfg, 26:26, scratch106, 31:31);\n\ts(mc_emem_arb_da_covers, 23:0, scratch107, 23:0);\n\ts(emc_clken_override, 3:1, scratch107, 26:24);\n\ts(emc_clken_override, 8:6, scratch107, 29:27);\n\ts(emc_clken_override, 16:16, scratch107, 30:30);\n\ts(emc_cfg, 28:28, scratch107, 31:31);\n\ts(emc_xm2_comp_pad_ctrl, 1:0, scratch108, 1:0);\n\ts(emc_xm2_comp_pad_ctrl, 6:4, scratch108, 4:2);\n\ts(emc_xm2_comp_pad_ctrl, 9:9, scratch108, 5:5);\n\ts(emc_xm2_comp_pad_ctrl, 19:11, scratch108, 14:6);\n\ts(emc_xm2_comp_pad_ctrl, 31:24, scratch108, 22:15);\n\ts(emc_rfc_pb, 8:0, scratch108, 31:23);\n\ts(emc_auto_cal_config3, 6:0, scratch109, 6:0);\n\ts(emc_auto_cal_config3, 14:8, scratch109, 13:7);\n\ts(emc_auto_cal_config3, 23:16, scratch109, 21:14);\n\ts(emc_cfg_update, 2:0, scratch109, 24:22);\n\ts(emc_cfg_update, 10:8, scratch109, 27:25);\n\ts(emc_cfg_update, 31:28, scratch109, 31:28);\n\ts(emc_auto_cal_config4, 6:0, scratch110, 6:0);\n\ts(emc_auto_cal_config4, 14:8, scratch110, 13:7);\n\ts(emc_auto_cal_config4, 23:16, scratch110, 21:14);\n\ts(emc_rfc, 9:0, scratch110, 31:22);\n\ts(emc_auto_cal_config5, 6:0, scratch111, 6:0);\n\ts(emc_auto_cal_config5, 14:8, scratch111, 13:7);\n\ts(emc_auto_cal_config5, 23:16, scratch111, 21:14);\n\ts(emc_txsr, 9:0, scratch111, 31:22);\n\ts(emc_auto_cal_config6, 6:0, scratch112, 6:0);\n\ts(emc_auto_cal_config6, 14:8, scratch112, 13:7);\n\ts(emc_auto_cal_config6, 23:16, scratch112, 21:14);\n\ts(emc_mc2emc_q, 2:0, scratch112, 24:22);\n\ts(emc_mc2emc_q, 10:8, scratch112, 27:25);\n\ts(emc_mc2emc_q, 27:24, scratch112, 31:28);\n\ts(emc_auto_cal_config7, 6:0, scratch113, 6:0);\n\ts(emc_auto_cal_config7, 14:8, scratch113, 13:7);\n\ts(emc_auto_cal_config7, 23:16, scratch113, 21:14);\n\ts(mc_emem_arb_ring1_throttle, 4:0, scratch113, 26:22);\n\ts(mc_emem_arb_ring1_throttle, 20:16, scratch113, 31:27);\n\ts(emc_auto_cal_config8, 6:0, scratch114, 6:0);\n\ts(emc_auto_cal_config8, 14:8, scratch114, 13:7);\n\ts(emc_auto_cal_config8, 23:16, scratch114, 21:14);\n\ts(emc_fbio_cfg7, 21:0, scratch115, 21:0);\n\ts(emc_ar2pden, 8:0, scratch115, 30:22);\n\ts(emc_cfg, 29:29, scratch115, 31:31);\n\ts(emc_pmacro_quse_ddll_rank0_0, 10:0, scratch123, 10:0);\n\ts(emc_pmacro_quse_ddll_rank0_0, 26:16, scratch123, 21:11);\n\ts(emc_rfc_slr, 8:0, scratch123, 30:22);\n\ts(emc_cfg, 30:30, scratch123, 31:31);\n\ts(emc_pmacro_quse_ddll_rank0_1, 10:0, scratch124, 10:0);\n\ts(emc_pmacro_quse_ddll_rank0_1, 26:16, scratch124, 21:11);\n\ts(emc_ibdly, 6:0, scratch124, 28:22);\n\ts(emc_ibdly, 29:28, scratch124, 30:29);\n\ts(emc_cfg, 31:31, scratch124, 31:31);\n\ts(emc_pmacro_quse_ddll_rank0_2, 10:0, scratch125, 10:0);\n\ts(emc_pmacro_quse_ddll_rank0_2, 26:16, scratch125, 21:11);\n\ts(mc_emem_arb_timing_rfcpb, 8:0, scratch125, 30:22);\n\ts(emc_fbio_cfg5, 4:4, scratch125, 31:31);\n\ts(emc_pmacro_quse_ddll_rank0_3, 10:0, scratch126, 10:0);\n\ts(emc_pmacro_quse_ddll_rank0_3, 26:16, scratch126, 21:11);\n\ts(emc_auto_cal_config9, 6:0, scratch126, 28:22);\n\ts(emc_fbio_cfg5, 15:13, scratch126, 31:29);\n\ts(emc_pmacro_quse_ddll_rank0_4, 10:0, scratch127, 10:0);\n\ts(emc_pmacro_quse_ddll_rank0_4, 26:16, scratch127, 21:11);\n\ts(emc_rdv_mask, 6:0, scratch127, 28:22);\n\ts(emc_cfg2, 5:3, scratch127, 31:29);\n\ts(emc_pmacro_quse_ddll_rank0_5, 10:0, scratch128, 10:0);\n\ts(emc_pmacro_quse_ddll_rank0_5, 26:16, scratch128, 21:11);\n\ts(emc_rdv_early_mask, 6:0, scratch128, 28:22);\n\ts(emc_pmacro_cmd_pad_tx_ctrl, 4:2, scratch128, 31:29);\n\ts(emc_pmacro_quse_ddll_rank1_0, 10:0, scratch129, 10:0);\n\ts(emc_pmacro_quse_ddll_rank1_0, 26:16, scratch129, 21:11);\n\ts(emc_rdv_early, 6:0, scratch129, 28:22);\n\ts(emc_pmacro_cmd_pad_tx_ctrl, 9:7, scratch129, 31:29);\n\ts(emc_pmacro_quse_ddll_rank1_1, 10:0, scratch130, 10:0);\n\ts(emc_pmacro_quse_ddll_rank1_1, 26:16, scratch130, 21:11);\n\ts(emc_quse_width, 4:0, scratch130, 26:22);\n\ts(emc_quse_width, 29:28, scratch130, 28:27);\n\ts(emc_pmacro_cmd_pad_tx_ctrl, 14:12, scratch130, 31:29);\n\ts(emc_pmacro_quse_ddll_rank1_2, 10:0, scratch131, 10:0);\n\ts(emc_pmacro_quse_ddll_rank1_2, 26:16, scratch131, 21:11);\n\ts(emc_pmacro_ddll_short_cmd_2, 6:0, scratch131, 28:22);\n\ts(emc_pmacro_cmd_pad_tx_ctrl, 19:17, scratch131, 31:29);\n\ts(emc_pmacro_quse_ddll_rank1_3, 10:0, scratch132, 10:0);\n\ts(emc_pmacro_quse_ddll_rank1_3, 26:16, scratch132, 21:11);\n\ts(emc_pmacro_cmd_rx_term_mode, 1:0, scratch132, 23:22);\n\ts(emc_pmacro_cmd_rx_term_mode, 5:4, scratch132, 25:24);\n\ts(emc_pmacro_cmd_rx_term_mode, 9:8, scratch132, 27:26);\n\ts(emc_pmacro_cmd_rx_term_mode, 13:13, scratch132, 28:28);\n\ts(emc_pmacro_data_pad_tx_ctrl, 4:2, scratch132, 31:29);\n\ts(emc_pmacro_quse_ddll_rank1_4, 10:0, scratch133, 10:0);\n\ts(emc_pmacro_quse_ddll_rank1_4, 26:16, scratch133, 21:11);\n\ts(emc_pmacro_data_rx_term_mode, 1:0, scratch133, 23:22);\n\ts(emc_pmacro_data_rx_term_mode, 5:4, scratch133, 25:24);\n\ts(emc_pmacro_data_rx_term_mode, 9:8, scratch133, 27:26);\n\ts(emc_pmacro_data_rx_term_mode, 13:13, scratch133, 28:28);\n\ts(emc_pmacro_data_pad_tx_ctrl, 9:7, scratch133, 31:29);\n\ts(emc_pmacro_quse_ddll_rank1_5, 10:0, scratch134, 10:0);\n\ts(emc_pmacro_quse_ddll_rank1_5, 26:16, scratch134, 21:11);\n\ts(mc_emem_arb_timing_rp, 6:0, scratch134, 28:22);\n\ts(emc_pmacro_data_pad_tx_ctrl, 14:12, scratch134, 31:29);\n\ts(emc_pmacro_ob_ddll_long_dq_rank0_0, 10:0, scratch135, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dq_rank0_0, 26:16, scratch135, 21:11);\n\ts(mc_emem_arb_timing_ras, 6:0, scratch135, 28:22);\n\ts(emc_pmacro_data_pad_tx_ctrl, 19:17, scratch135, 31:29);\n\ts(emc_pmacro_ob_ddll_long_dq_rank0_1, 10:0, scratch136, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dq_rank0_1, 26:16, scratch136, 21:11);\n\ts(mc_emem_arb_timing_faw, 6:0, scratch136, 28:22);\n\ts(emc_cfg, 17:16, scratch136, 30:29);\n\ts(emc_fbio_cfg5, 8:8, scratch136, 31:31);\n\ts(emc_pmacro_ob_ddll_long_dq_rank0_2, 10:0, scratch137, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dq_rank0_2, 26:16, scratch137, 21:11);\n\ts(mc_emem_arb_timing_rap2pre, 6:0, scratch137, 28:22);\n\ts(emc_fbio_cfg5, 1:0, scratch137, 30:29);\n\ts(emc_fbio_cfg5, 10:10, scratch137, 31:31);\n\ts(emc_pmacro_ob_ddll_long_dq_rank0_3, 10:0, scratch138, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dq_rank0_3, 26:16, scratch138, 21:11);\n\ts(mc_emem_arb_timing_wap2pre, 6:0, scratch138, 28:22);\n\ts(emc_fbio_cfg5, 3:2, scratch138, 30:29);\n\ts(emc_fbio_cfg5, 12:12, scratch138, 31:31);\n\ts(emc_pmacro_ob_ddll_long_dq_rank0_4, 10:0, scratch139, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dq_rank0_4, 26:16, scratch139, 21:11);\n\ts(mc_emem_arb_timing_r2w, 6:0, scratch139, 28:22);\n\ts(emc_cfg2, 27:26, scratch139, 30:29);\n\ts(emc_fbio_cfg5, 24:24, scratch139, 31:31);\n\ts(emc_pmacro_ob_ddll_long_dq_rank0_5, 10:0, scratch140, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dq_rank0_5, 26:16, scratch140, 21:11);\n\ts(mc_emem_arb_timing_w2r, 6:0, scratch140, 28:22);\n\ts(emc_fbio_cfg5, 27:25, scratch140, 31:29);\n\ts(emc_pmacro_ob_ddll_long_dq_rank1_0, 10:0, scratch141, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dq_rank1_0, 26:16, scratch141, 21:11);\n\ts(emc_wdv, 5:0, scratch141, 27:22);\n\ts(emc_fbio_cfg5, 23:20, scratch141, 31:28);\n\ts(emc_pmacro_ob_ddll_long_dq_rank1_1, 10:0, scratch142, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dq_rank1_1, 26:16, scratch142, 21:11);\n\ts(emc_quse, 5:0, scratch142, 27:22);\n\ts(emc_fbio_cfg5, 28:28, scratch142, 28:28);\n\ts(emc_fbio_cfg5, 31:30, scratch142, 30:29);\n\ts(emc_cfg2, 0:0, scratch142, 31:31);\n\ts(emc_pmacro_ob_ddll_long_dq_rank1_2, 10:0, scratch143, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dq_rank1_2, 26:16, scratch143, 21:11);\n\ts(emc_pdex2wr, 5:0, scratch143, 27:22);\n\ts(emc_cfg2, 2:1, scratch143, 29:28);\n\ts(emc_cfg2, 7:7, scratch143, 30:30);\n\ts(emc_cfg2, 10:10, scratch143, 31:31);\n\ts(emc_pmacro_ob_ddll_long_dq_rank1_3, 10:0, scratch144, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dq_rank1_3, 26:16, scratch144, 21:11);\n\ts(emc_pdex2rd, 5:0, scratch144, 27:22);\n\ts(emc_cfg2, 11:11, scratch144, 28:28);\n\ts(emc_cfg2, 16:14, scratch144, 31:29);\n\ts(emc_pmacro_ob_ddll_long_dq_rank1_4, 10:0, scratch145, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dq_rank1_4, 26:16, scratch145, 21:11);\n\ts(emc_pdex2che, 5:0, scratch145, 27:22);\n\ts(emc_cfg2, 20:20, scratch145, 28:28);\n\ts(emc_cfg2, 24:22, scratch145, 31:29);\n\ts(emc_pmacro_ob_ddll_long_dq_rank1_5, 10:0, scratch146, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dq_rank1_5, 26:16, scratch146, 21:11);\n\ts(emc_pchg2pden, 5:0, scratch146, 27:22);\n\ts(emc_cfg2, 25:25, scratch146, 28:28);\n\ts(emc_cfg2, 30:28, scratch146, 31:29);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank0_0, 10:0, scratch147, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank0_0, 26:16, scratch147, 21:11);\n\ts(emc_act2pden, 5:0, scratch147, 27:22);\n\ts(emc_cfg2, 31:31, scratch147, 28:28);\n\ts(emc_cfg_pipe, 2:0, scratch147, 31:29);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank0_1, 10:0, scratch148, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank0_1, 26:16, scratch148, 21:11);\n\ts(emc_cke2pden, 5:0, scratch148, 27:22);\n\ts(emc_cfg_pipe, 6:3, scratch148, 31:28);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank0_2, 10:0, scratch149, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank0_2, 26:16, scratch149, 21:11);\n\ts(emc_tcke, 5:0, scratch149, 27:22);\n\ts(emc_cfg_pipe, 10:7, scratch149, 31:28);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank0_3, 10:0, scratch150, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank0_3, 26:16, scratch150, 21:11);\n\ts(emc_trpab, 5:0, scratch150, 27:22);\n\ts(emc_cfg_pipe, 11:11, scratch150, 28:28);\n\ts(emc_cfg_pipe, 18:16, scratch150, 31:29);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank0_4, 10:0, scratch151, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank0_4, 26:16, scratch151, 21:11);\n\ts(emc_einput, 5:0, scratch151, 27:22);\n\ts(emc_cfg_pipe, 22:19, scratch151, 31:28);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank0_5, 10:0, scratch152, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank0_5, 26:16, scratch152, 21:11);\n\ts(emc_einput_duration, 5:0, scratch152, 27:22);\n\ts(emc_cfg_pipe, 26:23, scratch152, 31:28);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank1_0, 10:0, scratch153, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank1_0, 26:16, scratch153, 21:11);\n\ts(emc_puterm_extra, 5:0, scratch153, 27:22);\n\ts(emc_cfg_pipe, 27:27, scratch153, 28:28);\n\ts(emc_pmacro_tx_sel_clk_src0, 2:0, scratch153, 31:29);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank1_1, 10:0, scratch154, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank1_1, 26:16, scratch154, 21:11);\n\ts(emc_tckesr, 5:0, scratch154, 27:22);\n\ts(emc_pmacro_tx_sel_clk_src0, 6:3, scratch154, 31:28);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank1_2, 10:0, scratch155, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank1_2, 26:16, scratch155, 21:11);\n\ts(emc_tpd, 5:0, scratch155, 27:22);\n\ts(emc_pmacro_tx_sel_clk_src0, 10:7, scratch155, 31:28);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank1_3, 10:0, scratch156, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank1_3, 26:16, scratch156, 21:11);\n\ts(emc_wdv_mask, 5:0, scratch156, 27:22);\n\ts(emc_pmacro_tx_sel_clk_src0, 19:16, scratch156, 31:28);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank1_4, 10:0, scratch157, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank1_4, 26:16, scratch157, 21:11);\n\ts(emc_wdv_chk, 5:0, scratch157, 27:22);\n\ts(emc_pmacro_tx_sel_clk_src0, 23:20, scratch157, 31:28);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank1_5, 10:0, scratch158, 10:0);\n\ts(emc_pmacro_ob_ddll_long_dqs_rank1_5, 26:16, scratch158, 21:11);\n\ts(emc_cmd_brlshft0, 5:0, scratch158, 27:22);\n\ts(emc_pmacro_tx_sel_clk_src0, 26:24, scratch158, 30:28);\n\ts(emc_pmacro_tx_sel_clk_src1, 0:0, scratch158, 31:31);\n\ts(emc_pmacro_ib_ddll_long_dqs_rank0_0, 10:0, scratch159, 10:0);\n\ts(emc_pmacro_ib_ddll_long_dqs_rank0_0, 26:16, scratch159, 21:11);\n\ts(emc_cmd_brlshft1, 5:0, scratch159, 27:22);\n\ts(emc_pmacro_tx_sel_clk_src1, 4:1, scratch159, 31:28);\n\ts(emc_pmacro_ib_ddll_long_dqs_rank0_1, 10:0, scratch160, 10:0);\n\ts(emc_pmacro_ib_ddll_long_dqs_rank0_1, 26:16, scratch160, 21:11);\n\ts(emc_cmd_brlshft2, 5:0, scratch160, 27:22);\n\ts(emc_pmacro_tx_sel_clk_src1, 8:5, scratch160, 31:28);\n\ts(emc_pmacro_ib_ddll_long_dqs_rank0_2, 10:0, scratch161, 10:0);\n\ts(emc_pmacro_ib_ddll_long_dqs_rank0_2, 26:16, scratch161, 21:11);\n\ts(emc_cmd_brlshft3, 5:0, scratch161, 27:22);\n\ts(emc_pmacro_tx_sel_clk_src1, 10:9, scratch161, 29:28);\n\ts(emc_pmacro_tx_sel_clk_src1, 17:16, scratch161, 31:30);\n\ts(emc_pmacro_ib_ddll_long_dqs_rank0_3, 10:0, scratch162, 10:0);\n\ts(emc_pmacro_ib_ddll_long_dqs_rank0_3, 26:16, scratch162, 21:11);\n\ts(emc_wev, 5:0, scratch162, 27:22);\n\ts(emc_pmacro_tx_sel_clk_src1, 21:18, scratch162, 31:28);\n\ts(emc_pmacro_ib_ddll_long_dqs_rank1_0, 10:0, scratch163, 10:0);\n\ts(emc_pmacro_ib_ddll_long_dqs_rank1_0, 26:16, scratch163, 21:11);\n\ts(emc_wsv, 5:0, scratch163, 27:22);\n\ts(emc_pmacro_tx_sel_clk_src1, 25:22, scratch163, 31:28);\n\ts(emc_pmacro_ib_ddll_long_dqs_rank1_1, 10:0, scratch164, 10:0);\n\ts(emc_pmacro_ib_ddll_long_dqs_rank1_1, 26:16, scratch164, 21:11);\n\ts(emc_cfg3, 2:0, scratch164, 24:22);\n\ts(emc_cfg3, 6:4, scratch164, 27:25);\n\ts(emc_pmacro_tx_sel_clk_src1, 26:26, scratch164, 28:28);\n\ts(emc_pmacro_tx_sel_clk_src3, 2:0, scratch164, 31:29);\n\ts(emc_pmacro_ib_ddll_long_dqs_rank1_2, 10:0, scratch165, 10:0);\n\ts(emc_pmacro_ib_ddll_long_dqs_rank1_2, 26:16, scratch165, 21:11);\n\ts(emc_puterm_width, 31:31, scratch165, 22:22);\n\ts(emc_puterm_width, 4:0, scratch165, 27:23);\n\ts(emc_pmacro_tx_sel_clk_src3, 6:3, scratch165, 31:28);\n\ts(emc_pmacro_ib_ddll_long_dqs_rank1_3, 10:0, scratch166, 10:0);\n\ts(emc_pmacro_ib_ddll_long_dqs_rank1_3, 26:16, scratch166, 21:11);\n\ts(mc_emem_arb_timing_rcd, 5:0, scratch166, 27:22);\n\ts(emc_pmacro_tx_sel_clk_src3, 10:7, scratch166, 31:28);\n\ts(emc_pmacro_ddll_long_cmd_0, 10:0, scratch167, 10:0);\n\ts(emc_pmacro_ddll_long_cmd_0, 26:16, scratch167, 21:11);\n\ts(mc_emem_arb_timing_ccdmw, 5:0, scratch167, 27:22);\n\ts(emc_pmacro_tx_sel_clk_src3, 19:16, scratch167, 31:28);\n\ts(emc_pmacro_ddll_long_cmd_1, 10:0, scratch168, 10:0);\n\ts(emc_pmacro_ddll_long_cmd_1, 26:16, scratch168, 21:11);\n\ts(mc_emem_arb_override, 27:27, scratch168, 22:22);\n\ts(mc_emem_arb_override, 26:26, scratch168, 23:23);\n\ts(mc_emem_arb_override, 16:16, scratch168, 24:24);\n\ts(mc_emem_arb_override, 10:10, scratch168, 25:25);\n\ts(mc_emem_arb_override, 4:4, scratch168, 26:26);\n\ts(mc_emem_arb_override, 3:3, scratch168, 27:27);\n\ts(emc_pmacro_tx_sel_clk_src3, 23:20, scratch168, 31:28);\n\ts(emc_pmacro_ddll_long_cmd_2, 10:0, scratch169, 10:0);\n\ts(emc_pmacro_ddll_long_cmd_2, 26:16, scratch169, 21:11);\n\ts(emc_rrd, 4:0, scratch169, 26:22);\n\ts(emc_rext, 4:0, scratch169, 31:27);\n\ts(emc_pmacro_ddll_long_cmd_3, 10:0, scratch170, 10:0);\n\ts(emc_pmacro_ddll_long_cmd_3, 26:16, scratch170, 21:11);\n\ts(emc_tclkstop, 4:0, scratch170, 26:22);\n\ts(emc_wext, 4:0, scratch170, 31:27);\n\ts(emc_pmacro_perbit_fgcg_ctrl0, 10:0, scratch171, 10:0);\n\ts(emc_pmacro_perbit_fgcg_ctrl0, 26:16, scratch171, 21:11);\n\ts(emc_ref_ctrl2, 0:0, scratch171, 22:22);\n\ts(emc_ref_ctrl2, 26:24, scratch171, 25:23);\n\ts(emc_ref_ctrl2, 31:31, scratch171, 26:26);\n\ts(emc_we_duration, 4:0, scratch171, 31:27);\n\ts(emc_pmacro_perbit_fgcg_ctrl1, 10:0, scratch172, 10:0);\n\ts(emc_pmacro_perbit_fgcg_ctrl1, 26:16, scratch172, 21:11);\n\ts(emc_ws_duration, 4:0, scratch172, 26:22);\n\ts(emc_pmacro_pad_cfg_ctrl, 0:0, scratch172, 27:27);\n\ts(emc_pmacro_pad_cfg_ctrl, 9:9, scratch172, 28:28);\n\ts(emc_pmacro_pad_cfg_ctrl, 13:13, scratch172, 29:29);\n\ts(emc_pmacro_pad_cfg_ctrl, 17:16, scratch172, 31:30);\n\ts(emc_pmacro_perbit_fgcg_ctrl2, 10:0, scratch173, 10:0);\n\ts(emc_pmacro_perbit_fgcg_ctrl2, 26:16, scratch173, 21:11);\n\ts(mc_emem_arb_timing_rrd, 4:0, scratch173, 26:22);\n\ts(mc_emem_arb_timing_r2r, 4:0, scratch173, 31:27);\n\ts(emc_pmacro_perbit_fgcg_ctrl3, 10:0, scratch174, 10:0);\n\ts(emc_pmacro_perbit_fgcg_ctrl3, 26:16, scratch174, 21:11);\n\ts(mc_emem_arb_timing_w2w, 4:0, scratch174, 26:22);\n\ts(emc_pmacro_tx_sel_clk_src3, 26:24, scratch174, 29:27);\n\ts(emc_pmacro_tx_sel_clk_src2, 1:0, scratch174, 31:30);\n\ts(emc_pmacro_perbit_fgcg_ctrl4, 10:0, scratch175, 10:0);\n\ts(emc_pmacro_perbit_fgcg_ctrl4, 26:16, scratch175, 21:11);\n\ts(emc_pmacro_tx_sel_clk_src2, 10:2, scratch175, 30:22);\n\ts(emc_pmacro_tx_sel_clk_src2, 16:16, scratch175, 31:31);\n\ts(emc_pmacro_perbit_fgcg_ctrl5, 10:0, scratch176, 10:0);\n\ts(emc_pmacro_perbit_fgcg_ctrl5, 26:16, scratch176, 21:11);\n\ts(emc_pmacro_tx_sel_clk_src2, 26:17, scratch176, 31:22);\n\ts(mc_emem_arb_cfg, 8:0, scratch177, 8:0);\n\ts(mc_emem_arb_cfg, 20:16, scratch177, 13:9);\n\ts(mc_emem_arb_cfg, 31:24, scratch177, 21:14);\n\ts(emc_pmacro_tx_sel_clk_src4, 9:0, scratch177, 31:22);\n\ts(mc_emem_arb_misc1, 12:0, scratch178, 12:0);\n\ts(mc_emem_arb_misc1, 25:21, scratch178, 17:13);\n\ts(mc_emem_arb_misc1, 31:28, scratch178, 21:18);\n\ts(emc_pmacro_tx_sel_clk_src4, 10:10, scratch178, 22:22);\n\ts(emc_pmacro_tx_sel_clk_src4, 24:16, scratch178, 31:23);\n\ts(emc_mrs_wait_cnt2, 9:0, scratch179, 9:0);\n\ts(emc_mrs_wait_cnt2, 26:16, scratch179, 20:10);\n\ts(emc_odt_write, 5:0, scratch179, 26:21);\n\ts(emc_odt_write, 11:8, scratch179, 30:27);\n\ts(emc_odt_write, 31:31, scratch179, 31:31);\n\ts(emc_mrs_wait_cnt, 9:0, scratch180, 9:0);\n\ts(emc_mrs_wait_cnt, 26:16, scratch180, 20:10);\n\ts(emc_pmacro_ib_rxrt, 10:0, scratch180, 31:21);\n\ts(emc_auto_cal_interval, 20:0, scratch181, 20:0);\n\ts(emc_pmacro_ddll_long_cmd_4, 10:0, scratch181, 31:21);\n\ts(emc_emem_arb_refpb_hp_ctrl, 6:0, scratch182, 6:0);\n\ts(emc_emem_arb_refpb_hp_ctrl, 14:8, scratch182, 13:7);\n\ts(emc_emem_arb_refpb_hp_ctrl, 22:16, scratch182, 20:14);\n\ts(mc_emem_arb_outstanding_req, 8:0, scratch182, 29:21);\n\ts(mc_emem_arb_outstanding_req, 31:30, scratch182, 31:30);\n\ts(emc_xm2_comp_pad_ctrl2, 5:0, scratch183, 5:0);\n\ts(emc_xm2_comp_pad_ctrl2, 17:12, scratch183, 11:6);\n\ts(emc_xm2_comp_pad_ctrl2, 21:20, scratch183, 13:12);\n\ts(emc_xm2_comp_pad_ctrl2, 29:24, scratch183, 19:14);\n\ts(emc_pmacro_cmd_ctrl0, 0:0, scratch183, 20:20);\n\ts(emc_pmacro_cmd_ctrl0, 5:4, scratch183, 22:21);\n\ts(emc_pmacro_cmd_ctrl0, 8:8, scratch183, 23:23);\n\ts(emc_pmacro_cmd_ctrl0, 13:12, scratch183, 25:24);\n\ts(emc_pmacro_cmd_ctrl0, 16:16, scratch183, 26:26);\n\ts(emc_pmacro_cmd_ctrl0, 21:20, scratch183, 28:27);\n\ts(emc_pmacro_cmd_ctrl0, 24:24, scratch183, 29:29);\n\ts(emc_pmacro_cmd_ctrl0, 29:28, scratch183, 31:30);\n\ts(emc_cfg_dig_dll_1, 19:0, scratch184, 19:0);\n\ts(emc_pmacro_cmd_ctrl1, 0:0, scratch184, 20:20);\n\ts(emc_pmacro_cmd_ctrl1, 5:4, scratch184, 22:21);\n\ts(emc_pmacro_cmd_ctrl1, 8:8, scratch184, 23:23);\n\ts(emc_pmacro_cmd_ctrl1, 13:12, scratch184, 25:24);\n\ts(emc_pmacro_cmd_ctrl1, 16:16, scratch184, 26:26);\n\ts(emc_pmacro_cmd_ctrl1, 21:20, scratch184, 28:27);\n\ts(emc_pmacro_cmd_ctrl1, 24:24, scratch184, 29:29);\n\ts(emc_pmacro_cmd_ctrl1, 29:28, scratch184, 31:30);\n\ts(emc_quse_brlshft0, 19:0, scratch185, 19:0);\n\ts(emc_pmacro_cmd_ctrl2, 0:0, scratch185, 20:20);\n\ts(emc_pmacro_cmd_ctrl2, 5:4, scratch185, 22:21);\n\ts(emc_pmacro_cmd_ctrl2, 8:8, scratch185, 23:23);\n\ts(emc_pmacro_cmd_ctrl2, 13:12, scratch185, 25:24);\n\ts(emc_pmacro_cmd_ctrl2, 16:16, scratch185, 26:26);\n\ts(emc_pmacro_cmd_ctrl2, 21:20, scratch185, 28:27);\n\ts(emc_pmacro_cmd_ctrl2, 24:24, scratch185, 29:29);\n\ts(emc_pmacro_cmd_ctrl2, 29:28, scratch185, 31:30);\n\ts(emc_quse_brlshft1, 19:0, scratch186, 19:0);\n\ts(emc_pmacro_dsr_vttgen_ctrl0, 3:0, scratch186, 23:20);\n\ts(emc_pmacro_dsr_vttgen_ctrl0, 15:8, scratch186, 31:24);\n\ts(emc_quse_brlshft2, 19:0, scratch187, 19:0);\n\ts(emc_pmacro_perbit_rfu1_ctrl0, 5:0, scratch187, 25:20);\n\ts(emc_pmacro_perbit_rfu1_ctrl0, 21:16, scratch187, 31:26);\n\ts(emc_quse_brlshft3, 19:0, scratch188, 19:0);\n\ts(emc_pmacro_perbit_rfu1_ctrl1, 5:0, scratch188, 25:20);\n\ts(emc_pmacro_perbit_rfu1_ctrl1, 21:16, scratch188, 31:26);\n\ts(emc_dbg, 4:0, scratch189, 4:0);\n\ts(emc_dbg, 13:9, scratch189, 9:5);\n\ts(emc_dbg, 31:24, scratch189, 17:10);\n\ts(emc_trefbw, 13:0, scratch189, 31:18);\n\ts(emc_zcal_wait_cnt, 10:0, scratch191, 10:0);\n\ts(emc_zcal_wait_cnt, 21:16, scratch191, 16:11);\n\ts(emc_zcal_wait_cnt, 31:31, scratch191, 17:17);\n\ts(emc_qpop, 6:0, scratch191, 24:18);\n\ts(emc_qpop, 22:16, scratch191, 31:25);\n\ts(emc_zcal_mrw_cmd, 7:0, scratch192, 7:0);\n\ts(emc_zcal_mrw_cmd, 23:16, scratch192, 15:8);\n\ts(emc_zcal_mrw_cmd, 31:30, scratch192, 17:16);\n\ts(emc_pmacro_auto_cal_common, 5:0, scratch192, 23:18);\n\ts(emc_pmacro_auto_cal_common, 13:8, scratch192, 29:24);\n\ts(emc_pmacro_auto_cal_common, 16:16, scratch192, 30:30);\n\ts(emc_pmacro_tx_sel_clk_src4, 25:25, scratch192, 31:31);\n\ts(emc_dll_cfg1, 10:0, scratch193, 10:0);\n\ts(emc_dll_cfg1, 13:12, scratch193, 12:11);\n\ts(emc_dll_cfg1, 17:16, scratch193, 14:13);\n\ts(emc_dll_cfg1, 21:20, scratch193, 16:15);\n\ts(emc_dll_cfg1, 24:24, scratch193, 17:17);\n\ts(emc_pmacro_perbit_rfu1_ctrl2, 5:0, scratch193, 23:18);\n\ts(emc_pmacro_perbit_rfu1_ctrl2, 21:16, scratch193, 29:24);\n\ts(emc_pmacro_tx_sel_clk_src4, 26:26, scratch193, 30:30);\n\ts(emc_pmacro_tx_sel_clk_src5, 0:0, scratch193, 31:31);\n\ts(emc_pmacro_cmd_brick_ctrl_fdpd, 17:0, scratch194, 17:0);\n\ts(emc_pmacro_perbit_rfu1_ctrl3, 5:0, scratch194, 23:18);\n\ts(emc_pmacro_perbit_rfu1_ctrl3, 21:16, scratch194, 29:24);\n\ts(emc_pmacro_tx_sel_clk_src5, 2:1, scratch194, 31:30);\n\ts(emc_pmacro_data_brick_ctrl_fdpd, 17:0, scratch195, 17:0);\n\ts(emc_pmacro_perbit_rfu1_ctrl4, 5:0, scratch195, 23:18);\n\ts(emc_pmacro_perbit_rfu1_ctrl4, 21:16, scratch195, 29:24);\n\ts(emc_pmacro_tx_sel_clk_src5, 4:3, scratch195, 31:30);\n\ts(emc_dyn_self_ref_control, 15:0, scratch196, 15:0);\n\ts(emc_dyn_self_ref_control, 31:31, scratch196, 16:16);\n\ts(emc_emem_arb_refpb_bank_ctrl, 6:0, scratch196, 23:17);\n\ts(emc_emem_arb_refpb_bank_ctrl, 14:8, scratch196, 30:24);\n\ts(emc_emem_arb_refpb_bank_ctrl, 31:31, scratch196, 31:31);\n\ts(emc_pmacro_cmd_pad_rx_ctrl, 1:0, scratch197, 1:0);\n\ts(emc_pmacro_cmd_pad_rx_ctrl, 5:4, scratch197, 3:2);\n\ts(emc_pmacro_cmd_pad_rx_ctrl, 12:12, scratch197, 4:4);\n\ts(emc_pmacro_cmd_pad_rx_ctrl, 19:15, scratch197, 9:5);\n\ts(emc_pmacro_cmd_pad_rx_ctrl, 27:21, scratch197, 16:10);\n\ts(emc_pmacro_perbit_rfu1_ctrl5, 5:0, scratch197, 22:17);\n\ts(emc_pmacro_perbit_rfu1_ctrl5, 21:16, scratch197, 28:23);\n\ts(emc_pmacro_tx_sel_clk_src5, 7:5, scratch197, 31:29);\n\ts(emc_pmacro_data_pad_rx_ctrl, 1:0, scratch198, 1:0);\n\ts(emc_pmacro_data_pad_rx_ctrl, 5:4, scratch198, 3:2);\n\ts(emc_pmacro_data_pad_rx_ctrl, 12:12, scratch198, 4:4);\n\ts(emc_pmacro_data_pad_rx_ctrl, 19:15, scratch198, 9:5);\n\ts(emc_pmacro_data_pad_rx_ctrl, 27:21, scratch198, 16:10);\n\ts(emc_pmacro_tx_sel_clk_src5, 10:8, scratch198, 19:17);\n\ts(emc_pmacro_tx_sel_clk_src5, 26:16, scratch198, 30:20);\n\ts(emc_pmacro_cmd_pad_tx_ctrl, 0:0, scratch198, 31:31);\n\ts(emc_refresh, 15:0, scratch199, 15:0);\n\ts(emc_cmd_q, 4:0, scratch199, 20:16);\n\ts(emc_cmd_q, 10:8, scratch199, 23:21);\n\ts(emc_cmd_q, 14:12, scratch199, 26:24);\n\ts(emc_cmd_q, 28:24, scratch199, 31:27);\n\ts(emc_acpd_control, 15:0, scratch210, 15:0);\n\ts(emc_auto_cal_vref_sel1, 15:0, scratch210, 31:16);\n\ts(emc_pmacro_auto_cal_cfg0, 3:0, scratch211, 3:0);\n\ts(emc_pmacro_auto_cal_cfg0, 11:8, scratch211, 7:4);\n\ts(emc_pmacro_auto_cal_cfg0, 19:16, scratch211, 11:8);\n\ts(emc_pmacro_auto_cal_cfg0, 27:24, scratch211, 15:12);\n\ts(emc_pmacro_auto_cal_cfg1, 3:0, scratch211, 19:16);\n\ts(emc_pmacro_auto_cal_cfg1, 11:8, scratch211, 23:20);\n\ts(emc_pmacro_auto_cal_cfg1, 19:16, scratch211, 27:24);\n\ts(emc_pmacro_auto_cal_cfg1, 27:24, scratch211, 31:28);\n\ts(emc_pmacro_auto_cal_cfg2, 3:0, scratch212, 3:0);\n\ts(emc_pmacro_auto_cal_cfg2, 11:8, scratch212, 7:4);\n\ts(emc_pmacro_auto_cal_cfg2, 19:16, scratch212, 11:8);\n\ts(emc_pmacro_auto_cal_cfg2, 27:24, scratch212, 15:12);\n\ts(emc_xm2_comp_pad_ctrl3, 5:0, scratch212, 21:16);\n\ts(emc_xm2_comp_pad_ctrl3, 17:12, scratch212, 27:22);\n\ts(emc_xm2_comp_pad_ctrl3, 23:20, scratch212, 31:28);\n\ts(emc_cfg_dig_dll_period, 15:0, scratch213, 15:0);\n\ts(emc_prerefresh_req_cnt, 15:0, scratch213, 31:16);\n\ts(emc_pmacro_ddll_bypass, 0:0, scratch214, 0:0);\n\ts(emc_pmacro_ddll_bypass, 11:8, scratch214, 4:1);\n\ts(emc_pmacro_ddll_bypass, 16:13, scratch214, 8:5);\n\ts(emc_pmacro_ddll_bypass, 27:24, scratch214, 12:9);\n\ts(emc_pmacro_ddll_bypass, 31:29, scratch214, 15:13);\n\ts(emc_pmacro_data_pi_ctrl, 4:0, scratch214, 20:16);\n\ts(emc_pmacro_data_pi_ctrl, 12:8, scratch214, 25:21);\n\ts(emc_pmacro_data_pi_ctrl, 21:16, scratch214, 31:26);\n\ts(emc_pmacro_cmd_pi_ctrl, 4:0, scratch215, 4:0);\n\ts(emc_pmacro_cmd_pi_ctrl, 12:8, scratch215, 9:5);\n\ts(emc_pmacro_cmd_pi_ctrl, 21:16, scratch215, 15:10);\n\n\ts(emc_pin_gpio, 1:0, scratch9, 31:30);\n\ts(emc_pin_gpio_enable, 1:0, scratch10, 31:30);\n\ts(emc_dev_select, 1:0, scratch11, 31:30);\n\ts(emc_zcal_warm_cold_boot_enables, 1:0, scratch12, 31:30);\n\ts(emc_cfg_dig_dll_period_warm_boot, 1:0, scratch13, 31:30);\n\ts32(emc_bct_spare13, scratch45);\n\ts32(emc_bct_spare12, scratch46);\n\ts32(emc_bct_spare7, scratch47);\n\ts32(emc_bct_spare6, scratch48);\n\ts32(emc_bct_spare5, scratch50);\n\ts32(emc_bct_spare4, scratch51);\n\ts32(emc_bct_spare3, scratch56);\n\ts32(emc_bct_spare2, scratch57);\n\ts32(emc_bct_spare1, scratch58);\n\ts32(emc_bct_spare0, scratch59);\n\ts32(emc_bct_spare9, scratch60);\n\ts32(emc_bct_spare8, scratch61);\n\ts32(boot_rom_patch_data, scratch62);\n\ts32(boot_rom_patch_control, scratch63);\n\ts(mc_clken_override_allwarm_boot, 0:0, scratch65, 31:31);\n\ts(emc_extra_refresh_num, 2:0, scratch66, 31:29);\n\ts(pmc_io_dpd3_req_wait, 2:0, scratch72, 30:28);\n\ts(emc_clken_override_allwarm_boot, 0:0, scratch72, 31:31);\n\ts(memory_type, 2:0, scratch73, 30:28);\n\ts(emc_mrs_warm_boot_enable, 0:0, scratch73, 31:31);\n\ts(pmc_io_dpd4_req_wait, 2:0, scratch74, 30:28);\n\ts(clear_clock2_mc1, 0:0, scratch74, 31:31);\n\ts(emc_warm_boot_extramode_reg_write_enable, 0:0, scratch75, 28:28);\n\ts(clk_rst_pllm_misc20_override_enable, 0:0, scratch75, 29:29);\n\ts(emc_dbg_write_mux, 0:0, scratch75, 30:30);\n\ts(ahb_arbitration_xbar_ctrl_meminit_done, 0:0, scratch75, 31:31);\n\ts(emc_timing_control_wait, 7:0, scratch90, 31:24);\n\ts(emc_zcal_warm_boot_wait, 7:0, scratch91, 31:24);\n\ts(warm_boot_wait, 7:0, scratch92, 31:24);\n\ts(emc_pin_program_wait, 7:0, scratch93, 31:24);\n\ts(emc_auto_cal_wait, 9:0, scratch114, 31:22);\n\ts(swizzle_rank_byte_encode, 15:0, scratch215, 31:16);\n\ts(emc_pmacro_cmd_pad_tx_ctrl, 6:5, scratch216, 1:0);\n\ts(emc_pmacro_cmd_pad_tx_ctrl, 10:10, scratch216, 2:2);\n\ts(emc_pmacro_cmd_pad_tx_ctrl, 16:15, scratch216, 4:3);\n\ts(emc_pmacro_cmd_pad_tx_ctrl, 30:21, scratch216, 14:5);\n\ts(emc_pmacro_data_pad_tx_ctrl, 0:0, scratch216, 15:15);\n\ts(emc_pmacro_data_pad_tx_ctrl, 6:5, scratch216, 17:16);\n\ts(emc_pmacro_data_pad_tx_ctrl, 10:10, scratch216, 18:18);\n\ts(emc_pmacro_data_pad_tx_ctrl, 16:15, scratch216, 20:19);\n\ts(emc_pmacro_data_pad_tx_ctrl, 30:21, scratch216, 30:21);\n\n\t// LPDDR4 MRW.\n\ts(emc_mrw_lpddr2zcal_warm_boot, 23:16, scratch5, 7:0);\n\ts(emc_mrw_lpddr2zcal_warm_boot, 7:0, scratch5, 15:8);\n\ts(emc_warm_boot_mrw_extra, 23:16, scratch5, 23:16);\n\ts(emc_warm_boot_mrw_extra, 7:0, scratch5, 31:24);\n\ts(emc_mrw_lpddr2zcal_warm_boot, 31:30, scratch6, 1:0);\n\ts(emc_warm_boot_mrw_extra, 31:30, scratch6, 3:2);\n\ts(emc_mrw_lpddr2zcal_warm_boot, 27:26, scratch6, 5:4);\n\ts(emc_warm_boot_mrw_extra, 27:26, scratch6, 7:6);\n\ts(emc_mrw6, 27:0, scratch8, 27:0);\n\ts(emc_mrw6, 31:30, scratch8, 29:28);\n\ts(emc_mrw8, 27:0, scratch9, 27:0);\n\ts(emc_mrw8, 31:30, scratch9, 29:28);\n\ts(emc_mrw9, 27:0, scratch10, 27:0);\n\ts(emc_mrw9, 31:30, scratch10, 29:28);\n\ts(emc_mrw10, 27:0, scratch11, 27:0);\n\ts(emc_mrw10, 31:30, scratch11, 29:28);\n\ts(emc_mrw12, 27:0, scratch12, 27:0);\n\ts(emc_mrw12, 31:30, scratch12, 29:28);\n\ts(emc_mrw13, 27:0, scratch13, 27:0);\n\ts(emc_mrw13, 31:30, scratch13, 29:28);\n\ts(emc_mrw14, 27:0, scratch14, 27:0);\n\ts(emc_mrw14, 31:30, scratch14, 29:28);\n\ts(emc_mrw1, 7:0, scratch15, 7:0);\n\ts(emc_mrw1, 23:16, scratch15, 15:8);\n\ts(emc_mrw1, 27:26, scratch15, 17:16);\n\ts(emc_mrw1, 31:30, scratch15, 19:18);\n\ts(emc_warm_boot_mrw_extra, 7:0, scratch16, 7:0);\n\ts(emc_warm_boot_mrw_extra, 23:16, scratch16, 15:8);\n\ts(emc_warm_boot_mrw_extra, 27:26, scratch16, 17:16);\n\ts(emc_warm_boot_mrw_extra, 31:30, scratch16, 19:18);\n\ts(emc_mrw2, 7:0, scratch17, 7:0);\n\ts(emc_mrw2, 23:16, scratch17, 15:8);\n\ts(emc_mrw2, 27:26, scratch17, 17:16);\n\ts(emc_mrw2, 31:30, scratch17, 19:18);\n\ts(emc_mrw3, 7:0, scratch18, 7:0);\n\ts(emc_mrw3, 23:16, scratch18, 15:8);\n\ts(emc_mrw3, 27:26, scratch18, 17:16);\n\ts(emc_mrw3, 31:30, scratch18, 19:18);\n\ts(emc_mrw4, 7:0, scratch19, 7:0);\n\ts(emc_mrw4, 23:16, scratch19, 15:8);\n\ts(emc_mrw4, 27:26, scratch19, 17:16);\n\ts(emc_mrw4, 31:30, scratch19, 19:18);\n\n\ts32(emc_cmd_mapping_byte, secure_scratch8);\n\ts32(emc_pmacro_brick_mapping0, secure_scratch9);\n\ts32(emc_pmacro_brick_mapping1, secure_scratch10);\n\ts32(emc_pmacro_brick_mapping2, secure_scratch11);\n\ts32(mc_video_protect_gpu_override0, secure_scratch12);\n\ts(emc_cmd_mapping_cmd0_0, 6:0, secure_scratch13, 6:0);\n\ts(emc_cmd_mapping_cmd0_0, 14:8, secure_scratch13, 13:7);\n\ts(emc_cmd_mapping_cmd0_0, 22:16, secure_scratch13, 20:14);\n\ts(emc_cmd_mapping_cmd0_0, 30:24, secure_scratch13, 27:21);\n\ts(mc_untranslated_region_check, 0:0, secure_scratch13, 28:28);\n\ts(mc_untranslated_region_check, 9:8, secure_scratch13, 30:29);\n\ts(emc_adr_cfg, 0:0, secure_scratch13, 31:31);\n\ts(emc_cmd_mapping_cmd0_1, 6:0, secure_scratch14, 6:0);\n\ts(emc_cmd_mapping_cmd0_1, 14:8, secure_scratch14, 13:7);\n\ts(emc_cmd_mapping_cmd0_1, 22:16, secure_scratch14, 20:14);\n\ts(emc_cmd_mapping_cmd0_1, 30:24, secure_scratch14, 27:21);\n\ts(mc_video_protect_bom_adr_hi, 1:0, secure_scratch14, 29:28);\n\ts(mc_video_protect_write_access, 1:0, secure_scratch14, 31:30);\n\ts(emc_cmd_mapping_cmd1_0, 6:0, secure_scratch15, 6:0);\n\ts(emc_cmd_mapping_cmd1_0, 14:8, secure_scratch15, 13:7);\n\ts(emc_cmd_mapping_cmd1_0, 22:16, secure_scratch15, 20:14);\n\ts(emc_cmd_mapping_cmd1_0, 30:24, secure_scratch15, 27:21);\n\ts(mc_sec_carveout_adr_hi, 1:0, secure_scratch15, 29:28);\n\ts(mc_mts_carveout_adr_hi, 1:0, secure_scratch15, 31:30);\n\ts(emc_cmd_mapping_cmd1_1, 6:0, secure_scratch16, 6:0);\n\ts(emc_cmd_mapping_cmd1_1, 14:8, secure_scratch16, 13:7);\n\ts(emc_cmd_mapping_cmd1_1, 22:16, secure_scratch16, 20:14);\n\ts(emc_cmd_mapping_cmd1_1, 30:24, secure_scratch16, 27:21);\n\ts(mc_generalized_carveout5_bom_hi, 1:0, secure_scratch16, 29:28);\n\ts(mc_generalized_carveout3_bom_hi, 1:0, secure_scratch16, 31:30);\n\ts(emc_cmd_mapping_cmd2_0, 6:0, secure_scratch17, 6:0);\n\ts(emc_cmd_mapping_cmd2_0, 14:8, secure_scratch17, 13:7);\n\ts(emc_cmd_mapping_cmd2_0, 22:16, secure_scratch17, 20:14);\n\ts(emc_cmd_mapping_cmd2_0, 30:24, secure_scratch17, 27:21);\n\ts(mc_generalized_carveout2_bom_hi, 1:0, secure_scratch17, 29:28);\n\ts(mc_generalized_carveout4_bom_hi, 1:0, secure_scratch17, 31:30);\n\ts(emc_cmd_mapping_cmd2_1, 6:0, secure_scratch18, 6:0);\n\ts(emc_cmd_mapping_cmd2_1, 14:8, secure_scratch18, 13:7);\n\ts(emc_cmd_mapping_cmd2_1, 22:16, secure_scratch18, 20:14);\n\ts(emc_cmd_mapping_cmd2_1, 30:24, secure_scratch18, 27:21);\n\ts(mc_generalized_carveout1_bom_hi, 1:0, secure_scratch18, 29:28);\n\ts(emc_fbio_spare, 1:1, secure_scratch18, 30:30);\n\ts(emc_fbio_cfg8, 15:15, secure_scratch18, 31:31);\n\ts(emc_cmd_mapping_cmd3_0, 6:0, secure_scratch19, 6:0);\n\ts(emc_cmd_mapping_cmd3_0, 14:8, secure_scratch19, 13:7);\n\ts(emc_cmd_mapping_cmd3_0, 22:16, secure_scratch19, 20:14);\n\ts(emc_cmd_mapping_cmd3_0, 30:24, secure_scratch19, 27:21);\n\ts(mc_emem_adr_cfg, 0:0, secure_scratch19, 28:28);\n\ts(mc_sec_carveout_protect_write_access, 0:0, secure_scratch19, 29:29);\n\ts(mc_mts_carveout_reg_ctrl, 0:0, secure_scratch19, 30:30);\n\ts(mc_video_protect_vpr_override, 0:0, secure_scratch19, 31:31);\n\ts(emc_cmd_mapping_cmd3_1, 6:0, secure_scratch20, 6:0);\n\ts(emc_cmd_mapping_cmd3_1, 14:8, secure_scratch20, 13:7);\n\ts(emc_cmd_mapping_cmd3_1, 22:16, secure_scratch20, 20:14);\n\ts(emc_cmd_mapping_cmd3_1, 30:24, secure_scratch20, 27:21);\n\ts(mc_generalized_carveout2_cfg0, 6:3, secure_scratch20, 31:28);\n\ts(mc_generalized_carveout4_cfg0, 26:0, secure_scratch39, 26:0);\n\ts(mc_generalized_carveout2_cfg0, 10:7, secure_scratch39, 30:27);\n\ts(mc_video_protect_vpr_override, 1:1, secure_scratch39, 31:31);\n\ts(mc_generalized_carveout5_cfg0, 26:0, secure_scratch40, 26:0);\n\ts(mc_generalized_carveout2_cfg0, 17:14, secure_scratch40, 30:27);\n\ts(mc_video_protect_vpr_override, 2:2, secure_scratch40, 31:31);\n\ts(emc_cmd_mapping_cmd0_2, 6:0, secure_scratch41, 6:0);\n\ts(emc_cmd_mapping_cmd0_2, 14:8, secure_scratch41, 13:7);\n\ts(emc_cmd_mapping_cmd0_2, 22:16, secure_scratch41, 20:14);\n\ts(emc_cmd_mapping_cmd0_2, 27:24, secure_scratch41, 24:21);\n\ts(mc_generalized_carveout2_cfg0, 21:18, secure_scratch41, 28:25);\n\ts(mc_generalized_carveout2_cfg0, 13:11, secure_scratch41, 31:29);\n\ts(emc_cmd_mapping_cmd1_2, 6:0, secure_scratch42, 6:0);\n\ts(emc_cmd_mapping_cmd1_2, 14:8, secure_scratch42, 13:7);\n\ts(emc_cmd_mapping_cmd1_2, 22:16, secure_scratch42, 20:14);\n\ts(emc_cmd_mapping_cmd1_2, 27:24, secure_scratch42, 24:21);\n\ts(mc_generalized_carveout1_cfg0, 6:3, secure_scratch42, 28:25);\n\ts(mc_generalized_carveout1_cfg0, 13:11, secure_scratch42, 31:29);\n\ts(emc_cmd_mapping_cmd2_2, 6:0, secure_scratch43, 6:0);\n\ts(emc_cmd_mapping_cmd2_2, 14:8, secure_scratch43, 13:7);\n\ts(emc_cmd_mapping_cmd2_2, 22:16, secure_scratch43, 20:14);\n\ts(emc_cmd_mapping_cmd2_2, 27:24, secure_scratch43, 24:21);\n\ts(mc_generalized_carveout1_cfg0, 10:7, secure_scratch43, 28:25);\n\ts(mc_generalized_carveout3_cfg0, 13:11, secure_scratch43, 31:29);\n\ts(emc_cmd_mapping_cmd3_2, 6:0, secure_scratch44, 6:0);\n\ts(emc_cmd_mapping_cmd3_2, 14:8, secure_scratch44, 13:7);\n\ts(emc_cmd_mapping_cmd3_2, 22:16, secure_scratch44, 20:14);\n\ts(emc_cmd_mapping_cmd3_2, 27:24, secure_scratch44, 24:21);\n\ts(mc_generalized_carveout1_cfg0, 17:14, secure_scratch44, 28:25);\n\ts(mc_video_protect_vpr_override, 3:3, secure_scratch44, 29:29);\n\ts(mc_video_protect_vpr_override, 7:6, secure_scratch44, 31:30);\n\ts(mc_emem_adr_cfg_channel_mask, 31:9, secure_scratch45, 22:0);\n\ts(mc_emem_adr_cfg_dev0, 2:0, secure_scratch45, 25:23);\n\ts(mc_emem_adr_cfg_dev0, 9:8, secure_scratch45, 27:26);\n\ts(mc_emem_adr_cfg_dev0, 19:16, secure_scratch45, 31:28);\n\ts(mc_emem_adr_cfg_bank_mask0, 31:10, secure_scratch46, 21:0);\n\ts(mc_emem_adr_cfg_dev1, 2:0, secure_scratch46, 24:22);\n\ts(mc_emem_adr_cfg_dev1, 9:8, secure_scratch46, 26:25);\n\ts(mc_emem_adr_cfg_dev1, 19:16, secure_scratch46, 30:27);\n\ts(mc_video_protect_vpr_override, 8:8, secure_scratch46, 31:31);\n\ts(mc_emem_adr_cfg_bank_mask1, 31:10, secure_scratch47, 21:0);\n\ts(mc_generalized_carveout1_cfg0, 21:18, secure_scratch47, 25:22);\n\ts(mc_generalized_carveout3_cfg0, 6:3, secure_scratch47, 29:26);\n\ts(mc_video_protect_vpr_override, 9:9, secure_scratch47, 30:30);\n\ts(mc_video_protect_vpr_override, 11:11, secure_scratch47, 31:31);\n\ts(mc_emem_adr_cfg_bank_mask2, 31:10, secure_scratch48, 21:0);\n\ts(mc_generalized_carveout3_cfg0, 10:7, secure_scratch48, 25:22);\n\ts(mc_generalized_carveout3_cfg0, 17:14, secure_scratch48, 29:26);\n\ts(mc_video_protect_vpr_override, 15:14, secure_scratch48, 31:30);\n\ts(mc_video_protect_gpu_override1, 15:0, secure_scratch49, 15:0);\n\ts(mc_emem_cfg, 13:0, secure_scratch49, 29:16);\n\ts(mc_emem_cfg, 31:31, secure_scratch49, 30:30);\n\ts(mc_video_protect_vpr_override, 17:17, secure_scratch49, 31:31);\n\ts(mc_generalized_carveout3_bom, 31:17, secure_scratch50, 14:0);\n\ts(mc_generalized_carveout1_bom, 31:17, secure_scratch50, 29:15);\n\ts(mc_video_protect_vpr_override, 19:18, secure_scratch50, 31:30);\n\ts(mc_generalized_carveout4_bom, 31:17, secure_scratch51, 14:0);\n\ts(mc_generalized_carveout2_bom, 31:17, secure_scratch51, 29:15);\n\ts(mc_video_protect_vpr_override, 21:20, secure_scratch51, 31:30);\n\ts(mc_generalized_carveout5_bom, 31:17, secure_scratch52, 14:0);\n\ts(mc_video_protect_bom, 31:20, secure_scratch52, 26:15);\n\ts(mc_generalized_carveout3_cfg0, 21:18, secure_scratch52, 30:27);\n\ts(mc_video_protect_vpr_override, 22:22, secure_scratch52, 31:31);\n\ts(mc_video_protect_size_mb, 11:0, secure_scratch53, 11:0);\n\ts(mc_sec_carveout_bom, 31:20, secure_scratch53, 23:12);\n\ts(mc_video_protect_vpr_override, 23:23, secure_scratch53, 24:24);\n\ts(mc_video_protect_vpr_override, 26:26, secure_scratch53, 25:25);\n\ts(mc_video_protect_vpr_override, 31:29, secure_scratch53, 28:26);\n\ts(mc_video_protect_vpr_override1, 1:0, secure_scratch53, 30:29);\n\ts(mc_video_protect_vpr_override1, 4:4, secure_scratch53, 31:31);\n\ts(mc_sec_carveout_size_mb, 11:0, secure_scratch54, 11:0);\n\ts(mc_mts_carveout_bom, 31:20, secure_scratch54, 23:12);\n\ts(mc_video_protect_vpr_override1, 12:5, secure_scratch54, 31:24);\n\ts(mc_mts_carveout_size_mb, 11:0, secure_scratch55, 11:0);\n\ts(mc_generalized_carveout4_size_128kb, 11:0, secure_scratch55, 23:12);\n\ts(mc_video_protect_vpr_override1, 16:13, secure_scratch55, 27:24);\n\ts(mc_video_protect_vpr_override1, 26:25, secure_scratch55, 29:28);\n\ts(mc_generalized_carveout2_cfg0, 1:0, secure_scratch55, 31:30);\n\ts(mc_generalized_carveout3_size_128kb, 11:0, secure_scratch56, 11:0);\n\ts(mc_generalized_carveout2_size_128kb, 11:0, secure_scratch56, 23:12);\n\ts(mc_generalized_carveout2_cfg0, 2:2, secure_scratch56, 24:24);\n\ts(mc_generalized_carveout2_cfg0, 26:22, secure_scratch56, 29:25);\n\ts(mc_generalized_carveout1_cfg0, 1:0, secure_scratch56, 31:30);\n\ts(mc_generalized_carveout1_size_128kb, 11:0, secure_scratch57, 11:0);\n\ts(mc_generalized_carveout5_size_128kb, 11:0, secure_scratch57, 23:12);\n\ts(mc_generalized_carveout1_cfg0, 2:2, secure_scratch57, 24:24);\n\ts(mc_generalized_carveout1_cfg0, 26:22, secure_scratch57, 29:25);\n\ts(mc_generalized_carveout3_cfg0, 1:0, secure_scratch57, 31:30);\n\ts(mc_generalized_carveout3_cfg0, 2:2, secure_scratch58, 0:0);\n\ts(mc_generalized_carveout3_cfg0, 26:22, secure_scratch58, 5:1);\n\n\ts32(mc_generalized_carveout1_access0, secure_scratch59);\n\ts32(mc_generalized_carveout1_access1, secure_scratch60);\n\ts32(mc_generalized_carveout1_access2, secure_scratch61);\n\ts32(mc_generalized_carveout1_access3, secure_scratch62);\n\ts32(mc_generalized_carveout1_access4, secure_scratch63);\n\ts32(mc_generalized_carveout2_access0, secure_scratch64);\n\ts32(mc_generalized_carveout2_access1, secure_scratch65);\n\ts32(mc_generalized_carveout2_access2, secure_scratch66);\n\ts32(mc_generalized_carveout2_access3, secure_scratch67);\n\ts32(mc_generalized_carveout2_access4, secure_scratch68);\n\ts32(mc_generalized_carveout3_access0, secure_scratch69);\n\ts32(mc_generalized_carveout3_access1, secure_scratch70);\n\ts32(mc_generalized_carveout3_access2, secure_scratch71);\n\ts32(mc_generalized_carveout3_access3, secure_scratch72);\n\ts32(mc_generalized_carveout3_access4, secure_scratch73);\n\ts32(mc_generalized_carveout4_access0, secure_scratch74);\n\ts32(mc_generalized_carveout4_access1, secure_scratch75);\n\ts32(mc_generalized_carveout4_access2, secure_scratch76);\n\ts32(mc_generalized_carveout4_access3, secure_scratch77);\n\ts32(mc_generalized_carveout4_access4, secure_scratch78);\n\ts32(mc_generalized_carveout5_access0, secure_scratch79);\n\ts32(mc_generalized_carveout5_access1, secure_scratch80);\n\ts32(mc_generalized_carveout5_access2, secure_scratch81);\n\ts32(mc_generalized_carveout5_access3, secure_scratch82);\n\ts32(mc_generalized_carveout1_force_internal_access0, secure_scratch84);\n\ts32(mc_generalized_carveout1_force_internal_access1, secure_scratch85);\n\ts32(mc_generalized_carveout1_force_internal_access2, secure_scratch86);\n\ts32(mc_generalized_carveout1_force_internal_access3, secure_scratch87);\n\ts32(mc_generalized_carveout1_force_internal_access4, secure_scratch88);\n\ts32(mc_generalized_carveout2_force_internal_access0, secure_scratch89);\n\ts32(mc_generalized_carveout2_force_internal_access1, secure_scratch90);\n\ts32(mc_generalized_carveout2_force_internal_access2, secure_scratch91);\n\ts32(mc_generalized_carveout2_force_internal_access3, secure_scratch92);\n\ts32(mc_generalized_carveout2_force_internal_access4, secure_scratch93);\n\ts32(mc_generalized_carveout3_force_internal_access0, secure_scratch94);\n\ts32(mc_generalized_carveout3_force_internal_access1, secure_scratch95);\n\ts32(mc_generalized_carveout3_force_internal_access2, secure_scratch96);\n\ts32(mc_generalized_carveout3_force_internal_access3, secure_scratch97);\n\ts32(mc_generalized_carveout3_force_internal_access4, secure_scratch98);\n\ts32(mc_generalized_carveout4_force_internal_access0, secure_scratch99);\n\ts32(mc_generalized_carveout4_force_internal_access1, secure_scratch100);\n\ts32(mc_generalized_carveout4_force_internal_access2, secure_scratch101);\n\ts32(mc_generalized_carveout4_force_internal_access3, secure_scratch102);\n\ts32(mc_generalized_carveout4_force_internal_access4, secure_scratch103);\n\ts32(mc_generalized_carveout5_force_internal_access0, secure_scratch104);\n\ts32(mc_generalized_carveout5_force_internal_access1, secure_scratch105);\n\ts32(mc_generalized_carveout5_force_internal_access2, secure_scratch106);\n\ts32(mc_generalized_carveout5_force_internal_access3, secure_scratch107);\n\n\t// PLLM. Unused, BCT is used for PLLM.\n\tc32(0, scratch2);\n\ts(pllm_input_divider, 7:0, scratch2, 7:0);\n\ts(pllm_feedback_divider, 7:0, scratch2, 15:8);\n\ts(pllm_post_divider, 0:0, scratch2, 16:16);\n\ts(pllm_kvco, 0:0, scratch2, 17:17);\n\ts(pllm_kcp, 1:0, scratch2, 19:18);\n\n\tc32(0, scratch35);\n\ts(pllm_setup_control, 27:0, scratch35, 27:0);\n\n\t// PLLX.\n\ts(pllm_input_divider, 7:0, scratch3, 7:0);\n\tc(62, scratch3, 15:8); // 62 divn.\n\tc(0, scratch3, 20:16); // 0  divp.\n\ts(pllm_kvco, 0:0, scratch3, 21:21);\n\ts(pllm_kcp, 1:0, scratch3, 23:22);\n\t// s(pllm_kcp, 9:0, scratch3, 31:22);\n\n\tc32(0, scratch36);\n\ts(pllm_setup_control, 23:0, scratch36, 23:0);\n\n\t// PLLM/PLLX.\n\ts(pllm_stable_time, 9:0, scratch4, 9:0);\n\ts(pllm_stable_time, 9:0, scratch4, 19:10);\n}\n\nvoid sdram_lp0_entry(void *sdram_config, bdk_params_t *bp)\n{\n\tu32 chip_id = (APB_MISC(APB_MISC_GP_HIDREV) >> 4) & 0xF;\n\n\tif (chip_id != GP_HIDREV_MAJOR_T210B01)\n\t\t_sdram_lp0_save_params_t210(sdram_config);\n\telse\n\t\t_sdram_lp0_save_params_t210b01(sdram_config);\n}\n"
  },
  {
    "path": "modules/hekate_libsys_lp0/t210.h",
    "content": "/*\n* Copyright (c) 2018 naehrwert\n*\n* This program is free software; you can redistribute it and/or modify it\n* under the terms and conditions of the GNU General Public License,\n* version 2, as published by the Free Software Foundation.\n*\n* This program is distributed in the hope it will be useful, but WITHOUT\n* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n* more details.\n*\n* You should have received a copy of the GNU General Public License\n* along with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n#ifndef _T210_H_\n#define _T210_H_\n\n#include \"types.h\"\n\n#define HOST1X_BASE 0x50000000\n#define DISPLAY_A_BASE 0x54200000\n#define DSI_BASE 0x54300000\n#define VIC_BASE 0x54340000\n#define TSEC_BASE 0x54500000\n#define SOR1_BASE 0x54580000\n#define TMR_BASE 0x60005000\n#define CLOCK_BASE 0x60006000\n#define FLOW_CTLR_BASE 0x60007000\n#define SYSREG_BASE 0x6000C000\n#define SB_BASE (SYSREG_BASE + 0x200)\n#define GPIO_BASE 0x6000D000\n#define GPIO_1_BASE (GPIO_BASE)\n#define GPIO_2_BASE (GPIO_BASE + 0x100)\n#define GPIO_3_BASE (GPIO_BASE + 0x200)\n#define GPIO_4_BASE (GPIO_BASE + 0x300)\n#define GPIO_5_BASE (GPIO_BASE + 0x400)\n#define GPIO_6_BASE (GPIO_BASE + 0x500)\n#define GPIO_7_BASE (GPIO_BASE + 0x600)\n#define GPIO_8_BASE (GPIO_BASE + 0x700)\n#define EXCP_VEC_BASE 0x6000F000\n#define APB_MISC_BASE 0x70000000\n#define PINMUX_AUX_BASE 0x70003000\n#define UART_BASE 0x70006000\n#define RTC_BASE 0x7000E000\n#define PMC_BASE 0x7000E400\n#define SYSCTR0_BASE 0x7000F000\n#define FUSE_BASE 0x7000F800\n#define KFUSE_BASE 0x7000FC00\n#define SE_BASE 0x70012000\n#define MC_BASE 0x70019000\n#define EMC_BASE 0x7001B000\n#define MIPI_CAL_BASE 0x700E3000\n#define I2S_BASE 0x702D1000\n\n#define _REG(base, off) *(vu32 *)((base) + (off))\n\n#define HOST1X(off) _REG(HOST1X_BASE, off)\n#define DISPLAY_A(off) _REG(DISPLAY_A_BASE, off)\n#define DSI(off) _REG(DSI_BASE, off)\n#define VIC(off) _REG(VIC_BASE, off)\n#define TSEC(off) _REG(TSEC_BASE, off)\n#define SOR1(off) _REG(SOR1_BASE, off)\n#define TMR(off) _REG(TMR_BASE, off)\n#define CLOCK(off) _REG(CLOCK_BASE, off)\n#define FLOW_CTLR(off) _REG(FLOW_CTLR_BASE, off)\n#define SYSREG(off) _REG(SYSREG_BASE, off)\n#define SB(off) _REG(SB_BASE, off)\n#define GPIO(off) _REG(GPIO_BASE, off)\n#define GPIO_1(off) _REG(GPIO_1_BASE, off)\n#define GPIO_2(off) _REG(GPIO_2_BASE, off)\n#define GPIO_3(off) _REG(GPIO_3_BASE, off)\n#define GPIO_4(off) _REG(GPIO_4_BASE, off)\n#define GPIO_5(off) _REG(GPIO_5_BASE, off)\n#define GPIO_6(off) _REG(GPIO_6_BASE, off)\n#define GPIO_7(off) _REG(GPIO_7_BASE, off)\n#define GPIO_8(off) _REG(GPIO_8_BASE, off)\n#define EXCP_VEC(off) _REG(EXCP_VEC_BASE, off)\n#define APB_MISC(off) _REG(APB_MISC_BASE, off)\n#define PINMUX_AUX(off) _REG(PINMUX_AUX_BASE, off)\n#define RTC(off) _REG(RTC_BASE, off)\n#define PMC(off) _REG(PMC_BASE, off)\n#define SYSCTR0(off) _REG(SYSCTR0_BASE, off)\n#define FUSE(off) _REG(FUSE_BASE, off)\n#define KFUSE(off) _REG(KFUSE_BASE, off)\n#define SE(off) _REG(SE_BASE, off)\n#define MC(off) _REG(MC_BASE, off)\n#define EMC(off) _REG(EMC_BASE, off)\n#define MIPI_CAL(off) _REG(MIPI_CAL_BASE, off)\n#define I2S(off) _REG(I2S_BASE, off)\n\n/*! Misc registers. */\n#define APB_MISC_PP_PINMUX_GLOBAL 0x40\n#define APB_MISC_GP_HIDREV 0x804\n#define  GP_HIDREV_MAJOR_T210    0x1\n#define  GP_HIDREV_MAJOR_T210B01 0x2\n#define APB_MISC_GP_WIFI_EN_CFGPADCTRL 0xB64\n#define APB_MISC_GP_WIFI_RST_CFGPADCTRL 0xB68\n\n/*! System registers. */\n#define AHB_ARBITRATION_XBAR_CTRL 0xE0\n#define AHB_AHB_SPARE_REG 0x110\n\n/*! Secure boot registers. */\n#define SB_CSR 0x0\n#define SB_AA64_RESET_LOW 0x30\n#define SB_AA64_RESET_HIGH 0x34\n\n/*! SYSCTR0 registers. */\n#define SYSCTR0_CNTFID0 0x20\n\n#endif\n"
  },
  {
    "path": "modules/hekate_libsys_lp0/types.h",
    "content": "/*\n* Copyright (c) 2018 naehrwert\n*\n* This program is free software; you can redistribute it and/or modify it\n* under the terms and conditions of the GNU General Public License,\n* version 2, as published by the Free Software Foundation.\n*\n* This program is distributed in the hope it will be useful, but WITHOUT\n* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n* more details.\n*\n* You should have received a copy of the GNU General Public License\n* along with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n#ifndef _TYPES_H_\n#define _TYPES_H_\n\n#define NULL ((void *)0)\n\n#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))\n#define MAX(a, b) ((a) > (b) ? (a) : (b))\n#define MIN(a, b) ((a) < (b) ? (a) : (b))\n\n#define OFFSET_OF(t, m) ((u32)&((t *)NULL)->m)\n#define CONTAINER_OF(mp, t, mn) ((t *)((u32)mp - OFFSET_OF(t, mn)))\n\ntypedef char s8;\ntypedef short s16;\ntypedef short SHORT;\ntypedef int s32;\ntypedef int INT;\ntypedef long LONG;\ntypedef long long int s64;\ntypedef unsigned char u8;\ntypedef unsigned char BYTE;\ntypedef unsigned short u16;\ntypedef unsigned short WORD;\ntypedef unsigned short WCHAR;\ntypedef unsigned int u32;\ntypedef unsigned int UINT;\ntypedef unsigned long DWORD;\ntypedef unsigned long long QWORD;\ntypedef unsigned long long int u64;\ntypedef volatile unsigned char vu8;\ntypedef volatile unsigned short vu16;\ntypedef volatile unsigned int vu32;\n\ntypedef int bool;\n#define true  1\n#define false 0\n\n#endif\n"
  },
  {
    "path": "modules/hekate_libsys_minerva/Makefile",
    "content": "ifeq ($(strip $(DEVKITARM)),)\n$(error \"Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM\")\nendif\n\ninclude $(DEVKITARM)/base_rules\n\nTARGET := libsys_minerva\nBUILDDIR := ../../build/$(TARGET)\nOUTPUTDIR := ../../output\nBDKDIR := bdk\nBDKINC := -I../../$(BDKDIR)\n\n# Track compiler flags\nTRACK_CFLAGS = $(BUILDDIR)/.cflags\nTRACK_LDFLAGS = $(BUILDDIR)/.ldflags\n\nOBJS = $(addprefix $(BUILDDIR)/,\\\n\tsys_sdrammtc.o \\\n)\n\nARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork\nCFLAGS = $(ARCH) -O2 -nostdlib -fpie -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 -Wall -Wsign-compare $(CUSTOMDEFINES)\nLDFLAGS = $(ARCH) -fpie -pie -nostartfiles -lgcc -Wl,-z,max-page-size=256\n\n.PHONY: all\n\nall: $(TARGET).bso\n$(BUILDDIR)/%.o: ./%.c $(TRACK_CFLAGS)\n\t@$(CC) $(CFLAGS) $(BDKINC) -MMD -MP -c $< -o $@\n\n$(TARGET).bso: $(OBJS) $(TRACK_LDFLAGS)\n\t@$(CC) $(LDFLAGS) -e minerva_entry $(OBJS) -o $(OUTPUTDIR)/$(TARGET).bso\n\t@$(STRIP) -g $(OUTPUTDIR)/$(TARGET).bso\n\t@echo \"Built module: \"$(TARGET)\".bso\"\n\n$(BUILDDIR):\n\t@mkdir -p \"$(BUILDDIR)\"\n\n# Non objects change detectors.\n$(TRACK_CFLAGS): $(BUILDDIR)\n\t@echo '$(CFLAGS)' | cmp -s - $@ || echo '$(CFLAGS)' > $@\n$(TRACK_LDFLAGS): $(BUILDDIR)\n\t@echo '$(LDFLAGS)' | cmp -s - $@ || echo '$(LDFLAGS)' > $@\n-include $(OBJS:.o=.d)\n"
  },
  {
    "path": "modules/hekate_libsys_minerva/README.md",
    "content": "# Minerva Training Cell\n\n### Custom Nvidia Tegra X1 DRAM trainer.\n\nFor more, check [Here](https://github.com/CTCaer/minerva_tc).\n\n\n\n```\nMinerva Training Cell (c) 2018 CTCaer.\n\n/* Pain... And suffering. */\n```\n"
  },
  {
    "path": "modules/hekate_libsys_minerva/mtc.h",
    "content": "/*\n * Minerva Training Cell\n * DRAM Training for Tegra X1 SoC. Supports LPDDR4.\n *\n * Copyright (c) 2018-2025 CTCaer  <ctcaer@gmail.com>\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _MTC_H_\n#define _MTC_H_\n\n#include \"mtc_table.h\"\n#include \"types.h\"\n\n/* Address bases and access macros - Change these for mapped access */\n#define TMR_BASE      0x60005000\n#define CLOCK_BASE    0x60006000\n#define APB_MISC_BASE 0x70000000\n#define FUSE_BASE     0x7000F800\n#define MC_BASE       0x70019000\n#define EMC_BASE      0x7001B000\n#define EMC0_BASE     0x7001E000\n#define EMC1_BASE     0x7001F000\n\n#define MTC_INIT_MAGIC 0x3043544D\n#define MTC_NEW_MAGIC  0x5243544D\n#define MTC_IRB_MAGIC  0x4943544D\n\n#define MTC_INIT_FREQUENCY 204000\n\n#define _REG(base, off) *(vu32 *)((base) + (off))\n\n#define TMR(off)      _REG(TMR_BASE, off)\n#define CLOCK(off)    _REG(CLOCK_BASE, off)\n#define APB_MISC(off) _REG(APB_MISC_BASE, off)\n#define FUSE(off)     _REG(FUSE_BASE, off)\n#define MC(off)       _REG(MC_BASE, off)\n#define EMC(off)      _REG(EMC_BASE, off)\n#define EMC_CH0(off)  _REG(EMC0_BASE, off)\n#define EMC_CH1(off)  _REG(EMC1_BASE, off)\n/* End of addresses and access macros */\n\n#define EMC_TABLE_ENTRY_SIZE_R7   4928\n#define EMC_TABLE_ENTRY_SIZE_R3   4300\n#define EMC_TABLE_SIZE_ODINX02_R7 (EMC_TABLE_ENTRY_SIZE_R7 * 7)\n\n#define EMC_STATUS_UPDATE_TIMEOUT 2000\n#define EMC_PERIODIC_TRAIN_MS     100\n#define EMC_TEMP_COMP_MS          1000\n\n/* Training types */\n#define NEEDS_TRAINING_CA              BIT(0)\n#define NEEDS_TRAINING_CA_VREF         BIT(1)\n#define NEEDS_TRAINING_QUSE            BIT(2)\n#define NEEDS_TRAINING_QUSE_VREF       BIT(3)\n#define NEEDS_TRAINING_WR              BIT(4)\n#define NEEDS_TRAINING_WR_VREF         BIT(5)\n#define NEEDS_TRAINING_RD              BIT(6)\n#define NEEDS_TRAINING_RD_VREF         BIT(7)\n#define NEEDS_TRAINING_SWAP_RANK       BIT(8)\n#define NEEDS_TRAINING_IN_SELF_REFRESH BIT(9)\n\n#define NEEDS_TRAINING            (NEEDS_TRAINING_CA | NEEDS_TRAINING_CA_VREF | \\\n\t\t\t\t\t\t\t\t   NEEDS_TRAINING_QUSE | NEEDS_TRAINING_WR |    \\\n\t\t\t\t\t\t\t\t   NEEDS_TRAINING_WR_VREF | NEEDS_TRAINING_RD | \\\n\t\t\t\t\t\t\t\t   NEEDS_TRAINING_RD_VREF)\n#define NEEDS_TRAINING_CA_COMBO   (NEEDS_TRAINING_CA | NEEDS_TRAINING_CA_VREF)\n#define NEEDS_TRAINING_QUSE_COMBO (NEEDS_TRAINING_QUSE | NEEDS_TRAINING_QUSE_VREF)\n#define NEEDS_TRAINING_WR_COMBO   (NEEDS_TRAINING_WR | NEEDS_TRAINING_WR_VREF)\n#define NEEDS_TRAINING_RD_COMBO   (NEEDS_TRAINING_RD | NEEDS_TRAINING_RD_VREF)\n\ntypedef struct\n{\n\tu32 rate_to;\n\tu32 rate_from;\n\temc_table_t *mtc_table;\n\tu32 table_entries;\n\temc_table_t *current_emc_table;\n\tu32 train_mode;\n\tu32 sdram_id;\n\tu32 prev_temp;\n\tbool emc_2X_clk_src_is_pllmb;\n\tbool fsp_for_src_freq;\n\tbool train_ram_patterns;\n\tu32  init_done;\n} mtc_config_t;\n\nenum train_mode_t\n{\n\tOP_SWITCH         = 0,\n\tOP_TRAIN          = 1,\n\tOP_TRAIN_SWITCH   = 2,\n\tOP_PERIODIC_TRAIN = 3,\n\tOP_TEMP_COMP      = 4\n};\n\nenum comp_seq_t\n{\n\tDVFS_SEQUENCE              = 1,\n\tWRITE_TRAINING_SEQUENCE    = 2,\n\tPERIODIC_TRAINING_SEQUENCE = 3\n};\n\nenum tree_update_mode_t\n{\n\tDVFS_PT1                 = 10,\n\tDVFS_UPDATE              = 11,\n\tTRAINING_PT1             = 12,\n\tTRAINING_UPDATE          = 13,\n\tPERIODIC_TRAINING_UPDATE = 14\n};\n\nenum emc_channels\n{\n\tEMC_CHANNEL0 = 0,\n\tEMC_CHANNEL1 = 1\n};\n\nenum EMC_2X_CLK_SRC\n{\n\tPLLM_OUT0  = 0x0,\n\tPLLC_OUT0  = 0x1,\n\tPLLP_OUT0  = 0x2,\n\tCLK_M      = 0x3,\n\tPLLM_UD    = 0x4,\n\tPLLMB_UD   = 0x5,\n\tPLLMB_OUT0 = 0x6,\n\tPLLP_UD    = 0x7\n};\n\nenum DRAM_TYPE\n{\n\tDRAM_TYPE_DDR3   = 0,\n\tDRAM_TYPE_LPDDR4 = 1,\n\tDRAM_TYPE_LPDDR2 = 2,\n\tDRAM_TYPE_DDR2   = 3\n};\n\nenum DRAM_DEV_NO\n{\n\tONE_RANK = 1,\n\tTWO_RANK = 2\n};\n\nenum DRAM_OVER_TEMP_REF\n{\n\tREFRESH_X2 = 1,\n\tREFRESH_X4 = 2\n};\n\n/* Timers for the below two compensation functions should be paused when changing timings. */\n\n/* Change refresh rate based on dram temps. Run every 1000ms. */\n/* Timer should be run only when another component reports over temperature. */\nvoid _minerva_do_over_temp_compensation(mtc_config_t *mtc_cfg);\n\n/* Periodic compensation only for tight timings that need it. Run every 100ms. */\n/* Over temp and periodic compensation, should not access EMC_MRR at the same time. */\nu32  _minerva_do_periodic_compensation(emc_table_t *mtc_table_entry);\n\n#endif\n"
  },
  {
    "path": "modules/hekate_libsys_minerva/mtc_mc_emc_regs.h",
    "content": "/*\n * Minerva Training Cell\n * DRAM Training for Tegra X1 SoC. Supports LPDDR4.\n *\n * Copyright (c) 2018-2025 CTCaer  <ctcaer@gmail.com>\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _MTC_MC_EMC_REGS_H_\n#define _MTC_MC_EMC_REGS_H_\n\n/* APB misc registers */\n#define APB_MISC_GP_HIDREV 0x804\n#define  HIDREV_MAJOR_T210    0x1\n#define  HIDREV_MAJOR_T210B01 0x2\n#define  HIDREV_CHIPID_T210   0x21\n\n/* Fuse registers */\n#define FUSE_SKU_INFO 0x110\n#define  SKU_ODIN 0x83\n\n/* Clock controller registers */\n#define CLK_RST_CONTROLLER_PLLM_BASE           0x90\n#define CLK_RST_CONTROLLER_PLLM_MISC2          0x9C\n#define  PLLM_ENABLE    (1 << 30)\n#define  PLLM_LOCK      (1 << 27)\n#define  PLLM_EN_LCKDET (1 << 4)\n\n#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC      0x19C\n#define  EMC_2X_CLK_SRC_SHIFT 29\n\n#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X       0x280\n#define CLK_RST_CONTROLLER_CLK_ENB_X_SET       0x284\n#define CLK_RST_CONTROLLER_CLK_ENB_X_CLR       0x288\n#define CLK_RST_CONTROLLER_PLLMB_BASE          0x5E8\n#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL  0x664\n#define  EMC_DLL_PLLM_VCOB  (1 << 10)\n#define  EMC_DLL_SWITCH_OUT (1 << 11)\n\n#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_SAFE 0x724\n\n/* Memory controller registers */\n#define MC_EMEM_ADR_CFG               0x54\n#define MC_EMEM_ARB_CFG               0x90\n#define MC_EMEM_ARB_OUTSTANDING_REQ   0x94\n#define MC_EMEM_ARB_TIMING_RCD        0x98\n#define MC_EMEM_ARB_TIMING_RP         0x9C\n#define MC_EMEM_ARB_TIMING_RC         0xA0\n#define MC_EMEM_ARB_TIMING_RAS        0xA4\n#define MC_EMEM_ARB_TIMING_FAW        0xA8\n#define MC_EMEM_ARB_TIMING_RRD        0xAC\n#define MC_EMEM_ARB_TIMING_RAP2PRE    0xB0\n#define MC_EMEM_ARB_TIMING_WAP2PRE    0xB4\n#define MC_EMEM_ARB_TIMING_R2R        0xB8\n#define MC_EMEM_ARB_TIMING_W2W        0xBC\n#define MC_EMEM_ARB_TIMING_R2W        0xC0\n#define MC_EMEM_ARB_TIMING_W2R        0xC4\n#define MC_EMEM_ARB_MISC2             0xC8\n#define MC_EMEM_ARB_DA_TURNS          0xD0\n#define MC_EMEM_ARB_DA_COVERS         0xD4\n#define MC_EMEM_ARB_MISC0             0xD8\n#define MC_EMEM_ARB_MISC1             0xDC\n#define MC_EMEM_ARB_RING1_THROTTLE    0xE0\n\n#define MC_LATENCY_ALLOWANCE_AVPC_0    0x2E4\n#define MC_LATENCY_ALLOWANCE_HC_0      0x310\n#define MC_LATENCY_ALLOWANCE_HC_1      0x314\n#define MC_LATENCY_ALLOWANCE_MPCORE_0  0x320\n#define MC_LATENCY_ALLOWANCE_NVENC_0   0x328\n#define MC_LATENCY_ALLOWANCE_PPCS_0    0x344\n#define MC_LATENCY_ALLOWANCE_PPCS_1    0x348\n#define MC_LATENCY_ALLOWANCE_ISP2_0    0x370\n#define MC_LATENCY_ALLOWANCE_ISP2_1    0x374\n#define MC_LATENCY_ALLOWANCE_XUSB_0    0x37C\n#define MC_LATENCY_ALLOWANCE_XUSB_1    0x380\n#define MC_LATENCY_ALLOWANCE_TSEC_0    0x390\n#define MC_LATENCY_ALLOWANCE_VIC_0     0x394\n#define MC_LATENCY_ALLOWANCE_VI2_0     0x398\n#define MC_LATENCY_ALLOWANCE_GPU_0     0x3AC\n#define MC_LATENCY_ALLOWANCE_SDMMCA_0  0x3B8\n#define MC_LATENCY_ALLOWANCE_SDMMCAA_0 0x3BC\n#define MC_LATENCY_ALLOWANCE_SDMMC_0   0x3C0\n#define MC_LATENCY_ALLOWANCE_SDMMCAB_0 0x3C4\n#define MC_LATENCY_ALLOWANCE_NVDEC_0   0x3D8\n#define MC_LATENCY_ALLOWANCE_GPU2_0    0x3E8\n\n#define MC_MLL_MPCORER_PTSA_RATE  0x44C\n#define MC_FTOP_PTSA_RATE         0x50C\n\n#define MC_EMEM_ARB_TIMING_RFCPB      0x6C0\n#define MC_EMEM_ARB_TIMING_CCDMW      0x6C4\n#define MC_EMEM_ARB_REFPB_HP_CTRL     0x6F0\n#define MC_EMEM_ARB_REFPB_BANK_CTRL   0x6F4\n\n#define MC_PTSA_GRANT_DECREMENT       0x960\n\n#define MC_EMEM_ARB_DHYST_CTRL           0xBCC\n#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0 0xBD0\n#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1 0xBD4\n#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2 0xBD8\n#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3 0xBDC\n#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4 0xBE0\n#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5 0xBE4\n#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6 0xBE8\n#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7 0xBEC\n\n/* External Memory controller registers */\n#define EMC_INTSTATUS                 0x0\n#define  CLKCHANGE_COMPLETE_INT (1 << 4)\n\n#define EMC_DBG                       0x8\n#define  EMC_DBG_READ_MUX_ASSEMBLY      BIT(0)\n#define  EMC_DBG_WRITE_MUX_ACTIVE       BIT(1)\n#define  EMC_DBG_CFG_SWAP_ACTIVE_ONLY   (0 << 26u)\n#define  EMC_DBG_CFG_SWAP_SWAP          (1 << 26u)\n#define  EMC_DBG_CFG_SWAP_ASSEMBLY_ONLY (2 << 26u)\n#define  EMC_DBG_CFG_SWAP_MASK          (3 << 26u)\n#define  EMC_DBG_WRITE_ACTIVE_ONLY      BIT(30)\n#define EMC_CFG                       0xC\n#define EMC_PIN                       0x24\n#define EMC_TIMING_CONTROL            0x28\n#define EMC_RC                        0x2C\n#define EMC_RFC                       0x30\n#define EMC_RAS                       0x34\n#define EMC_RP                        0x38\n#define EMC_R2W                       0x3C\n#define EMC_W2R                       0x40\n#define EMC_R2P                       0x44\n#define EMC_W2P                       0x48\n#define EMC_RD_RCD                    0x4C\n#define EMC_WR_RCD                    0x50\n#define EMC_RRD                       0x54\n#define EMC_REXT                      0x58\n#define EMC_WDV                       0x5C\n#define EMC_QUSE                      0x60\n#define EMC_QRST                      0x64\n#define EMC_QSAFE                     0x68\n#define EMC_RDV                       0x6C\n#define EMC_REFRESH                   0x70\n#define EMC_BURST_REFRESH_NUM         0x74\n#define EMC_PDEX2WR                   0x78\n#define EMC_PDEX2RD                   0x7C\n#define EMC_PCHG2PDEN                 0x80\n#define EMC_ACT2PDEN                  0x84\n#define EMC_AR2PDEN                   0x88\n#define EMC_RW2PDEN                   0x8C\n#define EMC_TXSR                      0x90\n#define EMC_TCKE                      0x94\n#define EMC_TFAW                      0x98\n#define EMC_TRPAB                     0x9C\n#define EMC_TCLKSTABLE                0xA0\n#define EMC_TCLKSTOP                  0xA4\n#define EMC_TREFBW                    0xA8\n#define EMC_TPPD                      0xAC\n#define EMC_ODT_WRITE                 0xB0\n#define EMC_PDEX2MRR                  0xB4\n#define EMC_WEXT                      0xB8\n#define EMC_RFC_SLR                   0xC0\n#define EMC_MRS_WAIT_CNT2             0xC4\n#define EMC_MRS_WAIT_CNT              0xC8\n#define EMC_MRS                       0xCC\n#define EMC_EMRS                      0xD0\n#define EMC_REF                       0xD4\n#define EMC_MRW                       0xE8\n#define EMC_SELF_REF                  0xE0\n#define EMC_MRR                       0xEC\n#define EMC_FBIO_SPARE                0x100\n#define EMC_FBIO_CFG5                 0x104\n#define EMC_PDEX2CKE                  0x118\n#define EMC_CKE2PDEN                  0x11C\n#define EMC_MPC                       0x128\n#define EMC_EMRS2                     0x12C\n#define EMC_MRW2                      0x134\n#define EMC_MRW3                      0x138\n#define EMC_MRW4                      0x13C\n#define EMC_R2R                       0x144\n#define EMC_EINPUT                    0x14C\n#define EMC_EINPUT_DURATION           0x150\n#define EMC_PUTERM_EXTRA              0x154\n#define EMC_TCKESR                    0x158\n#define EMC_TPD                       0x15C\n#define EMC_AUTO_CAL_CONFIG           0x2A4\n\n#define EMC_EMC_STATUS                0x2B4\n#define  TIMING_UPDATE_STALLED  (1 << 23)\n#define  MRR_DIVLD              (1 << 20)\n#define  IN_SELF_REFRESH_MASK   (3 << 8)\n#define  IN_POWERDOWN_BOTH_MASK (3 << 4)\n#define  IN_POWERDOWN_1DEV_MASK (1 << 4)\n#define  REQ_FIFO_EMPTY         (1 << 0)\n\n#define EMC_CFG_2                     0x2B8\n#define EMC_CFG_DIG_DLL               0x2BC\n#define EMC_CFG_DIG_DLL_PERIOD        0x2C0\n#define EMC_DIG_DLL_STATUS            0x2C4\n#define EMC_RDV_MASK                  0x2CC\n#define EMC_WDV_MASK                  0x2D0\n#define EMC_RDV_EARLY_MASK            0x2D4\n#define EMC_RDV_EARLY                 0x2D8\n#define EMC_AUTO_CAL_CONFIG8          0x2DC\n#define EMC_ZCAL_INTERVAL             0x2E0\n#define EMC_ZCAL_WAIT_CNT             0x2E4\n#define EMC_ZQ_CAL                    0x2EC\n#define EMC_FDPD_CTRL_DQ              0x310\n#define EMC_FDPD_CTRL_CMD             0x314\n#define EMC_PMACRO_CMD_BRICK_CTRL_FDPD     0x318\n#define EMC_PMACRO_DATA_BRICK_CTRL_FDPD    0x31C\n#define EMC_SCRATCH0                  0x324\n#define EMC_PMACRO_BRICK_CTRL_RFU1    0x330\n#define EMC_PMACRO_BRICK_CTRL_RFU2    0x334\n#define EMC_TR_TIMING_0               0x3B4\n#define EMC_TR_CTRL_0                 0x3B8\n#define EMC_TR_CTRL_1                 0x3BC\n#define EMC_SWITCH_BACK_CTRL          0x3C0\n#define EMC_TR_RDV                    0x3C4\n#define EMC_STALL_THEN_EXE_AFTER_CLKCHANGE 0x3CC\n#define EMC_SEL_DPD_CTRL              0x3D8\n#define EMC_PRE_REFRESH_REQ_CNT       0x3DC\n#define EMC_DYN_SELF_REF_CONTROL      0x3E0\n#define EMC_TXSRDLL                   0x3E4\n#define EMC_CCFIFO_ADDR               0x3E8\n#define EMC_CCFIFO_DATA               0x3EC\n#define EMC_CCFIFO_STATUS             0x3F0\n#define EMC_TR_QPOP                   0x3F4\n#define EMC_TR_RDV_MASK               0x3F8\n#define EMC_TR_QSAFE                  0x3FC\n#define EMC_TR_QRST                   0x400\n#define EMC_AUTO_CAL_CONFIG2          0x458\n#define EMC_AUTO_CAL_CONFIG3          0x45C\n#define EMC_TR_DVFS                   0x460\n#define EMC_AUTO_CAL_CHANNEL          0x464\n#define EMC_IBDLY                     0x468\n#define EMC_OBDLY                     0x46c\n#define EMC_TXDSRVTTGEN               0x480\n#define EMC_WE_DURATION               0x48C\n#define EMC_WS_DURATION               0x490\n#define EMC_WEV                       0x494\n#define EMC_WSV                       0x498\n#define EMC_CFG_3                     0x49C\n#define EMC_MRW6                      0x4A4\n#define EMC_MRW7                      0x4A8\n#define EMC_MRW8                      0x4AC\n#define EMC_MRW14                     0x4C4\n#define EMC_MRW15                     0x4D0\n#define EMC_CFG_SYNC                  0x4D4\n#define EMC_FDPD_CTRL_CMD_NO_RAMP     0x4D8\n#define EMC_WDV_CHK                   0x4E0\n#define EMC_CFG_PIPE_2                0x554\n#define EMC_CFG_PIPE_CLK              0x558\n#define EMC_CFG_PIPE_1                0x55C\n#define EMC_CFG_PIPE                  0x560\n#define EMC_QPOP                      0x564\n#define EMC_QUSE_WIDTH                0x568\n#define EMC_PUTERM_WIDTH              0x56C\n#define EMC_AUTO_CAL_CONFIG7          0x574\n#define EMC_REFCTRL2                  0x580\n#define EMC_FBIO_CFG7                 0x584\n\n#define EMC_DATA_BRLSHFT_0            0x588\n#define  EMC_DATA_BRLSHFT_0_RANK0_BYTE0_DATA_BRLSHFT_SHIFT 0\n#define  EMC_DATA_BRLSHFT_0_RANK0_BYTE1_DATA_BRLSHFT_SHIFT 3\n#define  EMC_DATA_BRLSHFT_0_RANK0_BYTE2_DATA_BRLSHFT_SHIFT 6\n#define  EMC_DATA_BRLSHFT_0_RANK0_BYTE3_DATA_BRLSHFT_SHIFT 9\n#define  EMC_DATA_BRLSHFT_0_RANK0_BYTE4_DATA_BRLSHFT_SHIFT 12\n#define  EMC_DATA_BRLSHFT_0_RANK0_BYTE5_DATA_BRLSHFT_SHIFT 15\n#define  EMC_DATA_BRLSHFT_0_RANK0_BYTE6_DATA_BRLSHFT_SHIFT 18\n#define  EMC_DATA_BRLSHFT_0_RANK0_BYTE7_DATA_BRLSHFT_SHIFT 21\n\n#define EMC_DATA_BRLSHFT_1            0x58C\n#define  EMC_DATA_BRLSHFT_1_RANK1_BYTE0_DATA_BRLSHFT_SHIFT 0\n#define  EMC_DATA_BRLSHFT_1_RANK1_BYTE1_DATA_BRLSHFT_SHIFT 3\n#define  EMC_DATA_BRLSHFT_1_RANK1_BYTE2_DATA_BRLSHFT_SHIFT 6\n#define  EMC_DATA_BRLSHFT_1_RANK1_BYTE3_DATA_BRLSHFT_SHIFT 9\n#define  EMC_DATA_BRLSHFT_1_RANK1_BYTE4_DATA_BRLSHFT_SHIFT 12\n#define  EMC_DATA_BRLSHFT_1_RANK1_BYTE5_DATA_BRLSHFT_SHIFT 15\n#define  EMC_DATA_BRLSHFT_1_RANK1_BYTE6_DATA_BRLSHFT_SHIFT 18\n#define  EMC_DATA_BRLSHFT_1_RANK1_BYTE7_DATA_BRLSHFT_SHIFT 21\n\n#define EMC_RFCPB                     0x590\n#define EMC_DQS_BRLSHFT_0             0x594\n#define EMC_DQS_BRLSHFT_1             0x598\n#define EMC_CMD_BRLSHFT_0             0x59C\n#define EMC_CMD_BRLSHFT_1             0x5A0\n#define EMC_CMD_BRLSHFT_2             0x5A4\n#define EMC_CMD_BRLSHFT_3             0x5A8\n#define EMC_QUSE_BRLSHFT_0            0x5AC\n#define EMC_AUTO_CAL_CONFIG4          0x5B0\n#define EMC_AUTO_CAL_CONFIG5          0x5B4\n#define EMC_QUSE_BRLSHFT_1            0x5B8\n#define EMC_QUSE_BRLSHFT_2            0x5BC\n#define EMC_CCDMW                     0x5C0\n#define EMC_QUSE_BRLSHFT_3            0x5C4\n#define EMC_AUTO_CAL_CONFIG6          0x5CC\n#define EMC_DLL_CFG_0                 0x5E4\n#define EMC_DLL_CFG_1                 0x5E8\n#define EMC_CONFIG_SAMPLE_DELAY       0x5F0\n#define EMC_CFG_UPDATE                0x5F4\n\n#define EMC_PMACRO_QUSE_DDLL_RANK0_0 0x600\n#define EMC_PMACRO_QUSE_DDLL_RANK0_1 0x604\n#define EMC_PMACRO_QUSE_DDLL_RANK0_2 0x608\n#define EMC_PMACRO_QUSE_DDLL_RANK0_3 0x60C\n#define EMC_PMACRO_QUSE_DDLL_RANK0_4 0x610\n#define EMC_PMACRO_QUSE_DDLL_RANK0_5 0x614\n#define EMC_PMACRO_QUSE_DDLL_RANK1_4 0x630\n#define EMC_PMACRO_QUSE_DDLL_RANK1_5 0x634\n#define EMC_PMACRO_QUSE_DDLL_RANK1_0 0x620\n#define EMC_PMACRO_QUSE_DDLL_RANK1_1 0x624\n#define EMC_PMACRO_QUSE_DDLL_RANK1_2 0x628\n#define EMC_PMACRO_QUSE_DDLL_RANK1_3 0x62C\n\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0 0x640\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1 0x644\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2 0x648\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3 0x64C\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4 0x650\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5 0x654\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0 0x660\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1 0x664\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2 0x668\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3 0x66C\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4 0x670\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5 0x674\n\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0 0x680\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1 0x684\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2 0x688\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3 0x68C\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4 0x690\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5 0x694\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0 0x6A0\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1 0x6A4\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2 0x6A8\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3 0x6AC\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4 0x6B0\n#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5 0x6B4\n\n#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0 0x6C0\n#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1 0x6C4\n#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2 0x6C8\n#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3 0x6CC\n#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0 0x6E0\n#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1 0x6E4\n#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2 0x6E8\n#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3 0x6EC\n\n#define EMC_PMACRO_TX_PWRD_0 0x720\n#define EMC_PMACRO_TX_PWRD_1 0x724\n#define EMC_PMACRO_TX_PWRD_2 0x728\n#define EMC_PMACRO_TX_PWRD_3 0x72C\n#define EMC_PMACRO_TX_PWRD_4 0x730\n#define EMC_PMACRO_TX_PWRD_5 0x734\n\n#define EMC_PMACRO_TX_SEL_CLK_SRC_0 0x740\n#define EMC_PMACRO_TX_SEL_CLK_SRC_1 0x744\n#define EMC_PMACRO_TX_SEL_CLK_SRC_3 0x74C\n#define EMC_PMACRO_TX_SEL_CLK_SRC_2 0x748\n#define EMC_PMACRO_TX_SEL_CLK_SRC_4 0x750\n#define EMC_PMACRO_TX_SEL_CLK_SRC_5 0x754\n\n#define EMC_PMACRO_DDLL_BYPASS 0x760\n#define EMC_PMACRO_DDLL_PWRD_0 0x770\n#define EMC_PMACRO_DDLL_PWRD_1 0x774\n#define EMC_PMACRO_DDLL_PWRD_2 0x778\n\n#define EMC_PMACRO_CMD_CTRL_0 0x780\n#define EMC_PMACRO_CMD_CTRL_1 0x784\n#define EMC_PMACRO_CMD_CTRL_2 0x788\n\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0 0x800\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1 0x804\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2 0x808\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_3 0x80C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0 0x810\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1 0x814\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2 0x818\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_3 0x81C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0 0x820\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1 0x824\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2 0x828\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_3 0x82C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0 0x830\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1 0x834\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2 0x838\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_3 0x83C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0 0x840\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1 0x844\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2 0x848\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_3 0x84C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0 0x850\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1 0x854\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2 0x858\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_3 0x85C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0 0x860\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1 0x864\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2 0x868\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_3 0x86C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0 0x870\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1 0x874\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2 0x878\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_3 0x87C\n\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0 0x880\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1 0x884\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2 0x888\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_3 0x88C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0 0x890\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1 0x894\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2 0x898\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_3 0x89C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0 0x8A0\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1 0x8A4\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2 0x8A8\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_3 0x8AC\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0 0x8B0\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1 0x8B4\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2 0x8B8\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_3 0x8BC\n\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0 0x900\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1 0x904\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2 0x908\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_3 0x90C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0 0x910\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1 0x914\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2 0x918\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_3 0x91C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0 0x920\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1 0x924\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2 0x928\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_3 0x92C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0 0x930\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1 0x934\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2 0x938\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_3 0x93C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0 0x940\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1 0x944\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2 0x948\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_3 0x94C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0 0x950\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1 0x954\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2 0x958\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_3 0x95C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0 0x960\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1 0x964\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2 0x968\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_3 0x96C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0 0x970\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1 0x974\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2 0x978\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_3 0x97C\n\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_0 0x980\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_1 0x984\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_2 0x988\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_3 0x98C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_0 0x990\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_1 0x994\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_2 0x998\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_3 0x99C\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_0 0x9A0\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_1 0x9A4\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_2 0x9A8\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_3 0x9AC\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_0 0x9B0\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_1 0x9B4\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_2 0x9B8\n#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_3 0x9BC\n\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0 0xA00\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1 0xA04\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2 0xA08\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0 0xA10\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1 0xA14\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2 0xA18\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0 0xA20\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1 0xA24\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2 0xA28\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0 0xA30\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1 0xA34\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2 0xA38\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0 0xA40\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1 0xA44\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2 0xA48\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0 0xA50\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1 0xA54\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2 0xA58\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0 0xA60\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1 0xA64\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2 0xA68\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0 0xA70\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1 0xA74\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2 0xA78\n\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0 0xB00\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1 0xB04\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2 0xB08\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0 0xB10\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1 0xB14\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2 0xB18\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0 0xB20\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1 0xB24\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2 0xB28\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0 0xB30\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1 0xB34\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2 0xB38\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0 0xB40\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1 0xB44\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2 0xB48\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0 0xB50\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1 0xB54\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2 0xB58\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0 0xB60\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1 0xB64\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2 0xB68\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0 0xB70\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1 0xB74\n#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2 0xB78\n\n#define EMC_PMACRO_IB_VREF_DQ_0  0xBE0\n#define EMC_PMACRO_IB_VREF_DQ_1  0xBE4\n#define EMC_PMACRO_IB_VREF_DQS_0 0xBF0\n#define EMC_PMACRO_IB_VREF_DQS_1 0xBF4\n\n#define EMC_PMACRO_DDLL_LONG_CMD_0 0xC00\n#define EMC_PMACRO_DDLL_LONG_CMD_1 0xC04\n#define EMC_PMACRO_DDLL_LONG_CMD_2 0xC08\n#define EMC_PMACRO_DDLL_LONG_CMD_3 0xC0C\n#define EMC_PMACRO_DDLL_LONG_CMD_4 0xC10\n\n#define EMC_PMACRO_DDLL_SHORT_CMD_0 0xC20\n#define EMC_PMACRO_DDLL_SHORT_CMD_1 0xC24\n#define EMC_PMACRO_DDLL_SHORT_CMD_2 0xC28\n\n#define EMC_PMACRO_CFG_PM_GLOBAL_0    0xC30\n#define EMC_PMACRO_VTTGEN_CTRL_0      0xC34\n#define EMC_PMACRO_VTTGEN_CTRL_1      0xC38\n#define EMC_PMACRO_BG_BIAS_CTRL_0     0xC3C\n#define EMC_PMACRO_PAD_CFG_CTRL       0xC40\n#define EMC_PMACRO_ZCTRL              0xC44\n#define EMC_PMACRO_CMD_PAD_RX_CTRL    0xC50\n#define EMC_PMACRO_DATA_PAD_RX_CTRL   0xC54\n#define EMC_PMACRO_CMD_RX_TERM_MODE   0xC58\n#define EMC_PMACRO_DATA_RX_TERM_MODE  0xC5C\n#define EMC_PMACRO_CMD_PAD_TX_CTRL    0xC60\n#define EMC_PMACRO_DATA_PAD_TX_CTRL   0xC64\n#define EMC_PMACRO_COMMON_PAD_TX_CTRL 0xC68\n#define EMC_PMACRO_AUTOCAL_CFG_COMMON 0xC78\n#define EMC_PMACRO_VTTGEN_CTRL_2      0xCF0\n#define EMC_PMACRO_IB_RXRT            0xCF4\n#define EMC_PMACRO_TRAINING_CTRL_0    0xCF8\n#define  CH0_TRAINING_E_WRPTR (1 << 3)\n#define EMC_PMACRO_TRAINING_CTRL_1    0xCFC\n\n#define EMC_TRAINING_CMD              0xE00\n#define EMC_TRAINING_CTRL             0xE04\n#define EMC_TRAINING_STATUS           0xE08\n#define EMC_TRAINING_QUSE_CORS_CTRL   0xE0C\n#define EMC_TRAINING_QUSE_FINE_CTRL   0xE10\n#define EMC_TRAINING_QUSE_CTRL_MISC   0xE14\n#define EMC_TRAINING_WRITE_FINE_CTRL  0xE18\n#define EMC_TRAINING_WRITE_CTRL_MISC  0xE1C\n#define EMC_TRAINING_WRITE_VREF_CTRL  0xE20\n#define EMC_TRAINING_READ_FINE_CTRL   0xE24\n#define EMC_TRAINING_READ_CTRL_MISC   0xE28\n#define EMC_TRAINING_READ_VREF_CTRL   0xE2C\n#define EMC_TRAINING_CA_FINE_CTRL     0xE30\n#define EMC_TRAINING_CA_CTRL_MISC     0xE34\n#define EMC_TRAINING_CA_CTRL_MISC1    0xE38\n#define EMC_TRAINING_CA_VREF_CTRL     0xE3C\n#define EMC_TRAINING_SETTLE           0xE44\n#define EMC_TRAINING_MPC              0xE5C\n#define EMC_TRAINING_PATRAM_CTRL      0xE60\n#define EMC_TRAINING_PATRAM_DQ        0xE64\n#define EMC_TRAINING_PATRAM_DMI       0xE68\n#define EMC_TRAINING_VREF_SETTLE      0xE6C\n#define EMC_TRAINING_OPT_CA_VREF      0xEC0\n#define EMC_TRAINING_OPT_DQ_OB_VREF   0xEC4\n#define EMC_TRAINING_QUSE_VREF_CTRL   0xED0\n#define EMC_TRAINING_OPT_DQS_IB_VREF_RANK0 0xED4\n#define EMC_TRAINING_OPT_DQS_IB_VREF_RANK1 0xED8\n\n/* Per channel registers offsets. Should be used with EMC_BASE */\n#define EMC0_MRW10 0x34B4\n#define EMC0_MRW11 0x34B8\n#define EMC0_MRW12 0x34BC\n#define EMC0_MRW13 0x34C0\n#define EMC0_DATA_BRLSHFT_0 0x3588\n#define EMC0_DATA_BRLSHFT_1 0x358C\n#define EMC0_CMD_BRLSHFT_0  0x359C\n#define EMC0_QUSE_BRLSHFT_0 0x35AC\n#define EMC0_QUSE_BRLSHFT_2 0x35BC\n#define EMC0_TRAINING_RW_OFFSET_IB_BYTE0 0x3E98\n#define EMC0_TRAINING_RW_OFFSET_IB_BYTE1 0x3E9C\n#define EMC0_TRAINING_RW_OFFSET_IB_BYTE2 0x3EA0\n#define EMC0_TRAINING_RW_OFFSET_IB_BYTE3 0x3EA4\n#define EMC0_TRAINING_RW_OFFSET_IB_MISC  0x3EA8\n#define EMC0_TRAINING_RW_OFFSET_OB_BYTE0 0x3EAC\n#define EMC0_TRAINING_RW_OFFSET_OB_BYTE1 0x3EB0\n#define EMC0_TRAINING_RW_OFFSET_OB_BYTE2 0x3EB4\n#define EMC0_TRAINING_RW_OFFSET_OB_BYTE3 0x3EB8\n#define EMC0_TRAINING_RW_OFFSET_OB_MISC  0x3EBC\n#define EMC0_TRAINING_OPT_DQS_IB_VREF_RANK0 0x3ED4\n#define EMC0_TRAINING_OPT_DQS_IB_VREF_RANK1 0x3ED8\n\n#define EMC1_MRW10 0x44B4\n#define EMC1_MRW11 0x44B8\n#define EMC1_MRW12 0x44BC\n#define EMC1_MRW13 0x44C0\n#define EMC1_DATA_BRLSHFT_0 0x4588\n#define EMC1_DATA_BRLSHFT_1 0x458C\n#define EMC1_CMD_BRLSHFT_1  0x45A0\n#define EMC1_QUSE_BRLSHFT_1 0x45B8\n#define EMC1_QUSE_BRLSHFT_3 0x45C4\n#define EMC1_TRAINING_RW_OFFSET_IB_BYTE0 0x4E98\n#define EMC1_TRAINING_RW_OFFSET_IB_BYTE1 0x4E9C\n#define EMC1_TRAINING_RW_OFFSET_IB_BYTE2 0x4EA0\n#define EMC1_TRAINING_RW_OFFSET_IB_BYTE3 0x4EA4\n#define EMC1_TRAINING_RW_OFFSET_IB_MISC  0x4EA8\n#define EMC1_TRAINING_RW_OFFSET_OB_BYTE0 0x4EAC\n#define EMC1_TRAINING_RW_OFFSET_OB_BYTE1 0x4EB0\n#define EMC1_TRAINING_RW_OFFSET_OB_BYTE2 0x4EB4\n#define EMC1_TRAINING_RW_OFFSET_OB_BYTE3 0x4EB8\n#define EMC1_TRAINING_RW_OFFSET_OB_MISC  0x4EBC\n#define EMC1_TRAINING_OPT_DQS_IB_VREF_RANK0 0x4ED4\n#define EMC1_TRAINING_OPT_DQS_IB_VREF_RANK1 0x4ED8\n\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE0_SHIFT 0\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE1_SHIFT 16\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE2_SHIFT 0\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE3_SHIFT 16\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE4_SHIFT 0\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE5_SHIFT 16\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE6_SHIFT 0\n#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE7_SHIFT 16\n\n#endif\n"
  },
  {
    "path": "modules/hekate_libsys_minerva/mtc_switch_tables.h",
    "content": "/*\n * Minerva Training Cell\n * DRAM Training for Tegra X1 SoC. Supports LPDDR4.\n *\n * Copyright (c) 2018-2025 CTCaer  <ctcaer@gmail.com>\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _MTC_SWITCH_TABLES_H_\n#define _MTC_SWITCH_TABLES_H_\n\n#define DRAM_4GB_SAMSUNG_K4F6E304HB_MGCH       0\n#define DRAM_4GB_HYNIX_H9HCNNNBPUMLHR_NLN      1\n#define DRAM_4GB_MICRON_MT53B512M32D2NP_062_WT 2\n#define DRAM_4GB_COPPER_SAMSUNG                3\n#define DRAM_6GB_SAMSUNG_K4FHE3D4HM_MFCH       4\n#define DRAM_4GB_COPPER_HYNIX                  5\n#define DRAM_4GB_COPPER_MICRON                 6\n#define DRAM_8GB_SAMSUNG_K4FBE3D4HM_MGXX       7\n\n// odinx02_a2_0_3 and odinx02_a2_1. For sdram ids 0,2,3,4\nstatic const unsigned char odinx02_a2_0_3_10NoCfgVersion_V9_8_7_V1_6[EMC_TABLE_SIZE_ODINX02_R7] =\n{\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x32, 0x30, 0x34, 0x30, 0x30, 0x30, 0x5F, 0x4E, 0x6F,\n\t0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38, 0x2E,\n\t0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xE0, 0x1C, 0x03, 0x00, 0x20, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x70,\n\t0x5F, 0x6F, 0x75, 0x74, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x18, 0x40,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x25, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0D, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x27, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x1C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00,\n\t0xBE, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08,\n\t0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00,\n\t0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00,\n\t0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00,\n\t0x15, 0x00, 0xCC, 0x00, 0x0A, 0x00, 0x33, 0x00, 0x03, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F,\n\t0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0xFF, 0x0F, 0xFF, 0x0F, 0x13, 0x07, 0x00, 0x80, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x37, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xFF, 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x33, 0x60, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x65, 0x00, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48,\n\t0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x4C, 0x72, 0x72, 0x0E, 0x4C,\n\t0x0D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08,\n\t0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,\n\t0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x1C, 0x03, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00,\n\t0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00,\n\t0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00,\n\t0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0xCC, 0x00, 0x09, 0x00, 0x15, 0x00, 0xCC, 0x00, 0x0A, 0x00, 0x33, 0x00, 0x03, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, 0x13, 0x07, 0x00, 0x80, 0x0A, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x33, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0x65, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x0D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x08, 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xC1, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48,\n\t0x1C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00,\n\t0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, 0xBE, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F,\n\t0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00,\n\t0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00,\n\t0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00, 0x15, 0x00, 0xCC, 0x00, 0x0A, 0x00, 0x33, 0x00,\n\t0x03, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, 0x13, 0x07, 0x00, 0x80,\n\t0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x37, 0x80, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x00,\n\t0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xEF, 0xFF, 0xEF,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x33, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0x65, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x0D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,\n\t0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x02, 0x00, 0x00, 0x30,\n\t0x02, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0x27, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x48, 0x1C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91,\n\t0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, 0xBE, 0x00, 0x00, 0x00,\n\t0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00,\n\t0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00,\n\t0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00,\n\t0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00,\n\t0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00, 0x15, 0x00, 0xCC, 0x00,\n\t0x0A, 0x00, 0x33, 0x00, 0x03, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00,\n\t0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F,\n\t0x13, 0x07, 0x00, 0x80, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x37, 0x00, 0x05, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,\n\t0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xFF, 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x33, 0x60, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x65, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07,\n\t0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x28, 0x00, 0x28, 0x00,\n\t0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00,\n\t0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00,\n\t0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x92, 0x24, 0x00,\n\t0x49, 0x92, 0x24, 0x00, 0x49, 0x92, 0x24, 0x00, 0x49, 0x92, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x08, 0x4C, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, 0x01, 0x02, 0x03, 0x00,\n\t0x04, 0x05, 0xC3, 0x71, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x4C, 0x02, 0x00, 0x00,\n\t0xB2, 0x00, 0xFF, 0x00, 0xDA, 0x00, 0xFF, 0x00, 0x9D, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,\n\t0x0C, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x0C, 0x00, 0xFF, 0x00, 0x49, 0x00, 0x7F, 0x00,\n\t0x80, 0x00, 0xFF, 0x00, 0x04, 0x00, 0xFF, 0x00, 0xAD, 0x00, 0x08, 0x00, 0xFF, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0xFF, 0x00, 0xC6, 0x00, 0xFF, 0x00, 0xC6, 0x00, 0xFF, 0x00, 0x6D, 0x00, 0xFF, 0x00,\n\t0xFF, 0x00, 0xFF, 0x00, 0xE2, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,\n\t0xFF, 0x00, 0xFF, 0x00, 0x15, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x02, 0x80, 0x18, 0x40, 0x01, 0x00, 0x00, 0x00, 0x5C, 0x0D, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x34, 0x30, 0x38, 0x30, 0x30, 0x30, 0x5F, 0x4E, 0x6F,\n\t0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38, 0x2E,\n\t0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xC0, 0x39, 0x06, 0x00, 0x2C, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x70,\n\t0x5F, 0x75, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0xE0,\n\t0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,\n\t0x4A, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x12, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x30, 0x07, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0F, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x19, 0x00, 0x00, 0x00,\n\t0x21, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,\n\t0x07, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x1A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x4D, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x38, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x03, 0x1C, 0xC0, 0x00, 0x80, 0x00, 0x00,\n\t0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08,\n\t0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00,\n\t0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x98, 0x01, 0x0E, 0x00,\n\t0x1B, 0x00, 0x98, 0x01, 0x0A, 0x00, 0x66, 0x00, 0x04, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F,\n\t0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0x00, 0x00, 0x00, 0x00, 0x22, 0x0D, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x35, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xFF, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x66, 0x60, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x19, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0xCB, 0x00, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48,\n\t0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x4C, 0x72, 0x72, 0x0E, 0x4C,\n\t0x19, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x0F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x07, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08,\n\t0x0F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00,\n\t0x19, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x21, 0x00, 0x00, 0x00, 0x07, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x01, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x38, 0x06, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x03, 0x1C, 0xC0,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x0B, 0x08, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00,\n\t0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0x98, 0x01, 0x0E, 0x00, 0x1B, 0x00, 0x98, 0x01, 0x0A, 0x00, 0x66, 0x00, 0x04, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x22, 0x0D, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x66, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x23, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x15, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0xCB, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x19, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x12, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x08, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x08, 0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x01, 0x00, 0x05, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x07, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x81, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48,\n\t0x38, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00,\n\t0xBB, 0x03, 0x1C, 0xC0, 0x00, 0x80, 0x00, 0x00, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0x98, 0x01, 0x0E, 0x00, 0x1B, 0x00, 0x98, 0x01, 0x0A, 0x00, 0x66, 0x00,\n\t0x04, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x22, 0x0D, 0x00, 0x80,\n\t0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x35, 0x80, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00,\n\t0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x00,\n\t0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE2, 0xFF, 0xEF,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x66, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0xCB, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x19, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00,\n\t0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,\n\t0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30,\n\t0x07, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,\n\t0x23, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x07, 0x06, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x81, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00,\n\t0x4D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x48, 0x38, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91,\n\t0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x03, 0x1C, 0xC0, 0x00, 0x80, 0x00, 0x00, 0xBE, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x03, 0x00, 0x02, 0x00,\n\t0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00,\n\t0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x98, 0x01, 0x0E, 0x00, 0x1B, 0x00, 0x98, 0x01,\n\t0x0A, 0x00, 0x66, 0x00, 0x04, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00,\n\t0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00,\n\t0x22, 0x0D, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x35, 0x00, 0x05, 0x05,\n\t0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,\n\t0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xFF, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x66, 0x60, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x23, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0xCB, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07,\n\t0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x21, 0x00, 0x20, 0x00,\n\t0x22, 0x00, 0x21, 0x00, 0x22, 0x00, 0x21, 0x00, 0x21, 0x00, 0x20, 0x00, 0x03, 0x00, 0x02, 0x00,\n\t0x02, 0x00, 0x03, 0x00, 0x21, 0x00, 0x20, 0x00, 0x22, 0x00, 0x21, 0x00, 0x22, 0x00, 0x21, 0x00,\n\t0x21, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x01, 0x7F, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x02, 0x03, 0x02, 0x04, 0x00,\n\t0x07, 0x0A, 0xA4, 0x71, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x35, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x98, 0x04, 0x00, 0x00,\n\t0x59, 0x00, 0xFF, 0x00, 0x6D, 0x00, 0xFF, 0x00, 0x4F, 0x00, 0xFF, 0x00, 0xAF, 0x00, 0xFF, 0x00,\n\t0x06, 0x00, 0xFF, 0x00, 0xAF, 0x00, 0xFF, 0x00, 0x06, 0x00, 0xFF, 0x00, 0x49, 0x00, 0x40, 0x00,\n\t0x80, 0x00, 0xFF, 0x00, 0x04, 0x00, 0xFF, 0x00, 0x57, 0x00, 0x08, 0x00, 0xFF, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0xFF, 0x00, 0x63, 0x00, 0xFF, 0x00, 0x63, 0x00, 0xFF, 0x00, 0x36, 0x00, 0xFF, 0x00,\n\t0xFF, 0x00, 0xFF, 0x00, 0x71, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0xFF, 0x00, 0xFF, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x08, 0x09, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x35, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0xE0, 0x01, 0x00, 0x00, 0x00, 0xD6, 0x06, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x36, 0x36, 0x35, 0x36, 0x30, 0x30, 0x5F, 0x4E, 0x6F,\n\t0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38, 0x2E,\n\t0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x28, 0x0A, 0x00, 0x39, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x6D,\n\t0x5F, 0x75, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80,\n\t0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x2A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,\n\t0x78, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x30, 0x0A, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x11, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x1E, 0x00, 0x00, 0x00,\n\t0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,\n\t0xE4, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x02, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x23, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,\n\t0x7D, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x24, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x02, 0x0B, 0xC0, 0x00, 0x80, 0x00, 0x00,\n\t0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08,\n\t0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00,\n\t0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00,\n\t0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x9A, 0x02, 0x15, 0x00,\n\t0x1F, 0x00, 0x9A, 0x02, 0x0A, 0x00, 0xA7, 0x00, 0x05, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F,\n\t0x14, 0x00, 0x01, 0x00, 0x06, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0x00, 0x00, 0x00, 0x00, 0xC9, 0x14, 0x00, 0x80, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x33, 0x00, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05, 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xFF, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0xA7, 0x60, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x1E, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x4C, 0x01, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48,\n\t0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x4C, 0x72, 0x72, 0x0E, 0x4C,\n\t0x28, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08,\n\t0x11, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00,\n\t0x1E, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,\n\t0x26, 0x00, 0x00, 0x00, 0xE4, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x02, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x15, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x24, 0x0A, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x02, 0x0B, 0xC0,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x0B, 0x08, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,\n\t0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0x9A, 0x02, 0x15, 0x00, 0x1F, 0x00, 0x9A, 0x02, 0x0A, 0x00, 0xA7, 0x00, 0x05, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x06, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xC9, 0x14, 0x00, 0x80, 0x16, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0xA7, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x29, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x1B, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0x4C, 0x01, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x28, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x0B, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x08, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x04, 0x00, 0x05, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,\n\t0x24, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xE4, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x79, 0x02, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48,\n\t0x24, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00,\n\t0xBB, 0x02, 0x0B, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00,\n\t0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0x9A, 0x02, 0x15, 0x00, 0x1F, 0x00, 0x9A, 0x02, 0x0A, 0x00, 0xA7, 0x00,\n\t0x05, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x06, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xC9, 0x14, 0x00, 0x80,\n\t0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x33, 0x80, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05,\n\t0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02,\n\t0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00,\n\t0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE2, 0xFF, 0xEF,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0xA7, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, 0x05, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0x4C, 0x01, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x28, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,\n\t0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30,\n\t0x0A, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x11, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,\n\t0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xE4, 0x09, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x79, 0x02, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x00,\n\t0x7D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x48, 0x24, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91,\n\t0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x02, 0x0B, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x05, 0x00, 0x04, 0x00,\n\t0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00,\n\t0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x9A, 0x02, 0x15, 0x00, 0x1F, 0x00, 0x9A, 0x02,\n\t0x0A, 0x00, 0xA7, 0x00, 0x05, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00,\n\t0x06, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00,\n\t0xC9, 0x14, 0x00, 0x80, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x33, 0x00, 0x05, 0x05,\n\t0x00, 0x00, 0x05, 0x05, 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,\n\t0x11, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xFF, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0xA7, 0x60, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x28, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x1E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x4C, 0x01, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07,\n\t0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x22, 0x00, 0x20, 0x00,\n\t0x24, 0x00, 0x21, 0x00, 0x24, 0x00, 0x21, 0x00, 0x22, 0x00, 0x20, 0x00, 0x05, 0x00, 0x04, 0x00,\n\t0x04, 0x00, 0x05, 0x00, 0x22, 0x00, 0x20, 0x00, 0x24, 0x00, 0x21, 0x00, 0x24, 0x00, 0x21, 0x00,\n\t0x22, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x04, 0x03, 0x06, 0x00,\n\t0x0A, 0x0F, 0xA5, 0x71, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x57, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x7E, 0x07, 0x00, 0x00,\n\t0x3D, 0x00, 0xFF, 0x00, 0x43, 0x00, 0xFF, 0x00, 0x41, 0x00, 0xFF, 0x00, 0x90, 0x00, 0xFF, 0x00,\n\t0x05, 0x00, 0xFF, 0x00, 0x90, 0x00, 0xFF, 0x00, 0x05, 0x00, 0xFF, 0x00, 0x49, 0x00, 0x34, 0x00,\n\t0x80, 0x00, 0xFF, 0x00, 0x04, 0x00, 0xFF, 0x00, 0x35, 0x00, 0x08, 0x00, 0xFF, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0xFF, 0x00, 0x3D, 0x00, 0xFF, 0x00, 0x3D, 0x00, 0xFF, 0x00, 0x29, 0x00, 0xFF, 0x00,\n\t0xD8, 0x00, 0xFF, 0x00, 0x45, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,\n\t0xFF, 0x00, 0xFF, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x24, 0x00, 0x01, 0x08, 0x12, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x35, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x04, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5F, 0x4E, 0x6F,\n\t0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38, 0x2E,\n\t0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x35, 0x0C, 0x00, 0x39, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x6D,\n\t0x5F, 0x75, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80,\n\t0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x33, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,\n\t0x90, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x22, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x15, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x30, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x13, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0xF0, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x23, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,\n\t0x96, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x30, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x02, 0x07, 0xC0, 0x00, 0x80, 0x00, 0x00,\n\t0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08,\n\t0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,\n\t0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00,\n\t0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x20, 0x03, 0x19, 0x00,\n\t0x1F, 0x00, 0x20, 0x03, 0x0C, 0x00, 0xC8, 0x00, 0x06, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0x00, 0x00, 0x00, 0x00, 0xC8, 0x18, 0x00, 0x80, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x0A, 0x01, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x10, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0xC8, 0x60, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0x17, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x20, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x05, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x90, 0x01, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48,\n\t0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x4C, 0x72, 0x72, 0x0E, 0x4C,\n\t0x30, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08,\n\t0x13, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,\n\t0x27, 0x00, 0x00, 0x00, 0xF0, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x02, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x19, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x30, 0x0C, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x02, 0x07, 0xC0,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x0B, 0x08, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00,\n\t0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0x20, 0x03, 0x19, 0x00, 0x1F, 0x00, 0x20, 0x03, 0x0C, 0x00, 0xC8, 0x00, 0x06, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x18, 0x00, 0x80, 0x17, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0xC8, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x2D, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0x90, 0x01, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x30, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x0F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x0A, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x08, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x03, 0x00, 0x05, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00,\n\t0x25, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xF0, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xFC, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48,\n\t0x30, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00,\n\t0xBB, 0x02, 0x07, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,\n\t0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x06, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0x20, 0x03, 0x19, 0x00, 0x1F, 0x00, 0x20, 0x03, 0x0C, 0x00, 0xC8, 0x00,\n\t0x06, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x07, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x18, 0x00, 0x80,\n\t0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x01, 0x00, 0x02,\n\t0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00,\n\t0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xE2, 0xFF, 0xEF,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0xC8, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x29, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0x90, 0x01, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x30, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00,\n\t0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,\n\t0x0F, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,\n\t0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30,\n\t0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x13, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0x29, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xF0, 0x0B, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xFC, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00,\n\t0x96, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x48, 0x30, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91,\n\t0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x02, 0x07, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x06, 0x00, 0x05, 0x00,\n\t0x05, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00,\n\t0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x20, 0x03, 0x19, 0x00, 0x1F, 0x00, 0x20, 0x03,\n\t0x0C, 0x00, 0xC8, 0x00, 0x06, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x07, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00,\n\t0xC8, 0x18, 0x00, 0x80, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x33, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,\n\t0x01, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x10, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0xC8, 0x60, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n\t0x29, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x90, 0x01, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07,\n\t0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x23, 0x00, 0x1F, 0x00,\n\t0x24, 0x00, 0x22, 0x00, 0x24, 0x00, 0x22, 0x00, 0x23, 0x00, 0x20, 0x00, 0x06, 0x00, 0x05, 0x00,\n\t0x05, 0x00, 0x06, 0x00, 0x23, 0x00, 0x1F, 0x00, 0x24, 0x00, 0x22, 0x00, 0x24, 0x00, 0x22, 0x00,\n\t0x23, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x06, 0x04, 0x07, 0x00,\n\t0x0D, 0x12, 0x86, 0x71, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x68, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x02, 0x09, 0x00, 0x00,\n\t0x3D, 0x00, 0xFF, 0x00, 0x38, 0x00, 0xFF, 0x00, 0x41, 0x00, 0xFF, 0x00, 0x90, 0x00, 0xFF, 0x00,\n\t0x05, 0x00, 0xFF, 0x00, 0x90, 0x00, 0xFF, 0x00, 0x05, 0x00, 0xFF, 0x00, 0x49, 0x00, 0x34, 0x00,\n\t0x80, 0x00, 0xFF, 0x00, 0x04, 0x00, 0xFF, 0x00, 0x2C, 0x00, 0x08, 0x00, 0xFF, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0xFF, 0x00, 0x32, 0x00, 0xFF, 0x00, 0x32, 0x00, 0xFF, 0x00, 0x22, 0x00, 0xFF, 0x00,\n\t0xB4, 0x00, 0xFF, 0x00, 0x3A, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,\n\t0xFF, 0x00, 0xFF, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x24, 0x00, 0x01, 0x08, 0x12, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x35, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x04, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x31, 0x30, 0x36, 0x35, 0x36, 0x30, 0x30, 0x5F, 0x4E,\n\t0x6F, 0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38,\n\t0x2E, 0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x80, 0x42, 0x10, 0x00, 0x45, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x6D,\n\t0x5F, 0x75, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80,\n\t0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x2D, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x10, 0x0D, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08, 0x17, 0x00, 0x00, 0x00,\n\t0x13, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0x2F, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00,\n\t0xFC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x29, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,\n\t0xC8, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x10, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48, 0x3C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x91, 0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x01, 0xC0, 0x00, 0x80, 0x00, 0x00,\n\t0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x0B, 0x08,\n\t0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00,\n\t0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x07, 0x00, 0x07, 0x00,\n\t0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x2A, 0x04, 0x21, 0x00,\n\t0x25, 0x00, 0x2A, 0x04, 0x0F, 0x00, 0x0B, 0x01, 0x07, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x09, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0x00, 0x00, 0x00, 0x00, 0xAB, 0x20, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x0A, 0x01, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x10, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0B, 0x61, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x27, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x05, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x14, 0x02, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x03, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48,\n\t0x48, 0x48, 0x0E, 0x8C, 0x48, 0x48, 0x0E, 0x8C, 0x48, 0x48, 0x0E, 0x4C, 0x48, 0x48, 0x0E, 0x4C,\n\t0x40, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x17, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x0B, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x0D, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08,\n\t0x17, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00,\n\t0x27, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,\n\t0x2F, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x21, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48, 0x3C, 0x10, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x01, 0xC0,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x06, 0x06, 0x0B, 0x08, 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00,\n\t0x07, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0x2A, 0x04, 0x21, 0x00, 0x25, 0x00, 0x2A, 0x04, 0x0F, 0x00, 0x0B, 0x01, 0x07, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x09, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x20, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x61, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x26, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0x14, 0x02, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x40, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x00, 0x00, 0x00,\n\t0xF1, 0xF1, 0x03, 0x08, 0x15, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x07, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00,\n\t0x2D, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xFF, 0x03, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00,\n\t0x17, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48,\n\t0x3C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xFF, 0x3B, 0x00, 0x00,\n\t0xBB, 0x01, 0x01, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x0B, 0x08, 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x08, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00,\n\t0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x08, 0x00, 0x07, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x08, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0x2A, 0x04, 0x21, 0x00, 0x25, 0x00, 0x2A, 0x04, 0x0F, 0x00, 0x0B, 0x01,\n\t0x07, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x09, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x20, 0x00, 0x80,\n\t0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x01, 0x00, 0x02,\n\t0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00,\n\t0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xE2, 0xFF, 0xEF,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x61, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x05, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0x14, 0x02, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x40, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,\n\t0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\n\t0x0D, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08, 0x17, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00,\n\t0x31, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00,\n\t0xC8, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x2B, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0xF1, 0xF1, 0x03, 0x48, 0x3C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91,\n\t0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x01, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x0B, 0x08, 0x08, 0x00, 0x07, 0x00,\n\t0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x07, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00,\n\t0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x2A, 0x04, 0x21, 0x00, 0x25, 0x00, 0x2A, 0x04,\n\t0x0F, 0x00, 0x0B, 0x01, 0x07, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x09, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00,\n\t0xAB, 0x20, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x33, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,\n\t0x01, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x10, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x61, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x31, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x27, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x14, 0x02, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07,\n\t0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x24, 0x00, 0x1F, 0x00,\n\t0x26, 0x00, 0x23, 0x00, 0x26, 0x00, 0x23, 0x00, 0x24, 0x00, 0x20, 0x00, 0x08, 0x00, 0x07, 0x00,\n\t0x06, 0x00, 0x08, 0x00, 0x24, 0x00, 0x1F, 0x00, 0x26, 0x00, 0x23, 0x00, 0x26, 0x00, 0x23, 0x00,\n\t0x24, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x03, 0x03, 0x04, 0x03, 0x08, 0x05, 0x09, 0x00,\n\t0x11, 0x18, 0x88, 0x71, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x8B, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0xFF, 0x0B, 0x00, 0x00,\n\t0x3D, 0x00, 0xC0, 0x00, 0x38, 0x00, 0xC0, 0x00, 0x41, 0x00, 0xC0, 0x00, 0x90, 0x00, 0xC0, 0x00,\n\t0x05, 0x00, 0xC0, 0x00, 0x90, 0x00, 0xC0, 0x00, 0x05, 0x00, 0xC0, 0x00, 0x49, 0x00, 0x34, 0x00,\n\t0x80, 0x00, 0xC0, 0x00, 0x04, 0x00, 0xC0, 0x00, 0x21, 0x00, 0x08, 0x00, 0xC0, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0xC0, 0x00, 0x26, 0x00, 0xC0, 0x00, 0x26, 0x00, 0xC0, 0x00, 0x19, 0x00, 0xC0, 0x00,\n\t0x95, 0x00, 0xC0, 0x00, 0x2B, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,\n\t0xC0, 0x00, 0xC0, 0x00, 0x25, 0x00, 0x00, 0x00, 0x34, 0x00, 0x01, 0x08, 0x1B, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x48, 0x48, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x25, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x04, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x31, 0x33, 0x33, 0x31, 0x32, 0x30, 0x30, 0x5F, 0x4E,\n\t0x6F, 0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38,\n\t0x2E, 0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x50, 0x14, 0x00, 0x52, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x6D,\n\t0x5F, 0x75, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80,\n\t0xF0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,\n\t0xF0, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08, 0x1A, 0x00, 0x00, 0x00,\n\t0x1A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x09, 0x00, 0x06, 0x00, 0x2E, 0x00, 0x00, 0x00,\n\t0x36, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,\n\t0x08, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x30, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0xFA, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x12, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x91, 0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00,\n\t0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x0B, 0x08,\n\t0x0A, 0x00, 0x09, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00,\n\t0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x09, 0x00, 0x09, 0x00,\n\t0x08, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x34, 0x05, 0x29, 0x00,\n\t0x2B, 0x00, 0x34, 0x05, 0x13, 0x00, 0x4D, 0x01, 0x08, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0x00, 0x00, 0x00, 0x00, 0x8F, 0x28, 0x00, 0x80, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x02, 0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x4D, 0x61, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,\n\t0x26, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x2E, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x06, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x99, 0x02, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x53, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x43, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48,\n\t0x48, 0x48, 0x0E, 0x8C, 0x48, 0x48, 0x0E, 0x8C, 0x48, 0x48, 0x0E, 0x4C, 0x48, 0x48, 0x0E, 0x4C,\n\t0x50, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x17, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08,\n\t0x1A, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x09, 0x00, 0x06, 0x00,\n\t0x2E, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x36, 0x00, 0x00, 0x00, 0x08, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x27, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48, 0x48, 0x14, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x00, 0xC0,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x06, 0x06, 0x0B, 0x08, 0x0A, 0x00, 0x09, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x02, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x0A, 0x00,\n\t0x09, 0x00, 0x09, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0x34, 0x05, 0x29, 0x00, 0x2B, 0x00, 0x34, 0x05, 0x13, 0x00, 0x4D, 0x01, 0x08, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x28, 0x00, 0x80, 0x26, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x02, 0x07, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0xFF, 0x1F, 0xFF, 0x1F,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x4D, 0x61, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x3A, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x2C, 0x00, 0x00, 0x00, 0x09, 0x00, 0x06, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0x99, 0x02, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x53, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x43, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x50, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x26, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x12, 0x00, 0x00, 0x00,\n\t0xF1, 0xF1, 0x03, 0x08, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x0A, 0x00, 0x06, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x08, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x02, 0x05, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x00,\n\t0x0B, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,\n\t0x1C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48,\n\t0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xFF, 0x3B, 0x00, 0x00,\n\t0xBB, 0x01, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x0B, 0x08, 0x0A, 0x00, 0x09, 0x00, 0x08, 0x00, 0x0A, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00,\n\t0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x0A, 0x00, 0x09, 0x00, 0x09, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x0A, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0x34, 0x05, 0x29, 0x00, 0x2B, 0x00, 0x34, 0x05, 0x13, 0x00, 0x4D, 0x01,\n\t0x08, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x28, 0x00, 0x80,\n\t0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x02,\n\t0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00,\n\t0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0xFF, 0xEF,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x4D, 0x61, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x38, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x06, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0x99, 0x02, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x53, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x43, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x50, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00,\n\t0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\n\t0x11, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08, 0x1A, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x09, 0x00, 0x06, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,\n\t0x38, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x08, 0x14, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x00,\n\t0xFA, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x36, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0xF1, 0xF1, 0x03, 0x48, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91,\n\t0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x0B, 0x08, 0x0A, 0x00, 0x09, 0x00,\n\t0x08, 0x00, 0x0A, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x02, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x09, 0x00, 0x09, 0x00, 0x08, 0x00, 0x08, 0x00,\n\t0x0A, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x34, 0x05, 0x29, 0x00, 0x2B, 0x00, 0x34, 0x05,\n\t0x13, 0x00, 0x4D, 0x01, 0x08, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x0B, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00,\n\t0x8F, 0x28, 0x00, 0x80, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x33, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,\n\t0x01, 0x01, 0x00, 0x02, 0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x20, 0x20, 0x10, 0x00, 0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x10, 0x22, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x4D, 0x61, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,\n\t0x38, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x2E, 0x00, 0x00, 0x00, 0x09, 0x00, 0x06, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x99, 0x02, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x53, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x43, 0x00, 0x07,\n\t0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x25, 0x00, 0x1F, 0x00,\n\t0x28, 0x00, 0x23, 0x00, 0x28, 0x00, 0x23, 0x00, 0x25, 0x00, 0x20, 0x00, 0x0A, 0x00, 0x09, 0x00,\n\t0x08, 0x00, 0x0A, 0x00, 0x25, 0x00, 0x1F, 0x00, 0x28, 0x00, 0x23, 0x00, 0x28, 0x00, 0x23, 0x00,\n\t0x25, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x03, 0x03, 0x05, 0x04, 0x09, 0x07, 0x0B, 0x00,\n\t0x14, 0x1E, 0x8A, 0x71, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0xAD, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0xFC, 0x0E, 0x00, 0x00,\n\t0x3D, 0x00, 0x99, 0x00, 0x38, 0x00, 0x99, 0x00, 0x41, 0x00, 0x99, 0x00, 0x90, 0x00, 0x99, 0x00,\n\t0x05, 0x00, 0x99, 0x00, 0x90, 0x00, 0x99, 0x00, 0x05, 0x00, 0x99, 0x00, 0x49, 0x00, 0x34, 0x00,\n\t0x80, 0x00, 0x99, 0x00, 0x04, 0x00, 0x99, 0x00, 0x1B, 0x00, 0x08, 0x00, 0x99, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x99, 0x00, 0x1E, 0x00, 0x99, 0x00, 0x1E, 0x00, 0x99, 0x00, 0x18, 0x00, 0x99, 0x00,\n\t0x95, 0x00, 0x99, 0x00, 0x23, 0x00, 0x99, 0x00, 0x99, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,\n\t0x99, 0x00, 0x99, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x44, 0x00, 0x01, 0x08, 0x24, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x48, 0x48, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x2D, 0x08, 0x11, 0x00, 0x00, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x31, 0x36, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5F, 0x4E,\n\t0x6F, 0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38,\n\t0x2E, 0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x6A, 0x18, 0x00, 0x77, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x6D,\n\t0x5F, 0x75, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80,\n\t0xF0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,\n\t0x20, 0x01, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x44, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0x17, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x10,\n\t0x02, 0x00, 0x00, 0x10, 0x14, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08, 0x1D, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x06, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x3C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,\n\t0x20, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x06, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x38, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00,\n\t0x2C, 0x01, 0x00, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x99, 0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00,\n\t0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x0B, 0x08,\n\t0x0C, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00,\n\t0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0B, 0x00, 0x0B, 0x00,\n\t0x0A, 0x00, 0x0A, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x40, 0x06, 0x31, 0x00,\n\t0x2F, 0x00, 0x40, 0x06, 0x17, 0x00, 0x90, 0x01, 0x0A, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0x00, 0x00, 0x00, 0x00, 0x8C, 0x30, 0x00, 0x80, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x02, 0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x90, 0x61, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,\n\t0x2C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x34, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x06, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x20, 0x03, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x00, 0x32, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x53, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x43, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x48, 0x48, 0x0C, 0x88, 0x48, 0x48, 0x0C, 0x88, 0x48, 0x48, 0x0C, 0x48, 0x48, 0x48, 0x0C, 0x48,\n\t0x48, 0x48, 0x0E, 0x8C, 0x48, 0x48, 0x0E, 0x8C, 0x48, 0x48, 0x0E, 0x4C, 0x48, 0x48, 0x0E, 0x4C,\n\t0x60, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00,\n\t0x21, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,\n\t0x10, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x1C, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x10, 0x14, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08,\n\t0x1D, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x06, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00,\n\t0x3C, 0x00, 0x00, 0x00, 0x20, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x06, 0x00, 0x00,\n\t0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x2E, 0x00, 0x00, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48, 0x60, 0x18, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x00, 0xC0,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x66, 0x66, 0x0B, 0x08, 0x0C, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x05, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00, 0x08, 0x00, 0x02, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00,\n\t0x0B, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0x40, 0x06, 0x31, 0x00, 0x2F, 0x00, 0x40, 0x06, 0x17, 0x00, 0x90, 0x01, 0x0A, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x30, 0x00, 0x80, 0x2C, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x02, 0x07, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0xFF, 0x1F, 0xFF, 0x1F,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x90, 0x61, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x42, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x34, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x06, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0x20, 0x03, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x00, 0x32, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x53, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x43, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x60, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,\n\t0x29, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,\n\t0x1D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x10, 0x16, 0x00, 0x00, 0x00,\n\t0xF1, 0xF1, 0x03, 0x08, 0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x0E, 0x00, 0x06, 0x00, 0x34, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00,\n\t0x3A, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x20, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x08, 0x06, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x2C, 0x01, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x22, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48,\n\t0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x99, 0xFF, 0x3B, 0x00, 0x00,\n\t0xBB, 0x01, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x0B, 0x08, 0x0C, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x0C, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00,\n\t0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x0C, 0x00, 0x0B, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x0C, 0x00, 0x0C, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0x40, 0x06, 0x31, 0x00, 0x2F, 0x00, 0x40, 0x06, 0x17, 0x00, 0x90, 0x01,\n\t0x0A, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x0D, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x30, 0x00, 0x80,\n\t0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x02,\n\t0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00,\n\t0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0xFF, 0xEF,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x90, 0x61, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x3E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x06, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0x20, 0x03, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x00, 0x32, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x53, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x43, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x60, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,\n\t0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,\n\t0x1D, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x1D, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x24, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x10,\n\t0x14, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08, 0x1D, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x06, 0x00, 0x34, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,\n\t0x3E, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x20, 0x18, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x08, 0x06, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x2C, 0x01, 0x00, 0x00,\n\t0x2C, 0x01, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0xF1, 0xF1, 0x03, 0x48, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99,\n\t0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x0B, 0x08, 0x0C, 0x00, 0x0B, 0x00,\n\t0x0A, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00, 0x08, 0x00, 0x02, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x05, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0B, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x0A, 0x00,\n\t0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x40, 0x06, 0x31, 0x00, 0x2F, 0x00, 0x40, 0x06,\n\t0x17, 0x00, 0x90, 0x01, 0x0A, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x0D, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00,\n\t0x8C, 0x30, 0x00, 0x80, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x33, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,\n\t0x01, 0x01, 0x00, 0x02, 0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x20, 0x20, 0x10, 0x00, 0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x10, 0x22, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x90, 0x61, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,\n\t0x3E, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x34, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x06, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x20, 0x03, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x00, 0x32, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x53, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x43, 0x00, 0x07,\n\t0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x26, 0x00, 0x1E, 0x00,\n\t0x29, 0x00, 0x24, 0x00, 0x29, 0x00, 0x24, 0x00, 0x26, 0x00, 0x20, 0x00, 0x0C, 0x00, 0x0B, 0x00,\n\t0x0A, 0x00, 0x0C, 0x00, 0x26, 0x00, 0x1E, 0x00, 0x29, 0x00, 0x24, 0x00, 0x29, 0x00, 0x24, 0x00,\n\t0x26, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x0F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x03, 0x03, 0x06, 0x05, 0x0C, 0x08, 0x0D, 0x00,\n\t0x19, 0x24, 0x8C, 0x71, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0xD0, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x03, 0x12, 0x00, 0x00,\n\t0x3D, 0x00, 0x80, 0x00, 0x38, 0x00, 0x80, 0x00, 0x41, 0x00, 0x80, 0x00, 0x90, 0x00, 0x80, 0x00,\n\t0x05, 0x00, 0x80, 0x00, 0x90, 0x00, 0x80, 0x00, 0x05, 0x00, 0x80, 0x00, 0x49, 0x00, 0x34, 0x00,\n\t0x80, 0x00, 0x80, 0x00, 0x04, 0x00, 0x80, 0x00, 0x16, 0x00, 0x08, 0x00, 0x80, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x80, 0x00, 0x19, 0x00, 0x80, 0x00, 0x19, 0x00, 0x80, 0x00, 0x18, 0x00, 0x80, 0x00,\n\t0x95, 0x00, 0x80, 0x00, 0x1D, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,\n\t0x80, 0x00, 0x80, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x54, 0x00, 0x01, 0x08, 0x2D, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x48, 0x48, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x35, 0x08, 0x11, 0x00, 0x00, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x04, 0x00, 0x00\n};\n\n// odinx02_a2_2. For sdram id 1.\nstatic const unsigned char odinx02_a2_2_10NoCfgVersion_V9_8_7_V1_6[EMC_TABLE_SIZE_ODINX02_R7] =\n{\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x32, 0x30, 0x34, 0x30, 0x30, 0x30, 0x5F, 0x4E, 0x6F,\n\t0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38, 0x2E,\n\t0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xE0, 0x1C, 0x03, 0x00, 0x20, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x70,\n\t0x5F, 0x6F, 0x75, 0x74, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x18, 0x40,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x25, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0D, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x27, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x1C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00,\n\t0xBE, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08,\n\t0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00,\n\t0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00,\n\t0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00,\n\t0x15, 0x00, 0xCC, 0x00, 0x0A, 0x00, 0x33, 0x00, 0x03, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F,\n\t0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0xFF, 0x0F, 0xFF, 0x0F, 0x13, 0x07, 0x00, 0x80, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x37, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xFF, 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x33, 0x60, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x65, 0x00, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48,\n\t0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x4C, 0x72, 0x72, 0x0E, 0x4C,\n\t0x0D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08,\n\t0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00,\n\t0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x1C, 0x03, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00,\n\t0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00,\n\t0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00,\n\t0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0xCC, 0x00, 0x09, 0x00, 0x15, 0x00, 0xCC, 0x00, 0x0A, 0x00, 0x33, 0x00, 0x03, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, 0x13, 0x07, 0x00, 0x80, 0x0A, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05, 0x00, 0x02, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x33, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0x65, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x0D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x08, 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xC1, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48,\n\t0x1C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00,\n\t0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, 0xBE, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F,\n\t0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00,\n\t0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00,\n\t0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00, 0x15, 0x00, 0xCC, 0x00, 0x0A, 0x00, 0x33, 0x00,\n\t0x03, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, 0x13, 0x07, 0x00, 0x80,\n\t0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x37, 0x80, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x10, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x00,\n\t0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xEF, 0xFF, 0xEF,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x33, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0x65, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x0D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,\n\t0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x02, 0x00, 0x00, 0x30,\n\t0x02, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0x27, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x48, 0x1C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91,\n\t0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, 0xBE, 0x00, 0x00, 0x00,\n\t0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00,\n\t0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00,\n\t0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00,\n\t0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00,\n\t0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00, 0x15, 0x00, 0xCC, 0x00,\n\t0x0A, 0x00, 0x33, 0x00, 0x03, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00,\n\t0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F,\n\t0x13, 0x07, 0x00, 0x80, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x37, 0x00, 0x05, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,\n\t0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xFF, 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x33, 0x60, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x65, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07,\n\t0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x28, 0x00, 0x28, 0x00,\n\t0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00,\n\t0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00,\n\t0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x92, 0x24, 0x00,\n\t0x49, 0x92, 0x24, 0x00, 0x49, 0x92, 0x24, 0x00, 0x49, 0x92, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x08, 0x4C, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, 0x01, 0x02, 0x03, 0x00,\n\t0x04, 0x05, 0xC3, 0x71, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x4C, 0x02, 0x00, 0x00,\n\t0xB2, 0x00, 0xFF, 0x00, 0xDA, 0x00, 0xFF, 0x00, 0x9D, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,\n\t0x0C, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x0C, 0x00, 0xFF, 0x00, 0x49, 0x00, 0x7F, 0x00,\n\t0x80, 0x00, 0xFF, 0x00, 0x04, 0x00, 0xFF, 0x00, 0xAD, 0x00, 0x08, 0x00, 0xFF, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0xFF, 0x00, 0xC6, 0x00, 0xFF, 0x00, 0xC6, 0x00, 0xFF, 0x00, 0x6D, 0x00, 0xFF, 0x00,\n\t0xFF, 0x00, 0xFF, 0x00, 0xE2, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,\n\t0xFF, 0x00, 0xFF, 0x00, 0x15, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x02, 0x80, 0x18, 0x40, 0x01, 0x00, 0x00, 0x00, 0x5C, 0x0D, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x34, 0x30, 0x38, 0x30, 0x30, 0x30, 0x5F, 0x4E, 0x6F,\n\t0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38, 0x2E,\n\t0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xC0, 0x39, 0x06, 0x00, 0x2C, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x70,\n\t0x5F, 0x75, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0xE0,\n\t0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,\n\t0x4A, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x12, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x30, 0x07, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0F, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x00, 0x01, 0x00, 0x19, 0x00, 0x00, 0x00,\n\t0x21, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,\n\t0x07, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x1A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x4D, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x38, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x03, 0x1C, 0xC0, 0x00, 0x80, 0x00, 0x00,\n\t0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08,\n\t0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00,\n\t0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x98, 0x01, 0x0E, 0x00,\n\t0x1B, 0x00, 0x98, 0x01, 0x0A, 0x00, 0x66, 0x00, 0x04, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F,\n\t0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0x00, 0x00, 0x00, 0x00, 0x22, 0x0D, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x35, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xFF, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x66, 0x60, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x19, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0xCB, 0x00, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48,\n\t0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x4C, 0x72, 0x72, 0x0E, 0x4C,\n\t0x19, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,\n\t0x0F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x07, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08,\n\t0x0F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x00, 0x01, 0x00,\n\t0x19, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x21, 0x00, 0x00, 0x00, 0x07, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x01, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x38, 0x06, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x03, 0x1C, 0xC0,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x0B, 0x08, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00,\n\t0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0x98, 0x01, 0x0E, 0x00, 0x1B, 0x00, 0x98, 0x01, 0x0A, 0x00, 0x66, 0x00, 0x04, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x22, 0x0D, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05, 0x00, 0x02, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x66, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x23, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x15, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0xCB, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x19, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x08, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x08, 0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x01, 0x00, 0x05, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x07, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x81, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48,\n\t0x38, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00,\n\t0xBB, 0x03, 0x1C, 0xC0, 0x00, 0x80, 0x00, 0x00, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0x98, 0x01, 0x0E, 0x00, 0x1B, 0x00, 0x98, 0x01, 0x0A, 0x00, 0x66, 0x00,\n\t0x04, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x22, 0x0D, 0x00, 0x80,\n\t0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x35, 0x80, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00,\n\t0x10, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x00,\n\t0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE2, 0xFF, 0xEF,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x66, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0xCB, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x19, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00,\n\t0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,\n\t0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30,\n\t0x07, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,\n\t0x23, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x07, 0x06, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x81, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00,\n\t0x4D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x48, 0x38, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91,\n\t0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x03, 0x1C, 0xC0, 0x00, 0x80, 0x00, 0x00, 0xBE, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x03, 0x00, 0x02, 0x00,\n\t0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00,\n\t0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x98, 0x01, 0x0E, 0x00, 0x1B, 0x00, 0x98, 0x01,\n\t0x0A, 0x00, 0x66, 0x00, 0x04, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00,\n\t0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00,\n\t0x22, 0x0D, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x35, 0x00, 0x05, 0x05,\n\t0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,\n\t0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xFF, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x66, 0x60, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x23, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0xCB, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07,\n\t0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x21, 0x00, 0x20, 0x00,\n\t0x22, 0x00, 0x21, 0x00, 0x22, 0x00, 0x21, 0x00, 0x21, 0x00, 0x20, 0x00, 0x03, 0x00, 0x02, 0x00,\n\t0x02, 0x00, 0x03, 0x00, 0x21, 0x00, 0x20, 0x00, 0x22, 0x00, 0x21, 0x00, 0x22, 0x00, 0x21, 0x00,\n\t0x21, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x01, 0x7F, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x02, 0x03, 0x02, 0x04, 0x00,\n\t0x07, 0x0A, 0xA4, 0x71, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x35, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x98, 0x04, 0x00, 0x00,\n\t0x59, 0x00, 0xFF, 0x00, 0x6D, 0x00, 0xFF, 0x00, 0x4F, 0x00, 0xFF, 0x00, 0xAF, 0x00, 0xFF, 0x00,\n\t0x06, 0x00, 0xFF, 0x00, 0xAF, 0x00, 0xFF, 0x00, 0x06, 0x00, 0xFF, 0x00, 0x49, 0x00, 0x40, 0x00,\n\t0x80, 0x00, 0xFF, 0x00, 0x04, 0x00, 0xFF, 0x00, 0x57, 0x00, 0x08, 0x00, 0xFF, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0xFF, 0x00, 0x63, 0x00, 0xFF, 0x00, 0x63, 0x00, 0xFF, 0x00, 0x36, 0x00, 0xFF, 0x00,\n\t0xFF, 0x00, 0xFF, 0x00, 0x71, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0xFF, 0x00, 0xFF, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x08, 0x09, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x35, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0xE0, 0x01, 0x00, 0x00, 0x00, 0xD6, 0x06, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x36, 0x36, 0x35, 0x36, 0x30, 0x30, 0x5F, 0x4E, 0x6F,\n\t0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38, 0x2E,\n\t0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x28, 0x0A, 0x00, 0x39, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x6D,\n\t0x5F, 0x75, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80,\n\t0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x2A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,\n\t0x78, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x30, 0x0A, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x11, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x01, 0x00, 0x1E, 0x00, 0x00, 0x00,\n\t0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,\n\t0xE4, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x02, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x23, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,\n\t0x7D, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x24, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x02, 0x0B, 0xC0, 0x00, 0x80, 0x00, 0x00,\n\t0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08,\n\t0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00,\n\t0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00,\n\t0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x9A, 0x02, 0x15, 0x00,\n\t0x1F, 0x00, 0x9A, 0x02, 0x0A, 0x00, 0xA7, 0x00, 0x05, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F,\n\t0x14, 0x00, 0x01, 0x00, 0x06, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0x00, 0x00, 0x00, 0x00, 0xC9, 0x14, 0x00, 0x80, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x33, 0x00, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05, 0x10, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xFF, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0xA7, 0x60, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x1E, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x4C, 0x01, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48,\n\t0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x4C, 0x72, 0x72, 0x0E, 0x4C,\n\t0x28, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08,\n\t0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x01, 0x00,\n\t0x1E, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,\n\t0x26, 0x00, 0x00, 0x00, 0xE4, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x02, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x15, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x24, 0x0A, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x02, 0x0B, 0xC0,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x0B, 0x08, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,\n\t0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0x9A, 0x02, 0x15, 0x00, 0x1F, 0x00, 0x9A, 0x02, 0x0A, 0x00, 0xA7, 0x00, 0x05, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x06, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xC9, 0x14, 0x00, 0x80, 0x16, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05, 0x00, 0x02, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0xA7, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x29, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x1B, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0x4C, 0x01, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x28, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x0B, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x08, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x04, 0x00, 0x05, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,\n\t0x24, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xE4, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x79, 0x02, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48,\n\t0x24, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00,\n\t0xBB, 0x02, 0x0B, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00,\n\t0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0x9A, 0x02, 0x15, 0x00, 0x1F, 0x00, 0x9A, 0x02, 0x0A, 0x00, 0xA7, 0x00,\n\t0x05, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x06, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xC9, 0x14, 0x00, 0x80,\n\t0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x33, 0x80, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05,\n\t0x10, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02,\n\t0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00,\n\t0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE2, 0xFF, 0xEF,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0xA7, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, 0x05, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0x4C, 0x01, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x28, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,\n\t0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30,\n\t0x0A, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x05, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,\n\t0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xE4, 0x09, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x79, 0x02, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x00,\n\t0x7D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x48, 0x24, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91,\n\t0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x02, 0x0B, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x05, 0x00, 0x04, 0x00,\n\t0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00,\n\t0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x9A, 0x02, 0x15, 0x00, 0x1F, 0x00, 0x9A, 0x02,\n\t0x0A, 0x00, 0xA7, 0x00, 0x05, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00,\n\t0x06, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00,\n\t0xC9, 0x14, 0x00, 0x80, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x33, 0x00, 0x05, 0x05,\n\t0x00, 0x00, 0x05, 0x05, 0x10, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,\n\t0x11, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xFF, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0xA7, 0x60, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x28, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x1E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x4C, 0x01, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07,\n\t0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x22, 0x00, 0x20, 0x00,\n\t0x24, 0x00, 0x21, 0x00, 0x24, 0x00, 0x21, 0x00, 0x22, 0x00, 0x20, 0x00, 0x05, 0x00, 0x04, 0x00,\n\t0x04, 0x00, 0x05, 0x00, 0x22, 0x00, 0x20, 0x00, 0x24, 0x00, 0x21, 0x00, 0x24, 0x00, 0x21, 0x00,\n\t0x22, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x03, 0x04, 0x03, 0x04, 0x03, 0x06, 0x00,\n\t0x0A, 0x0F, 0xA5, 0x71, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x57, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x7E, 0x07, 0x00, 0x00,\n\t0x3D, 0x00, 0xFF, 0x00, 0x43, 0x00, 0xFF, 0x00, 0x41, 0x00, 0xFF, 0x00, 0x90, 0x00, 0xFF, 0x00,\n\t0x05, 0x00, 0xFF, 0x00, 0x90, 0x00, 0xFF, 0x00, 0x05, 0x00, 0xFF, 0x00, 0x49, 0x00, 0x34, 0x00,\n\t0x80, 0x00, 0xFF, 0x00, 0x04, 0x00, 0xFF, 0x00, 0x35, 0x00, 0x08, 0x00, 0xFF, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0xFF, 0x00, 0x3D, 0x00, 0xFF, 0x00, 0x3D, 0x00, 0xFF, 0x00, 0x29, 0x00, 0xFF, 0x00,\n\t0xD8, 0x00, 0xFF, 0x00, 0x45, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,\n\t0xFF, 0x00, 0xFF, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x24, 0x00, 0x01, 0x08, 0x12, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x35, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x04, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5F, 0x4E, 0x6F,\n\t0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38, 0x2E,\n\t0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x35, 0x0C, 0x00, 0x39, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x6D,\n\t0x5F, 0x75, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80,\n\t0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x33, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,\n\t0x90, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x22, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x15, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x30, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x13, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0xF0, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x23, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,\n\t0x96, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x30, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x02, 0x07, 0xC0, 0x00, 0x80, 0x00, 0x00,\n\t0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08,\n\t0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,\n\t0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00,\n\t0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x20, 0x03, 0x19, 0x00,\n\t0x1F, 0x00, 0x20, 0x03, 0x0C, 0x00, 0xC8, 0x00, 0x06, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0x00, 0x00, 0x00, 0x00, 0xC8, 0x18, 0x00, 0x80, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x0A, 0x01, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x10, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0xC8, 0x60, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0x17, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x20, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x05, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x90, 0x01, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48,\n\t0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x4C, 0x72, 0x72, 0x0E, 0x4C,\n\t0x30, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08,\n\t0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x05, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,\n\t0x27, 0x00, 0x00, 0x00, 0xF0, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x02, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x19, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x30, 0x0C, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x02, 0x07, 0xC0,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x0B, 0x08, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00,\n\t0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0x20, 0x03, 0x19, 0x00, 0x1F, 0x00, 0x20, 0x03, 0x0C, 0x00, 0xC8, 0x00, 0x06, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x18, 0x00, 0x80, 0x17, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0xC8, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x2D, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0x90, 0x01, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x30, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x0F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x0A, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x08, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x03, 0x00, 0x05, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00,\n\t0x25, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xF0, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xFC, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48,\n\t0x30, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00,\n\t0xBB, 0x02, 0x07, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,\n\t0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x06, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0x20, 0x03, 0x19, 0x00, 0x1F, 0x00, 0x20, 0x03, 0x0C, 0x00, 0xC8, 0x00,\n\t0x06, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x07, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x18, 0x00, 0x80,\n\t0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x11, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x01, 0x00, 0x02,\n\t0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00,\n\t0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xE2, 0xFF, 0xEF,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0xC8, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x29, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0x90, 0x01, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x30, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00,\n\t0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,\n\t0x0F, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,\n\t0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30,\n\t0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0x29, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xF0, 0x0B, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xFC, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00,\n\t0x96, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x48, 0x30, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91,\n\t0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x02, 0x07, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x06, 0x00, 0x05, 0x00,\n\t0x05, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00,\n\t0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x20, 0x03, 0x19, 0x00, 0x1F, 0x00, 0x20, 0x03,\n\t0x0C, 0x00, 0xC8, 0x00, 0x06, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x07, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00,\n\t0xC8, 0x18, 0x00, 0x80, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x33, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x11, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,\n\t0x01, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x10, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0xC8, 0x60, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n\t0x29, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x90, 0x01, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07,\n\t0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x23, 0x00, 0x1F, 0x00,\n\t0x24, 0x00, 0x22, 0x00, 0x24, 0x00, 0x22, 0x00, 0x23, 0x00, 0x20, 0x00, 0x06, 0x00, 0x05, 0x00,\n\t0x05, 0x00, 0x06, 0x00, 0x23, 0x00, 0x1F, 0x00, 0x24, 0x00, 0x22, 0x00, 0x24, 0x00, 0x22, 0x00,\n\t0x23, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x03, 0x03, 0x04, 0x03, 0x06, 0x04, 0x07, 0x00,\n\t0x0D, 0x12, 0x86, 0x71, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x68, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x02, 0x09, 0x00, 0x00,\n\t0x3D, 0x00, 0xFF, 0x00, 0x38, 0x00, 0xFF, 0x00, 0x41, 0x00, 0xFF, 0x00, 0x90, 0x00, 0xFF, 0x00,\n\t0x05, 0x00, 0xFF, 0x00, 0x90, 0x00, 0xFF, 0x00, 0x05, 0x00, 0xFF, 0x00, 0x49, 0x00, 0x34, 0x00,\n\t0x80, 0x00, 0xFF, 0x00, 0x04, 0x00, 0xFF, 0x00, 0x2C, 0x00, 0x08, 0x00, 0xFF, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0xFF, 0x00, 0x32, 0x00, 0xFF, 0x00, 0x32, 0x00, 0xFF, 0x00, 0x22, 0x00, 0xFF, 0x00,\n\t0xB4, 0x00, 0xFF, 0x00, 0x3A, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,\n\t0xFF, 0x00, 0xFF, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x24, 0x00, 0x01, 0x08, 0x12, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x35, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x04, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x31, 0x30, 0x36, 0x35, 0x36, 0x30, 0x30, 0x5F, 0x4E,\n\t0x6F, 0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38,\n\t0x2E, 0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x80, 0x42, 0x10, 0x00, 0x45, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x6D,\n\t0x5F, 0x75, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80,\n\t0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x2D, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x10, 0x0D, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08, 0x17, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x06, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0x2F, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00,\n\t0xFC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x29, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,\n\t0xC8, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x10, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48, 0x3C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x91, 0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x01, 0xC0, 0x00, 0x80, 0x00, 0x00,\n\t0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x0B, 0x08,\n\t0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00,\n\t0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x07, 0x00, 0x07, 0x00,\n\t0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x2A, 0x04, 0x21, 0x00,\n\t0x25, 0x00, 0x2A, 0x04, 0x0F, 0x00, 0x0B, 0x01, 0x07, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x09, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0x00, 0x00, 0x00, 0x00, 0xAB, 0x20, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x0A, 0x01, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x10, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0B, 0x61, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x27, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x05, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x14, 0x02, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x03, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48,\n\t0x48, 0x48, 0x0E, 0x8C, 0x48, 0x48, 0x0E, 0x8C, 0x48, 0x48, 0x0E, 0x4C, 0x48, 0x48, 0x0E, 0x4C,\n\t0x40, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,\n\t0x17, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x0B, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x0D, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08,\n\t0x17, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x06, 0x00, 0x05, 0x00,\n\t0x27, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,\n\t0x2F, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x21, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48, 0x3C, 0x10, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x01, 0xC0,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x06, 0x06, 0x0B, 0x08, 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00,\n\t0x07, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0x2A, 0x04, 0x21, 0x00, 0x25, 0x00, 0x2A, 0x04, 0x0F, 0x00, 0x0B, 0x01, 0x07, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x09, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x20, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x61, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x26, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0x14, 0x02, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x40, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x21, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x00, 0x00, 0x00,\n\t0xF1, 0xF1, 0x03, 0x08, 0x15, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x07, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00,\n\t0x2D, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xFF, 0x03, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00,\n\t0x17, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48,\n\t0x3C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xFF, 0x3B, 0x00, 0x00,\n\t0xBB, 0x01, 0x01, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x0B, 0x08, 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x08, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00,\n\t0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x08, 0x00, 0x07, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x08, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0x2A, 0x04, 0x21, 0x00, 0x25, 0x00, 0x2A, 0x04, 0x0F, 0x00, 0x0B, 0x01,\n\t0x07, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x09, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x20, 0x00, 0x80,\n\t0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x11, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x01, 0x00, 0x02,\n\t0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00,\n\t0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xE2, 0xFF, 0xEF,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x61, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x05, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0x14, 0x02, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x40, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,\n\t0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\n\t0x0D, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08, 0x17, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x80, 0x06, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00,\n\t0x31, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00,\n\t0xC8, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x2B, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0xF1, 0xF1, 0x03, 0x48, 0x3C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91,\n\t0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x01, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x0B, 0x08, 0x08, 0x00, 0x07, 0x00,\n\t0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x07, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00,\n\t0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x2A, 0x04, 0x21, 0x00, 0x25, 0x00, 0x2A, 0x04,\n\t0x0F, 0x00, 0x0B, 0x01, 0x07, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x09, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00,\n\t0xAB, 0x20, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x33, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x11, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,\n\t0x01, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x10, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x61, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x31, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x27, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x14, 0x02, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07,\n\t0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x24, 0x00, 0x1F, 0x00,\n\t0x26, 0x00, 0x23, 0x00, 0x26, 0x00, 0x23, 0x00, 0x24, 0x00, 0x20, 0x00, 0x08, 0x00, 0x07, 0x00,\n\t0x06, 0x00, 0x08, 0x00, 0x24, 0x00, 0x1F, 0x00, 0x26, 0x00, 0x23, 0x00, 0x26, 0x00, 0x23, 0x00,\n\t0x24, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x03, 0x03, 0x05, 0x03, 0x08, 0x05, 0x09, 0x00,\n\t0x11, 0x18, 0x88, 0x71, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x8B, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0xFF, 0x0B, 0x00, 0x00,\n\t0x3D, 0x00, 0xC0, 0x00, 0x38, 0x00, 0xC0, 0x00, 0x41, 0x00, 0xC0, 0x00, 0x90, 0x00, 0xC0, 0x00,\n\t0x05, 0x00, 0xC0, 0x00, 0x90, 0x00, 0xC0, 0x00, 0x05, 0x00, 0xC0, 0x00, 0x49, 0x00, 0x34, 0x00,\n\t0x80, 0x00, 0xC0, 0x00, 0x04, 0x00, 0xC0, 0x00, 0x21, 0x00, 0x08, 0x00, 0xC0, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0xC0, 0x00, 0x26, 0x00, 0xC0, 0x00, 0x26, 0x00, 0xC0, 0x00, 0x19, 0x00, 0xC0, 0x00,\n\t0x95, 0x00, 0xC0, 0x00, 0x2B, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,\n\t0xC0, 0x00, 0xC0, 0x00, 0x25, 0x00, 0x00, 0x00, 0x34, 0x00, 0x01, 0x08, 0x1B, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x48, 0x48, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x25, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x04, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x31, 0x33, 0x33, 0x31, 0x32, 0x30, 0x30, 0x5F, 0x4E,\n\t0x6F, 0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38,\n\t0x2E, 0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x50, 0x14, 0x00, 0x52, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x6D,\n\t0x5F, 0x75, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80,\n\t0xF0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,\n\t0xF0, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08, 0x1A, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x09, 0x00, 0x06, 0x00, 0x2E, 0x00, 0x00, 0x00,\n\t0x36, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,\n\t0x08, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x30, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0xFA, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x12, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x91, 0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00,\n\t0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x0B, 0x08,\n\t0x0A, 0x00, 0x09, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00,\n\t0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x09, 0x00, 0x09, 0x00,\n\t0x08, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x34, 0x05, 0x29, 0x00,\n\t0x2B, 0x00, 0x34, 0x05, 0x13, 0x00, 0x4D, 0x01, 0x08, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0x00, 0x00, 0x00, 0x00, 0x8F, 0x28, 0x00, 0x80, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x02, 0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x4D, 0x61, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,\n\t0x26, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x2E, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x06, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x99, 0x02, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x53, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x43, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48,\n\t0x48, 0x48, 0x0E, 0x8C, 0x48, 0x48, 0x0E, 0x8C, 0x48, 0x48, 0x0E, 0x4C, 0x48, 0x48, 0x0E, 0x4C,\n\t0x50, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x17, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08,\n\t0x1A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x09, 0x00, 0x06, 0x00,\n\t0x2E, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x36, 0x00, 0x00, 0x00, 0x08, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x27, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48, 0x48, 0x14, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x00, 0xC0,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x06, 0x06, 0x0B, 0x08, 0x0A, 0x00, 0x09, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x02, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x0A, 0x00,\n\t0x09, 0x00, 0x09, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0x34, 0x05, 0x29, 0x00, 0x2B, 0x00, 0x34, 0x05, 0x13, 0x00, 0x4D, 0x01, 0x08, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x28, 0x00, 0x80, 0x26, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x02, 0x07, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0xFF, 0x1F, 0xFF, 0x1F,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x4D, 0x61, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x3A, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x2C, 0x00, 0x00, 0x00, 0x09, 0x00, 0x06, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0x99, 0x02, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x53, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x43, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x50, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x28, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x12, 0x00, 0x00, 0x00,\n\t0xF1, 0xF1, 0x03, 0x08, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x0A, 0x00, 0x06, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x08, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x02, 0x05, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x00,\n\t0x0B, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,\n\t0x1C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48,\n\t0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xFF, 0x3B, 0x00, 0x00,\n\t0xBB, 0x01, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x0B, 0x08, 0x0A, 0x00, 0x09, 0x00, 0x08, 0x00, 0x0A, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00,\n\t0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x0A, 0x00, 0x09, 0x00, 0x09, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x0A, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0x34, 0x05, 0x29, 0x00, 0x2B, 0x00, 0x34, 0x05, 0x13, 0x00, 0x4D, 0x01,\n\t0x08, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x28, 0x00, 0x80,\n\t0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x11, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x02,\n\t0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00,\n\t0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0xFF, 0xEF,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x4D, 0x61, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x38, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x06, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0x99, 0x02, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x53, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x43, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x50, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00,\n\t0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\n\t0x11, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08, 0x1A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x80, 0x09, 0x00, 0x06, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,\n\t0x38, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x08, 0x14, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x00,\n\t0xFA, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x36, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0xF1, 0xF1, 0x03, 0x48, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91,\n\t0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x0B, 0x08, 0x0A, 0x00, 0x09, 0x00,\n\t0x08, 0x00, 0x0A, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x02, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x09, 0x00, 0x09, 0x00, 0x08, 0x00, 0x08, 0x00,\n\t0x0A, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x34, 0x05, 0x29, 0x00, 0x2B, 0x00, 0x34, 0x05,\n\t0x13, 0x00, 0x4D, 0x01, 0x08, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x0B, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00,\n\t0x8F, 0x28, 0x00, 0x80, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x33, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x11, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,\n\t0x01, 0x01, 0x00, 0x02, 0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x20, 0x20, 0x10, 0x00, 0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x10, 0x22, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x4D, 0x61, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,\n\t0x38, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x2E, 0x00, 0x00, 0x00, 0x09, 0x00, 0x06, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x99, 0x02, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x53, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x43, 0x00, 0x07,\n\t0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x25, 0x00, 0x1F, 0x00,\n\t0x28, 0x00, 0x23, 0x00, 0x28, 0x00, 0x23, 0x00, 0x25, 0x00, 0x20, 0x00, 0x0A, 0x00, 0x09, 0x00,\n\t0x08, 0x00, 0x0A, 0x00, 0x25, 0x00, 0x1F, 0x00, 0x28, 0x00, 0x23, 0x00, 0x28, 0x00, 0x23, 0x00,\n\t0x25, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x03, 0x03, 0x06, 0x04, 0x09, 0x07, 0x0B, 0x00,\n\t0x14, 0x1E, 0x8A, 0x71, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0xAD, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0xFC, 0x0E, 0x00, 0x00,\n\t0x3D, 0x00, 0x99, 0x00, 0x38, 0x00, 0x99, 0x00, 0x41, 0x00, 0x99, 0x00, 0x90, 0x00, 0x99, 0x00,\n\t0x05, 0x00, 0x99, 0x00, 0x90, 0x00, 0x99, 0x00, 0x05, 0x00, 0x99, 0x00, 0x49, 0x00, 0x34, 0x00,\n\t0x80, 0x00, 0x99, 0x00, 0x04, 0x00, 0x99, 0x00, 0x1B, 0x00, 0x08, 0x00, 0x99, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x99, 0x00, 0x1E, 0x00, 0x99, 0x00, 0x1E, 0x00, 0x99, 0x00, 0x18, 0x00, 0x99, 0x00,\n\t0x95, 0x00, 0x99, 0x00, 0x23, 0x00, 0x99, 0x00, 0x99, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,\n\t0x99, 0x00, 0x99, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x44, 0x00, 0x01, 0x08, 0x24, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x48, 0x48, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x2D, 0x08, 0x11, 0x00, 0x00, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x31, 0x36, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5F, 0x4E,\n\t0x6F, 0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38,\n\t0x2E, 0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x6A, 0x18, 0x00, 0x77, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x6D,\n\t0x5F, 0x75, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80,\n\t0xF0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,\n\t0x20, 0x01, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x44, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0x17, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x10,\n\t0x02, 0x00, 0x00, 0x10, 0x14, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08, 0x1D, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0C, 0x00, 0x06, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x3C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,\n\t0x20, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x06, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x38, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00,\n\t0x2C, 0x01, 0x00, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x99, 0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00,\n\t0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x0B, 0x08,\n\t0x0C, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00,\n\t0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0B, 0x00, 0x0B, 0x00,\n\t0x0A, 0x00, 0x0A, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x40, 0x06, 0x31, 0x00,\n\t0x2F, 0x00, 0x40, 0x06, 0x17, 0x00, 0x90, 0x01, 0x0A, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0x00, 0x00, 0x00, 0x00, 0x8C, 0x30, 0x00, 0x80, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x02, 0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x90, 0x61, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,\n\t0x2C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x34, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x06, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x20, 0x03, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x00, 0x32, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x53, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x43, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x48, 0x48, 0x0C, 0x88, 0x48, 0x48, 0x0C, 0x88, 0x48, 0x48, 0x0C, 0x48, 0x48, 0x48, 0x0C, 0x48,\n\t0x48, 0x48, 0x0E, 0x8C, 0x48, 0x48, 0x0E, 0x8C, 0x48, 0x48, 0x0E, 0x4C, 0x48, 0x48, 0x0E, 0x4C,\n\t0x60, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,\n\t0x21, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,\n\t0x10, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x1C, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x10, 0x14, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08,\n\t0x1D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0C, 0x00, 0x06, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00,\n\t0x3C, 0x00, 0x00, 0x00, 0x20, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x06, 0x00, 0x00,\n\t0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x2E, 0x00, 0x00, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48, 0x60, 0x18, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x00, 0xC0,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x66, 0x66, 0x0B, 0x08, 0x0C, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x05, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00, 0x08, 0x00, 0x02, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00,\n\t0x0B, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0x40, 0x06, 0x31, 0x00, 0x2F, 0x00, 0x40, 0x06, 0x17, 0x00, 0x90, 0x01, 0x0A, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x30, 0x00, 0x80, 0x2C, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x02, 0x07, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0xFF, 0x1F, 0xFF, 0x1F,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x90, 0x61, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x42, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x34, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x06, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0x20, 0x03, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x00, 0x32, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x53, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x43, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x60, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,\n\t0x2B, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,\n\t0x1D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x10, 0x16, 0x00, 0x00, 0x00,\n\t0xF1, 0xF1, 0x03, 0x08, 0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x0E, 0x00, 0x06, 0x00, 0x34, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00,\n\t0x3A, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x20, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x08, 0x06, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x2C, 0x01, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x22, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48,\n\t0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x99, 0xFF, 0x3B, 0x00, 0x00,\n\t0xBB, 0x01, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x0B, 0x08, 0x0C, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x0C, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00,\n\t0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x0C, 0x00, 0x0B, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x0C, 0x00, 0x0C, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0x40, 0x06, 0x31, 0x00, 0x2F, 0x00, 0x40, 0x06, 0x17, 0x00, 0x90, 0x01,\n\t0x0A, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x0D, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x30, 0x00, 0x80,\n\t0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x11, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x02,\n\t0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00,\n\t0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0xFF, 0xEF,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x90, 0x61, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x3E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x06, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0x20, 0x03, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x00, 0x32, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x53, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x43, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x60, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,\n\t0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,\n\t0x1D, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x1D, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x24, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x10,\n\t0x14, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08, 0x1D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x80, 0x0C, 0x00, 0x06, 0x00, 0x34, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,\n\t0x3E, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x20, 0x18, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x08, 0x06, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x2C, 0x01, 0x00, 0x00,\n\t0x2C, 0x01, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0xF1, 0xF1, 0x03, 0x48, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99,\n\t0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x0B, 0x08, 0x0C, 0x00, 0x0B, 0x00,\n\t0x0A, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00, 0x08, 0x00, 0x02, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x05, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0B, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x0A, 0x00,\n\t0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x40, 0x06, 0x31, 0x00, 0x2F, 0x00, 0x40, 0x06,\n\t0x17, 0x00, 0x90, 0x01, 0x0A, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x0D, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00,\n\t0x8C, 0x30, 0x00, 0x80, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x33, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x11, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,\n\t0x01, 0x01, 0x00, 0x02, 0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x20, 0x20, 0x10, 0x00, 0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x10, 0x22, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x90, 0x61, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,\n\t0x3E, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x34, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x06, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x20, 0x03, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x00, 0x32, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x53, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x43, 0x00, 0x07,\n\t0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x26, 0x00, 0x1E, 0x00,\n\t0x29, 0x00, 0x24, 0x00, 0x29, 0x00, 0x24, 0x00, 0x26, 0x00, 0x20, 0x00, 0x0C, 0x00, 0x0B, 0x00,\n\t0x0A, 0x00, 0x0C, 0x00, 0x26, 0x00, 0x1E, 0x00, 0x29, 0x00, 0x24, 0x00, 0x29, 0x00, 0x24, 0x00,\n\t0x26, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x0F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x03, 0x03, 0x06, 0x05, 0x0C, 0x08, 0x0D, 0x00,\n\t0x19, 0x24, 0x8C, 0x71, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0xD0, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x03, 0x12, 0x00, 0x00,\n\t0x3D, 0x00, 0x80, 0x00, 0x38, 0x00, 0x80, 0x00, 0x41, 0x00, 0x80, 0x00, 0x90, 0x00, 0x80, 0x00,\n\t0x05, 0x00, 0x80, 0x00, 0x90, 0x00, 0x80, 0x00, 0x05, 0x00, 0x80, 0x00, 0x49, 0x00, 0x34, 0x00,\n\t0x80, 0x00, 0x80, 0x00, 0x04, 0x00, 0x80, 0x00, 0x16, 0x00, 0x08, 0x00, 0x80, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x80, 0x00, 0x19, 0x00, 0x80, 0x00, 0x19, 0x00, 0x80, 0x00, 0x18, 0x00, 0x80, 0x00,\n\t0x95, 0x00, 0x80, 0x00, 0x1D, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,\n\t0x80, 0x00, 0x80, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x54, 0x00, 0x01, 0x08, 0x2D, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x48, 0x48, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x35, 0x08, 0x11, 0x00, 0x00, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x04, 0x00, 0x00\n};\n\n// odinx02_a2_0_3. For sdram id 7.\nstatic const unsigned char odinx02_a2_7_10NoCfgVersion_V9_8_7_V1_6[EMC_TABLE_SIZE_ODINX02_R7] =\n{\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x32, 0x30, 0x34, 0x30, 0x30, 0x30, 0x5F, 0x4E, 0x6F,\n\t0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38, 0x2E,\n\t0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xE0, 0x1C, 0x03, 0x00, 0x20, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x70,\n\t0x5F, 0x6F, 0x75, 0x74, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x18, 0x40,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x3A, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0D, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x3B, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x1C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00,\n\t0xBE, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08,\n\t0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00,\n\t0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00,\n\t0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00,\n\t0x15, 0x00, 0xCC, 0x00, 0x0A, 0x00, 0x33, 0x00, 0x03, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F,\n\t0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0xFF, 0x0F, 0xFF, 0x0F, 0x13, 0x07, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x37, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xFF, 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x33, 0x60, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x65, 0x00, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48,\n\t0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x4C, 0x72, 0x72, 0x0E, 0x4C,\n\t0x0D, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08,\n\t0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,\n\t0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x1C, 0x03, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00,\n\t0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00,\n\t0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00,\n\t0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0xCC, 0x00, 0x09, 0x00, 0x15, 0x00, 0xCC, 0x00, 0x0A, 0x00, 0x33, 0x00, 0x03, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, 0x13, 0x07, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x33, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0x65, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x0D, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x08, 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xC1, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48,\n\t0x1C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00,\n\t0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, 0xBE, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F,\n\t0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00, 0x10, 0x00, 0x14, 0x00,\n\t0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00,\n\t0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x14, 0x00, 0x14, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00, 0x15, 0x00, 0xCC, 0x00, 0x0A, 0x00, 0x33, 0x00,\n\t0x03, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F, 0x13, 0x07, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x37, 0x80, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x00,\n\t0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xEF, 0xFF, 0xEF,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x33, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0x65, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x0D, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00,\n\t0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x02, 0x00, 0x00, 0x30,\n\t0x02, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00,\n\t0x3B, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x48, 0x1C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91,\n\t0xBF, 0x3B, 0x00, 0x00, 0xA0, 0x00, 0x2C, 0x00, 0x00, 0x80, 0x00, 0x00, 0xBE, 0x00, 0x00, 0x00,\n\t0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x14, 0x00, 0x12, 0x00,\n\t0x10, 0x00, 0x14, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00,\n\t0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2E, 0x00,\n\t0x33, 0x00, 0x30, 0x00, 0x33, 0x00, 0x35, 0x00, 0x30, 0x00, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x12, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00,\n\t0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0xCC, 0x00, 0x09, 0x00, 0x15, 0x00, 0xCC, 0x00,\n\t0x0A, 0x00, 0x33, 0x00, 0x03, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00,\n\t0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0xFF, 0x0F, 0xFF, 0x0F,\n\t0x13, 0x07, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x37, 0x00, 0x05, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,\n\t0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xFF, 0xEF, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x33, 0x60, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x65, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07,\n\t0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x28, 0x00, 0x28, 0x00,\n\t0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00,\n\t0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00,\n\t0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x92, 0x24, 0x00,\n\t0x49, 0x92, 0x24, 0x00, 0x49, 0x92, 0x24, 0x00, 0x49, 0x92, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x08, 0x4C, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, 0x01, 0x02, 0x03, 0x00,\n\t0x04, 0x05, 0xA3, 0x72, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x4C, 0x02, 0x00, 0x00,\n\t0xB2, 0x00, 0xFF, 0x00, 0xDA, 0x00, 0xFF, 0x00, 0x9D, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,\n\t0x0C, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x0C, 0x00, 0xFF, 0x00, 0x49, 0x00, 0x7F, 0x00,\n\t0x80, 0x00, 0xFF, 0x00, 0x04, 0x00, 0xFF, 0x00, 0xAD, 0x00, 0x08, 0x00, 0xFF, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0xFF, 0x00, 0xC6, 0x00, 0xFF, 0x00, 0xC6, 0x00, 0xFF, 0x00, 0x6D, 0x00, 0xFF, 0x00,\n\t0xFF, 0x00, 0xFF, 0x00, 0xE2, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,\n\t0xFF, 0x00, 0xFF, 0x00, 0x15, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x02, 0x80, 0x18, 0x40, 0x01, 0x00, 0x00, 0x00, 0x5C, 0x0D, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x34, 0x30, 0x38, 0x30, 0x30, 0x30, 0x5F, 0x4E, 0x6F,\n\t0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38, 0x2E,\n\t0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xC0, 0x39, 0x06, 0x00, 0x2C, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x70,\n\t0x5F, 0x75, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0xE0,\n\t0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,\n\t0x73, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x12, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x30, 0x07, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0F, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x19, 0x00, 0x00, 0x00,\n\t0x21, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,\n\t0x07, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x1A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x76, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x38, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x03, 0x1C, 0xC0, 0x00, 0x80, 0x00, 0x00,\n\t0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08,\n\t0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00,\n\t0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x98, 0x01, 0x0E, 0x00,\n\t0x1B, 0x00, 0x98, 0x01, 0x0A, 0x00, 0x66, 0x00, 0x04, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F,\n\t0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0x00, 0x00, 0x00, 0x00, 0x22, 0x0D, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x35, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xFF, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x66, 0x60, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x19, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0xCB, 0x00, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48,\n\t0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x4C, 0x72, 0x72, 0x0E, 0x4C,\n\t0x19, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x0F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x07, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08,\n\t0x0F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00,\n\t0x19, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x21, 0x00, 0x00, 0x00, 0x07, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x01, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x38, 0x06, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x03, 0x1C, 0xC0,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x0B, 0x08, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00,\n\t0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0x98, 0x01, 0x0E, 0x00, 0x1B, 0x00, 0x98, 0x01, 0x0A, 0x00, 0x66, 0x00, 0x04, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x22, 0x0D, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x66, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x23, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x15, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0xCB, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x19, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x12, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x08, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x08, 0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x01, 0x00, 0x05, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x07, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x81, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48,\n\t0x38, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00,\n\t0xBB, 0x03, 0x1C, 0xC0, 0x00, 0x80, 0x00, 0x00, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0x98, 0x01, 0x0E, 0x00, 0x1B, 0x00, 0x98, 0x01, 0x0A, 0x00, 0x66, 0x00,\n\t0x04, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x04, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x22, 0x0D, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x35, 0x80, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00,\n\t0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x10, 0x10, 0x10, 0x00,\n\t0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE2, 0xFF, 0xEF,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x66, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0xCB, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x19, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00,\n\t0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,\n\t0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30,\n\t0x07, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x0F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,\n\t0x23, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x07, 0x06, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x81, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00,\n\t0x76, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x48, 0x38, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91,\n\t0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x03, 0x1C, 0xC0, 0x00, 0x80, 0x00, 0x00, 0xBE, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x03, 0x00, 0x02, 0x00,\n\t0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00,\n\t0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x98, 0x01, 0x0E, 0x00, 0x1B, 0x00, 0x98, 0x01,\n\t0x0A, 0x00, 0x66, 0x00, 0x04, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00,\n\t0x04, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00,\n\t0x22, 0x0D, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x35, 0x00, 0x05, 0x05,\n\t0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,\n\t0x11, 0x01, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x10, 0x10, 0x10, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xFF, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x66, 0x60, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x23, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0xCB, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07,\n\t0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x21, 0x00, 0x20, 0x00,\n\t0x22, 0x00, 0x21, 0x00, 0x22, 0x00, 0x21, 0x00, 0x21, 0x00, 0x20, 0x00, 0x03, 0x00, 0x02, 0x00,\n\t0x02, 0x00, 0x03, 0x00, 0x21, 0x00, 0x20, 0x00, 0x22, 0x00, 0x21, 0x00, 0x22, 0x00, 0x21, 0x00,\n\t0x21, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x01, 0x7F, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x02, 0x03, 0x02, 0x04, 0x00,\n\t0x07, 0x0A, 0x84, 0x72, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x35, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x98, 0x04, 0x00, 0x00,\n\t0x59, 0x00, 0xFF, 0x00, 0x6D, 0x00, 0xFF, 0x00, 0x4F, 0x00, 0xFF, 0x00, 0xAF, 0x00, 0xFF, 0x00,\n\t0x06, 0x00, 0xFF, 0x00, 0xAF, 0x00, 0xFF, 0x00, 0x06, 0x00, 0xFF, 0x00, 0x49, 0x00, 0x40, 0x00,\n\t0x80, 0x00, 0xFF, 0x00, 0x04, 0x00, 0xFF, 0x00, 0x57, 0x00, 0x08, 0x00, 0xFF, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0xFF, 0x00, 0x63, 0x00, 0xFF, 0x00, 0x63, 0x00, 0xFF, 0x00, 0x36, 0x00, 0xFF, 0x00,\n\t0xFF, 0x00, 0xFF, 0x00, 0x71, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0xFF, 0x00, 0xFF, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x08, 0x09, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x35, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0xE0, 0x01, 0x00, 0x00, 0x00, 0xD6, 0x06, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x36, 0x36, 0x35, 0x36, 0x30, 0x30, 0x5F, 0x4E, 0x6F,\n\t0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38, 0x2E,\n\t0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x28, 0x0A, 0x00, 0x39, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x6D,\n\t0x5F, 0x75, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80,\n\t0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x2A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,\n\t0xBB, 0x00, 0x00, 0x00, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x30, 0x0A, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x11, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x1E, 0x00, 0x00, 0x00,\n\t0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,\n\t0xE4, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x02, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x23, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,\n\t0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x24, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x02, 0x0B, 0xC0, 0x00, 0x80, 0x00, 0x00,\n\t0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08,\n\t0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00,\n\t0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00,\n\t0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x9A, 0x02, 0x15, 0x00,\n\t0x1F, 0x00, 0x9A, 0x02, 0x0A, 0x00, 0xA7, 0x00, 0x05, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F,\n\t0x14, 0x00, 0x01, 0x00, 0x06, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0x00, 0x00, 0x00, 0x00, 0xC9, 0x14, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x33, 0x00, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05, 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xFF, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0xA7, 0x60, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x1E, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x01, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x4C, 0x01, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48,\n\t0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x4C, 0x72, 0x72, 0x0E, 0x4C,\n\t0x28, 0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08,\n\t0x11, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00,\n\t0x1E, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,\n\t0x26, 0x00, 0x00, 0x00, 0xE4, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x02, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x15, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x24, 0x0A, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x02, 0x0B, 0xC0,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x0B, 0x08, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,\n\t0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0x9A, 0x02, 0x15, 0x00, 0x1F, 0x00, 0x9A, 0x02, 0x0A, 0x00, 0xA7, 0x00, 0x05, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x06, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xC9, 0x14, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0xA7, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x29, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x1B, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0x4C, 0x01, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x28, 0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0x5E, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x0B, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x08, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x04, 0x00, 0x05, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,\n\t0x24, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xE4, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x79, 0x02, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48,\n\t0x24, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00,\n\t0xBB, 0x02, 0x0B, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00,\n\t0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0x9A, 0x02, 0x15, 0x00, 0x1F, 0x00, 0x9A, 0x02, 0x0A, 0x00, 0xA7, 0x00,\n\t0x05, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00, 0x06, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xC9, 0x14, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x33, 0x80, 0x05, 0x05, 0x00, 0x00, 0x05, 0x05,\n\t0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x11, 0x01, 0x00, 0x02,\n\t0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00,\n\t0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE2, 0xFF, 0xEF,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0xA7, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, 0x05, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0x4C, 0x01, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x28, 0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00,\n\t0x5E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30,\n\t0x0A, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x11, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,\n\t0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xE4, 0x09, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x79, 0x02, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,\n\t0xC0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x48, 0x24, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91,\n\t0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x02, 0x0B, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x05, 0x00, 0x04, 0x00,\n\t0x04, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00,\n\t0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x9A, 0x02, 0x15, 0x00, 0x1F, 0x00, 0x9A, 0x02,\n\t0x0A, 0x00, 0xA7, 0x00, 0x05, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x01, 0x00,\n\t0x06, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00,\n\t0xC9, 0x14, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x33, 0x00, 0x05, 0x05,\n\t0x00, 0x00, 0x05, 0x05, 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,\n\t0x11, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xFF, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0xA7, 0x60, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x28, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x1E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x4C, 0x01, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07,\n\t0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x22, 0x00, 0x20, 0x00,\n\t0x24, 0x00, 0x21, 0x00, 0x24, 0x00, 0x21, 0x00, 0x22, 0x00, 0x20, 0x00, 0x05, 0x00, 0x04, 0x00,\n\t0x04, 0x00, 0x05, 0x00, 0x22, 0x00, 0x20, 0x00, 0x24, 0x00, 0x21, 0x00, 0x24, 0x00, 0x21, 0x00,\n\t0x22, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x04, 0x03, 0x06, 0x00,\n\t0x0A, 0x0F, 0x65, 0x72, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x57, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x7E, 0x07, 0x00, 0x00,\n\t0x3D, 0x00, 0xFF, 0x00, 0x43, 0x00, 0xFF, 0x00, 0x41, 0x00, 0xFF, 0x00, 0x90, 0x00, 0xFF, 0x00,\n\t0x05, 0x00, 0xFF, 0x00, 0x90, 0x00, 0xFF, 0x00, 0x05, 0x00, 0xFF, 0x00, 0x49, 0x00, 0x34, 0x00,\n\t0x80, 0x00, 0xFF, 0x00, 0x04, 0x00, 0xFF, 0x00, 0x35, 0x00, 0x08, 0x00, 0xFF, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0xFF, 0x00, 0x3D, 0x00, 0xFF, 0x00, 0x3D, 0x00, 0xFF, 0x00, 0x29, 0x00, 0xFF, 0x00,\n\t0xD8, 0x00, 0xFF, 0x00, 0x45, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,\n\t0xFF, 0x00, 0xFF, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x24, 0x00, 0x01, 0x08, 0x12, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x35, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x04, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5F, 0x4E, 0x6F,\n\t0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38, 0x2E,\n\t0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x35, 0x0C, 0x00, 0x39, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x6D,\n\t0x5F, 0x75, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80,\n\t0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x33, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,\n\t0xE0, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x22, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x15, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x30, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x13, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0xF0, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x23, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,\n\t0xE6, 0x00, 0x00, 0x00, 0xE6, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x30, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x02, 0x07, 0xC0, 0x00, 0x80, 0x00, 0x00,\n\t0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08,\n\t0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,\n\t0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00,\n\t0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x20, 0x03, 0x19, 0x00,\n\t0x1F, 0x00, 0x20, 0x03, 0x0C, 0x00, 0xC8, 0x00, 0x06, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0x00, 0x00, 0x00, 0x00, 0xC8, 0x18, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x0A, 0x01, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x10, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0xC8, 0x60, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0x17, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x20, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x05, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x90, 0x01, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48,\n\t0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x8C, 0x72, 0x72, 0x0E, 0x4C, 0x72, 0x72, 0x0E, 0x4C,\n\t0x30, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08,\n\t0x13, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,\n\t0x27, 0x00, 0x00, 0x00, 0xF0, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x02, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x19, 0x00, 0x00, 0x00, 0xE6, 0x00, 0x00, 0x00, 0xE6, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48, 0x30, 0x0C, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x02, 0x07, 0xC0,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x0B, 0x08, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00,\n\t0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0x20, 0x03, 0x19, 0x00, 0x1F, 0x00, 0x20, 0x03, 0x0C, 0x00, 0xC8, 0x00, 0x06, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x18, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0xC8, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x2D, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0x90, 0x01, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x30, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x0F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x0A, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x08, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x03, 0x00, 0x05, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00,\n\t0x25, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xF0, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xFC, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0xE6, 0x00, 0x00, 0x00, 0xE6, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x48,\n\t0x30, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xBF, 0x3B, 0x00, 0x00,\n\t0xBB, 0x02, 0x07, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,\n\t0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x06, 0x00, 0x06, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0x20, 0x03, 0x19, 0x00, 0x1F, 0x00, 0x20, 0x03, 0x0C, 0x00, 0xC8, 0x00,\n\t0x06, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x07, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x18, 0x00, 0x00,\n\t0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x01, 0x00, 0x02,\n\t0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00,\n\t0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xE2, 0xFF, 0xEF,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0xC8, 0x60, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x29, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0x90, 0x01, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x40, 0x72, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x30, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00,\n\t0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,\n\t0x0F, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,\n\t0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30,\n\t0x09, 0x00, 0x00, 0x00, 0x71, 0x71, 0x03, 0x08, 0x13, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0x29, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xF0, 0x0B, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xFC, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0xE6, 0x00, 0x00, 0x00,\n\t0xE6, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x71, 0x71, 0x03, 0x48, 0x30, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91,\n\t0xBF, 0x3B, 0x00, 0x00, 0xBB, 0x02, 0x07, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x06, 0x00, 0x05, 0x00,\n\t0x05, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00,\n\t0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x20, 0x03, 0x19, 0x00, 0x1F, 0x00, 0x20, 0x03,\n\t0x0C, 0x00, 0xC8, 0x00, 0x06, 0x03, 0xE0, 0xC1, 0x2F, 0x41, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x07, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00,\n\t0xC8, 0x18, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x33, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,\n\t0x01, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x10, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0xC8, 0x60, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n\t0x29, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x90, 0x01, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07,\n\t0x40, 0x72, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x23, 0x00, 0x1F, 0x00,\n\t0x24, 0x00, 0x22, 0x00, 0x24, 0x00, 0x22, 0x00, 0x23, 0x00, 0x20, 0x00, 0x06, 0x00, 0x05, 0x00,\n\t0x05, 0x00, 0x06, 0x00, 0x23, 0x00, 0x1F, 0x00, 0x24, 0x00, 0x22, 0x00, 0x24, 0x00, 0x22, 0x00,\n\t0x23, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x06, 0x04, 0x07, 0x00,\n\t0x0D, 0x12, 0x66, 0x72, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x68, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x02, 0x09, 0x00, 0x00,\n\t0x3D, 0x00, 0xFF, 0x00, 0x38, 0x00, 0xFF, 0x00, 0x41, 0x00, 0xFF, 0x00, 0x90, 0x00, 0xFF, 0x00,\n\t0x05, 0x00, 0xFF, 0x00, 0x90, 0x00, 0xFF, 0x00, 0x05, 0x00, 0xFF, 0x00, 0x49, 0x00, 0x34, 0x00,\n\t0x80, 0x00, 0xFF, 0x00, 0x04, 0x00, 0xFF, 0x00, 0x2C, 0x00, 0x08, 0x00, 0xFF, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0xFF, 0x00, 0x32, 0x00, 0xFF, 0x00, 0x32, 0x00, 0xFF, 0x00, 0x22, 0x00, 0xFF, 0x00,\n\t0xB4, 0x00, 0xFF, 0x00, 0x3A, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,\n\t0xFF, 0x00, 0xFF, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x24, 0x00, 0x01, 0x08, 0x12, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x72, 0x72, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x35, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x04, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x31, 0x30, 0x36, 0x35, 0x36, 0x30, 0x30, 0x5F, 0x4E,\n\t0x6F, 0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38,\n\t0x2E, 0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x80, 0x42, 0x10, 0x00, 0x45, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x6D,\n\t0x5F, 0x75, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80,\n\t0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x2B, 0x01, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x2D, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x10, 0x0D, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08, 0x17, 0x00, 0x00, 0x00,\n\t0x13, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0x2F, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00,\n\t0xFC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x29, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,\n\t0x33, 0x01, 0x00, 0x00, 0x33, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x10, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48, 0x3C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x91, 0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x01, 0xC0, 0x00, 0x80, 0x00, 0x00,\n\t0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x0B, 0x08,\n\t0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00,\n\t0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x07, 0x00, 0x07, 0x00,\n\t0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x2A, 0x04, 0x21, 0x00,\n\t0x25, 0x00, 0x2A, 0x04, 0x0F, 0x00, 0x0B, 0x01, 0x07, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x09, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0x00, 0x00, 0x00, 0x00, 0xAB, 0x20, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x0A, 0x01, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x10, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0B, 0x61, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x27, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x05, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x14, 0x02, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x03, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48,\n\t0x48, 0x48, 0x0E, 0x8C, 0x48, 0x48, 0x0E, 0x8C, 0x48, 0x48, 0x0E, 0x4C, 0x48, 0x48, 0x0E, 0x4C,\n\t0x40, 0x00, 0x00, 0x00, 0x2B, 0x01, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x17, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x0B, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x0D, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08,\n\t0x17, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00,\n\t0x27, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,\n\t0x2F, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x21, 0x00, 0x00, 0x00, 0x33, 0x01, 0x00, 0x00, 0x33, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48, 0x3C, 0x10, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x01, 0xC0,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x06, 0x06, 0x0B, 0x08, 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00,\n\t0x07, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0x2A, 0x04, 0x21, 0x00, 0x25, 0x00, 0x2A, 0x04, 0x0F, 0x00, 0x0B, 0x01, 0x07, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x09, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x20, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x61, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x26, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0x14, 0x02, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x40, 0x00, 0x00, 0x00, 0x2B, 0x01, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x00, 0x00, 0x00,\n\t0xF1, 0xF1, 0x03, 0x08, 0x15, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x07, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00,\n\t0x2D, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xFF, 0x03, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x33, 0x01, 0x00, 0x00, 0x33, 0x01, 0x00, 0x00,\n\t0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00,\n\t0x17, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48,\n\t0x3C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xFF, 0x3B, 0x00, 0x00,\n\t0xBB, 0x01, 0x01, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x0B, 0x08, 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x08, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00,\n\t0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x08, 0x00, 0x07, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x08, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0x2A, 0x04, 0x21, 0x00, 0x25, 0x00, 0x2A, 0x04, 0x0F, 0x00, 0x0B, 0x01,\n\t0x07, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x09, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x20, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x01, 0x00, 0x02,\n\t0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00,\n\t0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xE2, 0xFF, 0xEF,\n\t0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x61, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x05, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0x14, 0x02, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x13, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x40, 0x00, 0x00, 0x00, 0x2B, 0x01, 0x00, 0x00,\n\t0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\n\t0x0D, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08, 0x17, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00,\n\t0x31, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x33, 0x01, 0x00, 0x00,\n\t0x33, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x2B, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0xF1, 0xF1, 0x03, 0x48, 0x3C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91,\n\t0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x01, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x0B, 0x08, 0x08, 0x00, 0x07, 0x00,\n\t0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00,\n\t0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x07, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00,\n\t0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x2A, 0x04, 0x21, 0x00, 0x25, 0x00, 0x2A, 0x04,\n\t0x0F, 0x00, 0x0B, 0x01, 0x07, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x09, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00,\n\t0xAB, 0x20, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x33, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,\n\t0x01, 0x01, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x20, 0x20, 0x10, 0x00, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x10, 0xE2, 0xFF, 0xEF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x61, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x31, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x27, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x14, 0x02, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x13, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x03, 0x00, 0x07,\n\t0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x24, 0x00, 0x1F, 0x00,\n\t0x26, 0x00, 0x23, 0x00, 0x26, 0x00, 0x23, 0x00, 0x24, 0x00, 0x20, 0x00, 0x08, 0x00, 0x07, 0x00,\n\t0x06, 0x00, 0x08, 0x00, 0x24, 0x00, 0x1F, 0x00, 0x26, 0x00, 0x23, 0x00, 0x26, 0x00, 0x23, 0x00,\n\t0x24, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x03, 0x03, 0x04, 0x03, 0x08, 0x05, 0x09, 0x00,\n\t0x11, 0x18, 0x68, 0x72, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x8B, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0xFF, 0x0B, 0x00, 0x00,\n\t0x3D, 0x00, 0xC0, 0x00, 0x38, 0x00, 0xC0, 0x00, 0x41, 0x00, 0xC0, 0x00, 0x90, 0x00, 0xC0, 0x00,\n\t0x05, 0x00, 0xC0, 0x00, 0x90, 0x00, 0xC0, 0x00, 0x05, 0x00, 0xC0, 0x00, 0x49, 0x00, 0x34, 0x00,\n\t0x80, 0x00, 0xC0, 0x00, 0x04, 0x00, 0xC0, 0x00, 0x21, 0x00, 0x08, 0x00, 0xC0, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0xC0, 0x00, 0x26, 0x00, 0xC0, 0x00, 0x26, 0x00, 0xC0, 0x00, 0x19, 0x00, 0xC0, 0x00,\n\t0x95, 0x00, 0xC0, 0x00, 0x2B, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,\n\t0xC0, 0x00, 0xC0, 0x00, 0x25, 0x00, 0x00, 0x00, 0x34, 0x00, 0x01, 0x08, 0x1B, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x48, 0x48, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x25, 0x08, 0x11, 0x00, 0x08, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x04, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x31, 0x33, 0x33, 0x31, 0x32, 0x30, 0x30, 0x5F, 0x4E,\n\t0x6F, 0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38,\n\t0x2E, 0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x50, 0x14, 0x00, 0x52, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x6D,\n\t0x5F, 0x75, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80,\n\t0xF0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,\n\t0x75, 0x01, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08, 0x1A, 0x00, 0x00, 0x00,\n\t0x1A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x09, 0x00, 0x06, 0x00, 0x2E, 0x00, 0x00, 0x00,\n\t0x36, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,\n\t0x08, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x30, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0x7F, 0x01, 0x00, 0x00, 0x7F, 0x01, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x12, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x91, 0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00,\n\t0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x0B, 0x08,\n\t0x0A, 0x00, 0x09, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00,\n\t0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x09, 0x00, 0x09, 0x00,\n\t0x08, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x34, 0x05, 0x29, 0x00,\n\t0x2B, 0x00, 0x34, 0x05, 0x13, 0x00, 0x4D, 0x01, 0x08, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0x00, 0x00, 0x00, 0x00, 0x8F, 0x28, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x02, 0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x4D, 0x61, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,\n\t0x26, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x2E, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x06, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x99, 0x02, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x53, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x43, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x88, 0x72, 0x72, 0x0C, 0x48, 0x72, 0x72, 0x0C, 0x48,\n\t0x48, 0x48, 0x0E, 0x8C, 0x48, 0x48, 0x0E, 0x8C, 0x48, 0x48, 0x0E, 0x4C, 0x48, 0x48, 0x0E, 0x4C,\n\t0x50, 0x00, 0x00, 0x00, 0x75, 0x01, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x17, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08,\n\t0x1A, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x09, 0x00, 0x06, 0x00,\n\t0x2E, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x36, 0x00, 0x00, 0x00, 0x08, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x27, 0x00, 0x00, 0x00, 0x7F, 0x01, 0x00, 0x00, 0x7F, 0x01, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48, 0x48, 0x14, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x00, 0xC0,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x06, 0x06, 0x0B, 0x08, 0x0A, 0x00, 0x09, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x02, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x0A, 0x00,\n\t0x09, 0x00, 0x09, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0x34, 0x05, 0x29, 0x00, 0x2B, 0x00, 0x34, 0x05, 0x13, 0x00, 0x4D, 0x01, 0x08, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x28, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x02, 0x07, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0xFF, 0x1F, 0xFF, 0x1F,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x4D, 0x61, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x3A, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x2C, 0x00, 0x00, 0x00, 0x09, 0x00, 0x06, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0x99, 0x02, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x53, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x43, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x50, 0x00, 0x00, 0x00, 0x75, 0x01, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x26, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x12, 0x00, 0x00, 0x00,\n\t0xF1, 0xF1, 0x03, 0x08, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x0A, 0x00, 0x06, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x08, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x02, 0x05, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x7F, 0x01, 0x00, 0x00, 0x7F, 0x01, 0x00, 0x00,\n\t0x0B, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,\n\t0x1C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48,\n\t0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x91, 0xFF, 0x3B, 0x00, 0x00,\n\t0xBB, 0x01, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x0B, 0x08, 0x0A, 0x00, 0x09, 0x00, 0x08, 0x00, 0x0A, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00,\n\t0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x0A, 0x00, 0x09, 0x00, 0x09, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x0A, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0x34, 0x05, 0x29, 0x00, 0x2B, 0x00, 0x34, 0x05, 0x13, 0x00, 0x4D, 0x01,\n\t0x08, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x0B, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x28, 0x00, 0x00,\n\t0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x02,\n\t0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00,\n\t0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0xFF, 0xEF,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x4D, 0x61, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x38, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x06, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0x99, 0x02, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x53, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x43, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x50, 0x00, 0x00, 0x00, 0x75, 0x01, 0x00, 0x00,\n\t0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\n\t0x11, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08, 0x1A, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x09, 0x00, 0x06, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,\n\t0x38, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x08, 0x14, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x7F, 0x01, 0x00, 0x00,\n\t0x7F, 0x01, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x36, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0xF1, 0xF1, 0x03, 0x48, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x91,\n\t0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x0B, 0x08, 0x0A, 0x00, 0x09, 0x00,\n\t0x08, 0x00, 0x0A, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x02, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x04, 0x00, 0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x09, 0x00, 0x09, 0x00, 0x08, 0x00, 0x08, 0x00,\n\t0x0A, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x34, 0x05, 0x29, 0x00, 0x2B, 0x00, 0x34, 0x05,\n\t0x13, 0x00, 0x4D, 0x01, 0x08, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x0B, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00,\n\t0x8F, 0x28, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x33, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,\n\t0x01, 0x01, 0x00, 0x02, 0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x20, 0x20, 0x10, 0x00, 0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x10, 0x22, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x4D, 0x61, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,\n\t0x38, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x2E, 0x00, 0x00, 0x00, 0x09, 0x00, 0x06, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x99, 0x02, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x40, 0x72, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x53, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x43, 0x00, 0x07,\n\t0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x25, 0x00, 0x1F, 0x00,\n\t0x28, 0x00, 0x23, 0x00, 0x28, 0x00, 0x23, 0x00, 0x25, 0x00, 0x20, 0x00, 0x0A, 0x00, 0x09, 0x00,\n\t0x08, 0x00, 0x0A, 0x00, 0x25, 0x00, 0x1F, 0x00, 0x28, 0x00, 0x23, 0x00, 0x28, 0x00, 0x23, 0x00,\n\t0x25, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x03, 0x03, 0x05, 0x04, 0x09, 0x07, 0x0B, 0x00,\n\t0x14, 0x1E, 0x6A, 0x72, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0xAD, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0xFC, 0x0E, 0x00, 0x00,\n\t0x3D, 0x00, 0x99, 0x00, 0x38, 0x00, 0x99, 0x00, 0x41, 0x00, 0x99, 0x00, 0x90, 0x00, 0x99, 0x00,\n\t0x05, 0x00, 0x99, 0x00, 0x90, 0x00, 0x99, 0x00, 0x05, 0x00, 0x99, 0x00, 0x49, 0x00, 0x34, 0x00,\n\t0x80, 0x00, 0x99, 0x00, 0x04, 0x00, 0x99, 0x00, 0x1B, 0x00, 0x08, 0x00, 0x99, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x99, 0x00, 0x1E, 0x00, 0x99, 0x00, 0x1E, 0x00, 0x99, 0x00, 0x18, 0x00, 0x99, 0x00,\n\t0x95, 0x00, 0x99, 0x00, 0x23, 0x00, 0x99, 0x00, 0x99, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,\n\t0x99, 0x00, 0x99, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x44, 0x00, 0x01, 0x08, 0x24, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x48, 0x48, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x2D, 0x08, 0x11, 0x00, 0x00, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x31, 0x30, 0x5F, 0x31, 0x36, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5F, 0x4E,\n\t0x6F, 0x43, 0x66, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x56, 0x39, 0x2E, 0x38,\n\t0x2E, 0x37, 0x5F, 0x56, 0x31, 0x2E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x6A, 0x18, 0x00, 0x77, 0x03, 0x00, 0x00, 0x4C, 0x04, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x6D,\n\t0x5F, 0x75, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80,\n\t0xF0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x8A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,\n\t0xC0, 0x01, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x44, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0x17, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x10,\n\t0x02, 0x00, 0x00, 0x10, 0x14, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08, 0x1D, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x06, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x3C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,\n\t0x20, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x06, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x38, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00,\n\t0xCC, 0x01, 0x00, 0x00, 0xCC, 0x01, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x14, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0D, 0xA0, 0x60, 0x99, 0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00,\n\t0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x0B, 0x08,\n\t0x0C, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00,\n\t0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0B, 0x00, 0x0B, 0x00,\n\t0x0A, 0x00, 0x0A, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80,\n\t0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x40, 0x06, 0x31, 0x00,\n\t0x2F, 0x00, 0x40, 0x06, 0x17, 0x00, 0x90, 0x01, 0x0A, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3,\n\t0x00, 0x00, 0x00, 0x00, 0x8C, 0x30, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,\n\t0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x02, 0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00,\n\t0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x90, 0x61, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,\n\t0x2C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x34, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x06, 0x00, 0x80, 0x90, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x20, 0x03, 0x04, 0x00,\n\t0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x00, 0x32, 0x10, 0x00,\n\t0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x10, 0x11, 0x00, 0x53, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11,\n\t0x00, 0x43, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48,\n\t0x48, 0x48, 0x0C, 0x88, 0x48, 0x48, 0x0C, 0x88, 0x48, 0x48, 0x0C, 0x48, 0x48, 0x48, 0x0C, 0x48,\n\t0x48, 0x48, 0x0E, 0x8C, 0x48, 0x48, 0x0E, 0x8C, 0x48, 0x48, 0x0E, 0x4C, 0x48, 0x48, 0x0E, 0x4C,\n\t0x60, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00,\n\t0x21, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,\n\t0x10, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n\t0x1C, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x10, 0x14, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08,\n\t0x1D, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x06, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00,\n\t0x3C, 0x00, 0x00, 0x00, 0x20, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x06, 0x00, 0x00,\n\t0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n\t0x2E, 0x00, 0x00, 0x00, 0xCC, 0x01, 0x00, 0x00, 0xCC, 0x01, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x18, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48, 0x60, 0x18, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99, 0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x00, 0xC0,\n\t0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x66, 0x66, 0x0B, 0x08, 0x0C, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x05, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00, 0x08, 0x00, 0x02, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00,\n\t0x0B, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00,\n\t0x40, 0x06, 0x31, 0x00, 0x2F, 0x00, 0x40, 0x06, 0x17, 0x00, 0x90, 0x01, 0x0A, 0x03, 0xE0, 0xC1,\n\t0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00,\n\t0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x30, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x02, 0x00, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x02, 0x07, 0x00, 0x00, 0x00,\n\t0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00, 0xFF, 0x1F, 0xFF, 0x1F,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x90, 0x61, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x42, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08,\n\t0x34, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x06, 0x00, 0x80, 0x90, 0x01, 0x00, 0x04, 0x04, 0x07, 0x07,\n\t0x20, 0x03, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x00, 0x32, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x53, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00,\n\t0x00, 0xFC, 0x14, 0x11, 0x00, 0x43, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55,\n\t0x14, 0x14, 0x16, 0x48, 0x60, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,\n\t0x29, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,\n\t0x1D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,\n\t0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x10, 0x16, 0x00, 0x00, 0x00,\n\t0xF1, 0xF1, 0x03, 0x08, 0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n\t0x0E, 0x00, 0x06, 0x00, 0x34, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00,\n\t0x3A, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x20, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x08, 0x06, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,\n\t0x02, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0xCC, 0x01, 0x00, 0x00, 0xCC, 0x01, 0x00, 0x00,\n\t0x0D, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,\n\t0x22, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x48,\n\t0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x40, 0x60, 0x99, 0xFF, 0x3B, 0x00, 0x00,\n\t0xBB, 0x01, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x0B, 0x08, 0x0C, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x0C, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00,\n\t0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x0C, 0x00, 0x0B, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x0C, 0x00, 0x0C, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02, 0x12, 0x00, 0x00, 0x00,\n\t0x00, 0x40, 0x06, 0x00, 0x40, 0x06, 0x31, 0x00, 0x2F, 0x00, 0x40, 0x06, 0x17, 0x00, 0x90, 0x01,\n\t0x0A, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x0D, 0x08, 0x00, 0x00,\n\t0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x30, 0x00, 0x00,\n\t0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x33, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x00, 0x02,\n\t0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00, 0x20, 0x20, 0x10, 0x00,\n\t0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\n\t0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0xFF, 0xEF,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0xDC, 0x0A, 0x0A, 0x0A, 0x0A,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x90, 0x61, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t0x1F, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,\n\t0x14, 0x14, 0x16, 0x08, 0x3E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x06, 0x00, 0x80, 0x90, 0x00, 0x00,\n\t0x04, 0x04, 0x07, 0x07, 0x20, 0x03, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05, 0x00, 0x11, 0x10, 0x1F,\n\t0x14, 0x00, 0x00, 0x00, 0x00, 0x32, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01, 0x6A, 0x5B, 0x12, 0x01,\n\t0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11, 0x00, 0x53, 0x08, 0x0F,\n\t0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x43, 0x00, 0x07, 0x00, 0x32, 0x10, 0x00,\n\t0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x60, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00,\n\t0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,\n\t0x1D, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x1D, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n\t0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x24, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x10,\n\t0x14, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x03, 0x08, 0x1D, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x06, 0x00, 0x34, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,\n\t0x3E, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x20, 0x18, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x08, 0x06, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n\t0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,\n\t0x0E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0xCC, 0x01, 0x00, 0x00,\n\t0xCC, 0x01, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,\n\t0x40, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,\n\t0xF1, 0xF1, 0x03, 0x48, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xA0, 0x60, 0x99,\n\t0xFF, 0x3B, 0x00, 0x00, 0xBB, 0x01, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x0B, 0x08, 0x0C, 0x00, 0x0B, 0x00,\n\t0x0A, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x05, 0x00, 0x08, 0x00, 0x02, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n\t0x09, 0x00, 0x05, 0x00, 0x08, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0B, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x0A, 0x00,\n\t0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x20, 0x80, 0x0F, 0xF4, 0x20, 0x02,\n\t0x12, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x40, 0x06, 0x31, 0x00, 0x2F, 0x00, 0x40, 0x06,\n\t0x17, 0x00, 0x90, 0x01, 0x0A, 0x03, 0xE0, 0xC1, 0x2F, 0x61, 0x13, 0x1F, 0x14, 0x00, 0x00, 0x00,\n\t0x0D, 0x08, 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF3, 0x00, 0x00, 0x00, 0x00,\n\t0x8C, 0x30, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x33, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,\n\t0x01, 0x01, 0x00, 0x02, 0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x5C, 0x01, 0x00,\n\t0x20, 0x20, 0x10, 0x00, 0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x10, 0x22, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, 0xDC, 0xDC,\n\t0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x90, 0x61, 0x18, 0x01,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,\n\t0x3E, 0x00, 0x00, 0x00, 0x14, 0x14, 0x16, 0x08, 0x34, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x06, 0x00,\n\t0x80, 0xB0, 0x00, 0x00, 0x04, 0x04, 0x07, 0x07, 0x20, 0x03, 0x04, 0x00, 0x1F, 0x80, 0x13, 0x05,\n\t0x00, 0x11, 0x10, 0x1F, 0x14, 0x00, 0x00, 0x00, 0x00, 0x32, 0x10, 0x00, 0x00, 0x40, 0x12, 0x01,\n\t0x6A, 0x5B, 0x12, 0x01, 0x00, 0x10, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x10, 0x11,\n\t0x00, 0x53, 0x08, 0x0F, 0x00, 0x58, 0x10, 0x00, 0x00, 0xFC, 0x14, 0x11, 0x00, 0x43, 0x00, 0x07,\n\t0x00, 0x32, 0x10, 0x00, 0x5A, 0x3C, 0x55, 0x55, 0x14, 0x14, 0x16, 0x48, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,\n\t0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\n\t0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x26, 0x00, 0x1E, 0x00,\n\t0x29, 0x00, 0x24, 0x00, 0x29, 0x00, 0x24, 0x00, 0x26, 0x00, 0x20, 0x00, 0x0C, 0x00, 0x0B, 0x00,\n\t0x0A, 0x00, 0x0C, 0x00, 0x26, 0x00, 0x1E, 0x00, 0x29, 0x00, 0x24, 0x00, 0x29, 0x00, 0x24, 0x00,\n\t0x26, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,\n\t0x04, 0x01, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n\t0x0C, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x20, 0x10, 0x0A, 0x00, 0x28, 0x10, 0x00, 0x80,\n\t0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,\n\t0x0F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,\n\t0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,\n\t0x0A, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x03, 0x03, 0x06, 0x05, 0x0C, 0x08, 0x0D, 0x00,\n\t0x19, 0x24, 0x6C, 0x72, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x1A, 0x00, 0x80, 0x00,\n\t0x1A, 0x00, 0x80, 0x00, 0xD0, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x80, 0x00, 0x03, 0x12, 0x00, 0x00,\n\t0x3D, 0x00, 0x80, 0x00, 0x38, 0x00, 0x80, 0x00, 0x41, 0x00, 0x80, 0x00, 0x90, 0x00, 0x80, 0x00,\n\t0x05, 0x00, 0x80, 0x00, 0x90, 0x00, 0x80, 0x00, 0x05, 0x00, 0x80, 0x00, 0x49, 0x00, 0x34, 0x00,\n\t0x80, 0x00, 0x80, 0x00, 0x04, 0x00, 0x80, 0x00, 0x16, 0x00, 0x08, 0x00, 0x80, 0x00, 0x00, 0x00,\n\t0x04, 0x00, 0x80, 0x00, 0x19, 0x00, 0x80, 0x00, 0x19, 0x00, 0x80, 0x00, 0x18, 0x00, 0x80, 0x00,\n\t0x95, 0x00, 0x80, 0x00, 0x1D, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,\n\t0x80, 0x00, 0x80, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x54, 0x00, 0x01, 0x08, 0x2D, 0x00, 0x02, 0x08,\n\t0x00, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x00, 0xC0, 0x48, 0x48, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x51, 0x1A, 0xA0, 0x00, 0x00, 0x50, 0x05,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00,\n\t0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x35, 0x08, 0x11, 0x00, 0x00, 0x00, 0x04, 0x00,\n\t0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x18, 0x80, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x04, 0x00, 0x00\n};\n\n\n#endif\n"
  },
  {
    "path": "modules/hekate_libsys_minerva/mtc_table.h",
    "content": "/*\n * Minerva Training Cell\n * DRAM Training for Tegra X1 SoC. Supports DDR2/3 and LPDDR3/4.\n *\n * Copyright (c) 2018 CTCaer  <ctcaer@gmail.com>\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _MTC_TABLE_H_\n#define _MTC_TABLE_H_\n\n#include \"types.h\"\n\ntypedef struct\n{\n\tu32 pll_osc_in;\n\tu32 pll_out;\n\tu32 pll_feedback_div;\n\tu32 pll_input_div;\n\tu32 pll_post_div;\n} pllm_clk_config_t;\n\ntypedef struct\n{\n\tu32 emc_rc;\n\tu32 emc_rfc;\n\tu32 emc_rfcpb;\n\tu32 emc_refctrl2;\n\tu32 emc_rfc_slr;\n\tu32 emc_ras;\n\tu32 emc_rp;\n\tu32 emc_r2w;\n\tu32 emc_w2r;\n\tu32 emc_r2p;\n\tu32 emc_w2p;\n\tu32 emc_r2r;\n\tu32 emc_tppd;\n\tu32 emc_ccdmw;\n\tu32 emc_rd_rcd;\n\tu32 emc_wr_rcd;\n\tu32 emc_rrd;\n\tu32 emc_rext;\n\tu32 emc_wext;\n\tu32 emc_wdv_chk;\n\tu32 emc_wdv;\n\tu32 emc_wsv;\n\tu32 emc_wev;\n\tu32 emc_wdv_mask;\n\tu32 emc_ws_duration;\n\tu32 emc_we_duration;\n\tu32 emc_quse;\n\tu32 emc_quse_width;\n\tu32 emc_ibdly;\n\tu32 emc_obdly;\n\tu32 emc_einput;\n\tu32 emc_mrw6;\n\tu32 emc_einput_duration;\n\tu32 emc_puterm_extra;\n\tu32 emc_puterm_width;\n\tu32 emc_qrst;\n\tu32 emc_qsafe;\n\tu32 emc_rdv;\n\tu32 emc_rdv_mask;\n\tu32 emc_rdv_early;\n\tu32 emc_rdv_early_mask;\n\tu32 emc_refresh;\n\tu32 emc_burst_refresh_num;\n\tu32 emc_pre_refresh_req_cnt;\n\tu32 emc_pdex2wr;\n\tu32 emc_pdex2rd;\n\tu32 emc_pchg2pden;\n\tu32 emc_act2pden;\n\tu32 emc_ar2pden;\n\tu32 emc_rw2pden;\n\tu32 emc_cke2pden;\n\tu32 emc_pdex2cke;\n\tu32 emc_pdex2mrr;\n\tu32 emc_txsr;\n\tu32 emc_txsrdll;\n\tu32 emc_tcke;\n\tu32 emc_tckesr;\n\tu32 emc_tpd;\n\tu32 emc_tfaw;\n\tu32 emc_trpab;\n\tu32 emc_tclkstable;\n\tu32 emc_tclkstop;\n\tu32 emc_mrw7;\n\tu32 emc_trefbw;\n\tu32 emc_odt_write;\n\tu32 emc_fbio_cfg5;\n\tu32 emc_fbio_cfg7;\n\tu32 emc_cfg_dig_dll;\n\tu32 emc_cfg_dig_dll_period;\n\tu32 emc_pmacro_ib_rxrt;\n\tu32 emc_cfg_pipe_1;\n\tu32 emc_cfg_pipe_2;\n\tu32 emc_pmacro_quse_ddll_rank0_4;\n\tu32 emc_pmacro_quse_ddll_rank0_5;\n\tu32 emc_pmacro_quse_ddll_rank1_4;\n\tu32 emc_pmacro_quse_ddll_rank1_5;\n\tu32 emc_mrw8;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_4;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_5;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_0;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_1;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_2;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_3;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_4;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank0_5;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_0;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_1;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_2;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_3;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_4;\n\tu32 emc_pmacro_ob_ddll_long_dqs_rank1_5;\n\tu32 emc_pmacro_ddll_long_cmd_0;\n\tu32 emc_pmacro_ddll_long_cmd_1;\n\tu32 emc_pmacro_ddll_long_cmd_2;\n\tu32 emc_pmacro_ddll_long_cmd_3;\n\tu32 emc_pmacro_ddll_long_cmd_4;\n\tu32 emc_pmacro_ddll_short_cmd_0;\n\tu32 emc_pmacro_ddll_short_cmd_1;\n\tu32 emc_pmacro_ddll_short_cmd_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_3;\n\tu32 emc_txdsrvttgen;\n\tu32 emc_fdpd_ctrl_dq;\n\tu32 emc_fdpd_ctrl_cmd;\n\tu32 emc_fbio_spare;\n\tu32 emc_zcal_interval;\n\tu32 emc_zcal_wait_cnt;\n\tu32 emc_mrs_wait_cnt;\n\tu32 emc_mrs_wait_cnt2;\n\tu32 emc_auto_cal_channel;\n\tu32 emc_dll_cfg_0;\n\tu32 emc_dll_cfg_1;\n\tu32 emc_pmacro_autocal_cfg_common;\n\tu32 emc_pmacro_zctrl;\n\tu32 emc_cfg;\n\tu32 emc_cfg_pipe;\n\tu32 emc_dyn_self_ref_control;\n\tu32 emc_qpop;\n\tu32 emc_dqs_brlshft_0;\n\tu32 emc_dqs_brlshft_1;\n\tu32 emc_cmd_brlshft_2;\n\tu32 emc_cmd_brlshft_3;\n\tu32 emc_pmacro_pad_cfg_ctrl;\n\tu32 emc_pmacro_data_pad_rx_ctrl;\n\tu32 emc_pmacro_cmd_pad_rx_ctrl;\n\tu32 emc_pmacro_data_rx_term_mode;\n\tu32 emc_pmacro_cmd_rx_term_mode;\n\tu32 emc_pmacro_cmd_pad_tx_ctrl;\n\tu32 emc_pmacro_data_pad_tx_ctrl;\n\tu32 emc_pmacro_common_pad_tx_ctrl;\n\tu32 emc_pmacro_vttgen_ctrl_0;\n\tu32 emc_pmacro_vttgen_ctrl_1;\n\tu32 emc_pmacro_vttgen_ctrl_2;\n\tu32 emc_pmacro_brick_ctrl_rfu1;\n\tu32 emc_pmacro_cmd_brick_ctrl_fdpd;\n\tu32 emc_pmacro_brick_ctrl_rfu2;\n\tu32 emc_pmacro_data_brick_ctrl_fdpd;\n\tu32 emc_pmacro_bg_bias_ctrl_0;\n\tu32 emc_cfg_3;\n\tu32 emc_pmacro_tx_pwrd_0;\n\tu32 emc_pmacro_tx_pwrd_1;\n\tu32 emc_pmacro_tx_pwrd_2;\n\tu32 emc_pmacro_tx_pwrd_3;\n\tu32 emc_pmacro_tx_pwrd_4;\n\tu32 emc_pmacro_tx_pwrd_5;\n\tu32 emc_config_sample_delay;\n\tu32 emc_pmacro_tx_sel_clk_src_0;\n\tu32 emc_pmacro_tx_sel_clk_src_1;\n\tu32 emc_pmacro_tx_sel_clk_src_2;\n\tu32 emc_pmacro_tx_sel_clk_src_3;\n\tu32 emc_pmacro_tx_sel_clk_src_4;\n\tu32 emc_pmacro_tx_sel_clk_src_5;\n\tu32 emc_pmacro_ddll_bypass;\n\tu32 emc_pmacro_ddll_pwrd_0;\n\tu32 emc_pmacro_ddll_pwrd_1;\n\tu32 emc_pmacro_ddll_pwrd_2;\n\tu32 emc_pmacro_cmd_ctrl_0;\n\tu32 emc_pmacro_cmd_ctrl_1;\n\tu32 emc_pmacro_cmd_ctrl_2;\n\tu32 emc_tr_timing_0;\n\tu32 emc_tr_dvfs;\n\tu32 emc_tr_ctrl_1;\n\tu32 emc_tr_rdv;\n\tu32 emc_tr_qpop;\n\tu32 emc_tr_rdv_mask;\n\tu32 emc_mrw14;\n\tu32 emc_tr_qsafe;\n\tu32 emc_tr_qrst;\n\tu32 emc_training_ctrl;\n\tu32 emc_training_settle;\n\tu32 emc_training_vref_settle;\n\tu32 emc_training_ca_fine_ctrl;\n\tu32 emc_training_ca_ctrl_misc;\n\tu32 emc_training_ca_ctrl_misc1;\n\tu32 emc_training_ca_vref_ctrl;\n\tu32 emc_training_quse_cors_ctrl;\n\tu32 emc_training_quse_fine_ctrl;\n\tu32 emc_training_quse_ctrl_misc;\n\tu32 emc_training_quse_vref_ctrl;\n\tu32 emc_training_read_fine_ctrl;\n\tu32 emc_training_read_ctrl_misc;\n\tu32 emc_training_read_vref_ctrl;\n\tu32 emc_training_write_fine_ctrl;\n\tu32 emc_training_write_ctrl_misc;\n\tu32 emc_training_write_vref_ctrl;\n\tu32 emc_training_mpc;\n\tu32 emc_mrw15;\n} burst_regs_t;\n\ntypedef struct\n{\n\tu32 burst_regs[221];\n\tu32 burst_reg_per_ch[8];\n\tu32 shadow_regs_ca_train[221];\n\tu32 shadow_regs_quse_train[221];\n\tu32 shadow_regs_rdwr_train[221];\n} burst_regs_table_t;\n\ntypedef struct\n{\n\tu32 ptfv_dqsosc_movavg_c0d0u0;\n\tu32 ptfv_dqsosc_movavg_c0d0u1;\n\tu32 ptfv_dqsosc_movavg_c0d1u0;\n\tu32 ptfv_dqsosc_movavg_c0d1u1;\n\tu32 ptfv_dqsosc_movavg_c1d0u0;\n\tu32 ptfv_dqsosc_movavg_c1d0u1;\n\tu32 ptfv_dqsosc_movavg_c1d1u0;\n\tu32 ptfv_dqsosc_movavg_c1d1u1;\n\tu32 ptfv_write_samples;\n\tu32 ptfv_dvfs_samples;\n\tu32 ptfv_movavg_weight;\n\tu32 ptfv_config_ctrl;\n} ptfv_list_table_t;\n\ntypedef struct\n{\n\tu32 emc0_mrw10;\n\tu32 emc1_mrw10;\n\tu32 emc0_mrw11;\n\tu32 emc1_mrw11;\n\tu32 emc0_mrw12;\n\tu32 emc1_mrw12;\n\tu32 emc0_mrw13;\n\tu32 emc1_mrw13;\n} burst_reg_per_ch_t;\n\ntypedef struct\n{\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_0;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_1;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_2;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank0_3;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_0;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_1;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_2;\n\tu32 emc_pmacro_ib_ddll_long_dqs_rank1_3;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_0;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_1;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_2;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_0;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_1;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_2;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_0;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_1;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_2;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_0;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_1;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_2;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_0;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_1;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_2;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_0;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_1;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_2;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_0;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_1;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_2;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_0;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_1;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_2;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_0;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_1;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_2;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_0;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_1;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_2;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_0;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_1;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_2;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_0;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_1;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_2;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_0;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_1;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_2;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_0;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_1;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_2;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_0;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_1;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_2;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_0;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_1;\n\tu32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_2;\n\tu32 emc_pmacro_ib_vref_dqs_0;\n\tu32 emc_pmacro_ib_vref_dqs_1;\n\tu32 emc_pmacro_ib_vref_dq_0;\n\tu32 emc_pmacro_ib_vref_dq_1;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_0;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_1;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_2;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_3;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_4;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank0_5;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_0;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_1;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_2;\n\tu32 emc_pmacro_ob_ddll_long_dq_rank1_3;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_2;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_0;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_1;\n\tu32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_2;\n\tu32 emc_pmacro_quse_ddll_rank0_0;\n\tu32 emc_pmacro_quse_ddll_rank0_1;\n\tu32 emc_pmacro_quse_ddll_rank0_2;\n\tu32 emc_pmacro_quse_ddll_rank0_3;\n\tu32 emc_pmacro_quse_ddll_rank1_0;\n\tu32 emc_pmacro_quse_ddll_rank1_1;\n\tu32 emc_pmacro_quse_ddll_rank1_2;\n\tu32 emc_pmacro_quse_ddll_rank1_3;\n} trim_regs_t;\n\ntypedef struct\n{\n\tu32 emc_cmd_brlshft_0;\n\tu32 emc_cmd_brlshft_1;\n\tu32 emc0_data_brlshft_0;\n\tu32 emc1_data_brlshft_0;\n\tu32 emc0_data_brlshft_1;\n\tu32 emc1_data_brlshft_1;\n\tu32 emc_quse_brlshft_0;\n\tu32 emc_quse_brlshft_1;\n\tu32 emc_quse_brlshft_2;\n\tu32 emc_quse_brlshft_3;\n} trim_perch_regs_t;\n\ntypedef struct\n{\n\tu32 t_rp;\n\tu32 t_fc_lpddr4;\n\tu32 t_rfc;\n\tu32 t_pdex;\n\tu32 rl;\n} dram_timings_t;\n\ntypedef struct\n{\n\tu32 emc0_training_opt_dqs_ib_vref_rank0;\n\tu32 emc1_training_opt_dqs_ib_vref_rank0;\n\tu32 emc0_training_opt_dqs_ib_vref_rank1;\n\tu32 emc1_training_opt_dqs_ib_vref_rank1;\n} vref_perch_regs_t;\n\ntypedef struct\n{\n\tu32 trim_regs[138];\n\tu32 trim_perch_regs[10];\n\tu32 vref_perch_regs[4];\n} trim_regs_table_t;\n\ntypedef struct\n{\n\tu32 rev;\n\tchar dvfs_ver[60];\n\tu32 rate_khz;\n\tu32 min_volt;\n\tu32 gpu_min_volt;\n\tchar clock_src[32];\n\tu32 clk_src_emc;\n\tu32 needs_training;\n\tu32 training_pattern;\n\tu32 trained;\n\tu32 periodic_training;\n\tu32 trained_dram_clktree_c0d0u0;\n\tu32 trained_dram_clktree_c0d0u1;\n\tu32 trained_dram_clktree_c0d1u0;\n\tu32 trained_dram_clktree_c0d1u1;\n\tu32 trained_dram_clktree_c1d0u0;\n\tu32 trained_dram_clktree_c1d0u1;\n\tu32 trained_dram_clktree_c1d1u0;\n\tu32 trained_dram_clktree_c1d1u1;\n\tu32 current_dram_clktree_c0d0u0;\n\tu32 current_dram_clktree_c0d0u1;\n\tu32 current_dram_clktree_c0d1u0;\n\tu32 current_dram_clktree_c0d1u1;\n\tu32 current_dram_clktree_c1d0u0;\n\tu32 current_dram_clktree_c1d0u1;\n\tu32 current_dram_clktree_c1d1u0;\n\tu32 current_dram_clktree_c1d1u1;\n\tu32 run_clocks;\n\tu32 tree_margin;\n\tu32 num_burst;\n\tu32 num_burst_per_ch;\n\tu32 num_trim;\n\tu32 num_trim_per_ch;\n\tu32 num_mc_regs;\n\tu32 num_up_down;\n\tu32 vref_num;\n\tu32 training_mod_num;\n\tu32 dram_timing_num;\n\n\tptfv_list_table_t ptfv_list;\n\n\tburst_regs_t burst_regs;\n\tburst_reg_per_ch_t burst_reg_per_ch;\n\tburst_regs_t shadow_regs_ca_train;\n\tburst_regs_t shadow_regs_quse_train;\n\tburst_regs_t shadow_regs_rdwr_train;\n\ttrim_regs_t trim_regs;\n\ttrim_perch_regs_t trim_perch_regs;\n\tvref_perch_regs_t vref_perch_regs;\n\tdram_timings_t dram_timings;\n\n\tu32 training_mod_regs[20];\n\tu32 save_restore_mod_regs[12];\n\tu32 burst_mc_regs[33];\n\tu32 la_scale_regs[24];\n\n\tu32 min_mrs_wait;\n\tu32 emc_mrw;\n\tu32 emc_mrw2;\n\tu32 emc_mrw3;\n\tu32 emc_mrw4;\n\tu32 emc_mrw9;\n\tu32 emc_mrs;\n\tu32 emc_emrs;\n\tu32 emc_emrs2;\n\tu32 emc_auto_cal_config;\n\tu32 emc_auto_cal_config2;\n\tu32 emc_auto_cal_config3;\n\tu32 emc_auto_cal_config4;\n\tu32 emc_auto_cal_config5;\n\tu32 emc_auto_cal_config6;\n\tu32 emc_auto_cal_config7;\n\tu32 emc_auto_cal_config8;\n\tu32 emc_cfg_2;\n\tu32 emc_sel_dpd_ctrl;\n\tu32 emc_fdpd_ctrl_cmd_no_ramp;\n\tu32 dll_clk_src;\n\tu32 clk_out_enb_x_0_clk_enb_emc_dll;\n\tu32 latency;\n} emc_table_t;\n\n#endif"
  },
  {
    "path": "modules/hekate_libsys_minerva/sys_sdrammtc.c",
    "content": "/*\n * Minerva Training Cell\n * DRAM Training for Tegra X1 SoC. Supports LPDDR4.\n *\n * Copyright (c) 2018-2025 CTCaer  <ctcaer@gmail.com>\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n#include <stdlib.h>\n#include \"mtc.h\"\n#include \"mtc_mc_emc_regs.h\"\n#include \"mtc_switch_tables.h\"\n#include \"types.h\"\n#include <module.h>\n\n#define DVFS_T21X_CC_VERSION \"Minerva Training Cell v0.2_T21X\"\n#define DVFS_T210_CC_VERSION \"Minerva Training Cell v1.6_T210\"\n\n#define EPRINTF(...)\n#define EPRINTFARGS(...)\n\nbool train_ram_patterns;\n\n/*\n * REF:  PLL Input reference (OSC_FREQ).\n * DIVN: PLL feedback divider.\n * DIVM: PLL input divider.\n * DIVP: PLL post divider.\n * PLL_OUT = (REF / DIVM) * DIVN / DIVP\n *\n * DIVP    | DIVP\n * Encoded | Real\n * ----------------------\n * 0       | 1 (DIVP off)\n * 1       | 2\n * 2       | 3\n * 3       | 4\n * 4       | 5\n * 5       | 6\n * 6       | 8\n * 7       | 10\n * 8       | 12\n * 9       | 16\n * 10      | 12\n * 11      | 16\n * 12      | 20\n * 13      | 24\n * 14      | 32\n */\nstatic pllm_clk_config_t pllm_clk_config_table[] =\n{\n\t// pll_osc_in, pll_out, pll_feedback_div, pll_input_div, pll_post_div.\n\t// f_in,       f_out,   n,                m,             p.\n\t// f_out = ((f_in / m) * n) / p. Example: 1600000 = (38400 / 2) * 97.\n\t{38400, 297600,  93,  4, 2},\n\t{38400, 400000,  125, 4, 2},\n\t{38400, 408000,  85,  4, 1},\n\t{38400, 532800,  111, 4, 1},\n\t{38400, 665600,  104, 3, 1},\n\t{38400, 800000,  125, 3, 1},\n\t{38400, 931200,  97,  4, 0},\n\t{38400, 1065600, 111, 4, 0},\n\t{38400, 1200000, 125, 4, 0},\n\t{38400, 1331200, 104, 3, 0},\n\t{38400, 1459200, 76,  2, 0},\n\t{38400, 1600000, 125, 3, 0},\n\t{38400, 1728000, 90,  2, 0}, // Custom. Normalized 1733 MHz.\n\t{38400, 1795200, 187, 4, 0}, // Custom. Normalized 1800 MHz.\n\t{38400, 1862400, 97,  2, 0}, // JEDEC Standard. (T210 official max).\n\t{38400, 1894400, 148, 3, 0}, // Custom. Normalized 1900 MHz.\n\t{38400, 1932800, 151, 3, 0}, // Custom. Normalized 1933 MHz.\n\t{38400, 1958400, 102, 2, 0}, // Custom. Normalized 1966 MHz.\n\t{38400, 1996800, 104, 2, 0}, // Custom. Normalized 2000 MHz.\n\t{38400, 2035200, 106, 2, 0}, // Custom. Normalized 2033 MHz.\n\t{38400, 2064000, 215, 4, 0}, // Custom. Normalized 2066 MHz.\n\t{38400, 2099200, 164, 3, 0}, // Custom. Normalized 2100 MHz.\n\t{38400, 2131200, 111, 2, 0}, // JEDEC Standard. (T210B01 official max).\n\t{38400, 2163200, 169, 3, 0}, // Custom. Normalized 2166 MHz.\n\t{38400, 2188800, 114, 2, 0}, // Custom. Normalized 2200 MHz.\n\t{38400, 2227200, 116, 2, 0}, // Custom. Normalized 2233 MHz.\n\t{38400, 2265600, 118, 2, 0}, // Custom. Normalized 2266 MHz.\n\t{38400, 2291200, 179, 3, 0}, // Custom. Normalized 2300 MHz.\n\t{38400, 2329600, 182, 3, 0}, // Custom. Normalized 2333 MHz.\n\t{38400, 2361600, 123, 2, 0}, // Custom. Normalized 2366 MHz.\n \t{0,     0,       0,   0, 0}\n};\n\nstatic const u32 burst_regs_emc_addr_table[221] = {\n\tEMC_RC,\n\tEMC_RFC,\n\tEMC_RFCPB,\n\tEMC_REFCTRL2,\n\tEMC_RFC_SLR,\n\tEMC_RAS,\n\tEMC_RP,\n\tEMC_R2W,\n\tEMC_W2R,\n\tEMC_R2P,\n\tEMC_W2P,\n\tEMC_R2R,\n\tEMC_TPPD,\n\tEMC_CCDMW,\n\tEMC_RD_RCD,\n\tEMC_WR_RCD,\n\tEMC_RRD,\n\tEMC_REXT,\n\tEMC_WEXT,\n\tEMC_WDV_CHK,\n\tEMC_WDV,\n\tEMC_WSV,\n\tEMC_WEV,\n\tEMC_WDV_MASK,\n\tEMC_WS_DURATION,\n\tEMC_WE_DURATION,\n\tEMC_QUSE,\n\tEMC_QUSE_WIDTH,\n\tEMC_IBDLY,\n\tEMC_OBDLY,\n\tEMC_EINPUT,\n\tEMC_MRW6,\n\tEMC_EINPUT_DURATION,\n\tEMC_PUTERM_EXTRA,\n\tEMC_PUTERM_WIDTH,\n\tEMC_QRST,\n\tEMC_QSAFE,\n\tEMC_RDV,\n\tEMC_RDV_MASK,\n\tEMC_RDV_EARLY,\n\tEMC_RDV_EARLY_MASK,\n\tEMC_REFRESH,\n\tEMC_BURST_REFRESH_NUM,\n\tEMC_PRE_REFRESH_REQ_CNT,\n\tEMC_PDEX2WR,\n\tEMC_PDEX2RD,\n\tEMC_PCHG2PDEN,\n\tEMC_ACT2PDEN,\n\tEMC_AR2PDEN,\n\tEMC_RW2PDEN,\n\tEMC_CKE2PDEN,\n\tEMC_PDEX2CKE,\n\tEMC_PDEX2MRR,\n\tEMC_TXSR,\n\tEMC_TXSRDLL,\n\tEMC_TCKE,\n\tEMC_TCKESR,\n\tEMC_TPD,\n\tEMC_TFAW,\n\tEMC_TRPAB,\n\tEMC_TCLKSTABLE,\n\tEMC_TCLKSTOP,\n\tEMC_MRW7,\n\tEMC_TREFBW,\n\tEMC_ODT_WRITE,\n\tEMC_FBIO_CFG5,\n\tEMC_FBIO_CFG7,\n\tEMC_CFG_DIG_DLL,\n\tEMC_CFG_DIG_DLL_PERIOD,\n\tEMC_PMACRO_IB_RXRT,\n\tEMC_CFG_PIPE_1,\n\tEMC_CFG_PIPE_2,\n\tEMC_PMACRO_QUSE_DDLL_RANK0_4,\n\tEMC_PMACRO_QUSE_DDLL_RANK0_5,\n\tEMC_PMACRO_QUSE_DDLL_RANK1_4,\n\tEMC_PMACRO_QUSE_DDLL_RANK1_5,\n\tEMC_MRW8,\n\tEMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4,\n\tEMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5,\n\tEMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0,\n\tEMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1,\n\tEMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2,\n\tEMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3,\n\tEMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4,\n\tEMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5,\n\tEMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0,\n\tEMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1,\n\tEMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2,\n\tEMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3,\n\tEMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4,\n\tEMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5,\n\tEMC_PMACRO_DDLL_LONG_CMD_0,\n\tEMC_PMACRO_DDLL_LONG_CMD_1,\n\tEMC_PMACRO_DDLL_LONG_CMD_2,\n\tEMC_PMACRO_DDLL_LONG_CMD_3,\n\tEMC_PMACRO_DDLL_LONG_CMD_4,\n\tEMC_PMACRO_DDLL_SHORT_CMD_0,\n\tEMC_PMACRO_DDLL_SHORT_CMD_1,\n\tEMC_PMACRO_DDLL_SHORT_CMD_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_3,\n\tEMC_TXDSRVTTGEN,\n\tEMC_FDPD_CTRL_DQ,\n\tEMC_FDPD_CTRL_CMD,\n\tEMC_FBIO_SPARE,\n\tEMC_ZCAL_INTERVAL,\n\tEMC_ZCAL_WAIT_CNT,\n\tEMC_MRS_WAIT_CNT,\n\tEMC_MRS_WAIT_CNT2,\n\tEMC_AUTO_CAL_CHANNEL,\n\tEMC_DLL_CFG_0,\n\tEMC_DLL_CFG_1,\n\tEMC_PMACRO_AUTOCAL_CFG_COMMON,\n\tEMC_PMACRO_ZCTRL,\n\tEMC_CFG,\n\tEMC_CFG_PIPE,\n\tEMC_DYN_SELF_REF_CONTROL,\n\tEMC_QPOP,\n\tEMC_DQS_BRLSHFT_0,\n\tEMC_DQS_BRLSHFT_1,\n\tEMC_CMD_BRLSHFT_2,\n\tEMC_CMD_BRLSHFT_3,\n\tEMC_PMACRO_PAD_CFG_CTRL,\n\tEMC_PMACRO_DATA_PAD_RX_CTRL,\n\tEMC_PMACRO_CMD_PAD_RX_CTRL,\n\tEMC_PMACRO_DATA_RX_TERM_MODE,\n\tEMC_PMACRO_CMD_RX_TERM_MODE,\n\tEMC_PMACRO_CMD_PAD_TX_CTRL,\n\tEMC_PMACRO_DATA_PAD_TX_CTRL,\n\tEMC_PMACRO_COMMON_PAD_TX_CTRL,\n\tEMC_PMACRO_VTTGEN_CTRL_0,\n\tEMC_PMACRO_VTTGEN_CTRL_1,\n\tEMC_PMACRO_VTTGEN_CTRL_2,\n\tEMC_PMACRO_BRICK_CTRL_RFU1,\n\tEMC_PMACRO_CMD_BRICK_CTRL_FDPD,\n\tEMC_PMACRO_BRICK_CTRL_RFU2,\n\tEMC_PMACRO_DATA_BRICK_CTRL_FDPD,\n\tEMC_PMACRO_BG_BIAS_CTRL_0,\n\tEMC_CFG_3,\n\tEMC_PMACRO_TX_PWRD_0,\n\tEMC_PMACRO_TX_PWRD_1,\n\tEMC_PMACRO_TX_PWRD_2,\n\tEMC_PMACRO_TX_PWRD_3,\n\tEMC_PMACRO_TX_PWRD_4,\n\tEMC_PMACRO_TX_PWRD_5,\n\tEMC_CONFIG_SAMPLE_DELAY,\n\tEMC_PMACRO_TX_SEL_CLK_SRC_0,\n\tEMC_PMACRO_TX_SEL_CLK_SRC_1,\n\tEMC_PMACRO_TX_SEL_CLK_SRC_2,\n\tEMC_PMACRO_TX_SEL_CLK_SRC_3,\n\tEMC_PMACRO_TX_SEL_CLK_SRC_4,\n\tEMC_PMACRO_TX_SEL_CLK_SRC_5,\n\tEMC_PMACRO_DDLL_BYPASS,\n\tEMC_PMACRO_DDLL_PWRD_0,\n\tEMC_PMACRO_DDLL_PWRD_1,\n\tEMC_PMACRO_DDLL_PWRD_2,\n\tEMC_PMACRO_CMD_CTRL_0,\n\tEMC_PMACRO_CMD_CTRL_1,\n\tEMC_PMACRO_CMD_CTRL_2,\n\tEMC_TR_TIMING_0,\n\tEMC_TR_DVFS,\n\tEMC_TR_CTRL_1,\n\tEMC_TR_RDV,\n\tEMC_TR_QPOP,\n\tEMC_TR_RDV_MASK,\n\tEMC_MRW14,\n\tEMC_TR_QSAFE,\n\tEMC_TR_QRST,\n\tEMC_TRAINING_CTRL,\n\tEMC_TRAINING_SETTLE,\n\tEMC_TRAINING_VREF_SETTLE,\n\tEMC_TRAINING_CA_FINE_CTRL,\n\tEMC_TRAINING_CA_CTRL_MISC,\n\tEMC_TRAINING_CA_CTRL_MISC1,\n\tEMC_TRAINING_CA_VREF_CTRL,\n\tEMC_TRAINING_QUSE_CORS_CTRL,\n\tEMC_TRAINING_QUSE_FINE_CTRL,\n\tEMC_TRAINING_QUSE_CTRL_MISC,\n\tEMC_TRAINING_QUSE_VREF_CTRL,\n\tEMC_TRAINING_READ_FINE_CTRL,\n\tEMC_TRAINING_READ_CTRL_MISC,\n\tEMC_TRAINING_READ_VREF_CTRL,\n\tEMC_TRAINING_WRITE_FINE_CTRL,\n\tEMC_TRAINING_WRITE_CTRL_MISC,\n\tEMC_TRAINING_WRITE_VREF_CTRL,\n\tEMC_TRAINING_MPC,\n\tEMC_MRW15\n};\n\nstatic const u32 burst_reg_per_ch_emc01_addr_table[8] = {\n\tEMC0_MRW10,\n\tEMC1_MRW10,\n\tEMC0_MRW11,\n\tEMC1_MRW11,\n\tEMC0_MRW12,\n\tEMC1_MRW12,\n\tEMC0_MRW13,\n\tEMC1_MRW13\n};\n\nstatic const u32 vref_perch_regs_emc01_addr_table[4] = {\n\tEMC0_TRAINING_OPT_DQS_IB_VREF_RANK0,\n\tEMC1_TRAINING_OPT_DQS_IB_VREF_RANK0,\n\tEMC0_TRAINING_OPT_DQS_IB_VREF_RANK1,\n\tEMC1_TRAINING_OPT_DQS_IB_VREF_RANK1\n};\n\nstatic const u32 training_mod_regs_emc01_addr_table[20] = {\n\tEMC0_TRAINING_RW_OFFSET_IB_BYTE0,\n\tEMC1_TRAINING_RW_OFFSET_IB_BYTE0,\n\tEMC0_TRAINING_RW_OFFSET_IB_BYTE1,\n\tEMC1_TRAINING_RW_OFFSET_IB_BYTE1,\n\tEMC0_TRAINING_RW_OFFSET_IB_BYTE2,\n\tEMC1_TRAINING_RW_OFFSET_IB_BYTE2,\n\tEMC0_TRAINING_RW_OFFSET_IB_BYTE3,\n\tEMC1_TRAINING_RW_OFFSET_IB_BYTE3,\n\tEMC0_TRAINING_RW_OFFSET_IB_MISC,\n\tEMC1_TRAINING_RW_OFFSET_IB_MISC,\n\tEMC0_TRAINING_RW_OFFSET_OB_BYTE0,\n\tEMC1_TRAINING_RW_OFFSET_OB_BYTE0,\n\tEMC0_TRAINING_RW_OFFSET_OB_BYTE1,\n\tEMC1_TRAINING_RW_OFFSET_OB_BYTE1,\n\tEMC0_TRAINING_RW_OFFSET_OB_BYTE2,\n\tEMC1_TRAINING_RW_OFFSET_OB_BYTE2,\n\tEMC0_TRAINING_RW_OFFSET_OB_BYTE3,\n\tEMC1_TRAINING_RW_OFFSET_OB_BYTE3,\n\tEMC0_TRAINING_RW_OFFSET_OB_MISC,\n\tEMC1_TRAINING_RW_OFFSET_OB_MISC\n};\n\nstatic const u32 trim_regs_emc_addr_table[138] = {\n\tEMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0,\n\tEMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1,\n\tEMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2,\n\tEMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3,\n\tEMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0,\n\tEMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1,\n\tEMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2,\n\tEMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1,\n\tEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2,\n\tEMC_PMACRO_IB_VREF_DQS_0,\n\tEMC_PMACRO_IB_VREF_DQS_1,\n\tEMC_PMACRO_IB_VREF_DQ_0,\n\tEMC_PMACRO_IB_VREF_DQ_1,\n\tEMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0,\n\tEMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1,\n\tEMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2,\n\tEMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3,\n\tEMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4,\n\tEMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5,\n\tEMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0,\n\tEMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1,\n\tEMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2,\n\tEMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1,\n\tEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2,\n\tEMC_PMACRO_QUSE_DDLL_RANK0_0,\n\tEMC_PMACRO_QUSE_DDLL_RANK0_1,\n\tEMC_PMACRO_QUSE_DDLL_RANK0_2,\n\tEMC_PMACRO_QUSE_DDLL_RANK0_3,\n\tEMC_PMACRO_QUSE_DDLL_RANK1_0,\n\tEMC_PMACRO_QUSE_DDLL_RANK1_1,\n\tEMC_PMACRO_QUSE_DDLL_RANK1_2,\n\tEMC_PMACRO_QUSE_DDLL_RANK1_3\n};\n\nstatic const u32 trim_perch_regs_emc01_addr_table[10] = {\n\tEMC0_CMD_BRLSHFT_0,\n\tEMC1_CMD_BRLSHFT_1,\n\tEMC0_DATA_BRLSHFT_0,\n\tEMC1_DATA_BRLSHFT_0,\n\tEMC0_DATA_BRLSHFT_1,\n\tEMC1_DATA_BRLSHFT_1,\n\tEMC0_QUSE_BRLSHFT_0,\n\tEMC1_QUSE_BRLSHFT_1,\n\tEMC0_QUSE_BRLSHFT_2,\n\tEMC1_QUSE_BRLSHFT_3\n};\n\nstatic const u32 burst_mc_regs_addr_table[33] = {\n\tMC_EMEM_ARB_CFG,\n\tMC_EMEM_ARB_OUTSTANDING_REQ,\n\tMC_EMEM_ARB_REFPB_HP_CTRL,\n\tMC_EMEM_ARB_REFPB_BANK_CTRL,\n\tMC_EMEM_ARB_TIMING_RCD,\n\tMC_EMEM_ARB_TIMING_RP,\n\tMC_EMEM_ARB_TIMING_RC,\n\tMC_EMEM_ARB_TIMING_RAS,\n\tMC_EMEM_ARB_TIMING_FAW,\n\tMC_EMEM_ARB_TIMING_RRD,\n\tMC_EMEM_ARB_TIMING_RAP2PRE,\n\tMC_EMEM_ARB_TIMING_WAP2PRE,\n\tMC_EMEM_ARB_TIMING_R2R,\n\tMC_EMEM_ARB_TIMING_W2W,\n\tMC_EMEM_ARB_TIMING_R2W,\n\tMC_EMEM_ARB_TIMING_CCDMW,\n\tMC_EMEM_ARB_TIMING_W2R,\n\tMC_EMEM_ARB_TIMING_RFCPB,\n\tMC_EMEM_ARB_DA_TURNS,\n\tMC_EMEM_ARB_DA_COVERS,\n\tMC_EMEM_ARB_MISC0,\n\tMC_EMEM_ARB_MISC1,\n\tMC_EMEM_ARB_MISC2,\n\tMC_EMEM_ARB_RING1_THROTTLE,\n\tMC_EMEM_ARB_DHYST_CTRL,\n\tMC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0,\n\tMC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1,\n\tMC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2,\n\tMC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3,\n\tMC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4,\n\tMC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5,\n\tMC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6,\n\tMC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7\n};\n\nstatic const u32 la_scale_regs_mc_addr_table[24] = {\n\tMC_MLL_MPCORER_PTSA_RATE,\n\tMC_FTOP_PTSA_RATE,\n\tMC_PTSA_GRANT_DECREMENT,\n\tMC_LATENCY_ALLOWANCE_XUSB_0,\n\tMC_LATENCY_ALLOWANCE_XUSB_1,\n\tMC_LATENCY_ALLOWANCE_TSEC_0,\n\tMC_LATENCY_ALLOWANCE_SDMMCA_0,\n\tMC_LATENCY_ALLOWANCE_SDMMCAA_0,\n\tMC_LATENCY_ALLOWANCE_SDMMC_0,\n\tMC_LATENCY_ALLOWANCE_SDMMCAB_0,\n\tMC_LATENCY_ALLOWANCE_PPCS_0,\n\tMC_LATENCY_ALLOWANCE_PPCS_1,\n\tMC_LATENCY_ALLOWANCE_MPCORE_0,\n\tMC_LATENCY_ALLOWANCE_HC_0,\n\tMC_LATENCY_ALLOWANCE_HC_1,\n\tMC_LATENCY_ALLOWANCE_AVPC_0,\n\tMC_LATENCY_ALLOWANCE_GPU_0,\n\tMC_LATENCY_ALLOWANCE_GPU2_0,\n\tMC_LATENCY_ALLOWANCE_NVENC_0,\n\tMC_LATENCY_ALLOWANCE_NVDEC_0,\n\tMC_LATENCY_ALLOWANCE_VIC_0,\n\tMC_LATENCY_ALLOWANCE_VI2_0,\n\tMC_LATENCY_ALLOWANCE_ISP2_0,\n\tMC_LATENCY_ALLOWANCE_ISP2_1\n};\n\nstatic const u32 periodic_training_addr[10] =\n{\n\tEMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0,\n\tEMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1,\n\tEMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2,\n\tEMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3,\n\tEMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0,\n\tEMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1,\n\tEMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2,\n\tEMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3,\n\tEMC_DATA_BRLSHFT_0,\n\tEMC_DATA_BRLSHFT_1\n};\n\nstatic const u32 ram_pattern_dq_table[0x500] = {\n\t/* DQ RAM Patterns Table 0 */\n\t0x18181818, 0x61616161, 0x85858585, 0x14141414, 0x51515151,\n\t0x47474747, 0x1E1E1E1E, 0x79797979, 0xE5E5E5E5, 0x94949494,\n\t0x51515151, 0x46464646, 0x19191919, 0x67676767, 0x9C9C9C9C,\n\t0x71717171, 0xC5C5C5C5, 0x17171717, 0x5F5F5F5F, 0x7E7E7E7E,\n\t0xFBFBFBFB, 0xEDEDEDED, 0xB4B4B4B4, 0xD2D2D2D2, 0x48484848,\n\t0x21212121, 0x85858585, 0x16161616, 0x59595959, 0x66666666,\n\t0x9A9A9A9A, 0x69696969, 0xA4A4A4A4, 0x93939393, 0x4F4F4F4F,\n\t0x3F3F3F3F, 0xFCFCFCFC, 0xF3F3F3F3, 0xCDCDCDCD, 0x37373737,\n\t0xDCDCDCDC, 0x70707070, 0xC3C3C3C3, 0x0F0F0F0F, 0x3E3E3E3E,\n\t0xFAFAFAFA, 0xEBEBEBEB, 0xACACACAC, 0xB3B3B3B3, 0xCCCCCCCC,\n\t0x31313131, 0xC5C5C5C5, 0x15151515, 0x57575757, 0x5F5F5F5F,\n\t0x7F7F7F7F, 0xFDFDFDFD, 0xF4F4F4F4, 0xD0D0D0D0, 0x42424242,\n\t0x08080808, 0x23232323, 0x8F8F8F8F, 0x3F3F3F3F, 0x18181818,\n\t0x61616161, 0x85858585, 0x14141414, 0x51515151, 0x47474747,\n\t0x1E1E1E1E, 0x79797979, 0xE5E5E5E5, 0x94949494, 0x51515151,\n\t0x46464646, 0x19191919, 0x67676767, 0x9C9C9C9C, 0x71717171,\n\t0xC5C5C5C5, 0x17171717, 0x5F5F5F5F, 0x7E7E7E7E, 0xFBFBFBFB,\n\t0xEDEDEDED, 0xB4B4B4B4, 0xD2D2D2D2, 0x48484848, 0x21212121,\n\t0x85858585, 0x16161616, 0x59595959, 0x66666666, 0x9A9A9A9A,\n\t0x69696969, 0xA4A4A4A4, 0x93939393, 0x4F4F4F4F, 0x3F3F3F3F,\n\t0xFCFCFCFC, 0xF3F3F3F3, 0xCDCDCDCD, 0x37373737, 0xDCDCDCDC,\n\t0x70707070, 0xC3C3C3C3, 0x0F0F0F0F, 0x3E3E3E3E, 0xFAFAFAFA,\n\t0xEBEBEBEB, 0xACACACAC, 0xB3B3B3B3, 0xCCCCCCCC, 0x31313131,\n\t0xC5C5C5C5, 0x15151515, 0x57575757, 0x5F5F5F5F, 0x7F7F7F7F,\n\t0xFDFDFDFD, 0xF4F4F4F4, 0xD0D0D0D0, 0x42424242, 0x08080808,\n\t0x23232323, 0x8F8F8F8F, 0x3F3F3F3F, 0x06060606, 0x18181818,\n\t0x21212121, 0x05050505, 0x14141414, 0x11111111, 0x07070707,\n\t0x1E1E1E1E, 0x39393939, 0x25252525, 0x14141414, 0x11111111,\n\t0x06060606, 0x19191919, 0x27272727, 0x1C1C1C1C, 0x31313131,\n\t0x05050505, 0x17171717, 0x1F1F1F1F, 0x3E3E3E3E, 0x3B3B3B3B,\n\t0x2D2D2D2D, 0x34343434, 0x12121212, 0x08080808, 0x21212121,\n\t0x05050505, 0x16161616, 0x19191919, 0x26262626, 0x1A1A1A1A,\n\t0x29292929, 0x24242424, 0x13131313, 0x0F0F0F0F, 0x3F3F3F3F,\n\t0x3C3C3C3C, 0x33333333, 0x0D0D0D0D, 0x37373737, 0x1C1C1C1C,\n\t0x30303030, 0x03030303, 0x0F0F0F0F, 0x3E3E3E3E, 0x3A3A3A3A,\n\t0x2B2B2B2B, 0x2C2C2C2C, 0x33333333, 0x0C0C0C0C, 0x31313131,\n\t0x05050505, 0x15151515, 0x17171717, 0x1F1F1F1F, 0x3F3F3F3F,\n\t0x3D3D3D3D, 0x34343434, 0x10101010, 0x02020202, 0x08080808,\n\t0x23232323, 0x0F0F0F0F, 0x06060606, 0x18181818, 0x21212121,\n\t0x05050505, 0x14141414, 0x11111111, 0x07070707, 0x1E1E1E1E,\n\t0x39393939, 0x25252525, 0x14141414, 0x11111111, 0x06060606,\n\t0x19191919, 0x27272727, 0x1C1C1C1C, 0x31313131, 0x05050505,\n\t0x17171717, 0x1F1F1F1F, 0x3E3E3E3E, 0x3B3B3B3B, 0x2D2D2D2D,\n\t0x34343434, 0x12121212, 0x08080808, 0x21212121, 0x05050505,\n\t0x16161616, 0x19191919, 0x26262626, 0x1A1A1A1A, 0x29292929,\n\t0x24242424, 0x13131313, 0x0F0F0F0F, 0x3F3F3F3F, 0x3C3C3C3C,\n\t0x33333333, 0x0D0D0D0D, 0x37373737, 0x1C1C1C1C, 0x30303030,\n\t0x03030303, 0x0F0F0F0F, 0x3E3E3E3E, 0x3A3A3A3A, 0x2B2B2B2B,\n\t0x2C2C2C2C, 0x33333333, 0x0C0C0C0C, 0x31313131, 0x05050505,\n\t0x15151515, 0x17171717, 0x1F1F1F1F, 0x3F3F3F3F, 0x3D3D3D3D,\n\t0x34343434, 0x10101010, 0x02020202, 0x08080808, 0x23232323,\n\t0x0F0F0F0F,\n\n\t/* DQ RAM Patterns Table 1 */\n\t0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000,\n\t0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,\n\t0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF,\n\t0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000,\n\t0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,\n\t0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000,\n\t0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,\n\t0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,\n\t0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000,\n\t0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,\n\t0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000,\n\t0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,\n\t0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000,\n\t0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000,\n\t0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,\n\t0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000,\n\t0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF,\n\t0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,\n\t0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF,\n\t0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,\n\t0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,\n\t0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF,\n\t0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,\n\t0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000,\n\t0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,\n\t0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000,\n\t0x3F3F3F3F, 0x00000000, 0x00000000, 0x00000000, 0x00000000,\n\t0x00000000, 0x3F3F3F3F, 0x3F3F3F3F, 0x00000000, 0x00000000,\n\t0x00000000, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F,\n\t0x00000000, 0x00000000, 0x00000000, 0x3F3F3F3F, 0x3F3F3F3F,\n\t0x3F3F3F3F, 0x3F3F3F3F, 0x00000000, 0x00000000, 0x3F3F3F3F,\n\t0x00000000, 0x00000000, 0x00000000, 0x3F3F3F3F, 0x00000000,\n\t0x3F3F3F3F, 0x3F3F3F3F, 0x00000000, 0x00000000, 0x3F3F3F3F,\n\t0x3F3F3F3F, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000,\n\t0x3F3F3F3F, 0x00000000, 0x00000000, 0x3F3F3F3F, 0x3F3F3F3F,\n\t0x3F3F3F3F, 0x3F3F3F3F, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F,\n\t0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3F3F3F3F,\n\t0x3F3F3F3F, 0x3F3F3F3F, 0x00000000, 0x00000000, 0x00000000,\n\t0x3F3F3F3F, 0x00000000, 0x00000000, 0x00000000, 0x3F3F3F3F,\n\t0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,\n\t0x3F3F3F3F, 0x3F3F3F3F, 0x00000000, 0x00000000, 0x00000000,\n\t0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000,\n\t0x00000000, 0x00000000, 0x3F3F3F3F, 0x3F3F3F3F, 0x3F3F3F3F,\n\t0x3F3F3F3F, 0x00000000, 0x00000000, 0x3F3F3F3F, 0x00000000,\n\t0x00000000, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F,\n\t0x3F3F3F3F, 0x00000000, 0x00000000, 0x3F3F3F3F, 0x3F3F3F3F,\n\t0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F,\n\t0x00000000, 0x00000000, 0x3F3F3F3F, 0x3F3F3F3F, 0x3F3F3F3F,\n\t0x3F3F3F3F, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000,\n\t0x00000000, 0x00000000, 0x00000000, 0x3F3F3F3F, 0x3F3F3F3F,\n\t0x3F3F3F3F, 0x00000000, 0x00000000, 0x00000000, 0x3F3F3F3F,\n\t0x00000000,\n\n\t/* DQ RAM Patterns Table 2 */\n\t0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,\n\t0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,\n\t0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,\n\t0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,\n\t0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,\n\t0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,\n\t0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,\n\t0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,\n\t0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,\n\t0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,\n\t0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,\n\t0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,\n\t0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,\n\t0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,\n\t0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,\n\t0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,\n\t0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,\n\t0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,\n\t0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,\n\t0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,\n\t0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,\n\t0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,\n\t0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,\n\t0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,\n\t0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000,\n\t0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x3F3F3F3F,\n\t0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000,\n\t0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F,\n\t0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000,\n\t0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F,\n\t0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000,\n\t0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F,\n\t0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000,\n\t0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F,\n\t0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000,\n\t0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F,\n\t0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000,\n\t0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F,\n\t0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000,\n\t0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F,\n\t0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000,\n\t0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F,\n\t0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000,\n\t0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F,\n\t0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000,\n\t0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F,\n\t0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000,\n\t0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F,\n\t0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000,\n\t0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F,\n\t0x00000000, 0x3F3F3F3F, 0x00000000, 0x3F3F3F3F, 0x00000000,\n\t0x3F3F3F3F,\n\n\t/* DQ RAM Patterns Table 3 */\n\t0x80808080, 0x00000000, 0x80808080, 0x00000000, 0x80808080,\n\t0x00000000, 0x80808080, 0x40404040, 0x00000000, 0x40404040,\n\t0x00000000, 0x40404040, 0x00000000, 0x40404040, 0x20202020,\n\t0x00000000, 0x20202020, 0x00000000, 0x20202020, 0x00000000,\n\t0x20202020, 0x10101010, 0x00000000, 0x10101010, 0x00000000,\n\t0x10101010, 0x00000000, 0x10101010, 0x08080808, 0x00000000,\n\t0x08080808, 0x00000000, 0x08080808, 0x00000000, 0x08080808,\n\t0x04040404, 0x00000000, 0x04040404, 0x00000000, 0x04040404,\n\t0x00000000, 0x04040404, 0x02020202, 0x00000000, 0x02020202,\n\t0x00000000, 0x02020202, 0x00000000, 0x02020202, 0x01010101,\n\t0x00000000, 0x01010101, 0x00000000, 0x01010101, 0x00000000,\n\t0x01010101, 0x00000000, 0x00000000, 0x00000000, 0x00000000,\n\t0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80808080,\n\t0x00000000, 0x80808080, 0x00000000, 0x80808080, 0x00000000,\n\t0x80808080, 0x40404040, 0x00000000, 0x40404040, 0x00000000,\n\t0x40404040, 0x00000000, 0x40404040, 0x20202020, 0x00000000,\n\t0x20202020, 0x00000000, 0x20202020, 0x00000000, 0x20202020,\n\t0x10101010, 0x00000000, 0x10101010, 0x00000000, 0x10101010,\n\t0x00000000, 0x10101010, 0x08080808, 0x00000000, 0x08080808,\n\t0x00000000, 0x08080808, 0x00000000, 0x08080808, 0x04040404,\n\t0x00000000, 0x04040404, 0x00000000, 0x04040404, 0x00000000,\n\t0x04040404, 0x02020202, 0x00000000, 0x02020202, 0x00000000,\n\t0x02020202, 0x00000000, 0x02020202, 0x01010101, 0x00000000,\n\t0x01010101, 0x00000000, 0x01010101, 0x00000000, 0x01010101,\n\t0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,\n\t0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x20202020,\n\t0x00000000, 0x20202020, 0x00000000, 0x20202020, 0x00000000,\n\t0x20202020, 0x00000000, 0x20202020, 0x00000000, 0x10101010,\n\t0x00000000, 0x10101010, 0x00000000, 0x10101010, 0x00000000,\n\t0x10101010, 0x00000000, 0x10101010, 0x00000000, 0x08080808,\n\t0x00000000, 0x08080808, 0x00000000, 0x08080808, 0x00000000,\n\t0x08080808, 0x00000000, 0x08080808, 0x00000000, 0x04040404,\n\t0x00000000, 0x04040404, 0x00000000, 0x04040404, 0x00000000,\n\t0x04040404, 0x00000000, 0x04040404, 0x00000000, 0x02020202,\n\t0x00000000, 0x02020202, 0x00000000, 0x02020202, 0x00000000,\n\t0x02020202, 0x00000000, 0x02020202, 0x00000000, 0x01010101,\n\t0x00000000, 0x01010101, 0x00000000, 0x01010101, 0x00000000,\n\t0x01010101, 0x00000000, 0x01010101, 0x00000000, 0x00000000,\n\t0x00000000, 0x00000000, 0x00000000, 0x20202020, 0x00000000,\n\t0x20202020, 0x00000000, 0x20202020, 0x00000000, 0x20202020,\n\t0x00000000, 0x20202020, 0x00000000, 0x10101010, 0x00000000,\n\t0x10101010, 0x00000000, 0x10101010, 0x00000000, 0x10101010,\n\t0x00000000, 0x10101010, 0x00000000, 0x08080808, 0x00000000,\n\t0x08080808, 0x00000000, 0x08080808, 0x00000000, 0x08080808,\n\t0x00000000, 0x08080808, 0x00000000, 0x04040404, 0x00000000,\n\t0x04040404, 0x00000000, 0x04040404, 0x00000000, 0x04040404,\n\t0x00000000, 0x04040404, 0x00000000, 0x02020202, 0x00000000,\n\t0x02020202, 0x00000000, 0x02020202, 0x00000000, 0x02020202,\n\t0x00000000, 0x02020202, 0x00000000, 0x01010101, 0x00000000,\n\t0x01010101, 0x00000000, 0x01010101, 0x00000000, 0x01010101,\n\t0x00000000, 0x01010101, 0x00000000, 0x00000000, 0x00000000,\n\t0x00000000,\n\n\t/* DQ RAM Patterns Table 4 */\n\t0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA,\n\t0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555,\n\t0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC,\n\t0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333,\n\t0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA,\n\t0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555,\n\t0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC,\n\t0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333,\n\t0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA,\n\t0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555,\n\t0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC,\n\t0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333,\n\t0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA,\n\t0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555,\n\t0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC,\n\t0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333,\n\t0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA,\n\t0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555,\n\t0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC,\n\t0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333,\n\t0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA,\n\t0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555,\n\t0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC,\n\t0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333,\n\t0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA,\n\t0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555,\n\t0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC,\n\t0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333,\n\t0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA,\n\t0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555,\n\t0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC,\n\t0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333,\n\t0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA,\n\t0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555,\n\t0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC,\n\t0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333,\n\t0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA,\n\t0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555,\n\t0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC,\n\t0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333,\n\t0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA,\n\t0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555,\n\t0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC,\n\t0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333,\n\t0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA,\n\t0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555,\n\t0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC,\n\t0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333,\n\t0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA,\n\t0x55555555, 0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555,\n\t0xCCCCCCCC, 0x33333333, 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC,\n\t0x33333333\n};\n\nstatic const u32 ram_pattern_dmi_table[0x500] = {\n\t/* DMI RAM Patterns Table 0 */\n\t0xF, 0xF, 0x0, 0xF, 0xF, 0x0, 0xF, 0xF,\n\t0x0, 0xF, 0x0, 0xF, 0xF, 0x0, 0xF, 0xF,\n\t0xF, 0xF, 0x0, 0xF, 0xF, 0x0, 0x0, 0x0,\n\t0xF, 0xF, 0x0, 0xF, 0x0, 0x0, 0xF, 0x0,\n\t0xF, 0xF, 0xF, 0x0, 0xF, 0xF, 0xF, 0x0,\n\t0x0, 0xF, 0xF, 0x0, 0x0, 0xF, 0x0, 0xF,\n\t0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF,\n\t0x0, 0x0, 0x0, 0x0, 0xF, 0xF, 0xF, 0x0,\n\t0xF, 0xF, 0x0, 0xF, 0xF, 0x0, 0xF, 0xF,\n\t0x0, 0xF, 0x0, 0xF, 0xF, 0x0, 0xF, 0xF,\n\t0xF, 0xF, 0x0, 0xF, 0xF, 0x0, 0x0, 0x0,\n\t0xF, 0xF, 0x0, 0xF, 0x0, 0x0, 0xF, 0x0,\n\t0xF, 0xF, 0xF, 0x0, 0xF, 0xF, 0xF, 0x0,\n\t0x0, 0xF, 0xF, 0x0, 0x0, 0xF, 0x0, 0xF,\n\t0x0, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF,\n\t0x0, 0x0, 0x0, 0x0, 0xF, 0xF, 0xF, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\n\t/* DMI RAM Patterns Table 1 */\n\t0x0, 0x0, 0xF, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0xF, 0xF, 0x0, 0x0, 0x0, 0x0, 0xF, 0x0,\n\t0xF, 0x0, 0x0, 0x0, 0xF, 0xF, 0xF, 0xF,\n\t0x0, 0x0, 0xF, 0x0, 0x0, 0x0, 0xF, 0x0,\n\t0xF, 0xF, 0x0, 0x0, 0xF, 0xF, 0xF, 0x0,\n\t0xF, 0x0, 0xF, 0x0, 0x0, 0xF, 0xF, 0xF,\n\t0xF, 0xF, 0x0, 0xF, 0x0, 0x0, 0x0, 0x0,\n\t0xF, 0xF, 0xF, 0x0, 0x0, 0x0, 0xF, 0x0,\n\t0x0, 0x0, 0xF, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0xF, 0xF, 0x0, 0x0, 0x0, 0x0, 0xF, 0x0,\n\t0xF, 0x0, 0x0, 0x0, 0xF, 0xF, 0xF, 0xF,\n\t0x0, 0x0, 0xF, 0x0, 0x0, 0x0, 0xF, 0x0,\n\t0xF, 0xF, 0x0, 0x0, 0xF, 0xF, 0xF, 0x0,\n\t0xF, 0x0, 0xF, 0x0, 0x0, 0xF, 0xF, 0xF,\n\t0xF, 0xF, 0x0, 0xF, 0x0, 0x0, 0x0, 0x0,\n\t0xF, 0xF, 0xF, 0x0, 0x0, 0x0, 0xF, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\n\t/* DMI RAM Patterns Table 2 */\n\t0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF,\n\t0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF,\n\t0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF,\n\t0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF,\n\t0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF,\n\t0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF,\n\t0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF,\n\t0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF,\n\t0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF,\n\t0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF,\n\t0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF,\n\t0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF,\n\t0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF,\n\t0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF,\n\t0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF,\n\t0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\n\t/* DMI RAM Patterns Table 3 */\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0xF, 0x0, 0xF, 0x0, 0xF, 0x0, 0xF, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\n\t/* DMI RAM Patterns Table 4 */\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3,\n\t0xA, 0x5, 0xC, 0x3, 0xA, 0x5, 0xC, 0x3\n};\n\nstatic void _usleep(u32 microseconds)\n{\n\tu32 start = TMR(0x10);\n\twhile ((u32)(TMR(0x10) - start) <= microseconds)\n\t\t;\n}\n\nstatic u32 _div_o3(u32 a, u32 b)\n{\n\tu32 result = a / b;\n\n\tif ((b * result) < a)\n\t\treturn result + 1;\n\telse\n\t\treturn result;\n}\n\nstatic u32 _actual_osc_clocks(u32 in)\n{\n\tu32 actual_clock;\n\n\tactual_clock = 16 * in;\n\tif (in > 63)\n\t{\n\t\tactual_clock = 2048;\n\t\tif (in > 127)\n\t\t{\n\t\t\tif (in >= 192)\n\t\t\t\tactual_clock = 8192;\n\t\t\telse\n\t\t\t\tactual_clock = 4096;\n\t\t}\n\t}\n\n\treturn actual_clock;\n}\n\nstatic void _ccfifo_write(u32 addr, u32 data_val, u32 delay) //addr and delay are u16\n{\n\tEMC(EMC_CCFIFO_DATA) = data_val;\n\tEMC(EMC_CCFIFO_ADDR) = BIT(31) | (addr & 0xffff) | ((delay & 0x7FFF) << 16);\n}\n\nstatic bool _wait_emc_status(u32 reg_offset, u32 bit_mask, bool updated_state, u32 emc_channel)\n{\n\tbool err = true;\n\n\tfor (u32 i = 0; i < EMC_STATUS_UPDATE_TIMEOUT; i++)\n\t{\n\t\tif (emc_channel)\n\t\t{\n\t\t\tif (emc_channel != 1)\n\t\t\t\tgoto done;\n\n\t\t\tif (((EMC_CH1(reg_offset) & bit_mask) != 0) == updated_state)\n\t\t\t{\n\t\t\t\terr = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse if (((EMC(reg_offset) & bit_mask) != 0) == updated_state)\n\t\t{\n\t\t\terr = false;\n\t\t\tbreak;\n\t\t}\n\t\t_usleep(1);\n\t}\n\ndone:\n\treturn err;\n}\n\nstatic void _request_mmr_data(u32 data, bool dual_channel)\n{\n\tEMC(EMC_MRR) = data;\n\t_wait_emc_status(EMC_EMC_STATUS, MRR_DIVLD, true, EMC_CHANNEL0);\n\tif (dual_channel)\n\t\t_wait_emc_status(EMC_EMC_STATUS, MRR_DIVLD, true, EMC_CHANNEL1);\n}\n\nstatic void _start_periodic_compensation()\n{\n\tEMC(EMC_MPC) = 0x4B;\n\t(void)EMC(EMC_MPC);\n}\n\nstatic bool _timing_update(u32 dual_channel)\n{\n\tbool err = 0;\n\n\tEMC(EMC_TIMING_CONTROL) = 1;\n\terr = _wait_emc_status(EMC_EMC_STATUS, TIMING_UPDATE_STALLED, false, EMC_CHANNEL0);\n\tif (dual_channel)\n\t\terr |= _wait_emc_status(EMC_EMC_STATUS, TIMING_UPDATE_STALLED, false, EMC_CHANNEL1);\n\n\treturn err;\n}\n\nstatic u32 _get_dram_temperature()\n{\n\tu32 mr4_0 = 0;\n\tu32 mr4_1 = 0;\n\n\tbool channel1_enabled = (EMC(EMC_FBIO_CFG7) >> 2) & 1;\n\tu32 emc_cfg_o = EMC(EMC_CFG);\n\n\t_wait_emc_status(EMC_EMC_STATUS, MRR_DIVLD, false, EMC_CHANNEL0);\n\n\tif (emc_cfg_o & 0x20000000)\n\t{\n\t\tEMC(EMC_CFG) = emc_cfg_o & 0xDFFFFFFF;\n\t\t_timing_update(channel1_enabled);\n\t}\n\n\t_request_mmr_data(0x80040000, EMC_CHANNEL0);\n\tmr4_0 = EMC(EMC_MRR) & 0xFFFF;\n\n\tif (mr4_0 < 0xF001)\n\t\tmr4_0 &= 0x7;\n\telse\n\t{\n\t\tmr4_0 = -1;\n\t\tgoto out;\n\t}\n\n\tif (channel1_enabled)\n\t{\n\t\t_request_mmr_data(0x40040000, EMC_CHANNEL1);\n\t\tmr4_1 = EMC(EMC_MRR) & 0xFFFF;\n\n\t\tif (mr4_1 < 0xF001)\n\t\t\tmr4_1 &= 0x7;\n\t\telse\n\t\t\tgoto out;\n\n\t\tif (mr4_1 > mr4_0)\n\t\t\tmr4_0 = mr4_1;\n\t}\n\nout:\n\tif (emc_cfg_o & 0x20000000)\n\t{\n\t\tEMC(EMC_CFG) = emc_cfg_o;\n\t\t_timing_update(channel1_enabled);\n\t}\n\n\treturn mr4_0;\n}\n\nstatic u32 _pllm_clk_base_cfg(u32 rate_KHz, u32 clk_src_emc, bool new_src_is_PLLMB)\n{\n\tu32 dividers = 0;\n\tu32 i = 0;\n\tu32 pll_ref = 38400; // Only 38.4MHz crystal is supported for T210.\n\n\tpllm_clk_config_t *pllm_clk_config = NULL;\n\n\tfor (i = 0; pllm_clk_config_table[i].pll_osc_in; i++)\n\t{\n\t\tif (pllm_clk_config_table[i].pll_osc_in == pll_ref && (pllm_clk_config_table[i].pll_out - 19200) <= rate_KHz)\n\t\t\tpllm_clk_config = &pllm_clk_config_table[i];\n\t}\n\n\tif (pllm_clk_config && pllm_clk_config->pll_osc_in)\n\t{\n\t\tdividers = pllm_clk_config->pll_input_div | (pllm_clk_config->pll_feedback_div << 8) | ((pllm_clk_config->pll_post_div & 0x1F) << 20);\n\t\tif (new_src_is_PLLMB)\n\t\t{\n\t\t\tCLOCK(CLK_RST_CONTROLLER_PLLMB_BASE)  = dividers;\n\t\t\tCLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) |= PLLM_ENABLE;\n\n\t\t\tif ((clk_src_emc >> EMC_2X_CLK_SRC_SHIFT) == PLLM_UD)\n\t\t\t\tclk_src_emc  = (clk_src_emc & 0x1FFFFFFF) | (PLLMB_UD << EMC_2X_CLK_SRC_SHIFT);\n\t\t\telse if (!(clk_src_emc >> EMC_2X_CLK_SRC_SHIFT))\n\t\t\t\tclk_src_emc |= (PLLMB_OUT0 << EMC_2X_CLK_SRC_SHIFT);\n\n\t\t\twhile (!(CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) & PLLM_LOCK))\n\t\t\t\t;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCLOCK(CLK_RST_CONTROLLER_PLLM_BASE)   = dividers;\n\t\t\tCLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) |= PLLM_EN_LCKDET;\n\t\t\tCLOCK(CLK_RST_CONTROLLER_PLLM_BASE)  |= PLLM_ENABLE;\n\n\t\t\tif ((clk_src_emc >> EMC_2X_CLK_SRC_SHIFT) == PLLM_UD)\n\t\t\t\tclk_src_emc = (clk_src_emc & 0x1FFFFFFF) | (PLLM_UD << EMC_2X_CLK_SRC_SHIFT);\n\t\t\twhile (!(CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) & PLLM_LOCK))\n\t\t\t\t;\n\t\t}\n\t}\n\treturn clk_src_emc;\n}\n\nstatic void _change_dll_src(emc_table_t *mtc_table_entry, u32 clk_src_emc)\n{\n\tu32 emc_2x_clk_src = clk_src_emc >> EMC_2X_CLK_SRC_SHIFT;\n\n\tu32 dll_setting = ((((mtc_table_entry->dll_clk_src & 0x1FFFFFFF)\n\t\t| (emc_2x_clk_src << EMC_2X_CLK_SRC_SHIFT)) & 0xFFFFFF00)\n\t\t| (clk_src_emc & 0xFF)) & 0xFFFFF3FF;\n\n\tif (emc_2x_clk_src == PLLMB_UD)\n\t\tdll_setting |= EMC_DLL_PLLM_VCOB;\n\telse if (emc_2x_clk_src != PLLM_UD)\n\t\tdll_setting |= EMC_DLL_SWITCH_OUT;\n\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = dll_setting;\n\n\t// Commit clock write.\n\t(void)CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X);\n\t_usleep(2);\n\n\t// Enable/Disable EMC DLL.\n\tif (mtc_table_entry->clk_out_enb_x_0_clk_enb_emc_dll)\n\t\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = BIT(14);\n\telse\n\t\tCLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_CLR) = BIT(14);\n\n\t// Commit clock write.\n\t(void)CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X);\n\t_usleep(2);\n}\n\nstatic u32 _digital_dll_prelock(emc_table_t *mtc_table_entry, bool in_training, u32 selected_clk_src_emc)\n{\n\tu32 dual_channel = (EMC(EMC_FBIO_CFG7) >> 1) & ((EMC(EMC_FBIO_CFG7) >> 2) & 1);\n\n\tEMC(EMC_CFG_DIG_DLL) = (EMC(EMC_CFG_DIG_DLL) & 0xFFFFF824) | 0x3C8;\n\n\t_timing_update(dual_channel);\n\n\twhile (EMC(EMC_CFG_DIG_DLL) & 1)\n\t\t;\n\tif (dual_channel)\n\t\twhile (EMC_CH1(EMC_CFG_DIG_DLL) & 1)\n\t\t\t;\n\n\tEMC(EMC_DLL_CFG_0) = mtc_table_entry->burst_regs.emc_dll_cfg_0;\n\tEMC(EMC_DLL_CFG_1) = mtc_table_entry->burst_regs.emc_dll_cfg_1;\n\n\t_change_dll_src(mtc_table_entry, selected_clk_src_emc);\n\n\tEMC(EMC_CFG_DIG_DLL) |= 1;\n\n\t_timing_update(dual_channel);\n\n\twhile (!(EMC(EMC_CFG_DIG_DLL) & 1))\n\t\t;\n\tif (dual_channel)\n\t\twhile (!(EMC_CH1(EMC_CFG_DIG_DLL) & 1))\n\t\t\t;\n\n\twhile ((((EMC(EMC_DIG_DLL_STATUS) >> 17) & 1) ^ 1) | (((EMC(EMC_DIG_DLL_STATUS) >> 15) & 1) ^ 1))\n\t\t;\n\n\tif (in_training)\n\t{\n\t\tEMC(EMC_DBG) |= EMC_DBG_WRITE_MUX_ACTIVE;\n\t\tEMC(EMC_CFG_DIG_DLL) &= 0xFFFFFFFE; // Disable CFG_DLL_EN.\n\t\tEMC(EMC_DBG) &= ~EMC_DBG_WRITE_MUX_ACTIVE;\n\n\t\twhile (EMC(EMC_CFG_DIG_DLL) & 1)\n\t\t\t;\n\t\tif (dual_channel)\n\t\t\twhile (EMC_CH1(EMC_CFG_DIG_DLL) & 1)\n\t\t\t\t;\n\t}\n\n\treturn EMC(EMC_DIG_DLL_STATUS) & 0x7FF;\n}\n\nstatic void _digital_dll_disable()\n{\n\tbool dual_channel = (EMC(EMC_FBIO_CFG7) >> 1) & ((EMC(EMC_FBIO_CFG7) >> 2) & 1);\n\n\tEMC(EMC_CFG_DIG_DLL) &= 0xFFFFFFFE;\n\n\t_timing_update(dual_channel);\n\n\twhile (EMC(EMC_CFG_DIG_DLL) & 1)\n\t\t;\n\tif (dual_channel)\n\t\twhile (EMC_CH1(EMC_CFG_DIG_DLL) & 1)\n\t\t\t;\n}\n\nstatic void _digital_dll_enable_rs(u32 channel1_enabled)\n{\n\tEMC(EMC_CFG_DIG_DLL) = (EMC(EMC_CFG_DIG_DLL) & 0xFFFFFF24) | 0x89;\n\n\t_timing_update(channel1_enabled);\n\n\twhile (!(EMC(EMC_CFG_DIG_DLL) & 1))\n\t\t;\n\tif (channel1_enabled)\n\t\twhile (!(EMC_CH1(EMC_CFG_DIG_DLL) & 1))\n\t\t\t;\n}\n\nstatic u32 _dvfs_power_ramp_down(bool flip_backward, emc_table_t *src_emc_table_entry, emc_table_t *dst_emc_table_entry, u32 src_clock_period)\n{\n\tu32 pmacro_cmd_pad;\n\tu32 pmacro_rfu1;\n\tu32 pmacro_cfg5;\n\tu32 pmacro_com_pad;\n\tu32 pmacro_dq_pad;\n\n\tu32 src_clk_per_pc = (100000 / src_clock_period) + 1;\n\n\tif (flip_backward)\n\t{\n\t\tpmacro_cmd_pad = dst_emc_table_entry->burst_regs.emc_pmacro_cmd_pad_tx_ctrl;\n\t\tpmacro_dq_pad  = dst_emc_table_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl;\n\t\tpmacro_rfu1    = dst_emc_table_entry->burst_regs.emc_pmacro_brick_ctrl_rfu1;\n\t\tpmacro_cfg5    = dst_emc_table_entry->burst_regs.emc_fbio_cfg5;\n\t\tpmacro_com_pad = dst_emc_table_entry->burst_regs.emc_pmacro_common_pad_tx_ctrl;\n\t}\n\telse\n\t{\n\t\tpmacro_cmd_pad = src_emc_table_entry->burst_regs.emc_pmacro_cmd_pad_tx_ctrl;\n\t\tpmacro_dq_pad  = (dst_emc_table_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl & 0x101) | src_emc_table_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl;\n\t\tpmacro_rfu1    = src_emc_table_entry->burst_regs.emc_pmacro_brick_ctrl_rfu1;\n\t\tpmacro_cfg5    = src_emc_table_entry->burst_regs.emc_fbio_cfg5;\n\t\tpmacro_com_pad = src_emc_table_entry->burst_regs.emc_pmacro_common_pad_tx_ctrl;\n\t}\n\n\tu32 pmacro_cmd_pad_drvforceon = pmacro_cmd_pad | 0x4000000;\n\n\tu32 ramp_down_wait = src_clock_period * 12;\n\n\t_ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad_drvforceon, 0);\n\t_ccfifo_write(EMC_FBIO_CFG5, pmacro_cfg5 | 0x100, 12);\n\n\tif (src_clock_period >= 1000) // Dvfs high speed threshold.\n\t{\n\t\t_ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xF800F800, (u32)(src_clk_per_pc + 19));\n\t\tramp_down_wait += 100000 + (src_clock_period * 20);\n\t}\n\telse\n\t{\n\t\tif (src_clock_period >= 416) // Iobrick dcc threshold.\n\t\t\t_ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xFEEDFEED, (u32)src_clk_per_pc);\n\t\telse\n\t\t{\n\t\t\tpmacro_dq_pad = (pmacro_dq_pad & 0xFEFEFDFD) | 0x10200;\n\t\t\tpmacro_cmd_pad_drvforceon = (pmacro_cmd_pad & 0xFAFEFDFD) | 0x4010200;\n\t\t\t_ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL,  pmacro_cmd_pad_drvforceon, (u32)src_clk_per_pc);\n\t\t\t_ccfifo_write(EMC_PMACRO_DATA_PAD_TX_CTRL, pmacro_dq_pad, 0);\n\t\t\t_ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1,  pmacro_rfu1 & 0xFEEDFEED, 0);\n\t\t}\n\t\tramp_down_wait += 300000;\n\t\t_ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xFE40FE40, (u32)src_clk_per_pc);\n\n\t\tif (src_clock_period >= 416) // Iobrick dcc threshold.\n\t\t\t_ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xF800F800, (u32)src_clk_per_pc);\n\t\telse\n\t\t{\n\t\t\t_ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL,  pmacro_cmd_pad_drvforceon & 0xFEFEFDFD, (u32)src_clk_per_pc);\n\t\t\t_ccfifo_write(EMC_PMACRO_DATA_PAD_TX_CTRL, pmacro_dq_pad & 0xFEFEFDFD, 0);\n\t\t\t_ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1,  pmacro_rfu1 & 0xF800F800, 0);\n\t\t}\n\t}\n\n\tif (src_clock_period >= 1666) // Dvfs mid speed threshold.\n\t\t_ccfifo_write(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_com_pad & 0xFFFFFFF0, (u32)src_clk_per_pc);\n\telse\n\t{\n\t\tramp_down_wait += 400000;\n\t\t_ccfifo_write(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_com_pad & 0xFFFFFFFA, (u32)src_clk_per_pc);\n\t\t_ccfifo_write(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_com_pad & 0xFFFFFFF0, (u32)src_clk_per_pc);\n\t\t_ccfifo_write(EMC_INTSTATUS, 0, (u32)src_clk_per_pc);\n\t}\n\n\treturn ramp_down_wait;\n}\n\nstatic u32 _dvfs_power_ramp_up(bool flip_backward, emc_table_t *src_emc_table_entry, emc_table_t *dst_emc_table_entry, u32 needs_training, u32 dst_clock_period)\n{\n\tu32 pmacro_cmd_pad;\n\tu32 pmacro_dq_pad;\n\tu32 pmacro_rfu1;\n\tu32 pmacro_cfg5;\n\tu32 pmacro_com_pad;\n\tu32 pmacro_cmd_pad_data;\n\tu32 ramp_up_wait = 0;\n\n\tu32 dst_clk_per_pc = (100000 / dst_clock_period) + 1;\n\n\tif (flip_backward)\n\t{\n\t\tpmacro_cmd_pad = src_emc_table_entry->burst_regs.emc_pmacro_cmd_pad_tx_ctrl;\n\t\tpmacro_dq_pad  = src_emc_table_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl;\n\t\tpmacro_rfu1    = src_emc_table_entry->burst_regs.emc_pmacro_brick_ctrl_rfu1;\n\t\tpmacro_cfg5    = src_emc_table_entry->burst_regs.emc_fbio_cfg5;\n\t\tpmacro_com_pad = src_emc_table_entry->burst_regs.emc_pmacro_common_pad_tx_ctrl;\n\t}\n\telse if (needs_training & NEEDS_TRAINING_CA_COMBO)\n\t{\n\t\tpmacro_cmd_pad = dst_emc_table_entry->shadow_regs_ca_train.emc_pmacro_cmd_pad_tx_ctrl;\n\t\tpmacro_dq_pad  = dst_emc_table_entry->shadow_regs_ca_train.emc_pmacro_data_pad_tx_ctrl;\n\t\tpmacro_rfu1    = dst_emc_table_entry->shadow_regs_ca_train.emc_pmacro_brick_ctrl_rfu1;\n\t\tpmacro_cfg5    = dst_emc_table_entry->shadow_regs_ca_train.emc_fbio_cfg5;\n\t\tpmacro_com_pad = dst_emc_table_entry->shadow_regs_ca_train.emc_pmacro_common_pad_tx_ctrl;\n\t}\n\telse if (needs_training & NEEDS_TRAINING_QUSE_COMBO)\n\t{\n\t\tpmacro_cmd_pad = dst_emc_table_entry->shadow_regs_quse_train.emc_pmacro_cmd_pad_tx_ctrl;\n\t\tpmacro_dq_pad  = dst_emc_table_entry->shadow_regs_quse_train.emc_pmacro_data_pad_tx_ctrl;\n\t\tpmacro_rfu1    = dst_emc_table_entry->shadow_regs_quse_train.emc_pmacro_brick_ctrl_rfu1;\n\t\tpmacro_cfg5    = dst_emc_table_entry->shadow_regs_quse_train.emc_fbio_cfg5;\n\t\tpmacro_com_pad = dst_emc_table_entry->shadow_regs_quse_train.emc_pmacro_common_pad_tx_ctrl;\n\t}\n\telse if (needs_training & (NEEDS_TRAINING_WR_COMBO | NEEDS_TRAINING_RD_COMBO))\n\t{\n\t\tpmacro_cmd_pad = dst_emc_table_entry->shadow_regs_rdwr_train.emc_pmacro_cmd_pad_tx_ctrl;\n\t\tpmacro_dq_pad  = dst_emc_table_entry->shadow_regs_rdwr_train.emc_pmacro_data_pad_tx_ctrl;\n\t\tpmacro_rfu1    = dst_emc_table_entry->shadow_regs_rdwr_train.emc_pmacro_brick_ctrl_rfu1;\n\t\tpmacro_cfg5    = dst_emc_table_entry->shadow_regs_rdwr_train.emc_fbio_cfg5;\n\t\tpmacro_com_pad = dst_emc_table_entry->shadow_regs_rdwr_train.emc_pmacro_common_pad_tx_ctrl;\n\t}\n\telse\n\t{\n\t\tpmacro_cmd_pad = dst_emc_table_entry->burst_regs.emc_pmacro_cmd_pad_tx_ctrl;\n\t\tpmacro_dq_pad  = dst_emc_table_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl;\n\t\tpmacro_rfu1    = dst_emc_table_entry->burst_regs.emc_pmacro_brick_ctrl_rfu1;\n\t\tpmacro_cfg5    = dst_emc_table_entry->burst_regs.emc_fbio_cfg5;\n\t\tpmacro_com_pad = dst_emc_table_entry->burst_regs.emc_pmacro_common_pad_tx_ctrl;\n\t}\n\n\tpmacro_cmd_pad_data = (pmacro_cmd_pad & 0xFAFEFDFD) | 0x4000000;\n\n\tif (dst_clock_period >= 1666) // Dvfs mid speed threshold.\n\t{\n\t\t_ccfifo_write(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_com_pad | 8, 0);\n\n\t\t_ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 | 0x600, 0);\n\t\t_ccfifo_write(EMC_FBIO_CFG5, pmacro_cfg5 & 0xFFFFFEFF, 12);\n\n\t\tramp_up_wait = (dst_clock_period * 12) + 0;\n\t}\n\telse\n\t{\n\t\t_ccfifo_write(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_com_pad & 0xA, 0);\n\t\t_ccfifo_write(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_com_pad & 0xF, dst_clk_per_pc);\n\n\t\tif (dst_clock_period < 1000) // Dvfs high speed threshold.\n\t\t{\n\t\t\tif (dst_clock_period >= 416) // Iobrick dcc threshold.\n\t\t\t\t_ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xFE40FE40, dst_clk_per_pc);\n\t\t\telse\n\t\t\t{\n\t\t\t\t_ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL,  (pmacro_cmd_pad & 0xFAFEFDFD) | 0x4010200, dst_clk_per_pc);\n\t\t\t\t_ccfifo_write(EMC_PMACRO_DATA_PAD_TX_CTRL, (pmacro_dq_pad & 0xFEFEFDFD) | 0x10200, 0);\n\t\t\t\t_ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1,  pmacro_rfu1 & 0xFE40FE40, 0);\n\t\t\t}\n\n\t\t\t_ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xFEEDFEED, dst_clk_per_pc);\n\n\t\t\tif (dst_clock_period >= 416) // Iobrick dcc threshold.\n\t\t\t\t_ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1, dst_clk_per_pc);\n\t\t\telse\n\t\t\t{\n\t\t\t\tpmacro_cmd_pad_data = pmacro_cmd_pad | 0x5010202;\n\t\t\t\t_ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL,  pmacro_cmd_pad_data, dst_clk_per_pc);\n\t\t\t\t_ccfifo_write(EMC_PMACRO_DATA_PAD_TX_CTRL, pmacro_dq_pad | 0x1010202, 0);\n\t\t\t\t_ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1,  pmacro_rfu1, 0);\n\t\t\t}\n\n\t\t\tramp_up_wait = 500000 + (dst_clock_period * 10);\n\t\t}\n\t\telse // 1000 > dst_clock_period < 1666.\n\t\t{\n\t\t\t_ccfifo_write(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 | 0x6000600, dst_clk_per_pc);\n\n\t\t\tramp_up_wait = 200000 + (dst_clock_period * 10);\n\t\t}\n\n\t\t_ccfifo_write(EMC_FBIO_CFG5, pmacro_cfg5 & 0xFFFFFEFF, dst_clk_per_pc + 9);\n\t}\n\n\t_ccfifo_write(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad_data & 0xFBFFFFFF, 5);\n\n\treturn ramp_up_wait;\n}\n\nstatic u32 _minerva_update_clock_tree_delay(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u32 dram_dev_num, u32 channel1_enabled, enum tree_update_mode_t update_type)\n{\n\tu32 cval = 0;\n\tu32 adelta = 0;\n\ts32 tdelta = 0;\n\n\tu32 temp_ch0_0 = 0;\n\tu32 temp_ch0_1 = 0;\n\tu32 temp_ch1_0 = 0;\n\tu32 temp_ch1_1 = 0;\n\n\tu32 upd_type_bits = BIT(update_type);\n\tu32 dst_rate_mhz = dst_emc_entry->rate_khz / 1000;\n\tu32 src_rate_mhz = src_emc_entry->rate_khz / 1000;\n\n\tu32 tval = 1000000 * _actual_osc_clocks(src_emc_entry->run_clocks) / 2;\n\n\tif (update_type > PERIODIC_TRAINING_UPDATE)\n\t\treturn 0;\n\n\tif (upd_type_bits & 0x5400)\n\t{\n\t\t_request_mmr_data(0x80130000, channel1_enabled); // Dev0 MRR 19.\n\t\tu32 mrr = EMC(EMC_MRR);\n\t\ttemp_ch0_0 = (mrr & 0xFF) << 8;\n\t\ttemp_ch0_1 = mrr & 0xFF00;\n\t\tif (channel1_enabled)\n\t\t{\n\t\t\tmrr = EMC_CH1(EMC_MRR);\n\t\t\ttemp_ch1_0 = (mrr & 0xFF) << 8;\n\t\t\ttemp_ch1_1 = mrr & 0xFF00;\n\t\t}\n\n\t\t_request_mmr_data(0x80120000, channel1_enabled); // Dev0 MRR 18.\n\t\tmrr = EMC(EMC_MRR);\n\t\ttemp_ch0_0 |= mrr & 0xFF;\n\t\ttemp_ch0_1 |= (mrr & 0xFF00) >> 8;\n\t\tif (channel1_enabled)\n\t\t{\n\t\t\tmrr = EMC_CH1(EMC_MRR);\n\t\t\ttemp_ch1_0 |= mrr & 0xFF;\n\t\t\ttemp_ch1_1 |= (mrr & 0xFF00) >> 8;\n\t\t}\n\t}\n\n\tcval = tval / (src_rate_mhz * temp_ch0_0);\n\tswitch (update_type)\n\t{\n\tcase DVFS_PT1:\n\tcase TRAINING_PT1:\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 += 100 * cval;\n\t\tif (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800))\n\t\t\tgoto calc_td0_0;\n\t\tbreak;\n\tcase DVFS_UPDATE:\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 =\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 / dst_emc_entry->ptfv_list.ptfv_dvfs_samples;\n\t\tbreak;\n\tcase TRAINING_UPDATE:\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 =\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 / dst_emc_entry->ptfv_list.ptfv_write_samples;\n\t\tbreak;\n\tcase PERIODIC_TRAINING_UPDATE:\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 =\n\t\t\t(100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0)\n\t\t\t/ (dst_emc_entry->ptfv_list.ptfv_movavg_weight + 1);\n\t\tbreak;\n\tdefault:\n\t\tif (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800))\n\t\t\tgoto calc_td0_0;\n\t\tbreak;\n\t}\n\n\ttdelta = dst_emc_entry->current_dram_clktree_c0d0u0 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 / 100);\n\tif (tdelta < 0)\n\t\ttdelta *= -1;\n\tadelta = tdelta;\n\tif (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdelta * 128) / 1000000) > dst_emc_entry->tree_margin)\n\t\tdst_emc_entry->current_dram_clktree_c0d0u0 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 / 100;\n\ncalc_td0_0:\n\tcval = tval / (src_rate_mhz * temp_ch0_1);\n\tswitch (update_type)\n\t{\n\tcase DVFS_PT1:\n\tcase TRAINING_PT1:\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 += 100 * cval;\n\t\tif (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800))\n\t\t\tgoto calc_td1_0;\n\t\tbreak;\n\tcase DVFS_UPDATE:\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 =\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 / dst_emc_entry->ptfv_list.ptfv_dvfs_samples;\n\t\tbreak;\n\tcase TRAINING_UPDATE:\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 =\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 / dst_emc_entry->ptfv_list.ptfv_write_samples;\n\t\tbreak;\n\tcase PERIODIC_TRAINING_UPDATE:\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 =\n\t\t\t(100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1)\n\t\t\t/ (dst_emc_entry->ptfv_list.ptfv_movavg_weight + 1);\n\t\tbreak;\n\tdefault:\n\t\tif (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800))\n\t\t\tgoto calc_td1_0;\n\t\tbreak;\n\t}\n\n\ttdelta = dst_emc_entry->current_dram_clktree_c0d0u1 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 / 100);\n\tif (tdelta < 0)\n\t\ttdelta *= -1;\n\tif ((u32)tdelta > adelta)\n\t\tadelta = tdelta;\n\tif (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdelta * 128) / 1000000) > dst_emc_entry->tree_margin)\n\t\tdst_emc_entry->current_dram_clktree_c0d0u1 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 / 100;\n\ncalc_td1_0:\n\tif (channel1_enabled)\n\t{\n\t\tcval = tval / (src_rate_mhz * temp_ch1_0);\n\t\tswitch (update_type)\n\t\t{\n\t\tcase DVFS_PT1:\n\t\tcase TRAINING_PT1:\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 += 100 * cval;\n\t\t\tif (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800))\n\t\t\t\tgoto calc_td1_1;\n\t\t\tbreak;\n\t\tcase DVFS_UPDATE:\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 =\n\t\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 / dst_emc_entry->ptfv_list.ptfv_dvfs_samples;\n\t\t\tbreak;\n\t\tcase TRAINING_UPDATE:\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 =\n\t\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 / dst_emc_entry->ptfv_list.ptfv_write_samples;\n\t\t\tbreak;\n\t\tcase PERIODIC_TRAINING_UPDATE:\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 =\n\t\t\t\t(100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0)\n\t\t\t\t/ (dst_emc_entry->ptfv_list.ptfv_movavg_weight + 1);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tif (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800))\n\t\t\t\tgoto calc_td1_1;\n\t\t\tbreak;\n\t\t}\n\n\t\ttdelta = dst_emc_entry->current_dram_clktree_c1d0u0 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 / 100);\n\t\tif (tdelta < 0)\n\t\t\ttdelta *= -1;\n\t\tif ((u32)tdelta > adelta)\n\t\t\tadelta = tdelta;\n\t\tif (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdelta * 128) / 1000000) > dst_emc_entry->tree_margin)\n\t\t\tdst_emc_entry->current_dram_clktree_c1d0u0 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 / 100;\n\ncalc_td1_1:\n\t\tcval = tval / (src_rate_mhz * temp_ch1_1);\n\t\tswitch (update_type)\n\t\t{\n\t\tcase DVFS_PT1:\n\t\tcase TRAINING_PT1:\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 += 100 * cval;\n\t\t\tif (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800))\n\t\t\t\tgoto calc_dev2;\n\t\t\tbreak;\n\t\tcase DVFS_UPDATE:\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 =\n\t\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 / dst_emc_entry->ptfv_list.ptfv_dvfs_samples;\n\t\t\tbreak;\n\t\tcase TRAINING_UPDATE:\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 =\n\t\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 / dst_emc_entry->ptfv_list.ptfv_write_samples;\n\t\t\tbreak;\n\t\tcase PERIODIC_TRAINING_UPDATE:\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 =\n\t\t\t\t(100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1)\n\t\t\t\t/ (dst_emc_entry->ptfv_list.ptfv_movavg_weight + 1);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tif (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800))\n\t\t\t\tgoto calc_dev2;\n\t\t\tbreak;\n\t\t}\n\n\t\ttdelta = dst_emc_entry->current_dram_clktree_c1d0u1 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 / 100);\n\t\tif (tdelta < 0)\n\t\t\ttdelta *= -1;\n\t\tif ((u32)tdelta > adelta)\n\t\t\tadelta = tdelta;\n\t\tif (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdelta * 128) / 1000000) > dst_emc_entry->tree_margin)\n\t\t\tdst_emc_entry->current_dram_clktree_c1d0u1 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 / 100;\n\t}\n\ncalc_dev2:\n\tif (dram_dev_num != TWO_RANK)\n\t\tgoto out;\n\n\tif (update_type <= PERIODIC_TRAINING_UPDATE && upd_type_bits & 0x5400)\n\t{\n\t\t_request_mmr_data(0x40130000, channel1_enabled); // Dev1 MRR 19.\n\t\tu32 mrr = EMC(EMC_MRR);\n\t\ttemp_ch0_0 = (mrr & 0xFF) << 8;\n\t\ttemp_ch0_1 = mrr & 0xFF00;\n\t\tif (channel1_enabled)\n\t\t{\n\t\t\tmrr = EMC_CH1(EMC_MRR);\n\t\t\ttemp_ch1_0 = (mrr & 0xFF) << 8;\n\t\t\ttemp_ch1_1 = mrr & 0xFF00;\n\t\t}\n\n\t\t_request_mmr_data(0x40120000, channel1_enabled); // Dev1 MRR 18\n\t\tmrr = EMC(EMC_MRR);\n\t\ttemp_ch0_0 |= mrr & 0xFF;\n\t\ttemp_ch0_1 |= (mrr & 0xFF00) >> 8;\n\t\tif (channel1_enabled)\n\t\t{\n\t\t\tmrr = EMC_CH1(EMC_MRR);\n\t\t\ttemp_ch1_0 |= mrr & 0xFF;\n\t\t\ttemp_ch1_1 |= (mrr & 0xFF00) >> 8;\n\t\t}\n\t}\n\n\tcval = tval / (src_rate_mhz * temp_ch0_0);\n\tswitch (update_type )\n\t{\n\tcase DVFS_PT1:\n\tcase TRAINING_PT1:\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 += 100 * cval;\n\t\tif (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800))\n\t\t\tgoto calc_tmp_td0_1;\n\t\tbreak;\n\tcase DVFS_UPDATE:\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 =\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 / dst_emc_entry->ptfv_list.ptfv_dvfs_samples;\n\t\tbreak;\n\tcase TRAINING_UPDATE:\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 =\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 / dst_emc_entry->ptfv_list.ptfv_write_samples;\n\t\tbreak;\n\tcase PERIODIC_TRAINING_UPDATE:\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 =\n\t\t\t(100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0)\n\t\t\t/ (dst_emc_entry->ptfv_list.ptfv_movavg_weight + 1);\n\t\tbreak;\n\tdefault:\n\t\tif (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800))\n\t\t\tgoto calc_tmp_td0_1;\n\t\tbreak;\n\t}\n\n\ttdelta = dst_emc_entry->current_dram_clktree_c0d1u0 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 / 100);\n\tif (tdelta < 0)\n\t\ttdelta *= -1;\n\tif ((u32)tdelta > adelta)\n\t\tadelta = tdelta;\n\tif (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdelta * 128) / 1000000) > dst_emc_entry->tree_margin)\n\t\tdst_emc_entry->current_dram_clktree_c0d1u0 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 / 100;\n\ncalc_tmp_td0_1:\n\tcval = tval / (src_rate_mhz * temp_ch0_1);\n\tswitch (update_type)\n\t{\n\tcase DVFS_PT1:\n\tcase TRAINING_PT1:\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 += 100 * cval;\n\t\tif (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800))\n\t\t\tgoto calc_tmp_td1_0;\n\t\tbreak;\n\tcase DVFS_UPDATE:\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 =\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 / dst_emc_entry->ptfv_list.ptfv_dvfs_samples;\n\t\tbreak;\n\tcase TRAINING_UPDATE:\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 =\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 / dst_emc_entry->ptfv_list.ptfv_write_samples;\n\t\tbreak;\n\tcase PERIODIC_TRAINING_UPDATE:\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 =\n\t\t\t(100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1)\n\t\t\t/ (dst_emc_entry->ptfv_list.ptfv_movavg_weight + 1);\n\t\tbreak;\n\tdefault:\n\t\tif (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800))\n\t\t\tgoto calc_tmp_td1_0;\n\t\tbreak;\n\t}\n\n\ttdelta = dst_emc_entry->current_dram_clktree_c0d1u1 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 / 100);\n\tif (tdelta < 0)\n\t\ttdelta *= -1;\n\tif ((u32)tdelta > adelta)\n\t\tadelta = tdelta;\n\tif (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdelta * 128) / 1000000) > dst_emc_entry->tree_margin)\n\t\tdst_emc_entry->current_dram_clktree_c0d1u1 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 / 100;\n\ncalc_tmp_td1_0:\n\tif (channel1_enabled)\n\t{\n\t\tcval = tval / (src_rate_mhz * temp_ch1_0);\n\t\tswitch (update_type)\n\t\t{\n\t\tcase DVFS_PT1:\n\t\tcase TRAINING_PT1:\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 += 100 * cval;\n\t\t\tif (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800))\n\t\t\t\tgoto calc_tmp_td1_1;\n\t\t\tbreak;\n\t\tcase DVFS_UPDATE:\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 =\n\t\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 / dst_emc_entry->ptfv_list.ptfv_dvfs_samples;\n\t\t\tbreak;\n\t\tcase TRAINING_UPDATE:\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 =\n\t\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 / dst_emc_entry->ptfv_list.ptfv_write_samples;\n\t\t\tbreak;\n\t\tcase PERIODIC_TRAINING_UPDATE:\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 =\n\t\t\t\t(100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0)\n\t\t\t\t/ (dst_emc_entry->ptfv_list.ptfv_movavg_weight + 1);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tif (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800))\n\t\t\t\tgoto calc_tmp_td1_1;\n\t\t\tbreak;\n\t\t}\n\n\t\ttdelta = dst_emc_entry->current_dram_clktree_c1d1u0 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 / 100);\n\t\tif (tdelta < 0)\n\t\t\ttdelta *= -1;\n\t\tif ((u32)tdelta > adelta)\n\t\t\tadelta = tdelta;\n\t\tif (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdelta * 128) / 1000000) > dst_emc_entry->tree_margin)\n\t\t\tdst_emc_entry->current_dram_clktree_c1d1u0 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 / 100;\n\ncalc_tmp_td1_1:\n\t\tcval = tval / (src_rate_mhz * temp_ch1_1);\n\t\tswitch (update_type)\n\t\t{\n\t\tcase DVFS_PT1:\n\t\tcase TRAINING_PT1:\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 += 100 * cval;\n\t\t\tif (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800))\n\t\t\t\tgoto out;\n\t\t\tbreak;\n\t\tcase DVFS_UPDATE:\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 =\n\t\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 / dst_emc_entry->ptfv_list.ptfv_dvfs_samples;\n\t\t\tbreak;\n\t\tcase TRAINING_UPDATE:\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 =\n\t\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 / dst_emc_entry->ptfv_list.ptfv_write_samples;\n\t\t\tbreak;\n\t\tcase PERIODIC_TRAINING_UPDATE:\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 =\n\t\t\t\t(100 * cval + dst_emc_entry->ptfv_list.ptfv_movavg_weight * dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1)\n\t\t\t\t/ (dst_emc_entry->ptfv_list.ptfv_movavg_weight + 1);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tif (update_type > PERIODIC_TRAINING_UPDATE || !(upd_type_bits & 0x6800))\n\t\t\t\tgoto out;\n\t\t\tbreak;\n\t\t}\n\n\t\ttdelta = dst_emc_entry->current_dram_clktree_c1d1u1 - (dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 / 100);\n\t\tif (tdelta < 0)\n\t\t\ttdelta *= -1;\n\t\tif ((u32)tdelta > adelta)\n\t\t\tadelta = tdelta;\n\t\tif (update_type == TRAINING_UPDATE || ((dst_rate_mhz * tdelta * 128) / 1000000) > dst_emc_entry->tree_margin)\n\t\t\tdst_emc_entry->current_dram_clktree_c1d1u1 = dst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 / 100;\n\t}\n\nout:\n\tif (update_type == TRAINING_UPDATE)\n\t{\n\t\tdst_emc_entry->trained_dram_clktree_c0d0u0 = dst_emc_entry->current_dram_clktree_c0d0u0;\n\t\tdst_emc_entry->trained_dram_clktree_c0d0u1 = dst_emc_entry->current_dram_clktree_c0d0u1;\n\t\tdst_emc_entry->trained_dram_clktree_c0d1u0 = dst_emc_entry->current_dram_clktree_c0d1u0;\n\t\tdst_emc_entry->trained_dram_clktree_c0d1u1 = dst_emc_entry->current_dram_clktree_c0d1u1;\n\t\tdst_emc_entry->trained_dram_clktree_c1d0u0 = dst_emc_entry->current_dram_clktree_c1d0u0;\n\t\tdst_emc_entry->trained_dram_clktree_c1d0u1 = dst_emc_entry->current_dram_clktree_c1d0u1;\n\t\tdst_emc_entry->trained_dram_clktree_c1d1u0 = dst_emc_entry->current_dram_clktree_c1d1u0;\n\t\tdst_emc_entry->trained_dram_clktree_c1d1u1 = dst_emc_entry->current_dram_clktree_c1d1u1;\n\t}\n\n\treturn (u32)adelta;\n}\n\nstatic u32 _minerva_periodic_compensation_handler(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u32 dram_dev_num, u32 channel1_enabled, enum comp_seq_t seq_type)\n{\n\tif (!dst_emc_entry->periodic_training)\n\t\treturn 0;\n\n\tu32 delay = 1000 * _actual_osc_clocks(src_emc_entry->run_clocks) / src_emc_entry->rate_khz + 2;\n\n\tif (seq_type == DVFS_SEQUENCE)\n\t{\n\t\tif (src_emc_entry->periodic_training && dst_emc_entry->ptfv_list.ptfv_config_ctrl & 1)\n\t\t{\n\t\t\tu32 samples = dst_emc_entry->ptfv_list.ptfv_dvfs_samples;\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 * samples;\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 * samples;\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 * samples;\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 * samples;\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 * samples;\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 * samples;\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 * samples;\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 = src_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 * samples;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 = 0;\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 = 0;\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 = 0;\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 = 0;\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 = 0;\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 = 0;\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 = 0;\n\t\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 = 0;\n\n\t\t\tfor (u32 i = 0; i < dst_emc_entry->ptfv_list.ptfv_dvfs_samples; i++)\n\t\t\t{\n\t\t\t\t_start_periodic_compensation();\n\t\t\t\t_usleep(delay);\n\t\t\t\t_minerva_update_clock_tree_delay(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, DVFS_PT1);\n\t\t\t}\n\t\t}\n\n\t\treturn _minerva_update_clock_tree_delay(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, DVFS_UPDATE);\n\t}\n\telse if (seq_type == WRITE_TRAINING_SEQUENCE)\n\t{\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u0 = 0;\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d0u1 = 0;\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u0 = 0;\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d0u1 = 0;\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u0 = 0;\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c0d1u1 = 0;\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u0 = 0;\n\t\tdst_emc_entry->ptfv_list.ptfv_dqsosc_movavg_c1d1u1 = 0;\n\n\t\tfor (u32 i = 0; i < dst_emc_entry->ptfv_list.ptfv_write_samples; i++)\n\t\t{\n\t\t\t_start_periodic_compensation();\n\t\t\t_usleep(delay);\n\t\t\t_minerva_update_clock_tree_delay(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, TRAINING_PT1);\n\t\t}\n\n\t\treturn _minerva_update_clock_tree_delay(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, TRAINING_UPDATE);\n\t}\n\telse if (seq_type == PERIODIC_TRAINING_SEQUENCE)\n\t{\n\t\t_start_periodic_compensation();\n\t\t_usleep(delay);\n\t\treturn _minerva_update_clock_tree_delay(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, PERIODIC_TRAINING_UPDATE);\n\t}\n\n\treturn seq_type;\n}\n\n#define STORE_TRIM_VAL(chan, rank, reg, byte) \\\n\t\t((mtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank##rank##_##reg >>\t\\\n\t \t\tEMC_PMACRO_OB_DDLL_LONG_DQ_BYTE##byte##_SHIFT) & 0x7FF) \\\n\t\t+ \\\n\t\t(((mtc_table_entry->trim_perch_regs.emc##chan##_data_brlshft_##rank >>\t\\\n\t\t\tEMC_DATA_BRLSHFT_##rank##_RANK##rank##_BYTE##byte##_DATA_BRLSHFT_SHIFT) & 0x7) << 6)\n\nstatic u32 _minerva_apply_periodic_compensation_trimmer(emc_table_t *mtc_table_entry, u32 trim_emc_reg_addr)\n{\n\tu32 trimmer = 0;\n\ts32 tree_delta[4] = {0};\n\ts32 tree_delta_taps[4] = {0};\n\ts32 new_trim[] = {\n\t\t// chan, rank, reg, byte.\n\t\tSTORE_TRIM_VAL(0, 0, 0, 0),\n\t\tSTORE_TRIM_VAL(0, 0, 0, 1),\n\t\tSTORE_TRIM_VAL(0, 0, 1, 2),\n\t\tSTORE_TRIM_VAL(0, 0, 1, 3),\n\n\t\tSTORE_TRIM_VAL(1, 0, 2, 4),\n\t\tSTORE_TRIM_VAL(1, 0, 2, 5),\n\t\tSTORE_TRIM_VAL(1, 0, 3, 6),\n\t\tSTORE_TRIM_VAL(1, 0, 3, 7),\n\n\t\tSTORE_TRIM_VAL(0, 1, 0, 0),\n\t\tSTORE_TRIM_VAL(0, 1, 0, 1),\n\t\tSTORE_TRIM_VAL(0, 1, 1, 2),\n\t\tSTORE_TRIM_VAL(0, 1, 1, 3),\n\n\t\tSTORE_TRIM_VAL(1, 1, 2, 4),\n\t\tSTORE_TRIM_VAL(1, 1, 2, 5),\n\t\tSTORE_TRIM_VAL(1, 1, 3, 6),\n\t\tSTORE_TRIM_VAL(1, 1, 3, 7)\n\t};\n\n\tu32 dst_rate_mhz = mtc_table_entry->rate_khz / 1000;\n\n\tswitch (trim_emc_reg_addr)\n\t{\n\tcase EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0:\n\tcase EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1:\n\tcase EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2:\n\tcase EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3:\n\tcase EMC_DATA_BRLSHFT_0:\n\t\ttree_delta[0] = (mtc_table_entry->current_dram_clktree_c0d0u0 - mtc_table_entry->trained_dram_clktree_c0d0u0) * 128;\n\t\ttree_delta[1] = (mtc_table_entry->current_dram_clktree_c0d0u1 - mtc_table_entry->trained_dram_clktree_c0d0u1) * 128;\n\t\ttree_delta[2] = (mtc_table_entry->current_dram_clktree_c1d0u0 - mtc_table_entry->trained_dram_clktree_c1d0u0) * 128;\n\t\ttree_delta[3] = (mtc_table_entry->current_dram_clktree_c1d0u1 - mtc_table_entry->trained_dram_clktree_c1d0u1) * 128;\n\t\ttree_delta_taps[0] = (tree_delta[0] * (s32)dst_rate_mhz) / 1000000;\n\t\ttree_delta_taps[1] = (tree_delta[1] * (s32)dst_rate_mhz) / 1000000;\n\t\ttree_delta_taps[2] = (tree_delta[2] * (s32)dst_rate_mhz) / 1000000;\n\t\ttree_delta_taps[3] = (tree_delta[3] * (s32)dst_rate_mhz) / 1000000;\n\t\tfor (u32 i = 0; i < 4; i++)\n\t\t{\n\t\t\t// Check if tap exceeds margins and apply it.\n\t\t\tif ((tree_delta_taps[i] > (s32)mtc_table_entry->tree_margin) || (tree_delta_taps[i] < (-1 * (s32)mtc_table_entry->tree_margin)))\n\t\t\t{\n\t\t\t\tnew_trim[i * 2]     += tree_delta_taps[i];\n\t\t\t\tnew_trim[i * 2 + 1] += tree_delta_taps[i];\n\t\t\t}\n\t\t}\n\t\tif (trim_emc_reg_addr == EMC_DATA_BRLSHFT_0)\n\t\t{\n\t\t\tfor (u32 i = 0; i < 8; i++)\n\t\t\t\tnew_trim[i] /= 64;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (u32 i = 0; i < 8; i++)\n\t\t\t\tnew_trim[i] %= 64;\n\t\t}\n\t\tbreak;\n\tcase EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0:\n\tcase EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1:\n\tcase EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2:\n\tcase EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3:\n\tcase EMC_DATA_BRLSHFT_1:\n\t\ttree_delta[0] = (mtc_table_entry->current_dram_clktree_c0d1u0 - mtc_table_entry->trained_dram_clktree_c0d1u0) * 128;\n\t\ttree_delta[1] = (mtc_table_entry->current_dram_clktree_c0d1u1 - mtc_table_entry->trained_dram_clktree_c0d1u1) * 128;\n\t\ttree_delta[2] = (mtc_table_entry->current_dram_clktree_c1d1u0 - mtc_table_entry->trained_dram_clktree_c1d1u0) * 128;\n\t\ttree_delta[3] = (mtc_table_entry->current_dram_clktree_c1d1u1 - mtc_table_entry->trained_dram_clktree_c1d1u1) * 128;\n\t\ttree_delta_taps[0] = (tree_delta[0] * (s32)dst_rate_mhz) / 1000000;\n\t\ttree_delta_taps[1] = (tree_delta[1] * (s32)dst_rate_mhz) / 1000000;\n\t\ttree_delta_taps[2] = (tree_delta[2] * (s32)dst_rate_mhz) / 1000000;\n\t\ttree_delta_taps[3] = (tree_delta[3] * (s32)dst_rate_mhz) / 1000000;\n\t\tfor (u32 i = 0; i < 4; i++)\n\t\t{\n\t\t\t// Check if tap exceeds margins and apply it.\n\t\t\tif ((tree_delta_taps[i] > (s32)mtc_table_entry->tree_margin) || (tree_delta_taps[i] < (-1 * (s32)mtc_table_entry->tree_margin)))\n\t\t\t{\n\t\t\t\tnew_trim[8 + i * 2]     += tree_delta_taps[i];\n\t\t\t\tnew_trim[8 + i * 2 + 1] += tree_delta_taps[i];\n\t\t\t}\n\t\t}\n\t\tif (trim_emc_reg_addr == EMC_DATA_BRLSHFT_1)\n\t\t{\n\t\t\tfor (u32 i = 0; i < 8; i++)\n\t\t\t\tnew_trim[i + 8] /= 64;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (u32 i = 0; i < 8; i++)\n\t\t\t\tnew_trim[i + 8] %= 64;\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\tswitch (trim_emc_reg_addr)\n\t{\n\tcase EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0:\n\t\ttrimmer = (new_trim[0] & 0x7FF) | ((new_trim[1] & 0x7FF) << 16);\n\t\tbreak;\n\tcase EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1:\n\t\ttrimmer = (new_trim[2] & 0x7FF) | ((new_trim[3] & 0x7FF) << 16);\n\t\tbreak;\n\tcase EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2:\n\t\ttrimmer = (new_trim[4] & 0x7FF) | ((new_trim[5] & 0x7FF) << 16);\n\t\tbreak;\n\tcase EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3:\n\t\ttrimmer = (new_trim[6] & 0x7FF) | ((new_trim[7] & 0x7FF) << 16);\n\t\tbreak;\n\tcase EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0:\n\t\ttrimmer = (new_trim[8] & 0x7FF) | ((new_trim[9] & 0x7FF) << 16);\n\t\tbreak;\n\tcase EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1:\n\t\ttrimmer = (new_trim[10] & 0x7FF) | ((new_trim[11] & 0x7FF) << 16);\n\t\tbreak;\n\tcase EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2:\n\t\ttrimmer = (new_trim[12] & 0x7FF) | ((new_trim[13] & 0x7FF) << 16);\n\t\tbreak;\n\tcase EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3:\n\t\ttrimmer = (new_trim[14] & 0x7FF) | ((new_trim[15] & 0x7FF) << 16);\n\t\tbreak;\n\tcase EMC_DATA_BRLSHFT_0:\n\t\ttrimmer = ((new_trim[0] & 7) << EMC_DATA_BRLSHFT_0_RANK0_BYTE0_DATA_BRLSHFT_SHIFT)\n\t\t\t\t| ((new_trim[1] & 7) << EMC_DATA_BRLSHFT_0_RANK0_BYTE1_DATA_BRLSHFT_SHIFT)\n\t\t\t\t| ((new_trim[2] & 7) << EMC_DATA_BRLSHFT_0_RANK0_BYTE2_DATA_BRLSHFT_SHIFT)\n\t\t\t\t| ((new_trim[3] & 7) << EMC_DATA_BRLSHFT_0_RANK0_BYTE3_DATA_BRLSHFT_SHIFT)\n\t\t\t\t| ((new_trim[4] & 7) << EMC_DATA_BRLSHFT_0_RANK0_BYTE4_DATA_BRLSHFT_SHIFT)\n\t\t\t\t| ((new_trim[5] & 7) << EMC_DATA_BRLSHFT_0_RANK0_BYTE5_DATA_BRLSHFT_SHIFT)\n\t\t\t\t| ((new_trim[6] & 7) << EMC_DATA_BRLSHFT_0_RANK0_BYTE6_DATA_BRLSHFT_SHIFT)\n\t\t\t\t| ((new_trim[7] & 7) << EMC_DATA_BRLSHFT_0_RANK0_BYTE7_DATA_BRLSHFT_SHIFT);\n\t\tbreak;\n\tcase EMC_DATA_BRLSHFT_1:\n\t\ttrimmer = ((new_trim[8]  & 7) << EMC_DATA_BRLSHFT_1_RANK1_BYTE0_DATA_BRLSHFT_SHIFT)\n\t\t\t\t| ((new_trim[9]  & 7) << EMC_DATA_BRLSHFT_1_RANK1_BYTE1_DATA_BRLSHFT_SHIFT)\n\t\t\t\t| ((new_trim[10] & 7) << EMC_DATA_BRLSHFT_1_RANK1_BYTE2_DATA_BRLSHFT_SHIFT)\n\t\t\t\t| ((new_trim[11] & 7) << EMC_DATA_BRLSHFT_1_RANK1_BYTE3_DATA_BRLSHFT_SHIFT)\n\t\t\t\t| ((new_trim[12] & 7) << EMC_DATA_BRLSHFT_1_RANK1_BYTE4_DATA_BRLSHFT_SHIFT)\n\t\t\t\t| ((new_trim[13] & 7) << EMC_DATA_BRLSHFT_1_RANK1_BYTE5_DATA_BRLSHFT_SHIFT)\n\t\t\t\t| ((new_trim[14] & 7) << EMC_DATA_BRLSHFT_1_RANK1_BYTE6_DATA_BRLSHFT_SHIFT)\n\t\t\t\t| ((new_trim[15] & 7) << EMC_DATA_BRLSHFT_1_RANK1_BYTE7_DATA_BRLSHFT_SHIFT);\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn trimmer;\n}\n\nstatic bool _check_freq_changed(u32 dst_entry_rate_KHz, u32 dst_entry_clk_src_emc, u32 src_entry_rate_KHz, u32 src_entry_clk_src_emc)\n{\n\tu64 dst_div_clock;\n\tu64 src_div_clock;\n\tu32 src_end_div_clk_ratio;\n\n\tu32 src_entry_emc_2X_clk_src = src_entry_clk_src_emc >> EMC_2X_CLK_SRC_SHIFT;\n\tu32 dst_entry_emc_2X_clk_src = dst_entry_clk_src_emc >> EMC_2X_CLK_SRC_SHIFT;\n\tu32 src_entry_emc_2X_clk_src_div = src_entry_clk_src_emc & 0xFF;\n\tu32 dst_entry_emc_2X_clk_src_div = dst_entry_clk_src_emc & 0xFF;\n\tu32 pll_post_divider = 0;\n\n\tswitch (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) >> EMC_2X_CLK_SRC_SHIFT)\n\t{\n\t\tcase PLLM_OUT0:\n\t\tcase PLLM_UD:\n\t\t\tpll_post_divider = (CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) >> 20) & 0x1F;\n\t\t\tbreak;\n\t\tcase PLLMB_UD:\n\t\tcase PLLMB_OUT0:\n\t\t\tpll_post_divider = (CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) >> 20) & 0x1F;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t}\n\n\t// Hang if post div is wrong.\n\tif (pll_post_divider > 5)\n\t\twhile (true)\n\t\t\t;\n\n\tif (src_entry_emc_2X_clk_src <= PLLMB_UD)\n\t\tsrc_entry_emc_2X_clk_src_div = 0;\n\tif (dst_entry_emc_2X_clk_src <= PLLMB_UD)\n\t\tdst_entry_emc_2X_clk_src_div = 0;\n\n\tif (dst_entry_emc_2X_clk_src != src_entry_emc_2X_clk_src\n\t\t&& (dst_entry_emc_2X_clk_src & 0xFFFFFFFB || src_entry_emc_2X_clk_src & 0xFFFFFFFB))\n\t\t\treturn true;\n\n\tdst_div_clock = dst_entry_rate_KHz * (pll_post_divider + 1)\n\t\t* ((dst_entry_emc_2X_clk_src_div >> 1) * 10 + (dst_entry_emc_2X_clk_src_div & 1) * 5 + 10) / 10; // Accounting for 7.1 div.\n\tsrc_div_clock = src_entry_rate_KHz * (pll_post_divider + 1)\n\t\t* ((src_entry_emc_2X_clk_src_div >> 1) * 10 + (src_entry_emc_2X_clk_src_div & 1) * 5 + 10) / 10; // Accounting for 7.1 div.\n\n\tsrc_end_div_clk_ratio = (src_div_clock * 1000) / dst_div_clock;\n\n\tif (src_end_div_clk_ratio > 1010 || src_end_div_clk_ratio < 990)\n\t\treturn true;\n\telse\n\t\treturn false;\n}\n\nstatic void _save_train_results(emc_table_t *mtc_table_entry, u32 needs_training, u32 dram_dev_num, bool channel1_enabled)\n{\n\tbool needs_ca_training        = !!(needs_training & NEEDS_TRAINING_CA);\n\tbool needs_ca_vref_training   = !!(needs_training & NEEDS_TRAINING_CA_VREF);\n\tbool needs_quse_training      = !!(needs_training & NEEDS_TRAINING_QUSE);\n\tbool needs_quse_vref_training = !!(needs_training & NEEDS_TRAINING_QUSE_VREF);\n\tbool needs_wr_training        = !!(needs_training & NEEDS_TRAINING_WR);\n\tbool needs_wr_vref_training   = !!(needs_training & NEEDS_TRAINING_WR_VREF);\n\tbool needs_rd_training        = !!(needs_training & NEEDS_TRAINING_RD);\n\tbool needs_rd_vref_training   = !!(needs_training & NEEDS_TRAINING_RD_VREF);\n\tbool needs_training_in_self_refresh = !!(needs_training & NEEDS_TRAINING_IN_SELF_REFRESH);\n\n\tif (needs_ca_training)\n\t{\n\t\tmtc_table_entry->trim_perch_regs.emc_cmd_brlshft_0 = EMC_CH0(EMC_CMD_BRLSHFT_0);\n\t\tmtc_table_entry->trim_perch_regs.emc_cmd_brlshft_1 = channel1_enabled ? EMC_CH1(EMC_CMD_BRLSHFT_1) : 0;\n\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_4 = EMC_CH0(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4);\n\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_5 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5) : 0;\n\n\t\tif (needs_training_in_self_refresh)\n\t\t{\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd0_0 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd0_1 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd0_2 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd1_0 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd1_1 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd1_2 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd2_0 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd2_1 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd2_2 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd3_0 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd3_1 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd3_2 = EMC(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2);\n\t\t}\n\t}\n\n\tif (needs_ca_vref_training)\n\t{\n\t\tmtc_table_entry->burst_reg_per_ch.emc0_mrw10 = (EMC_CH0(EMC_TRAINING_OPT_CA_VREF) & 0xFFFF) | 0x880C0000;\n\t\tmtc_table_entry->burst_reg_per_ch.emc1_mrw10 = (channel1_enabled ? EMC_CH1(EMC_TRAINING_OPT_CA_VREF) & 0xFFFF : 0) | 0x880C0000;\n\n\t\tu32 mrw11_dev_selectn;\n\t\tif (dram_dev_num == TWO_RANK)\n\t\t\tmrw11_dev_selectn = 0x480C0000;\n\t\telse\n\t\t\tmrw11_dev_selectn = 0xC80C0000;\n\n\t\tmtc_table_entry->burst_reg_per_ch.emc0_mrw11 =\n\t\t\t((EMC_CH0(EMC_TRAINING_OPT_CA_VREF) >> 16) & 0xFF)\n\t\t\t| (EMC_CH0(EMC_TRAINING_OPT_CA_VREF) >> 24 << 8)\n\t\t\t| (mrw11_dev_selectn & 0xFFFFFF00);\n\n\t\tmtc_table_entry->burst_reg_per_ch.emc1_mrw11 =\n\t\t\t(((channel1_enabled ? EMC_CH1(EMC_TRAINING_OPT_CA_VREF) : 0) >> 16) & 0xFF)\n\t\t\t| ((channel1_enabled ? EMC_CH1(EMC_TRAINING_OPT_CA_VREF) : 0) >> 24 << 8)\n\t\t\t| (mrw11_dev_selectn & 0xFFFFFF00);\n\t}\n\n\tif (needs_quse_training || needs_rd_training)\n\t{\n\t\tmtc_table_entry->trim_perch_regs.emc_quse_brlshft_0 = EMC_CH0(EMC_QUSE_BRLSHFT_0);\n\t\tmtc_table_entry->trim_perch_regs.emc_quse_brlshft_1 = channel1_enabled ? EMC_CH1(EMC_QUSE_BRLSHFT_1) : 0;\n\n\t\tmtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank0_0 = EMC_CH0(EMC_PMACRO_QUSE_DDLL_RANK0_0);\n\t\tmtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank0_1 = EMC_CH0(EMC_PMACRO_QUSE_DDLL_RANK0_1);\n\t\tmtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank0_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_QUSE_DDLL_RANK0_2) : 0;\n\t\tmtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank0_3 = channel1_enabled ? EMC_CH1(EMC_PMACRO_QUSE_DDLL_RANK0_3) : 0;\n\n\t\tif (dram_dev_num == TWO_RANK)\n\t\t{\n\t\t\tmtc_table_entry->trim_perch_regs.emc_quse_brlshft_2 = EMC_CH0(EMC_QUSE_BRLSHFT_2);\n\t\t\tmtc_table_entry->trim_perch_regs.emc_quse_brlshft_3 = channel1_enabled ? EMC_CH1(EMC_QUSE_BRLSHFT_3) : 0;\n\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank1_0 = EMC_CH0(EMC_PMACRO_QUSE_DDLL_RANK1_0);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank1_1 = EMC_CH0(EMC_PMACRO_QUSE_DDLL_RANK1_1);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank1_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_QUSE_DDLL_RANK1_2) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_quse_ddll_rank1_3 = channel1_enabled ? EMC_CH1(EMC_PMACRO_QUSE_DDLL_RANK1_3) : 0;\n\t\t}\n\t}\n\n\tif (needs_quse_vref_training)\n\t{\n\t\tif (dram_dev_num == TWO_RANK)\n\t\t{\n\t\t\tu32 emc0_opt_dqs_array[4] = {0};\n\t\t\tu32 emc1_opt_dqs_array[4] = {0};\n\t\t\tu32 emc1_training_opt_dqs_ib_vref_rank0_val = channel1_enabled ? EMC_CH1(EMC_TRAINING_OPT_DQS_IB_VREF_RANK0) : 0;\n\t\t\tu32 emc1_training_opt_dqs_ib_vref_rank1_val = channel1_enabled ? EMC_CH1(EMC_TRAINING_OPT_DQS_IB_VREF_RANK1) : 0;\n\n\t\t\tfor (u32 i = 0; i < 4; i++)\n\t\t\t{\n\t\t\t\temc0_opt_dqs_array[i] = (EMC_CH0(EMC_TRAINING_OPT_DQS_IB_VREF_RANK0) >> (8 * i)) & 0xFF;\n\t\t\t\temc1_opt_dqs_array[i] = (emc1_training_opt_dqs_ib_vref_rank0_val >> (8 * i)) & 0xFF;\n\t\t\t}\n\n\t\t\tu32 ib_vref_dqs_0 = 0;\n\t\t\tu32 ib_vref_dqs_1 = 0;\n\t\t\tfor (u32 i = 0; i < 4; i++)\n\t\t\t{\n\t\t\t\tib_vref_dqs_0 |= (emc0_opt_dqs_array[i] + ((EMC_CH0(EMC_TRAINING_OPT_DQS_IB_VREF_RANK1) >> (8 * i)) & 0xFF)) >> 1 << (8 * i);\n\t\t\t\tib_vref_dqs_1 |= (emc1_opt_dqs_array[i] + ((emc1_training_opt_dqs_ib_vref_rank1_val >> (8 * i)) & 0xFF)) >> 1 << (8 * i);\n\t\t\t}\n\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_vref_dqs_0 = ib_vref_dqs_0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_vref_dqs_1 = ib_vref_dqs_1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_vref_dqs_0 = EMC(EMC_PMACRO_IB_VREF_DQS_0);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_vref_dqs_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_VREF_DQS_1) : 0;\n\t\t}\n\t}\n\n\tif (needs_rd_training)\n\t{\n\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_0 = EMC_CH0(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0);\n\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_1 = EMC_CH0(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1);\n\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2) : 0;\n\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_3 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3) : 0;\n\n\t\tif (dram_dev_num == TWO_RANK)\n\t\t{\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_0 = EMC_CH0(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_1 = EMC_CH0(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_3 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3) : 0;\n\t\t}\n\n\t\tif (needs_training_in_self_refresh)\n\t\t{\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte0_0 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte0_1 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte0_2 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte1_0 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte1_1 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte1_2 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte2_0 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte2_1 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte2_2 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte3_0 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte3_1 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte3_2 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte4_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte4_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte4_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte5_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte5_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte5_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte6_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte6_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte6_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte7_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte7_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte7_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2) : 0;\n\n\t\t\tif (dram_dev_num == TWO_RANK)\n\t\t\t{\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte0_0 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte0_1 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte0_2 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte1_0 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte1_1 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte1_2 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte2_0 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte2_1 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte2_2 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte3_0 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte3_1 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte3_2 = EMC_CH0(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte4_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte4_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte4_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte5_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte5_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte5_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte6_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte6_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte6_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte7_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte7_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte7_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2) : 0;\n\t\t\t}\n\t\t}\n\n\t\tif (needs_rd_vref_training)\n\t\t{\n\t\t\tchar ib_vref_dq_byte0_icr = (EMC(EMC_PMACRO_IB_VREF_DQ_0) & 0x7F) + (mtc_table_entry->save_restore_mod_regs[0] & 0x7F);\n\t\t\tif (mtc_table_entry->save_restore_mod_regs[0] & 0x80000000) // < 0 check.\n\t\t\t\tib_vref_dq_byte0_icr = (EMC(EMC_PMACRO_IB_VREF_DQ_0) & 0x7F) - (mtc_table_entry->save_restore_mod_regs[0] & 0x7F);\n\n\t\t\tchar ib_vref_dq_byte1_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_0) >> 8) & 0x7F) + (mtc_table_entry->save_restore_mod_regs[1] & 0x7F);\n\t\t\tif (mtc_table_entry->save_restore_mod_regs[1] & 0x80000000)\n\t\t\t\tib_vref_dq_byte1_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_0) >> 8) & 0x7F) - (mtc_table_entry->save_restore_mod_regs[1] & 0x7F);\n\n\t\t\tchar ib_vref_dq_byte2_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_0) >> 16) & 0x7F) + (mtc_table_entry->save_restore_mod_regs[2] & 0x7F);\n\t\t\tif (mtc_table_entry->save_restore_mod_regs[2] & 0x80000000)\n\t\t\t\tib_vref_dq_byte2_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_0) >> 16) & 0x7F) - (mtc_table_entry->save_restore_mod_regs[2] & 0x7F);\n\n\t\t\tchar ib_vref_dq_byte3_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_0) >> 24) & 0x7F) + (mtc_table_entry->save_restore_mod_regs[3] & 0x7F);\n\t\t\tif (mtc_table_entry->save_restore_mod_regs[3] & 0x80000000)\n\t\t\t\tib_vref_dq_byte3_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_0) >> 24) & 0x7F) - (mtc_table_entry->save_restore_mod_regs[3] & 0x7F);\n\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_vref_dq_0 =\n\t\t\t\t ((ib_vref_dq_byte0_icr & 0x7F)\n\t\t\t\t| (ib_vref_dq_byte1_icr & 0x7F) << 8)\n\t\t\t\t| ((ib_vref_dq_byte2_icr & 0x7F) << 16)\n\t\t\t\t| ((ib_vref_dq_byte3_icr & 0x7F) << 24);\n\n\t\t\tchar ib_vref_dq_byte4_icr = (EMC(EMC_PMACRO_IB_VREF_DQ_1) & 0x7F) + (mtc_table_entry->save_restore_mod_regs[4] & 0x7F);\n\t\t\tif (mtc_table_entry->save_restore_mod_regs[4] & 0x80000000)\n\t\t\t\tib_vref_dq_byte4_icr = (EMC(EMC_PMACRO_IB_VREF_DQ_1) & 0x7F) - (mtc_table_entry->save_restore_mod_regs[4] & 0x7F);\n\n\t\t\tchar ib_vref_dq_byte5_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_1) >> 8) & 0x7F) + (mtc_table_entry->save_restore_mod_regs[5] & 0x7F);\n\t\t\tif (mtc_table_entry->save_restore_mod_regs[5] & 0x80000000)\n\t\t\t\tib_vref_dq_byte5_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_1) >> 8) & 0x7F) - (mtc_table_entry->save_restore_mod_regs[5] & 0x7F);\n\n\t\t\tchar ib_vref_dq_byte6_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_1) >> 16) & 0x7F) + (mtc_table_entry->save_restore_mod_regs[6] & 0x7F);\n\t\t\tif (mtc_table_entry->save_restore_mod_regs[6] & 0x80000000)\n\t\t\t\tib_vref_dq_byte6_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_1) >> 16) & 0x7F) - (mtc_table_entry->save_restore_mod_regs[6] & 0x7F);\n\n\t\t\tchar ib_vref_dq_byte7_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_1) >> 24) & 0x7F) + (mtc_table_entry->save_restore_mod_regs[7] & 0x7F);\n\t\t\tif (mtc_table_entry->save_restore_mod_regs[7] & 0x80000000)\n\t\t\t\tib_vref_dq_byte7_icr = ((EMC(EMC_PMACRO_IB_VREF_DQ_1) >> 24) & 0x7F) - (mtc_table_entry->save_restore_mod_regs[7] & 0x7F);\n\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ib_vref_dq_1 =\n\t\t\t\t ((ib_vref_dq_byte4_icr & 0x7F)\n\t\t\t\t| (ib_vref_dq_byte5_icr & 0x7F) << 8)\n\t\t\t\t| ((ib_vref_dq_byte6_icr & 0x7F) << 16)\n\t\t\t\t| ((ib_vref_dq_byte7_icr & 0x7F) << 24);\n\t\t}\n\t}\n\n\tif (needs_wr_training)\n\t{\n\t\tmtc_table_entry->trim_perch_regs.emc0_data_brlshft_0 = EMC_CH0(EMC_DATA_BRLSHFT_0);\n\t\tmtc_table_entry->trim_perch_regs.emc1_data_brlshft_0 = channel1_enabled ? EMC_CH1(EMC_DATA_BRLSHFT_0) : 0;\n\n\t\tif (dram_dev_num == TWO_RANK)\n\t\t{\n\t\t\tmtc_table_entry->trim_perch_regs.emc0_data_brlshft_1 = EMC_CH0(EMC_DATA_BRLSHFT_1);\n\t\t\tmtc_table_entry->trim_perch_regs.emc1_data_brlshft_1 = channel1_enabled ? EMC_CH1(EMC_DATA_BRLSHFT_1) : 0;\n\t\t}\n\n\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_0 = EMC_CH0(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0);\n\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_1 = EMC_CH0(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1);\n\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) : 0;\n\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_3 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3) : 0;\n\n\t\tif (dram_dev_num == TWO_RANK)\n\t\t{\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_0 = EMC_CH0(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_1 = EMC_CH0(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_3 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3) : 0;\n\t\t}\n\n\t\tif (needs_training_in_self_refresh)\n\t\t{\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte0_0 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte0_1 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte0_2 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte1_0 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte1_1 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte1_2 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte2_0 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte2_1 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte2_2 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte3_0 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte3_1 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte3_2 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2);\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte4_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte4_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte4_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte5_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte5_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte5_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte6_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte6_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte6_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte7_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte7_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1) : 0;\n\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte7_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2) : 0;\n\n\t\t\tif (dram_dev_num == TWO_RANK)\n\t\t\t{\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte0_0 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte0_1 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte0_2 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte1_0 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte1_1 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte1_2 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte2_0 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte2_1 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte2_2 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte3_0 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte3_1 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte3_2 = EMC_CH0(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2);\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte4_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte4_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte4_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte5_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte5_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte5_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte6_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte6_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte6_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte7_0 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte7_1 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1) : 0;\n\t\t\t\tmtc_table_entry->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte7_2 = channel1_enabled ? EMC_CH1(EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2) : 0;\n\t\t\t}\n\t\t}\n\n\t\tif (needs_wr_vref_training) // mode 12/13 (MRW).\n\t\t{\n\t\t\tu32 emc1_ranks_sub_partitions = 0;\n\t\t\temc1_ranks_sub_partitions = channel1_enabled ? EMC_CH1(EMC_TRAINING_OPT_DQ_OB_VREF) : 0;\n\n\t\t\tu8 emc0_ib_vref_dq_byte8_modded_plus = mtc_table_entry->save_restore_mod_regs[8] + EMC_CH0(EMC_TRAINING_OPT_DQ_OB_VREF);\n\t\t\tif (mtc_table_entry->save_restore_mod_regs[8] & 0x80000000) // < 0 check.\n\t\t\t\temc0_ib_vref_dq_byte8_modded_plus = EMC_CH0(EMC_TRAINING_OPT_DQ_OB_VREF) - mtc_table_entry->save_restore_mod_regs[8];\n\n\t\t\tu8 emc0_mrw12_op_sp1 = ((EMC_CH0(EMC_TRAINING_OPT_DQ_OB_VREF) & 0xFFFF) >> 8) + mtc_table_entry->save_restore_mod_regs[9];\n\t\t\tif (mtc_table_entry->save_restore_mod_regs[9] & 0x80000000)\n\t\t\t\temc0_mrw12_op_sp1 = ((EMC_CH0(EMC_TRAINING_OPT_DQ_OB_VREF) & 0xFFFF) >> 8) - mtc_table_entry->save_restore_mod_regs[9];\n\n\t\t\tu8 emc0_mrw13_op_sp0 = ((EMC_CH0(EMC_TRAINING_OPT_DQ_OB_VREF) >> 16) & 0xFF) + mtc_table_entry->save_restore_mod_regs[8];\n\t\t\tif (mtc_table_entry->save_restore_mod_regs[8] & 0x80000000)\n\t\t\t\temc0_mrw13_op_sp0 = ((EMC_CH0(EMC_TRAINING_OPT_DQ_OB_VREF) >> 16) & 0xFF) - mtc_table_entry->save_restore_mod_regs[8];\n\n\t\t\tu8 emc0_ib_vref_dq_byte9_modded_a_plus = mtc_table_entry->save_restore_mod_regs[9] + (EMC_CH0(EMC_TRAINING_OPT_DQ_OB_VREF) >> 24);\n\t\t\tif (mtc_table_entry->save_restore_mod_regs[9] & 0x80000000)\n\t\t\t\temc0_ib_vref_dq_byte9_modded_a_plus = (EMC_CH0(EMC_TRAINING_OPT_DQ_OB_VREF) >> 24) - (u8)mtc_table_entry->save_restore_mod_regs[9];\n\n\t\t\tu8 emc0_ib_vref_dq_byte10_modded_plus = emc1_ranks_sub_partitions + mtc_table_entry->save_restore_mod_regs[10];\n\t\t\tif (mtc_table_entry->save_restore_mod_regs[10] & 0x80000000)\n\t\t\t\temc0_ib_vref_dq_byte10_modded_plus = emc1_ranks_sub_partitions - mtc_table_entry->save_restore_mod_regs[10];\n\n\t\t\tu8 emc0_ib_vref_dq_byte11_modded_plus = ((emc1_ranks_sub_partitions & 0xFFFF) >> 8) + mtc_table_entry->save_restore_mod_regs[11];\n\t\t\tif (mtc_table_entry->save_restore_mod_regs[11] & 0x80000000)\n\t\t\t\temc0_ib_vref_dq_byte11_modded_plus = ((emc1_ranks_sub_partitions & 0xFFFF) >> 8) - mtc_table_entry->save_restore_mod_regs[11];\n\n\t\t\tu8 emc1_mrw13_op_sp0 = ((emc1_ranks_sub_partitions >> 16) & 0xFF) + mtc_table_entry->save_restore_mod_regs[10];\n\t\t\tif (mtc_table_entry->save_restore_mod_regs[10] & 0x80000000)\n\t\t\t\temc1_mrw13_op_sp0 = ((emc1_ranks_sub_partitions >> 16) & 0xFF) - mtc_table_entry->save_restore_mod_regs[10];\n\n\t\t\tu8 emc1_mrw13_op_sp1 = (emc1_ranks_sub_partitions >> 24) + mtc_table_entry->save_restore_mod_regs[11];\n\t\t\tif (mtc_table_entry->save_restore_mod_regs[11] & 0x80000000)\n\t\t\t\temc1_mrw13_op_sp1 = (emc1_ranks_sub_partitions >> 24) - mtc_table_entry->save_restore_mod_regs[11];\n\n\t\t\tu32 mr13_dev_ext_cnt_sp_addr = 0xC80E0000;\n\t\t\tif (dram_dev_num == TWO_RANK)\n\t\t\t\tmr13_dev_ext_cnt_sp_addr = 0x480E0000;\n\n\t\t\tmtc_table_entry->burst_reg_per_ch.emc1_mrw12 = (u8)emc0_ib_vref_dq_byte10_modded_plus | 0x880E0000 | (emc0_ib_vref_dq_byte11_modded_plus << 8);\n\t\t\tmtc_table_entry->burst_reg_per_ch.emc0_mrw12 = emc0_ib_vref_dq_byte8_modded_plus | 0x880E0000 | (emc0_mrw12_op_sp1 << 8);\n\t\t\tmtc_table_entry->burst_reg_per_ch.emc0_mrw13 = emc0_ib_vref_dq_byte9_modded_a_plus << 8 | emc0_mrw13_op_sp0 | mr13_dev_ext_cnt_sp_addr;\n\t\t\tmtc_table_entry->burst_reg_per_ch.emc1_mrw13 = (emc1_mrw13_op_sp1 << 8) | emc1_mrw13_op_sp0 | mr13_dev_ext_cnt_sp_addr;\n\t\t}\n\t}\n}\n\nstatic u32 _minerva_change_clock(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, u32 needs_training, u32 selected_clk_src_emc)\n{\n\tu32 emc_dbg_o;\n\tu32 emc_pin_o;\n\tu32 emc_cfg_pipe_clk_o;\n\tu32 emc_sel_dpd_ctrl;\n\tu32 emc_cfg;\n\tu32 emc_dbg_val;\n\tu32 emc_zq_cal = 0;\n\tu32 ramp_up_wait;\n\tu32 ramp_down_wait;\n\tu32 bg_regulator_mode_change;\n\tu32 mr13_flip_fspop;\n\tu32 mr13_flip_fspwr;\n\tu32 mr13_catr_enable;\n\n\t/* needs_training flags */\n\t/*\n\t | bit | Description                      |\n\t |-----|----------------------------------|\n\t |  0  | Needs CA              training   |\n\t |  1  | Needs CA_VREF         training   |\n\t |  2  | Needs QUSE            training   |\n\t |  3  | Needs QUSE_VREF       training   |\n\t |  4  | Needs WR              training   |\n\t |  5  | Needs WR_VREF         training   |\n\t |  6  | Needs RD              training   |\n\t |  7  | Needs RD_VREF         training   |\n\t |  8  | Needs SWAP_RANK       training   |\n\t |  9  | Needs IN_SELF_REFRESH training   |\n\t */\n\n\tbool compensate_trimmer_applicable = false;\n\tbool in_training              = !!(needs_training & NEEDS_TRAINING);\n\n\tbool needs_ca_combo_training  = !!(needs_training & NEEDS_TRAINING_CA_COMBO);\n\tbool needs_ca_training        = !!(needs_training & NEEDS_TRAINING_CA);\n\tbool needs_ca_vref_training   = !!(needs_training & NEEDS_TRAINING_CA_VREF);\n\tbool needs_quse_training      = !!(needs_training & NEEDS_TRAINING_QUSE);\n\tbool needs_quse_vref_training = !!(needs_training & NEEDS_TRAINING_QUSE_VREF);\n\tbool needs_wr_training        = !!(needs_training & NEEDS_TRAINING_WR);\n\tbool needs_wr_vref_training   = !!(needs_training & NEEDS_TRAINING_WR_VREF);\n\tbool needs_rd_training        = !!(needs_training & NEEDS_TRAINING_RD);\n\tbool needs_rd_vref_training   = !!(needs_training & NEEDS_TRAINING_RD_VREF);\n\tbool needs_swap_rank_training = !!(needs_training & NEEDS_TRAINING_SWAP_RANK);\n\n\tbool zcal_resistor_shared = (src_emc_entry->burst_regs.emc_zcal_wait_cnt >> 31) & 1;\n\tbool enable_bg_regulator  = (dst_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0 & 1) ^ 1;\n\tbool channel1_enabled     = (src_emc_entry->burst_regs.emc_fbio_cfg7 >> 2) & 1;\n\tu32  dram_type = EMC(EMC_FBIO_CFG5) & 3;\n\tu32  dram_dev_num = (MC(MC_EMEM_ADR_CFG) & 1) + 1;\n\n\tu32 src_clock_period = 1000000000 / src_emc_entry->rate_khz; // In picoseconds.\n\tu32 dst_clock_period = 1000000000 / dst_emc_entry->rate_khz; // In picoseconds.\n\n\t// Get current FSP op/write value.\n\tbool enable_fsp_opwr = !(EMC(EMC_MRW3) & 0xC0);\n\n\tif (dram_type != DRAM_TYPE_LPDDR4)\n\t{\n\t\tEPRINTF(\"MTC Error: DRAM is not LPDDR4\");\n\t\treturn 5;\n\t}\n\n\tu32 tFC_lpddr4 = dst_emc_entry->dram_timings.t_fc_lpddr4 * 1000;\n\tu32 tZQCAL_lpddr4 = 1000000;\n\tif (dst_clock_period <= 2000)\n\t\ttZQCAL_lpddr4 -= tFC_lpddr4;\n\ts32 tZQCAL_lpddr4_fc_adj = tZQCAL_lpddr4 / dst_clock_period;\n\n\t(void)EMC(EMC_CFG);\n\t(void)EMC(EMC_AUTO_CAL_CONFIG);\n\n\t// Step 1 - Pre DVFS SW sequence.\n\tEPRINTF(\"Step 1\");\n\temc_dbg_o = EMC(EMC_DBG);\n\temc_pin_o = EMC(EMC_PIN);\n\temc_cfg = dst_emc_entry->burst_regs.emc_cfg & 0xFFFFFFF;\n\temc_sel_dpd_ctrl = dst_emc_entry->emc_sel_dpd_ctrl & 0xFFFFFEC3;\n\temc_cfg_pipe_clk_o = EMC(EMC_CFG_PIPE_CLK);\n\t_digital_dll_disable();\n\n\t// Step 1.2 - Disable AUTOCAL temporarily.\n\tEPRINTF(\"Step 1.2\");\n\tEMC(EMC_AUTO_CAL_CONFIG) = (dst_emc_entry->emc_auto_cal_config & 0x7FFFF9FF) | 0x600;\n\t(void)EMC(EMC_AUTO_CAL_CONFIG);\n\n\t// Step 1.3 - Disable other power features.\n\tEPRINTF(\"Step 1.3\");\n\tEMC(EMC_DBG) = emc_dbg_o | EMC_DBG_WRITE_MUX_ACTIVE;\n\tEMC(EMC_CFG)          = emc_cfg;\n\tEMC(EMC_SEL_DPD_CTRL) = emc_sel_dpd_ctrl;\n\tEMC(EMC_DBG) = emc_dbg_o;\n\n\tif (!in_training && dst_emc_entry->periodic_training)\n\t{\n\t\tif (dram_dev_num == TWO_RANK)\n\t\t{\n\t\t\t_wait_emc_status(EMC_EMC_STATUS, IN_POWERDOWN_BOTH_MASK, false, EMC_CHANNEL0);\n\t\t\tif (channel1_enabled)\n\t\t\t\t_wait_emc_status(EMC_EMC_STATUS, IN_POWERDOWN_BOTH_MASK, false, EMC_CHANNEL1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_wait_emc_status(EMC_EMC_STATUS, IN_POWERDOWN_1DEV_MASK, false, EMC_CHANNEL0);\n\t\t\tif (channel1_enabled)\n\t\t\t\t_wait_emc_status(EMC_EMC_STATUS, IN_POWERDOWN_1DEV_MASK, false, EMC_CHANNEL1);\n\t\t}\n\n\t\t_wait_emc_status(EMC_EMC_STATUS, IN_SELF_REFRESH_MASK, false, EMC_CHANNEL0);\n\t\tif (channel1_enabled)\n\t\t\t_wait_emc_status(EMC_EMC_STATUS, IN_SELF_REFRESH_MASK, false, EMC_CHANNEL1);\n\n\t\t// Reset clock tree delays.\n\t\tdst_emc_entry->current_dram_clktree_c0d0u0 = dst_emc_entry->trained_dram_clktree_c0d0u0;\n\t\tdst_emc_entry->current_dram_clktree_c0d0u1 = dst_emc_entry->trained_dram_clktree_c0d0u1;\n\t\tdst_emc_entry->current_dram_clktree_c0d1u0 = dst_emc_entry->trained_dram_clktree_c0d1u0;\n\t\tdst_emc_entry->current_dram_clktree_c0d1u1 = dst_emc_entry->trained_dram_clktree_c0d1u1;\n\t\tdst_emc_entry->current_dram_clktree_c1d0u0 = dst_emc_entry->trained_dram_clktree_c1d0u0;\n\t\tdst_emc_entry->current_dram_clktree_c1d0u1 = dst_emc_entry->trained_dram_clktree_c1d0u1;\n\t\tdst_emc_entry->current_dram_clktree_c1d1u0 = dst_emc_entry->trained_dram_clktree_c1d1u0;\n\t\tdst_emc_entry->current_dram_clktree_c1d1u1 = dst_emc_entry->trained_dram_clktree_c1d1u1;\n\n\t\tu32 adelta = _minerva_periodic_compensation_handler(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, DVFS_SEQUENCE);\n\n\t\tif (((dst_emc_entry->rate_khz / 1000) * 128) * adelta / 1000000 > dst_emc_entry->tree_margin)\n\t\t\tcompensate_trimmer_applicable = true;\n\t}\n\n\tEMC(EMC_INTSTATUS) = CLKCHANGE_COMPLETE_INT;\n\tEMC(EMC_DBG) = emc_dbg_o | EMC_DBG_WRITE_MUX_ACTIVE;\n\tEMC(EMC_CFG) = emc_cfg;\n\tEMC(EMC_SEL_DPD_CTRL) = emc_sel_dpd_ctrl;\n\tEMC(EMC_CFG_PIPE_CLK) = emc_cfg_pipe_clk_o | 1; // CLK_ALWAYS_ON.\n\tEMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = dst_emc_entry->emc_fdpd_ctrl_cmd_no_ramp & 0xFFFFFFFE;\n\n\tbg_regulator_mode_change = src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0 ^ dst_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0;\n\tbg_regulator_mode_change = (bg_regulator_mode_change | (bg_regulator_mode_change >> 2)) & 1;\n\n\tif (bg_regulator_mode_change)\n\t{\n\t\tEMC(EMC_DBG) = emc_dbg_o | EMC_DBG_WRITE_MUX_ACTIVE;\n\t\tif (enable_bg_regulator)\n\t\t\tEMC(EMC_PMACRO_BG_BIAS_CTRL_0) = src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0 & 0xFFFFFFFE;\n\t\telse\n\t\t\tEMC(EMC_PMACRO_BG_BIAS_CTRL_0) = src_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0 & 0xFFFFFFFB;\n\t}\n\n\t// Check if we need to turn on VREF generator.\n\tif ((!(src_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl & 0x100) && (dst_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl & 0x100)) ||\n\t\t(!(src_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl & 1)     && (dst_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl & 1)))\n\t{\n\t\tEMC(EMC_PMACRO_DATA_PAD_TX_CTRL) =\n\t\t\t(((dst_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl & 1) | (src_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl & 0xFFFFFFFE)) & 0xFFFFFEFF)\n\t\t\t| (((dst_emc_entry->burst_regs.emc_pmacro_data_pad_tx_ctrl >> 8) & 0x1) << 8);\n\t}\n\n\t_usleep(1);\n\n\tEMC(EMC_DBG) = emc_dbg_o;\n\n\t// Step 2 - Prelock the DLL.\n\tEPRINTF(\"Step 2\");\n\tif (dst_emc_entry->burst_regs.emc_cfg_dig_dll & 1)\n\t\t_digital_dll_prelock(dst_emc_entry, in_training, selected_clk_src_emc); // Prelock enabled for target frequency.\n\telse\n\t{\n\t\t_change_dll_src(dst_emc_entry, selected_clk_src_emc);\n\t\t_digital_dll_disable(); // Disabling DLL for target frequency.\n\t}\n\n\t// Step 3 - Prepare autocal for the clock change.\n\tEPRINTF(\"Step 3\");\n\tEMC(EMC_AUTO_CAL_CONFIG) = (dst_emc_entry->emc_auto_cal_config & 0x7FFFF9FF) | 0x600;\n\tEMC(EMC_DBG) = emc_dbg_o | EMC_DBG_WRITE_MUX_ACTIVE;\n\tEMC(EMC_AUTO_CAL_CONFIG2) = dst_emc_entry->emc_auto_cal_config2;\n\tEMC(EMC_AUTO_CAL_CONFIG3) = dst_emc_entry->emc_auto_cal_config3;\n\tEMC(EMC_AUTO_CAL_CONFIG4) = dst_emc_entry->emc_auto_cal_config4;\n\tEMC(EMC_AUTO_CAL_CONFIG5) = dst_emc_entry->emc_auto_cal_config5;\n\tEMC(EMC_AUTO_CAL_CONFIG6) = dst_emc_entry->emc_auto_cal_config6;\n\tEMC(EMC_AUTO_CAL_CONFIG7) = dst_emc_entry->emc_auto_cal_config7;\n\tEMC(EMC_AUTO_CAL_CONFIG8) = dst_emc_entry->emc_auto_cal_config8;\n\tEMC(EMC_DBG) = emc_dbg_o;\n\tEMC(EMC_AUTO_CAL_CONFIG) = (dst_emc_entry->emc_auto_cal_config & 0x7FFFF9FE) | 0x601;\n\n\t// Step 4 - Update EMC_CFG.\n\tEPRINTF(\"Step 4\");\n\tif (src_clock_period <= 50000)\n\t\tEMC(EMC_CFG_2) = dst_emc_entry->emc_cfg_2;\n\telse\n\t\t_ccfifo_write(EMC_SELF_REF, 1, 0);\n\n\t// Step 5 - Prepare reference variables for ZQCAL regs.\n\tEPRINTF(\"Step 5\");\n\t// u32 zq_wait_long = 0;\n\t// u32 zq_wait_short = 0;\n\n\t// zq_wait_long = _fceil(1000.0f / dst_clock_period);\n\n\t// Step 7 - Bug 200024907 - Patch RP R2P.\n\tEPRINTF(\"Step 7\");\n\tif (needs_ca_combo_training && dram_dev_num == TWO_RANK)\n\t\tEMC(EMC_PIN) = 0x107;\n\n\tu32 R2P_war = 0;\n\tu32 TRPab_war = 0;\n\tu32 RP_war = 0;\n\tu32 W2P_war = 0;\n\n\tu32 nRTP = 8;  // <= 1066MHz.\n\tif (   src_clock_period < 1000000 /  266  // 266MHz  - 3759.39 ps.\n\t\t&& src_clock_period < 1000000 /  533  // 533MHz  - 1876.17 ps.\n\t\t&& src_clock_period < 1000000 /  800  // 800MHz  - 1250.00 ps.\n\t\t&& src_clock_period < 1000000 / 1066) // 1066MHz - 938.09 ps.\n\t\tnRTP = 10; // 1067MHz < x <= 1333MHz.\n\tif (src_clock_period < 1000000 / 1333)    // 1333MHz - 750.19 ps.\n\t\tnRTP = 12; // 1333MHz < x <= 1600MHz.\n\tif (src_clock_period < 1000000 / 1600)    // 1600MHz - 625.00 ps.\n\t\tnRTP = 14; // 1600MHz < x <= 1866MHz.\n\tif (src_clock_period < 1000000 / 1866)    // 1866MHz - 535.91 ps.\n\t\tnRTP = 16; // > 1866MHz\n\n\tu32 tRPST = (src_emc_entry->emc_mrw >> 7) & 1;\n\n\tu32 deltaTWATM = _div_o3(7500, src_clock_period);\n\tif (deltaTWATM < 8)\n\t\tdeltaTWATM = 8;\n\n\tu32 tRTM = src_emc_entry->dram_timings.rl + _div_o3(3600, src_clock_period) + deltaTWATM + tRPST + nRTP + 1;\n\n\tif (tRTM <= src_emc_entry->burst_regs.emc_rp + src_emc_entry->burst_regs.emc_r2p)\n\t{\n\t\tTRPab_war = src_emc_entry->burst_regs.emc_trpab;\n\t\tR2P_war = src_emc_entry->burst_regs.emc_r2p;\n\t\tRP_war = src_emc_entry->burst_regs.emc_rp;\n\t}\n\telse\n\t{\n\t\tR2P_war = tRTM - src_emc_entry->burst_regs.emc_rp;\n\t\tTRPab_war = src_emc_entry->burst_regs.emc_trpab;\n\t\tRP_war = src_emc_entry->burst_regs.emc_rp;\n\t\tif (R2P_war > 63)\n\t\t{\n\t\t\tRP_war = tRTM - 63;\n\t\t\tR2P_war = 63;\n\t\t\tif (src_emc_entry->burst_regs.emc_trpab < tRTM - 63)\n\t\t\t\tTRPab_war = tRTM - 63;\n\t\t\telse\n\t\t\t\tTRPab_war = src_emc_entry->burst_regs.emc_trpab;\n\t\t}\n\t}\n\n\tif (RP_war >= deltaTWATM)\n\t\tW2P_war = src_emc_entry->burst_regs.emc_w2p;\n\telse\n\t{\n\t\tu32 W2P_war_temp = deltaTWATM + src_emc_entry->burst_regs.emc_w2p;\n\t\tW2P_war = W2P_war_temp - RP_war;\n\t\tif (W2P_war > 63)\n\t\t{\n\t\t\tRP_war = W2P_war_temp - 63;\n\t\t\tW2P_war = 63;\n\t\t\tif (TRPab_war < RP_war)\n\t\t\t\tTRPab_war = RP_war;\n\t\t}\n\t}\n\n\tif (src_emc_entry->burst_regs.emc_w2p   != W2P_war ||\n\t\tsrc_emc_entry->burst_regs.emc_rp    != RP_war  ||\n\t\tsrc_emc_entry->burst_regs.emc_r2p   != R2P_war ||\n\t\tsrc_emc_entry->burst_regs.emc_trpab != TRPab_war)\n\t{\n\t\tEMC(EMC_DBG) = emc_dbg_o | EMC_DBG_WRITE_MUX_ACTIVE;\n\t\tEMC(EMC_RP)    = RP_war;\n\t\tEMC(EMC_R2P)   = R2P_war;\n\t\tEMC(EMC_W2P)   = W2P_war;\n\t\tEMC(EMC_TRPAB) = TRPab_war;\n\t\tEMC(EMC_DBG) = emc_dbg_o;\n\t\t(void)EMC(EMC_TRPAB);\n\t\t_usleep(1);\n\t}\n\n\t// Step 7.2 - Program FSP reference registers and send MRWs to new FSPWR.\n\tEPRINTF(\"Step 7.2\");\n\tif (enable_fsp_opwr)\n\t{\n\t\tmr13_flip_fspop = dst_emc_entry->emc_mrw3 | 0xC0;\n\t\tmr13_flip_fspwr = (dst_emc_entry->emc_mrw3 & 0xFFFFFF3F) | 0x40;\n\t}\n\telse\n\t{\n\t\tmr13_flip_fspop = dst_emc_entry->emc_mrw3 & 0xFFFFFF3F;\n\t\tmr13_flip_fspwr = mr13_flip_fspop | 0x80;\n\t}\n\n\tif (dram_dev_num == TWO_RANK)\n\t{\n\t\tif (needs_swap_rank_training)\n\t\t\tmr13_catr_enable = (mr13_flip_fspwr & 0x3FFFFFFF) | 0x40000001;\n\t\telse\n\t\t\tmr13_catr_enable = (mr13_flip_fspwr & 0x3FFFFFFF) | 0x80000001;\n\n\t\tif (needs_ca_combo_training)\n\t\t{\n\t\t\tif (needs_swap_rank_training)\n\t\t\t\tmr13_flip_fspop = (mr13_flip_fspop & 0x3FFFFFFF) | 0x80000000;\n\t\t\telse\n\t\t\t\tmr13_flip_fspop = (mr13_flip_fspop & 0x3FFFFFFF) | 0x40000000;\n\t\t}\n\t}\n\telse\n\t\tmr13_catr_enable = mr13_flip_fspwr | 1;\n\n\tEMC(EMC_MRW3) = mr13_flip_fspwr;\n\tEMC(EMC_MRW)  = dst_emc_entry->emc_mrw;\n\tEMC(EMC_MRW2) = dst_emc_entry->emc_mrw2;\n\n\t// Step 8 - Program the shadow registers.\n\tEPRINTF(\"Step 8\");\n\t// Writing burst_regs.\n\tu32 reg_addr = 0;\n\tu32 reg_val  = 0;\n\tburst_regs_table_t *dst_burst_regs = (burst_regs_table_t *)&dst_emc_entry->burst_regs;\n\tu32 *burst_val_table = dst_burst_regs->burst_regs;\n\n\tif (in_training)\n\t{\n\t\tif (needs_ca_combo_training)\n\t\t\tburst_val_table = dst_burst_regs->shadow_regs_ca_train;\n\t\telse if (needs_training & NEEDS_TRAINING_QUSE_COMBO)\n\t\t\tburst_val_table = dst_burst_regs->shadow_regs_quse_train;\n\t\telse if (needs_training & (NEEDS_TRAINING_WR_COMBO | NEEDS_TRAINING_RD_COMBO))\n\t\t\tburst_val_table = dst_burst_regs->shadow_regs_rdwr_train;\n\t\telse\n\t\t\tburst_val_table = NULL;\n\t}\n\n\tfor (u32 i = 0; burst_val_table && i < dst_emc_entry->num_burst; i++)\n\t{\n\t\treg_addr = burst_regs_emc_addr_table[i];\n\t\treg_val  = burst_val_table[i];\n\n\t\tswitch (reg_addr)\n\t\t{\n\t\tcase EMC_CFG:\n\t\t\treg_val &= 0xFFFFFFF;\n\t\t\tbreak;\n\t\tcase EMC_ZCAL_INTERVAL:\n\t\t\treg_val = 0;\n\t\t\tbreak;\n\t\tcase EMC_PMACRO_BRICK_CTRL_RFU1:\n\t\t\treg_val &= 0xF800F800;\n\t\t\tbreak;\n\t\tcase EMC_PMACRO_CMD_PAD_TX_CTRL:\n\t\t\treg_val = (reg_val & 0xFAFEFDFD) | BIT(26); // CMD_CMD_TX_DRVFORCEON.\n\t\t\tbreak;\n\t\tcase EMC_PMACRO_DATA_PAD_TX_CTRL:\n\t\t\treg_val &= 0xFEFEFDFD;\n\t\t\tbreak;\n\t\tcase EMC_PMACRO_COMMON_PAD_TX_CTRL:\n\t\t\treg_val &= 0xFFFFFFF0;\n\t\t\tbreak;\n\t\tcase EMC_PMACRO_AUTOCAL_CFG_COMMON:\n\t\t\treg_val |= BIT(16); // E_CAL_BYPASS_DVFS.\n\t\t\tbreak;\n\t\tcase EMC_TRAINING_CTRL:\n\t\t\treg_val |= needs_swap_rank_training << 14;\n\t\t\tbreak;\n\t\t}\n\n\t\tEMC(reg_addr) = reg_val;\n\t}\n\n\tif (in_training)\n\t\tEMC(EMC_MRW) = (src_emc_entry->run_clocks & 0xFF) | 0x170000;\n\telse\n\t\tEMC(EMC_MRW) = (dst_emc_entry->run_clocks & 0xFF) | 0x170000;\n\n\t// Writing burst_regs_per_ch.\n\tfor (u32 i = 0; dst_emc_entry->num_burst_per_ch > i; i++)\n\t{\n\t\treg_addr = burst_reg_per_ch_emc01_addr_table[i];\n\t\tif (reg_addr && (channel1_enabled || ((reg_addr - 0x4000) > 0xFFF)))\n\t\t{\n\t\t\tEMC(reg_addr) = dst_burst_regs->burst_reg_per_ch[i];\n\t\t}\n\t}\n\n\t// Writing vref_regs.\n\ttrim_regs_table_t *trim_regs_table = (trim_regs_table_t *)&dst_emc_entry->trim_regs;\n\tfor (u32 i = 0; dst_emc_entry->vref_num > i; i++)\n\t{\n\t\treg_addr = vref_perch_regs_emc01_addr_table[i];\n\t\tif (reg_addr && (channel1_enabled || (reg_addr - 0x4000) > 0xFFF))\n\t\t\tEMC(reg_addr) = trim_regs_table->vref_perch_regs[i];\n\t}\n\n\t// Writing training mod regs.\n\tif (in_training)\n\t{\n\t\tfor (u32 i = 0; dst_emc_entry->training_mod_num > i; i++)\n\t\t{\n\t\t\treg_addr = training_mod_regs_emc01_addr_table[i];\n\t\t\tif (reg_addr && (channel1_enabled || (reg_addr - 0x4000) > 0xFFF))\n\t\t\t\tEMC(reg_addr) = dst_emc_entry->training_mod_regs[i];\n\t\t}\n\t}\n\n\t// Writing trim_regs\n\tfor (u32 i = 0; dst_emc_entry->num_trim > i; i++)\n\t{\n\t\treg_addr = trim_regs_emc_addr_table[i];\n\t\tif (reg_addr)\n\t\t{\n\t\t\tif (((reg_addr & 0xFFFFFFF0) == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0 ||\n\t\t\t\t (reg_addr & 0xFFFFFFF0) == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0 ||\n\t\t\t\t (reg_addr & 0xFFFFFFF8) == EMC_DATA_BRLSHFT_0)\n\t\t\t\t&& compensate_trimmer_applicable)\n\t\t\t{\n\t\t\t\tEMC(reg_addr) = _minerva_apply_periodic_compensation_trimmer(dst_emc_entry, reg_addr);\n\t\t\t}\n\t\t\telse\n\t\t\t\tEMC(reg_addr) = trim_regs_table->trim_regs[i];\n\t\t}\n\t}\n\n\t// Writing trim_regs_per_ch\n\tfor (u32 i = 0; dst_emc_entry->num_trim_per_ch > i; i++)\n\t{\n\t\treg_addr = trim_perch_regs_emc01_addr_table[i];\n\t\tif (reg_addr && (channel1_enabled || (reg_addr - 0x4000) > 0xFFF))\n\t\t{\n\t\t\tif (((reg_addr & 0xFFFFFFF8) == EMC0_DATA_BRLSHFT_0 ||\n\t\t\t\t (reg_addr & 0xFFFFFFF8) == EMC1_DATA_BRLSHFT_0)\n\t\t\t\t&& compensate_trimmer_applicable)\n\t\t\t{\n\t\t\t\tEMC(reg_addr) = _minerva_apply_periodic_compensation_trimmer(dst_emc_entry, reg_addr & 0xFFF);\n\t\t\t}\n\t\t\telse\n\t\t\t\tEMC(reg_addr) = trim_regs_table->trim_perch_regs[i];\n\t\t}\n\t}\n\n\tif (in_training)\n\t{\n\t\t// Check delta wrt previous values (save value if margin exceeds what is set in table).\n\t\tif (needs_wr_training && dst_emc_entry->periodic_training)\n\t\t\t_minerva_periodic_compensation_handler(src_emc_entry, dst_emc_entry, dram_dev_num, channel1_enabled, WRITE_TRAINING_SEQUENCE);\n\t}\n\telse\n\t{\n\t\t// Writing burst_mc_regs.\n\t\tfor (u32 i = 0; dst_emc_entry->num_mc_regs > i; i++)\n\t\t\tMC(burst_mc_regs_addr_table[i]) = dst_emc_entry->burst_mc_regs[i];\n\n\t\t// Writing la_scale_regs.\n\t\tif (dst_emc_entry->rate_khz < src_emc_entry->rate_khz)\n\t\t{\n\t\t\tfor (u32 i = 0; dst_emc_entry->num_up_down > i; i++)\n\t\t\t\tMC(la_scale_regs_mc_addr_table[i]) = dst_emc_entry->la_scale_regs[i];\n\t\t}\n\t}\n\n\t// Step 9 - LPDDR4.\n\tEPRINTF(\"Step 9\");\n\tEMC(EMC_ZCAL_INTERVAL) = src_emc_entry->burst_regs.emc_zcal_interval & 0xFF000000;\n\tEMC(EMC_ZCAL_WAIT_CNT) = dst_emc_entry->burst_regs.emc_zcal_wait_cnt & 0xFFFFF800;\n\tEMC(EMC_DBG) = emc_dbg_o | EMC_DBG_WRITE_ACTIVE_ONLY | EMC_DBG_WRITE_MUX_ACTIVE;\n\tEMC(EMC_ZCAL_INTERVAL) = src_emc_entry->burst_regs.emc_zcal_interval & 0xFF000000;\n\tEMC(EMC_DBG) = emc_dbg_o;\n\n\tif (in_training)\n\t{\n\t\tEMC(EMC_DBG) = emc_dbg_o | EMC_DBG_WRITE_MUX_ACTIVE;\n\t\tEMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = dst_emc_entry->burst_regs.emc_pmacro_autocal_cfg_common | 0x10000;\n\n\t\tif (needs_ca_combo_training)\n\t\t\tEMC(EMC_FBIO_CFG5) = src_emc_entry->burst_regs.emc_fbio_cfg5 | 0x8000000;\n\n\t\tEMC(EMC_DBG) = emc_dbg_o;\n\n\t\tif (channel1_enabled)\n\t\t\t_ccfifo_write(EMC_CFG_SYNC, 0, 0);\n\n\t\t_ccfifo_write(EMC_DBG, (emc_dbg_o & ~EMC_DBG_CFG_SWAP_MASK) | EMC_DBG_CFG_SWAP_SWAP, 0);\n\t}\n\n\t// Step 10 - Self refresh\n\tEPRINTF(\"Step 10\");\n\t_ccfifo_write(EMC_SELF_REF, 0x101, 0);\n\n\tif (!needs_ca_combo_training && (dst_clock_period <= 2000))\n\t{\n\t\t_ccfifo_write(EMC_MRW3, mr13_flip_fspwr ^ 0x40, 0);\n\t\t_ccfifo_write(EMC_MRW6,  (src_emc_entry->burst_regs.emc_mrw6  & 0xC0C0) | (dst_emc_entry->burst_regs.emc_mrw6  & 0xFFFF3F3F), 0);\n\t\t_ccfifo_write(EMC_MRW14, (src_emc_entry->burst_regs.emc_mrw14 & 0x3838) | (dst_emc_entry->burst_regs.emc_mrw14 & 0xFFFF0707), 0);\n\t\tif (dram_dev_num == TWO_RANK)\n\t\t{\n\t\t\t_ccfifo_write(EMC_MRW7,  (src_emc_entry->burst_regs.emc_mrw7  & 0xC0C0) | (dst_emc_entry->burst_regs.emc_mrw7  & 0xFFFF3F3F), 0);\n\t\t\t_ccfifo_write(EMC_MRW15, (src_emc_entry->burst_regs.emc_mrw15 & 0x3838) | (dst_emc_entry->burst_regs.emc_mrw15 & 0xFFFF0707), 0);\n\t\t}\n\n\t\tif (dram_dev_num == ONE_RANK || zcal_resistor_shared)\n\t\t\temc_zq_cal = 0x80000001;\n\t\telse\n\t\t\temc_zq_cal = 1;\n\n\t\t_ccfifo_write(EMC_ZQ_CAL, emc_zq_cal, 0);\n\t}\n\n\temc_dbg_val = emc_dbg_o;\n\tu32 tRP_src_timing = (src_emc_entry->dram_timings.t_rp * 1000) / src_clock_period;\n\tu32 ref_delay = 0;\n\n\tif (in_training)\n\t{\n\t\temc_dbg_val = (emc_dbg_o & ~EMC_DBG_CFG_SWAP_MASK) | EMC_DBG_WRITE_ACTIVE_ONLY | EMC_DBG_CFG_SWAP_SWAP;\n\t\t_ccfifo_write(EMC_DBG, emc_dbg_val, 0);\n\t}\n\n\tif (needs_ca_combo_training)\n\t{\n\t\t_ccfifo_write(EMC_PMACRO_DATA_RX_TERM_MODE, src_emc_entry->burst_regs.emc_pmacro_data_rx_term_mode & 0xFFFFFCCC, 0);\n\n\t\tif (dram_dev_num == TWO_RANK && needs_swap_rank_training)\n\t\t{\n\t\t\t_ccfifo_write(EMC_MRW3, mr13_flip_fspop | 8, tRP_src_timing);\n\t\t\t_ccfifo_write(EMC_MRW3, mr13_catr_enable | 8, 0);\n\t\t}\n\t\telse\n\t\t\t_ccfifo_write(EMC_MRW3, mr13_catr_enable | 8, tRP_src_timing);\n\n\t\t_ccfifo_write(EMC_TR_CTRL_0, 0x15A, 0);\n\t\tref_delay = 1000000 / src_clock_period;\n\t}\n\telse\n\t{\n\t\t_ccfifo_write(EMC_MRW3, mr13_flip_fspop | 8, tRP_src_timing);\n\t\tref_delay = tFC_lpddr4 / src_clock_period;\n\t}\n\n\t_ccfifo_write(EMC_INTSTATUS, 0, ref_delay);\n\t_ccfifo_write(EMC_PIN, emc_pin_o & 0xFFFFFFF8, 30);\n\n\t// Step 11 - Ramp down.\n\tEPRINTF(\"Step 11\");\n\t_ccfifo_write(EMC_CFG_SYNC, 0, 0);\n\t_ccfifo_write(EMC_DBG, emc_dbg_val | EMC_DBG_WRITE_ACTIVE_ONLY | EMC_DBG_WRITE_MUX_ACTIVE, 0); // WRITE_MUX_ACTIVE | WRITE_ACTIVE_ONLY\n\n\tramp_down_wait = _dvfs_power_ramp_down(false, src_emc_entry, dst_emc_entry, src_clock_period);\n\n\t// Step 12 - Trigger clock change.\n\tEPRINTF(\"Step 12\");\n\t_ccfifo_write(EMC_STALL_THEN_EXE_AFTER_CLKCHANGE, 1, 0);\n\tif (!in_training)\n\t\t_ccfifo_write(EMC_DBG, (emc_dbg_val & ~EMC_DBG_WRITE_ACTIVE_ONLY) | EMC_DBG_WRITE_MUX_ACTIVE, 0);\n\n\t// Step 13 - Ramp up.\n\tEPRINTF(\"Step 13\");\n\tramp_up_wait = _dvfs_power_ramp_up(false, src_emc_entry, dst_emc_entry, needs_training, dst_clock_period);\n\n\t_ccfifo_write(EMC_DBG, emc_dbg_val, 0);\n\n\t// Step 14 - Bringup CKE pins.\n\tEPRINTF(\"Step 14\");\n\tu32 emc_pin_val_final = 0;\n\tif (needs_ca_combo_training)\n\t{\n\t\temc_pin_val_final = emc_pin_o & 0xFFFFFFF8;\n\t\tif (dram_dev_num == TWO_RANK)\n\t\t{\n\t\t\tif (needs_swap_rank_training)\n\t\t\t\temc_pin_val_final |= 5;\n\t\t\telse\n\t\t\t\temc_pin_val_final |= 6;\n\t\t}\n\t}\n\telse if (dram_dev_num == TWO_RANK)\n\t\temc_pin_val_final = emc_pin_o | 7;\n\telse\n\t\temc_pin_val_final = (emc_pin_o & 0xFFFFFFF8) | 1;\n\n\t_ccfifo_write(EMC_PIN, emc_pin_val_final, 0);\n\n\t// Step 15 - Zqlatch.\n\tEPRINTF(\"Step 15\");\n\tif (!needs_ca_combo_training)\n\t{\n\t\ts32 zq_latch_dvfs_wait_time;\n\t\tu32 T_PDEX_timing = _div_o3(dst_emc_entry->dram_timings.t_pdex * 1000, dst_clock_period);\n\n\t\tif (dst_clock_period > 2000)\n\t\t\tzq_latch_dvfs_wait_time = (s32)tZQCAL_lpddr4_fc_adj - (s32)T_PDEX_timing;\n\t\telse\n\t\t\tzq_latch_dvfs_wait_time =\n\t\t\t\t(s32)tZQCAL_lpddr4_fc_adj - (ramp_up_wait + ramp_down_wait) / dst_clock_period;\n\n\t\tif (dram_dev_num == ONE_RANK)\n\t\t{\n\t\t\tif (dst_clock_period > 2000)\n\t\t\t\t_ccfifo_write(EMC_ZQ_CAL, 0x80000001, T_PDEX_timing);\n\n\t\t\tif (!in_training)\n\t\t\t\t_ccfifo_write(EMC_MRW3, (mr13_flip_fspop & 0xF3FFFFF7) | 0xC000000, T_PDEX_timing);\n\n\t\t\temc_zq_cal = 0x80000002;\n\t\t}\n\t\telse if (zcal_resistor_shared)\n\t\t{\n\t\t\tif (dst_clock_period > 2000)\n\t\t\t\t_ccfifo_write(EMC_ZQ_CAL, 0x80000001, T_PDEX_timing);\n\n\t\t\ts32 T_PDEX_timing_final = zq_latch_dvfs_wait_time + (s32)T_PDEX_timing;\n\n\t\t\tif (T_PDEX_timing_final < 0)\n\t\t\t\tT_PDEX_timing_final = 0;\n\n\t\t\t_ccfifo_write(EMC_ZQ_CAL, 0x80000002, T_PDEX_timing_final);\n\t\t\t_ccfifo_write(EMC_ZQ_CAL, 0x40000001, 0);\n\n\t\t\tif (!in_training)\n\t\t\t\t_ccfifo_write(EMC_MRW3, (mr13_flip_fspop & 0xF3FFFFF7) | 0xC000000, 0);\n\n\t\t\temc_zq_cal = 0x40000002;\n\t\t\tzq_latch_dvfs_wait_time = 1000000 / dst_clock_period;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (dst_clock_period > 2000)\n\t\t\t\t_ccfifo_write(EMC_ZQ_CAL, 1, T_PDEX_timing);\n\n\t\t\tif (!in_training)\n\t\t\t\t_ccfifo_write(EMC_MRW3, (mr13_flip_fspop & 0xF3FFFFF7) | 0xC000000, T_PDEX_timing);\n\n\t\t\temc_zq_cal = 2;\n\t\t}\n\n\t\t// Disable self-refresh.\n\t\tif (!in_training)\n\t\t{\n\t\t\t_ccfifo_write(EMC_SELF_REF, 0, 0);\n\t\t\t_ccfifo_write(EMC_REF,      0, 0);\n\t\t}\n\n\t\tif (zq_latch_dvfs_wait_time < 0)\n\t\t\tzq_latch_dvfs_wait_time = 0;\n\n\t\t_ccfifo_write(EMC_ZQ_CAL, emc_zq_cal, (u32)zq_latch_dvfs_wait_time);\n\t}\n\n\t_ccfifo_write(EMC_INTSTATUS, 0, 10); // WAR: delay for zqlatch.\n\n\t// Step 16 - LPDDR4 Conditional training kickoff.\n\tEPRINTF(\"Step 16\");\n\tif (in_training)\n\t{\n\t\t_ccfifo_write(EMC_INTSTATUS, 0, 1020000 / dst_clock_period);\n\n\t\tu32 training_command = 0;\n\n\t\tif (needs_ca_training)\n\t\t\ttraining_command |= BIT(1);  // CA: Initiates CA Training.\n\t\tif (needs_ca_vref_training)\n\t\t\ttraining_command |= BIT(5);  // CA_VREF: Initiates CA_VREF Training.\n\t\tif (needs_quse_training)\n\t\t\ttraining_command |= BIT(4);  // QUSE: Initiates QUSE Training.\n\t\tif (needs_quse_vref_training)\n\t\t\ttraining_command |= BIT(8);  // QUSE_VREF: Initiates DQS_VREF Training.\n\t\tif (needs_wr_training)\n\t\t\ttraining_command |= BIT(3);  // WR: Initiates WR Training.\n\t\tif (needs_wr_vref_training)\n\t\t\ttraining_command |= BIT(6);  // WR_VREF: Initiates OB (write) DRAM_VREF Training.\n\t\tif (needs_rd_training)\n\t\t\ttraining_command |= BIT(2);  // RD: Initiates RD Training.\n\t\tif (needs_rd_vref_training)\n\t\t\ttraining_command |= BIT(7);  // RD_VREF: Initiates IB_DQ_VREF Training.\n\t\ttraining_command     |= BIT(31); // GO: Start the Training.\n\n\t\t_ccfifo_write(EMC_TRAINING_CMD, training_command, 0);\n\n\t\tif (bg_regulator_mode_change)\n\t\t{\n\t\t\tif (enable_bg_regulator)\n\t\t\t\t_ccfifo_write(EMC_PMACRO_BG_BIAS_CTRL_0,\n\t\t\t\t\tsrc_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0 & 0xFFFFFFFE, 0);\n\t\t\telse\n\t\t\t\t_ccfifo_write(EMC_PMACRO_BG_BIAS_CTRL_0,\n\t\t\t\t\tsrc_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0 & 0xFFFFFFFB, 0);\n\t\t}\n\n\t\t_ccfifo_write(EMC_SWITCH_BACK_CTRL, 1, 0);\n\n\t\tif (!needs_ca_combo_training || needs_swap_rank_training)\n\t\t{\n\t\t\t_ccfifo_write(EMC_MRW3, mr13_flip_fspop ^ 0xC0, 0);\n\t\t\t_ccfifo_write(EMC_INTSTATUS, 0, 1000000 / dst_clock_period);\n\t\t}\n\n\t\t_ccfifo_write(EMC_PIN, emc_pin_o & 0xFFFFFFF8, 0);\n\t\t_ccfifo_write(EMC_CFG_SYNC, 0, 0);\n\t\t_ccfifo_write(EMC_DBG, emc_dbg_val | EMC_DBG_WRITE_ACTIVE_ONLY | EMC_DBG_WRITE_MUX_ACTIVE, 0);\n\n\t\t_dvfs_power_ramp_down(true, src_emc_entry, dst_emc_entry, dst_clock_period);\n\n\t\t_ccfifo_write(EMC_STALL_THEN_EXE_AFTER_CLKCHANGE, 1, 0);\n\t\t_ccfifo_write(EMC_DBG, (emc_dbg_val & ~EMC_DBG_WRITE_ACTIVE_ONLY) | EMC_DBG_WRITE_MUX_ACTIVE, 0);\n\n\t\t_dvfs_power_ramp_up(true, src_emc_entry, dst_emc_entry, needs_training, src_clock_period);\n\n\t\t_ccfifo_write(EMC_DBG, emc_dbg_val, 0);\n\n\t\tif (dram_dev_num == TWO_RANK)\n\t\t\t_ccfifo_write(EMC_PIN, emc_pin_o | 7, 0);\n\t\telse\n\t\t\t_ccfifo_write(EMC_PIN, (emc_pin_o & 0xFFFFFFF8) | 1, 0);\n\n\t\tif (needs_ca_combo_training)\n\t\t{\n\t\t\t_ccfifo_write(EMC_TR_CTRL_0, 0x4A, 200000 / src_clock_period);\n\t\t\t_ccfifo_write(EMC_TR_CTRL_0, 0x40, 1000000 / src_clock_period);\n\t\t\t_ccfifo_write(EMC_MRW3, mr13_catr_enable & 0xFFFFFFFE, 0);\n\t\t\t_ccfifo_write(EMC_INTSTATUS, 0, 1000000 / src_clock_period);\n\t\t\t_ccfifo_write(EMC_PMACRO_DATA_RX_TERM_MODE, src_emc_entry->burst_regs.emc_pmacro_data_rx_term_mode, 0);\n\t\t}\n\n\t\t_ccfifo_write(EMC_DBG, emc_dbg_o, 0);\n\n\t\t_ccfifo_write(EMC_ZQ_CAL, 0x80000001, 0);\n\t\t_ccfifo_write(EMC_ZQ_CAL, 0x80000002, 1000000 / src_clock_period);\n\n\t\tif ((!needs_ca_combo_training || needs_swap_rank_training) && dram_dev_num == TWO_RANK)\n\t\t{\n\n\t\t\t_ccfifo_write(EMC_ZQ_CAL, 0x40000001, 0);\n\t\t\t_ccfifo_write(EMC_ZQ_CAL, 0x40000002, 1000000 / src_clock_period);\n\t\t}\n\n\t\tif (!needs_ca_combo_training)\n\t\t\t_ccfifo_write(EMC_MRW3, (mr13_flip_fspop & 0xF3FFFFF7) ^ 0xC0000C0, 0);\n\n\t\t_ccfifo_write(EMC_SELF_REF, 0, 0);\n\t}\n\n\t// Step 19.2.\n\tEPRINTF(\"Step 19.2\");\n\tif (bg_regulator_mode_change)\n\t{\n\t\t_ccfifo_write(EMC_DBG, emc_dbg_o | EMC_DBG_WRITE_MUX_ACTIVE, 0);\n\n\t\tu32 bg_regulator_switch_complete_wait_clks = 0;\n\t\tif (in_training)\n\t\t{\n\t\t\tbg_regulator_switch_complete_wait_clks = 1250000 / src_clock_period;\n\t\t\t_ccfifo_write(EMC_PMACRO_BG_BIAS_CTRL_0,\n\t\t\t\tsrc_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0, bg_regulator_switch_complete_wait_clks);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (ramp_up_wait <= 1250000)\n\t\t\t\tbg_regulator_switch_complete_wait_clks = (1250000 - ramp_up_wait) / dst_clock_period;\n\t\t\t_ccfifo_write(EMC_PMACRO_BG_BIAS_CTRL_0,\n\t\t\t\tdst_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0, bg_regulator_switch_complete_wait_clks);\n\t\t}\n\n\t\t_ccfifo_write(EMC_DBG, emc_dbg_o, 0);\n\t}\n\n\t// Step 20 - Issue ref and optional QRST.\n\tEPRINTF(\"Step 20\");\n\tif (in_training)\n\t\t_ccfifo_write(EMC_REF, 0, 0);\n\n\t// Step 21 - Restore ZCAL and ZCAL interval.\n\tEPRINTF(\"Step 21\");\n\t_ccfifo_write(EMC_DBG, emc_dbg_o | EMC_DBG_WRITE_MUX_ACTIVE, 0);\n\n\tif (in_training)\n\t\t_ccfifo_write(EMC_ZCAL_INTERVAL, src_emc_entry->burst_regs.emc_zcal_interval, 0);\n\n\t_ccfifo_write(EMC_CFG, dst_emc_entry->burst_regs.emc_cfg & 0xEFFFFFFF, 0);\n\n\t// Step 22 - Restore EMC_CFG_PIPE_CLK.\n\tEPRINTF(\"Step 22\");\n\t//if (in_training && dram_type == DRAM_TYPE_LPDDR4)////////////////\n\tif (in_training)\n\t\t_ccfifo_write(EMC_SEL_DPD_CTRL, src_emc_entry->emc_sel_dpd_ctrl, 0);\n\n\t_ccfifo_write(EMC_DBG, emc_dbg_o, 0);\n\t_ccfifo_write(EMC_CFG_PIPE_CLK, emc_cfg_pipe_clk_o, 0);\n\n\tif (bg_regulator_mode_change)\n\t{\n\t\tif (enable_bg_regulator)\n\t\t\tEMC(EMC_PMACRO_BG_BIAS_CTRL_0) = dst_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0 & 0xFFFFFFFB;\n\t\telse\n\t\t\tEMC(EMC_PMACRO_BG_BIAS_CTRL_0) = dst_emc_entry->burst_regs.emc_pmacro_bg_bias_ctrl_0 & 0xFFFFFFFE;\n\t}\n\n\t// Step 23 - Clock Change.\n\tEPRINTF(\"Step 23 - Clock Change\");\n\t// During training save current clock.\n\tif (in_training)\n\t{\n\t\tu32 emc_clk_src = CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC);\n\t\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_SAFE) = emc_clk_src;\n\t\t_change_dll_src(src_emc_entry, emc_clk_src);\n\t}\n\n\t// Set CFG_DLL_MODE to RUN_PERIODIC.\n\tEMC(EMC_CFG_DIG_DLL) = (EMC(EMC_CFG_DIG_DLL) & 0xFFFFFF24) | 0x88;\n\t(void)EMC(EMC_CFG_DIG_DLL);\n\n\t(void)EMC(EMC_FBIO_CFG7);\n\t(void)MC(MC_EMEM_ADR_CFG);\n\t(void)EMC(EMC_INTSTATUS);\n\n\t// Do clock change.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = selected_clk_src_emc;\n\t(void)CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC);\n\n\tif (_wait_emc_status(EMC_INTSTATUS, CLKCHANGE_COMPLETE_INT, true, 0))\n\t\treturn 4; // Clkchange handshake timeout error.\n\n\t// Step 24 - Save training results.\n\tEPRINTF(\"Step 24\");\n\tif (in_training)\n\t{\n\t\t(void)MC(MC_EMEM_ADR_CFG);\n\t\temc_dbg_val = EMC(EMC_DBG);\n\t\tEMC(EMC_DBG) |= EMC_DBG_READ_MUX_ASSEMBLY;\n\n\t\t_save_train_results(dst_emc_entry, needs_training, dram_dev_num, channel1_enabled);\n\n\t\tEMC(EMC_DBG) = emc_dbg_val;\n\t}\n\n\t// Step 25 - Program MC updown regs.\n\tEPRINTF(\"Step 25\");\n\tif (!in_training && (dst_emc_entry->rate_khz > src_emc_entry->rate_khz))\n\t{\n\t\tfor (u32 i = 0; dst_emc_entry->num_up_down > i; i++)\n\t\t\tMC(la_scale_regs_mc_addr_table[i]) = dst_emc_entry->la_scale_regs[i];\n\n\t\tbool dual_channel = (EMC(EMC_FBIO_CFG7) >> 1) & ((EMC(EMC_FBIO_CFG7) >> 2) & 1);\n\t\tif (_timing_update(dual_channel))\n\t\t\treturn 4;\n\t}\n\n\t// Step 26 - Restore ZCAL regs.\n\tEPRINTF(\"Step 26\");\n\tEMC(EMC_DBG) = emc_dbg_o | EMC_DBG_WRITE_MUX_ACTIVE;\n\tEMC(EMC_ZCAL_WAIT_CNT) = dst_emc_entry->burst_regs.emc_zcal_wait_cnt;\n\tEMC(EMC_ZCAL_INTERVAL) = dst_emc_entry->burst_regs.emc_zcal_interval;\n\tEMC(EMC_DBG) = emc_dbg_o;\n\n\t// Step 27 - Restore EMC_CFG, FDPD regs.\n\tEPRINTF(\"Step 27\");\n\tEMC(EMC_DBG) = emc_dbg_o | EMC_DBG_WRITE_MUX_ACTIVE;\n\tEMC(EMC_CFG) = dst_emc_entry->burst_regs.emc_cfg;\n\tEMC(EMC_DBG) = emc_dbg_o;\n\tEMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = dst_emc_entry->emc_fdpd_ctrl_cmd_no_ramp;\n\tEMC(EMC_SEL_DPD_CTRL) = dst_emc_entry->emc_sel_dpd_ctrl;\n\n\t// Step 28 - Training recover.\n\tEPRINTF(\"Step 28\");\n\tif (in_training)\n\t{\n\t\tEMC(EMC_DBG) = emc_dbg_o | EMC_DBG_WRITE_MUX_ACTIVE;\n\t\tEMC(EMC_CFG)              = dst_emc_entry->burst_regs.emc_cfg;\n\t\tEMC(EMC_SEL_DPD_CTRL)     = dst_emc_entry->emc_sel_dpd_ctrl;\n\t\tEMC(EMC_ZCAL_WAIT_CNT)    = src_emc_entry->burst_regs.emc_zcal_wait_cnt;\n\t\tEMC(EMC_ZCAL_INTERVAL)    = src_emc_entry->burst_regs.emc_zcal_interval;\n\t\tEMC(EMC_AUTO_CAL_CONFIG2) = src_emc_entry->emc_auto_cal_config2;\n\t\tEMC(EMC_AUTO_CAL_CONFIG3) = src_emc_entry->emc_auto_cal_config3;\n\t\tEMC(EMC_AUTO_CAL_CONFIG4) = src_emc_entry->emc_auto_cal_config4;\n\t\tEMC(EMC_AUTO_CAL_CONFIG5) = src_emc_entry->emc_auto_cal_config5;\n\t\tEMC(EMC_AUTO_CAL_CONFIG6) = src_emc_entry->emc_auto_cal_config6;\n\t\tEMC(EMC_AUTO_CAL_CONFIG7) = src_emc_entry->emc_auto_cal_config7;\n\t\tEMC(EMC_AUTO_CAL_CONFIG8) = src_emc_entry->emc_auto_cal_config8;\n\t\tEMC(EMC_DBG) = emc_dbg_o;\n\t\tEMC(EMC_TR_DVFS) = dst_emc_entry->burst_regs.emc_tr_dvfs & 0xFFFFFFFE;\n\t}\n\n\tEMC(EMC_DBG) = emc_dbg_o | EMC_DBG_WRITE_MUX_ACTIVE;\n\tEMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = dst_emc_entry->burst_regs.emc_pmacro_autocal_cfg_common;\n\tEMC(EMC_DBG) = emc_dbg_o;\n\n\t// Step 29 - Power fix WAR.\n\tEPRINTF(\"Step 29\");\n\tEMC(EMC_PMACRO_CFG_PM_GLOBAL_0) = 0xFF0000;\n\tEMC(EMC_PMACRO_TRAINING_CTRL_0) = CH0_TRAINING_E_WRPTR;\n\tEMC(EMC_PMACRO_TRAINING_CTRL_1) = CH0_TRAINING_E_WRPTR;\n\tEMC(EMC_PMACRO_CFG_PM_GLOBAL_0) = 0;\n\n\t// Step 30 - Re-enable autocal.\n\tEPRINTF(\"Step 30\");\n\tif (in_training)\n\t\tEMC(EMC_AUTO_CAL_CONFIG) = src_emc_entry->emc_auto_cal_config;\n\telse\n\t{\n\t\tif (dst_emc_entry->burst_regs.emc_cfg_dig_dll & 1)\n\t\t\t_digital_dll_enable_rs(channel1_enabled);\n\t\tEMC(EMC_AUTO_CAL_CONFIG) = dst_emc_entry->emc_auto_cal_config;\n\t}\n\n\treturn 0;\n}\n\nstatic void _minerva_train(emc_table_t *src_emc_entry, emc_table_t *dst_emc_entry, bool switch_rate, u32 selected_clk_src_emc)\n{\n\tu32 needs_training_num = 0;\n\tu32 emc_cfg_dig_dll_val = 0;\n\tu32 needs_training_emc_table[8] = {0};\n\n\tu32 needs_training = dst_emc_entry->needs_training;\n\n\t // Must start as true.\n\tif (train_ram_patterns)\n\t{\n\t\tu32 train_table_off = dst_emc_entry->training_pattern * 256;\n\t\tfor (u32 i = 0; i < 256; i++)\n\t\t{\n\t\t\tEMC(EMC_TRAINING_PATRAM_DQ) = ram_pattern_dq_table[train_table_off + i];\n\t\t\tEMC(EMC_TRAINING_PATRAM_DMI) = ram_pattern_dmi_table[train_table_off + i] & 0xF;\n\t\t\tEMC(EMC_TRAINING_PATRAM_CTRL) = 0x80000000 + i;\n\t\t}\n\t\ttrain_ram_patterns = false;\n\t}\n\n\tif (!dst_emc_entry->trained)\n\t{\n\t\tif (needs_training & NEEDS_TRAINING_CA_COMBO)\n\t\t{\n\t\t\tneeds_training_emc_table[needs_training_num++] =\n\t\t\t\tneeds_training & (NEEDS_TRAINING_CA_COMBO | NEEDS_TRAINING_IN_SELF_REFRESH);\n\t\t\tif (MC(MC_EMEM_ADR_CFG) & 1) // if mapping W8 (1KB page).\n\t\t\t\tneeds_training_emc_table[needs_training_num++] =\n\t\t\t\t\tneeds_training & (NEEDS_TRAINING_CA_COMBO | NEEDS_TRAINING_SWAP_RANK | NEEDS_TRAINING_IN_SELF_REFRESH);\n\t\t}\n\n\t\tif (needs_training & NEEDS_TRAINING_QUSE_COMBO)\n\t\t{\n\t\t\tneeds_training_emc_table[needs_training_num++] =\n\t\t\t\tneeds_training & (NEEDS_TRAINING_QUSE_COMBO | NEEDS_TRAINING_IN_SELF_REFRESH);\n\t\t\tif (MC(MC_EMEM_ADR_CFG) & 1)\n\t\t\t\tneeds_training_emc_table[needs_training_num++] =\n\t\t\t\t\tneeds_training & (NEEDS_TRAINING_QUSE | NEEDS_TRAINING_IN_SELF_REFRESH);\n\t\t}\n\n\t\tif (needs_training & (NEEDS_TRAINING_WR_COMBO | NEEDS_TRAINING_RD_COMBO))\n\t\t\tneeds_training_emc_table[needs_training_num++] =\n\t\t\t\tneeds_training & (NEEDS_TRAINING_WR_COMBO | NEEDS_TRAINING_RD_COMBO | NEEDS_TRAINING_IN_SELF_REFRESH);\n\n\t\tfor (u32 i = 0; needs_training_num > i; i++) // Runs more than once for needs_training CA/QUSE/WR/RD.\n\t\t{\n\t\t\t_minerva_change_clock(src_emc_entry, dst_emc_entry, needs_training_emc_table[i], selected_clk_src_emc);\n\n\t\t\tbool dual_channel = (EMC(EMC_FBIO_CFG7) >> 1) & ((EMC(EMC_FBIO_CFG7) >> 2) & 1);\n\n\t\t\tEMC(EMC_DBG) = (EMC(EMC_DBG) & ~EMC_DBG_CFG_SWAP_MASK) | EMC_DBG_CFG_SWAP_ASSEMBLY_ONLY;\n\t\t\tEMC(EMC_CFG_UPDATE) = (EMC(EMC_CFG_UPDATE) & 0xFFFFFFF9) | 4;\n\t\t\t_timing_update(dual_channel);\n\n\t\t\tEMC(EMC_CFG_UPDATE) &= 0xFFFFFFF9;\n\t\t\tEMC(EMC_DBG) &= ~EMC_DBG_CFG_SWAP_MASK; // EMC_DBG_CFG_SWAP_ACTIVE_ONLY.\n\t\t\tEMC(EMC_CFG_DIG_DLL) = (EMC(EMC_CFG_DIG_DLL) & 0xFFFFFF3E) | 0x80;\n\t\t\t_timing_update(dual_channel);\n\n\t\t\temc_cfg_dig_dll_val = EMC(EMC_CFG_DIG_DLL) & 0xFFFFFFFE;\n\t\t\tif (dst_emc_entry->burst_regs.emc_cfg_dig_dll == 1)\n\t\t\t\temc_cfg_dig_dll_val = EMC(EMC_CFG_DIG_DLL) | 1;\n\t\t\tEMC(EMC_CFG_DIG_DLL) = (emc_cfg_dig_dll_val & 0xFFFFFF3F) | 0x80;\n\t\t\t_timing_update(dual_channel);\n\n\t\t\twhile (!(EMC(EMC_DIG_DLL_STATUS) & 0x8000))\n\t\t\t\t;\n\n\t\t\t// Bug 200024907.\n\t\t\tEMC(EMC_RP) = src_emc_entry->burst_regs.emc_rp;\n\t\t\tEMC(EMC_R2P) = src_emc_entry->burst_regs.emc_r2p;\n\t\t\tEMC(EMC_W2P) = src_emc_entry->burst_regs.emc_w2p;\n\t\t\tEMC(EMC_TRPAB) = src_emc_entry->burst_regs.emc_trpab;\n\n\t\t\t_timing_update(dual_channel);\n\t\t}\n\n\t\tEPRINTF(\"Trained\");\n\t\tdst_emc_entry->trained = 1;\n\t}\n\n\tif (switch_rate)\n\t\t_minerva_change_clock(src_emc_entry, dst_emc_entry, 0, selected_clk_src_emc);\n}\n\nvoid _minerva_do_over_temp_compensation(mtc_config_t *mtc_cfg)\n{\n\tif (!mtc_cfg->current_emc_table)\n\t\treturn;\n\n\tu32 dram_type = EMC(EMC_FBIO_CFG5) & 3;\n\n\t// Only LPDDR chips are supported.\n\tif (dram_type != DRAM_TYPE_LPDDR4)\n\t\treturn;\n\n\ts32 dram_temp = _get_dram_temperature();\n\n\tif (dram_temp < 0 || mtc_cfg->prev_temp == (u32)dram_temp)\n\t\treturn;\n\n\tu32 refr = mtc_cfg->current_emc_table->burst_regs.emc_refresh;\n\tu32 pre_refr = mtc_cfg->current_emc_table->burst_regs.emc_pre_refresh_req_cnt;\n\tu32 dyn_self_ref = mtc_cfg->current_emc_table->burst_regs.emc_dyn_self_ref_control;\n\n\tswitch (dram_temp)\n\t{\n\t// Normal temp (<= 85 oC).\n\tcase 0:\n\tcase 1:\n\tcase 2:\n\tcase 3:\n\t\tif (mtc_cfg->prev_temp < 4)\n\t\t{\n\t\t\tmtc_cfg->prev_temp = (u32)dram_temp;\n\t\t\treturn;\n\t\t}\n\t\tbreak;\n\t// Over temp (> 85 oC).\n\tcase 4: // 2x refresh.\n\t\trefr = (refr & 0xFFFF0000) | ((refr & 0xFFFF) >> REFRESH_X2);\n\t\tpre_refr = (pre_refr & 0xFFFF0000) | ((pre_refr & 0xFFFF) >> REFRESH_X2);\n\t\tdyn_self_ref = (dyn_self_ref & 0xFFFF0000) | ((dyn_self_ref & 0xFFFF) >> REFRESH_X2);\n\t\tbreak;\n\tcase 5: // 4x refresh.\n\tcase 6: // Temp 6 normally needs a derating emc table.\n\t\trefr = (refr & 0xFFFF0000) | ((refr & 0xFFFF) >> REFRESH_X4);\n\t\tpre_refr = (pre_refr & 0xFFFF0000) | ((pre_refr & 0xFFFF) >> REFRESH_X4);\n\t\tdyn_self_ref = (dyn_self_ref & 0xFFFF0000) | ((dyn_self_ref & 0xFFFF) >> REFRESH_X4);\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\tmtc_cfg->prev_temp = dram_temp;\n\n\tEMC(EMC_REFRESH) = refr;\n\tEMC(EMC_PRE_REFRESH_REQ_CNT) = pre_refr;\n\tEMC(EMC_DYN_SELF_REF_CONTROL) = dyn_self_ref;\n}\n\nu32 _minerva_do_periodic_compensation(emc_table_t *mtc_table_entry)\n{\n\tif (mtc_table_entry && mtc_table_entry->periodic_training)\n\t{\n\t\tu32  dram_dev_num = (MC(MC_EMEM_ADR_CFG) & 1) + 1;\n\t\tu32  pd_mask = (dram_dev_num == TWO_RANK) ? IN_POWERDOWN_BOTH_MASK : IN_POWERDOWN_1DEV_MASK;\n\t\tbool channel1_enabled = (mtc_table_entry->burst_regs.emc_fbio_cfg7 >> 2) & 1;\n\n\t\t(void)EMC(EMC_DBG);\n\n\t\t// Safekeep current config.\n\t\tu32 emc_cfg_o = EMC(EMC_CFG);\n\t\tu32 emc_cfg_dig_dll_o = EMC(EMC_CFG_DIG_DLL);\n\t\tu32 emc_cfg_update_o = EMC(EMC_CFG_UPDATE);\n\n\t\t// Step 1 - Disable digital DLL.\n\t\tEMC(EMC_CFG_DIG_DLL) = emc_cfg_dig_dll_o & 0xFFFFFFFE;\n\n\t\t// Step 1.2 - Always update auto cal in clock change.\n\t\tEMC(EMC_CFG_UPDATE) = (emc_cfg_update_o & 0xFFFFF9FF) | 0x400;\n\n\t\t// Step 1.3 - Disable other power features.\n\t\tEMC(EMC_CFG) = emc_cfg_o & 0xFFFFFFF;\n\n\t\t// Timing update and wait for everything to power down.\n\t\t_timing_update(channel1_enabled);\n\n\t\t_wait_emc_status(EMC_EMC_STATUS, pd_mask, 0, EMC_CHANNEL0);\n\t\tif (channel1_enabled)\n\t\t\t_wait_emc_status(EMC_EMC_STATUS, pd_mask, 0, EMC_CHANNEL1);\n\n\t\t_wait_emc_status(EMC_EMC_STATUS, IN_SELF_REFRESH_MASK, 0, EMC_CHANNEL0);\n\t\tif (channel1_enabled)\n\t\t\t_wait_emc_status(EMC_EMC_STATUS, IN_SELF_REFRESH_MASK, 0, EMC_CHANNEL1);\n\n\t\t_wait_emc_status(EMC_CFG_DIG_DLL, 1, 0, EMC_CHANNEL0);\n\t\tif (channel1_enabled)\n\t\t\t_wait_emc_status(EMC_CFG_DIG_DLL, 1, 0, EMC_CHANNEL1);\n\n\t\t// Step 2 - Osc kick off - this assumes training and dvfs have set correct MR23.\n\t\t_start_periodic_compensation();\n\n\t\t// Step 3 - Let dram capture its clock tree delays.\n\t\t_usleep(1000 * _actual_osc_clocks(mtc_table_entry->run_clocks) / mtc_table_entry->rate_khz + 2);\n\n\t\t// Step 4 - Check delta wrt previous values (save value if margin exceeds what is set in table).\n\t\tu32 adelta = _minerva_update_clock_tree_delay(mtc_table_entry, mtc_table_entry, dram_dev_num, channel1_enabled, PERIODIC_TRAINING_UPDATE);\n\n\t\t// Step 5 - Apply compensation w.r.t. trained values (if clock tree has drifted more than the set margin).\n\t\tif (adelta && ((mtc_table_entry->rate_khz / 1000) * 128) * adelta / 1000000 > mtc_table_entry->tree_margin)\n\t\t{\n\t\t\tfor (u32 i = 0; i < 10; i++)\n\t\t\t{\n\t\t\t\tEMC(periodic_training_addr[i]) =\n\t\t\t\t\t_minerva_apply_periodic_compensation_trimmer(mtc_table_entry, periodic_training_addr[i]);\n\t\t\t}\n\t\t}\n\n\t\t// Step 6 - Restore other power features.\n\t\tEMC(EMC_CFG) = emc_cfg_o;\n\n\t\t// Step 6.1 - Restore the DLL.\n\t\tEMC(EMC_CFG_DIG_DLL) = emc_cfg_dig_dll_o;\n\n\t\t// Step 6.2 - Timing update for applying the new trimmers.\n\t\t_timing_update(channel1_enabled);\n\n\t\t// Step 6.3 - Restore the UPDATE_DLL_IN_UPDATE field.\n\t\tEMC(EMC_CFG_UPDATE) = emc_cfg_update_o;\n\t}\n\n\treturn 0;\n}\n\nstatic int _minerva_set_ir_boost(mtc_config_t *mtc_cfg)\n{\n\tswitch (mtc_cfg->train_mode)\n\t{\n\tcase OP_SWITCH:\n\t\tbreak;\n\tcase OP_TRAIN:\n\t\treturn 4;\n\tcase OP_TRAIN_SWITCH:\n\t\tbreak;\n\tdefault:\n\t\treturn 4;\n\t}\n\n\tEPRINTFARGS(\"Requested op %d from %d to %d.\", OP_SWITCH, src_rate_khz, dst_rate_khz);\n\n\tbool boost = mtc_cfg->rate_to > MTC_INIT_FREQUENCY;\n\n\tu32 clk_new     = (PLLP_OUT0 << 29u) | 0x188000 | (boost ? 0 : 2);\n\tu32 clk_cur     = CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC);\n\tu32 clk_cur_src = clk_cur >> 29u;\n\n\t// Already at requested clock.\n\tif (clk_new == clk_cur)\n\t{\n\t\tmtc_cfg->rate_from = mtc_cfg->rate_to;\n\t\treturn 0;\n\t}\n\n\tif (clk_cur_src != PLLP_OUT0)\n\t\treturn 3;\n\n\t// Clear clock change interrupt.\n\tEMC(EMC_INTSTATUS) = CLKCHANGE_COMPLETE_INT;\n\n\tu32 emc_dbg_o = EMC(EMC_DBG);\n\tu32 emc_dbg_c = emc_dbg_o & ~(EMC_DBG_WRITE_MUX_ACTIVE | EMC_DBG_READ_MUX_ASSEMBLY);\n\tEMC(EMC_DBG)  = emc_dbg_c;\n\t(void)EMC(EMC_DBG);\n\n\t// Save registers.\n\tu32 emc_cfg_o          = EMC(EMC_CFG);\n\tu32 emc_auto_cal_cfg_o = EMC(EMC_AUTO_CAL_CONFIG);\n\tu32 emc_sel_dpd_ctrl_o = EMC(EMC_SEL_DPD_CTRL);\n\tu32 emc_cfg_pipe_clk_o = EMC(EMC_CFG_PIPE_CLK);\n\tu32 emc_fdpd_ctl_cmd_o = EMC(EMC_FDPD_CTRL_CMD_NO_RAMP);\n\n\tEMC(EMC_DBG) = emc_dbg_c | EMC_DBG_WRITE_MUX_ACTIVE;\n\t(void)EMC(EMC_DBG);\n\n\t// Disable autocal.\n\tEMC(EMC_AUTO_CAL_CONFIG) = (emc_auto_cal_cfg_o & 0x7FFFF9FE) | 0x601;\n\t(void)EMC(EMC_AUTO_CAL_CONFIG);\n\n\t// Disable other power features.\n\tEMC(EMC_CFG)          = emc_cfg_o & 0xFFFFFFF;\n\tEMC(EMC_SEL_DPD_CTRL) = emc_sel_dpd_ctrl_o & 0xFFFFFEC3;\n\tEMC(EMC_CFG_PIPE_CLK) = emc_cfg_pipe_clk_o | BIT(0);\n\tEMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = emc_fdpd_ctl_cmd_o & ~BIT(0);\n\n\tEMC(EMC_DBG) = emc_dbg_c;\n\t(void)EMC(EMC_DBG);\n\t_usleep(5);\n\n\tif (boost)\n\t{\n\t\t// Program arbiter regs.\n\t\tMC(MC_EMEM_ARB_CFG)          = 0x1000003;\n\t\tMC(MC_EMEM_ARB_TIMING_RP)    = 1;\n\t\tMC(MC_EMEM_ARB_TIMING_RC)    = 6;\n\t\tMC(MC_EMEM_ARB_TIMING_RAS)   = 3;\n\t\tMC(MC_EMEM_ARB_TIMING_FAW)   = 4;\n\t\tMC(MC_EMEM_ARB_TIMING_RFCPB) = 0xE;\n\t\tMC(MC_EMEM_ARB_DA_COVERS)    = 0x30203;\n\t\tMC(MC_EMEM_ARB_MISC0)        = 0x71E30507;\n\n\t\t// Program base timings.\n\t\tEMC(EMC_RP)      = 8;\n\t\tEMC(EMC_TRPAB)   = 9;\n\t\tEMC(EMC_RC)      = 25;\n\t\tEMC(EMC_RAS)     = 18;\n\t\tEMC(EMC_R2W)     = 15;\n\t\tEMC(EMC_RD_RCD)  = 8;\n\t\tEMC(EMC_WR_RCD)  = 8;\n\t\tEMC(EMC_TFAW)    = 17; // 13 on 2133 MHz modules.\n\n\t\t// ZQ calibration.\n\t\tEMC(EMC_ZCAL_WAIT_CNT) = 0xE0198;\n\n\t\t// Set refresh timings.\n\t\tEMC(EMC_RFC)     = 115;\n\t\tEMC(EMC_RFCPB)   = 58;\n\t\tEMC(EMC_TREFBW)  = 0x18DD; // 0x638.\n\t\tEMC(EMC_REFRESH) = 0x181E; // 0x607.\n\t\tEMC(EMC_PRE_REFRESH_REQ_CNT) = 0x607; // 0x181.\n\t\tEMC(EMC_DYN_SELF_REF_CONTROL) = (EMC(EMC_DYN_SELF_REF_CONTROL) & 0xFFFF0000) | 0xD22;\n\t}\n\telse\n\t{\n\t\t// Program arbiter regs.\n\t\tMC(MC_EMEM_ARB_CFG)          = 0x8000001;\n\t\tMC(MC_EMEM_ARB_TIMING_RP)    = 0;\n\t\tMC(MC_EMEM_ARB_TIMING_RC)    = 3;\n\t\tMC(MC_EMEM_ARB_TIMING_RAS)   = 1;\n\t\tMC(MC_EMEM_ARB_TIMING_FAW)   = 2;\n\t\tMC(MC_EMEM_ARB_TIMING_RFCPB) = 7;\n\t\tMC(MC_EMEM_ARB_DA_COVERS)    = 0x30201;\n\t\tMC(MC_EMEM_ARB_MISC0)        = 0x72A30504;\n\n\t\t// Program base timings.\n\t\tEMC(EMC_RP)     = 4;\n\t\tEMC(EMC_TRPAB)  = 5;\n\t\tEMC(EMC_RC)     = 13;\n\t\tEMC(EMC_RAS)    = 9;\n\t\tEMC(EMC_R2W)    = 11;\n\t\tEMC(EMC_RD_RCD) = 6;\n\t\tEMC(EMC_WR_RCD) = 6;\n\t\tEMC(EMC_TFAW)   = 9; // 8 on 2133 MHz modules.\n\n\t\t// Program ZQ calibration.\n\t\tEMC(EMC_ZCAL_WAIT_CNT) = 0x900CC;\n\n\t\t// Program refresh timings.\n\t\tEMC(EMC_RFC)     = 58;\n\t\tEMC(EMC_RFCPB)   = 29;\n\t\tEMC(EMC_TREFBW)  = 0x31C;\n\t\tEMC(EMC_REFRESH) = 0x304;\n\t\tEMC(EMC_PRE_REFRESH_REQ_CNT) = 0xC1;\n\t\tEMC(EMC_DYN_SELF_REF_CONTROL) = (EMC(EMC_DYN_SELF_REF_CONTROL) & 0xFFFF0000) | 0x713;\n\t}\n\n\t// Restore power features and pipe clock.\n\tEMC(EMC_CFG) = emc_cfg_o & 0xEFFFFFFF;\n\tEMC(EMC_CFG_PIPE_CLK) = emc_cfg_pipe_clk_o;\n\tEMC(EMC_DBG) = emc_dbg_o;\n\t(void)EMC(EMC_DBG);\n\n\t// Do clock change.\n\tCLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = clk_new;\n\t(void)CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC);\n\n\t// Clock change handshake.\n\t_wait_emc_status(EMC_INTSTATUS, CLKCHANGE_COMPLETE_INT, true, 0);\n\n\t// Restore regs.\n\tEMC(EMC_CFG)             = emc_cfg_o;\n\tEMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = emc_fdpd_ctl_cmd_o;\n\tEMC(EMC_SEL_DPD_CTRL)    = emc_sel_dpd_ctrl_o;\n\tEMC(EMC_AUTO_CAL_CONFIG) = emc_auto_cal_cfg_o;\n\n\tEMC(EMC_TIMING_CONTROL) = 1;\n\n\t// Min 20us before next clock change.\n\t_usleep(20);\n\n\tmtc_cfg->rate_from = mtc_cfg->rate_to;\n\n\treturn 0;\n}\n\nstatic u32 _minerva_do_training_switch(mtc_config_t *mtc_cfg)\n{\n\tu32 src_emc_entry_idx = 100;\n\tu32 dst_emc_entry_idx = 100;\n\tu32 selected_clk_src_emc;\n\tu32 emc_clk_src;\n\tbool freq_changed = false;\n\tbool src_is_pllmb;\n\temc_table_t *src_emc_entry;\n\temc_table_t *dst_emc_entry;\n\n\tif (mtc_cfg->table_entries > 32)\n\t\treturn 4;\n\n\tif (mtc_cfg->mtc_table[0].rev == MTC_IRB_MAGIC)\n\t\treturn _minerva_set_ir_boost(mtc_cfg);\n\n\t// Find tables.\n\tfor (u32 i = 0; i < mtc_cfg->table_entries; i++)\n\t{\n\t\tu32 table_entry_rate = mtc_cfg->mtc_table[i].rate_khz;\n\t\tif (mtc_cfg->rate_from == table_entry_rate)\n\t\t\tsrc_emc_entry_idx = i;\n\t\tif (mtc_cfg->rate_to   == table_entry_rate)\n\t\t\tdst_emc_entry_idx = i;\n\t}\n\n\t// Check if tables were found.\n\tif (src_emc_entry_idx >= mtc_cfg->table_entries ||\n\t\tdst_emc_entry_idx >= mtc_cfg->table_entries)\n\t\treturn 4;\n\n\tsrc_emc_entry = (emc_table_t *)&mtc_cfg->mtc_table[src_emc_entry_idx];\n\tdst_emc_entry = (emc_table_t *)&mtc_cfg->mtc_table[dst_emc_entry_idx];\n\n\tu32 src_rate_khz = src_emc_entry->rate_khz;\n\tu32 dst_rate_khz = dst_emc_entry->rate_khz;\n\tu32 src_clk_src_emc = src_emc_entry->clk_src_emc;\n\tu32 dst_clk_src_emc = dst_emc_entry->clk_src_emc;\n\n\tfreq_changed = _check_freq_changed(dst_rate_khz, dst_clk_src_emc, src_rate_khz, src_clk_src_emc);\n\tEPRINTFARGS(\"Requested op %d from %d to %d.\", mtc_cfg->train_mode, src_rate_khz, dst_rate_khz);\n\n\t// Get current clock source.\n\temc_clk_src = CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) >> EMC_2X_CLK_SRC_SHIFT;\n\tsrc_is_pllmb = emc_clk_src == PLLMB_UD || emc_clk_src == PLLMB_OUT0;\n\n\tif (freq_changed)\n\t{\n\t\tif (emc_clk_src == PLLM_UD ||\n\t\t\temc_clk_src == PLLM_OUT0) // Clock source is PLLM. Switch based on src_is_pllmb.\n\t\t{\n\t\t\tsrc_is_pllmb = !src_is_pllmb;\n\t\t}\n\t\telse if (emc_clk_src == PLLMB_UD ||\n\t\t\t\t emc_clk_src == PLLMB_OUT0) // Clock source is PLLMB. Switch to PLLM.\n\t\t{\n\t\t\tsrc_is_pllmb = false;\n\t\t}\n\t\tselected_clk_src_emc = _pllm_clk_base_cfg(dst_rate_khz, dst_clk_src_emc, src_is_pllmb);\n\t}\n\telse\n\t{\n\t\tselected_clk_src_emc = dst_clk_src_emc;\n\t\temc_clk_src = selected_clk_src_emc >> EMC_2X_CLK_SRC_SHIFT;\n\t\tif (src_is_pllmb)\n\t\t{\n\t\t\tif (emc_clk_src == PLLM_UD || emc_clk_src == PLLMB_UD)\n\t\t\t\tselected_clk_src_emc = (selected_clk_src_emc & 0x1FFFFFFF) | (PLLMB_UD << EMC_2X_CLK_SRC_SHIFT);\n\t\t\telse if (emc_clk_src == PLLM_OUT0 || emc_clk_src == PLLMB_OUT0)\n\t\t\t\tselected_clk_src_emc = (selected_clk_src_emc & 0x1FFFFFFF) | (PLLMB_OUT0 << EMC_2X_CLK_SRC_SHIFT);\n\t\t}\n\t}\n\n\tswitch (mtc_cfg->train_mode)\n\t{\n\tcase OP_SWITCH:\n\t\t_minerva_change_clock(src_emc_entry, dst_emc_entry, 0, selected_clk_src_emc);\n\t\tmtc_cfg->current_emc_table = dst_emc_entry;\n\t\tmtc_cfg->rate_from = dst_emc_entry->rate_khz;\n\t\tif (dst_emc_entry->periodic_training)\n\t\t\t_minerva_do_periodic_compensation(dst_emc_entry);\n\t\treturn 0;\n\tcase OP_TRAIN:\n\t\t_minerva_train(src_emc_entry, dst_emc_entry, false, selected_clk_src_emc);\n\t\treturn 0;\n\tcase OP_TRAIN_SWITCH:\n\t\t_minerva_train(src_emc_entry, dst_emc_entry, true, selected_clk_src_emc);\n\t\tmtc_cfg->current_emc_table = dst_emc_entry;\n\t\tmtc_cfg->rate_from = dst_emc_entry->rate_khz;\n\t\tif (dst_emc_entry->periodic_training)\n\t\t\t_minerva_do_periodic_compensation(dst_emc_entry);\n\t\treturn 0;\n\tdefault:\n\t\treturn 4;\n\t}\n}\n\nstatic void _minerva_get_table(mtc_config_t *mtc_cfg)\n{\n\tu32 hidrev  = APB_MISC(APB_MISC_GP_HIDREV);\n\tu32 chip_id = (hidrev >> 8) & 0xFF;\n\tu32 major   = (hidrev >> 4) & 0xF;\n\n\t// Check that SoC is T210/T210B01.\n\tif (chip_id != HIDREV_CHIPID_T210)\n\t\tgoto error;\n\n\t// Check if SoC SKU is ODIN.\n\tif (FUSE(FUSE_SKU_INFO) != SKU_ODIN)\n\t\tgoto error;\n\n\t// Clear table storage.\n\tmemcpy(mtc_cfg->mtc_table, DVFS_T21X_CC_VERSION, sizeof(DVFS_T21X_CC_VERSION));\n\tmemcpy(mtc_cfg->mtc_table, DVFS_T210_CC_VERSION, sizeof(DVFS_T210_CC_VERSION));\n\tmemset(mtc_cfg->mtc_table, 0, EMC_TABLE_ENTRY_SIZE_R7 * 10);\n\n\t// Check if init rate boost mode.\n\tif (mtc_cfg->init_done == MTC_IRB_MAGIC)\n\t{\n\t\tmtc_cfg->mtc_table[0].rev = MTC_IRB_MAGIC;\n\t\tmtc_cfg->table_entries = 1; // Avoid OOB.\n\n\t\tgoto init_cfg;\n\t}\n\n\t// Check if ODINX02.\n\tif (major != HIDREV_MAJOR_T210)\n\t\tgoto error;\n\n\t// ODINX02 table: 204, 408, 666, 800, 1066, 1333, 1600 MHz.\n\tmtc_cfg->table_entries = EMC_TABLE_SIZE_ODINX02_R7 / EMC_TABLE_ENTRY_SIZE_R7;\n\n\tswitch (mtc_cfg->sdram_id)\n\t{\n\tcase DRAM_4GB_HYNIX_H9HCNNNBPUMLHR_NLN:\n\t\tmemcpy(mtc_cfg->mtc_table, odinx02_a2_2_10NoCfgVersion_V9_8_7_V1_6, EMC_TABLE_SIZE_ODINX02_R7);\n\t\tbreak;\n\tcase DRAM_8GB_SAMSUNG_K4FBE3D4HM_MGXX:\n\t\tmemcpy(mtc_cfg->mtc_table, odinx02_a2_7_10NoCfgVersion_V9_8_7_V1_6, EMC_TABLE_SIZE_ODINX02_R7);\n\t\tbreak;\n\tcase DRAM_4GB_SAMSUNG_K4F6E304HB_MGCH:\n\tcase DRAM_4GB_MICRON_MT53B512M32D2NP_062_WT:\n\tcase DRAM_4GB_COPPER_SAMSUNG:\n\tcase DRAM_6GB_SAMSUNG_K4FHE3D4HM_MFCH:\n\tdefault:\n\t\tmemcpy(mtc_cfg->mtc_table, odinx02_a2_0_3_10NoCfgVersion_V9_8_7_V1_6, EMC_TABLE_SIZE_ODINX02_R7);\n\t\tbreak;\n\t}\n\ninit_cfg:\n\tmtc_cfg->rate_to    = 0;\n\tmtc_cfg->rate_from  = 0;\n\tmtc_cfg->train_mode = -1;\n\tmtc_cfg->prev_temp  = 0;\n\tmtc_cfg->current_emc_table = NULL;\n\n\t// Important!\n\tmtc_cfg->train_ram_patterns = true;\n\tmtc_cfg->init_done = MTC_INIT_MAGIC;\n\n\treturn;\n\nerror:\n\tmtc_cfg->init_done = 0;\n\treturn;\n}\n\nvoid minerva_entry(mtc_config_t *mtc_cfg, bdk_params_t *bp)\n{\n\tEPRINTF(\"-- Minerva Training Cell --\");\n\n\ttrain_ram_patterns = mtc_cfg->train_ram_patterns;\n\n\tif (mtc_cfg->init_done != MTC_INIT_MAGIC)\n\t{\n\t\tif (mtc_cfg->init_done == MTC_NEW_MAGIC ||\n\t\t\tmtc_cfg->init_done == MTC_IRB_MAGIC)\n\t\t\t_minerva_get_table(mtc_cfg);\n\n\t\treturn;\n\t}\n\n\tswitch (mtc_cfg->train_mode)\n\t{\n\tcase OP_SWITCH:\n\t\tEPRINTF(\"Switching..\");\n\t\t_minerva_do_training_switch(mtc_cfg);\n\t\tbreak;\n\tcase OP_TRAIN:\n\t\tEPRINTF(\"Training..\");\n\t\t_minerva_do_training_switch(mtc_cfg);\n\t\tbreak;\n\tcase OP_TRAIN_SWITCH:\n\t\tEPRINTF(\"Training and switching..\");\n\t\t_minerva_do_training_switch(mtc_cfg);\n\t\tbreak;\n\tcase OP_PERIODIC_TRAIN:\n\t\tEPRINTF(\"Periodic training..\");\n\t\t_minerva_do_periodic_compensation(mtc_cfg->current_emc_table);\n\t\tbreak;\n\tcase OP_TEMP_COMP:\n\t\tEPRINTF(\"Over temperature compensation..\");\n\t\t_minerva_do_over_temp_compensation(mtc_cfg);\n\t\tbreak;\n\t}\n\n\tmtc_cfg->train_ram_patterns = train_ram_patterns;\n}\n"
  },
  {
    "path": "modules/hekate_libsys_minerva/types.h",
    "content": "/*\n* Copyright (c) 2018 naehrwert\n*\n* This program is free software; you can redistribute it and/or modify it\n* under the terms and conditions of the GNU General Public License,\n* version 2, as published by the Free Software Foundation.\n*\n* This program is distributed in the hope it will be useful, but WITHOUT\n* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n* more details.\n*\n* You should have received a copy of the GNU General Public License\n* along with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n#ifndef _TYPES_H_\n#define _TYPES_H_\n\n#define NULL ((void *)0)\n\n#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))\n#define BIT(n) (1U << (n))\n#define MAX(a, b) ((a) > (b) ? (a) : (b))\n#define MIN(a, b) ((a) < (b) ? (a) : (b))\n\n#define OFFSET_OF(t, m) ((u32)&((t *)NULL)->m)\n#define CONTAINER_OF(mp, t, mn) ((t *)((u32)mp - OFFSET_OF(t, mn)))\n\ntypedef char s8;\ntypedef short s16;\ntypedef short SHORT;\ntypedef int s32;\ntypedef int INT;\ntypedef long LONG;\ntypedef long long int s64;\ntypedef unsigned char u8;\ntypedef unsigned char BYTE;\ntypedef unsigned short u16;\ntypedef unsigned short WORD;\ntypedef unsigned short WCHAR;\ntypedef unsigned int u32;\ntypedef unsigned int UINT;\ntypedef unsigned long DWORD;\ntypedef unsigned long long QWORD;\ntypedef unsigned long long int u64;\ntypedef volatile unsigned char vu8;\ntypedef volatile unsigned short vu16;\ntypedef volatile unsigned int vu32;\n\ntypedef int bool;\n#define true  1\n#define false 0\n\n#endif\n"
  },
  {
    "path": "modules/simple_sample/Makefile",
    "content": "ifeq ($(strip $(DEVKITARM)),)\n$(error \"Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM\")\nendif\n\ninclude $(DEVKITARM)/base_rules\n\nTARGET := module_sample\nBUILDDIR := ../../build/$(TARGET)\nOUTPUTDIR := ../../output\nSOURCEDIR = simple_sample\nBDKDIR := bdk\nBDKINC := -I../../$(BDKDIR)\nVPATH = $(dir ./) $(dir $(wildcard ./*/))\n\n# Track compiler flags\nTRACK_CFLAGS = $(BUILDDIR)/.cflags\nTRACK_LDFLAGS = $(BUILDDIR)/.ldflags\n\nOBJS = $(addprefix $(BUILDDIR)/,\\\n\tmodule_sample.o \\\n\tgfx.o \\\n)\n\nGFX_INC   := '\"../modules/$(SOURCEDIR)/gfx/gfx.h\"'\n\nCUSTOMDEFINES := -DGFX_INC=$(GFX_INC)\n\nARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork\nCFLAGS = $(ARCH) -O2 -nostdlib -fpie -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 -Wall -Wsign-compare $(CUSTOMDEFINES)\nLDFLAGS = $(ARCH) -fpie -pie -nostartfiles -lgcc -Wl,-z,max-page-size=256\n\n.PHONY: clean all\n\nall: $(TARGET).bso\n$(BUILDDIR)/%.o: ./%.c $(TRACK_CFLAGS)\n\t@$(CC) $(CFLAGS) $(BDKINC) -MMD -MP -c $< -o $@\n\n$(TARGET).bso: $(OBJS) $(TRACK_LDFLAGS)\n\t@$(CC) $(LDFLAGS) -e mod_entry $(OBJS) -o $(OUTPUTDIR)/$(TARGET).bso\n\t@$(STRIP) -g $(OUTPUTDIR)/$(TARGET).bso\n\t@echo \"Built module: \"$(TARGET)\".bso\"\n\nclean:\n\t@rm -rf $(BUILDDIR)/$(TARGET)\n\t@rm -rf $(OUTPUTDIR)/$(TARGET).bso\n\n$(BUILDDIR):\n\t@mkdir -p \"$(BUILDDIR)\"\n\n# Non objects change detectors.\n$(TRACK_CFLAGS): $(BUILDDIR)\n\t@echo '$(CFLAGS)' | cmp -s - $@ || echo '$(CFLAGS)' > $@\n$(TRACK_LDFLAGS): $(BUILDDIR)\n\t@echo '$(LDFLAGS)' | cmp -s - $@ || echo '$(LDFLAGS)' > $@\n-include $(OBJS:.o=.d)\n"
  },
  {
    "path": "modules/simple_sample/gfx/gfx.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2020 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <stdarg.h>\n#include <string.h>\n#include \"gfx.h\"\n\n// Global gfx console and context.\ngfx_ctxt_t gfx_ctxt;\ngfx_con_t gfx_con;\n\nstatic const u8 _gfx_font[] = {\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( )\n\t0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, // Char 033 (!)\n\t0x00, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, // Char 034 (\")\n\t0x00, 0x66, 0x66, 0xFF, 0x66, 0xFF, 0x66, 0x66, // Char 035 (#)\n\t0x00, 0x18, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x18, // Char 036 ($)\n\t0x00, 0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, // Char 037 (%)\n\t0x00, 0x3C, 0x66, 0x3C, 0x1C, 0xE6, 0x66, 0xFC, // Char 038 (&)\n\t0x00, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, // Char 039 (')\n\t0x00, 0x30, 0x18, 0x0C, 0x0C, 0x18, 0x30, 0x00, // Char 040 (()\n\t0x00, 0x0C, 0x18, 0x30, 0x30, 0x18, 0x0C, 0x00, // Char 041 ())\n\t0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, // Char 042 (*)\n\t0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, // Char 043 (+)\n\t0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0C, 0x00, // Char 044 (,)\n\t0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, // Char 045 (-)\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, // Char 046 (.)\n\t0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, // Char 047 (/)\n\t0x00, 0x3C, 0x66, 0x76, 0x6E, 0x66, 0x3C, 0x00, // Char 048 (0)\n\t0x00, 0x18, 0x1C, 0x18, 0x18, 0x18, 0x7E, 0x00, // Char 049 (1)\n\t0x00, 0x3C, 0x62, 0x30, 0x0C, 0x06, 0x7E, 0x00, // Char 050 (2)\n\t0x00, 0x3C, 0x62, 0x38, 0x60, 0x66, 0x3C, 0x00, // Char 051 (3)\n\t0x00, 0x6C, 0x6C, 0x66, 0xFE, 0x60, 0x60, 0x00, // Char 052 (4)\n\t0x00, 0x7E, 0x06, 0x7E, 0x60, 0x66, 0x3C, 0x00, // Char 053 (5)\n\t0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x3C, 0x00, // Char 054 (6)\n\t0x00, 0x7E, 0x30, 0x30, 0x18, 0x18, 0x18, 0x00, // Char 055 (7)\n\t0x00, 0x3C, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, // Char 056 (8)\n\t0x00, 0x3C, 0x66, 0x7C, 0x60, 0x66, 0x3C, 0x00, // Char 057 (9)\n\t0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, // Char 058 (:)\n\t0x00, 0x00, 0x18, 0x00, 0x18, 0x18, 0x0C, 0x00, // Char 059 (;)\n\t0x00, 0x70, 0x1C, 0x06, 0x06, 0x1C, 0x70, 0x00, // Char 060 (<)\n\t0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, // Char 061 (=)\n\t0x00, 0x0E, 0x38, 0x60, 0x60, 0x38, 0x0E, 0x00, // Char 062 (>)\n\t0x00, 0x3C, 0x66, 0x30, 0x18, 0x00, 0x18, 0x00, // Char 063 (?)\n\t0x00, 0x3C, 0x66, 0x76, 0x76, 0x06, 0x46, 0x3C, // Char 064 (@)\n\t0x00, 0x3C, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // Char 065 (A)\n\t0x00, 0x3E, 0x66, 0x3E, 0x66, 0x66, 0x3E, 0x00, // Char 066 (B)\n\t0x00, 0x3C, 0x66, 0x06, 0x06, 0x66, 0x3C, 0x00, // Char 067 (C)\n\t0x00, 0x1E, 0x36, 0x66, 0x66, 0x36, 0x1E, 0x00, // Char 068 (D)\n\t0x00, 0x7E, 0x06, 0x1E, 0x06, 0x06, 0x7E, 0x00, // Char 069 (E)\n\t0x00, 0x3E, 0x06, 0x1E, 0x06, 0x06, 0x06, 0x00, // Char 070 (F)\n\t0x00, 0x3C, 0x66, 0x06, 0x76, 0x66, 0x3C, 0x00, // Char 071 (G)\n\t0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // Char 072 (H)\n\t0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // Char 073 (I)\n\t0x00, 0x78, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, // Char 074 (J)\n\t0x00, 0x66, 0x36, 0x1E, 0x1E, 0x36, 0x66, 0x00, // Char 075 (K)\n\t0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7E, 0x00, // Char 076 (L)\n\t0x00, 0x46, 0x6E, 0x7E, 0x56, 0x46, 0x46, 0x00, // Char 077 (M)\n\t0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00, // Char 078 (N)\n\t0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 079 (O)\n\t0x00, 0x3E, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00, // Char 080 (P)\n\t0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x70, 0x00, // Char 081 (Q)\n\t0x00, 0x3E, 0x66, 0x3E, 0x1E, 0x36, 0x66, 0x00, // Char 082 (R)\n\t0x00, 0x3C, 0x66, 0x0C, 0x30, 0x66, 0x3C, 0x00, // Char 083 (S)\n\t0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // Char 084 (T)\n\t0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 085 (U)\n\t0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // Char 086 (V)\n\t0x00, 0x46, 0x46, 0x56, 0x7E, 0x6E, 0x46, 0x00, // Char 087 (W)\n\t0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, // Char 088 (X)\n\t0x00, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, // Char 089 (Y)\n\t0x00, 0x7E, 0x30, 0x18, 0x0C, 0x06, 0x7E, 0x00, // Char 090 (Z)\n\t0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, // Char 091 ([)\n\t0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00, // Char 092 (\\)\n\t0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, // Char 093 (])\n\t0x00, 0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, // Char 094 (^)\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // Char 095 (_)\n\t0x00, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, // Char 096 (`)\n\t0x00, 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x7C, 0x00, // Char 097 (a)\n\t0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x00, // Char 098 (b)\n\t0x00, 0x00, 0x3C, 0x06, 0x06, 0x06, 0x3C, 0x00, // Char 099 (c)\n\t0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, // Char 100 (d)\n\t0x00, 0x00, 0x3C, 0x66, 0x7E, 0x06, 0x3C, 0x00, // Char 101 (e)\n\t0x00, 0x38, 0x0C, 0x3E, 0x0C, 0x0C, 0x0C, 0x00, // Char 102 (f)\n\t0x00, 0x00, 0x7C, 0x66, 0x7C, 0x40, 0x3C, 0x00, // Char 103 (g)\n\t0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x00, // Char 104 (h)\n\t0x00, 0x18, 0x00, 0x1C, 0x18, 0x18, 0x3C, 0x00, // Char 105 (i)\n\t0x00, 0x30, 0x00, 0x30, 0x30, 0x30, 0x1E, 0x00, // Char 106 (j)\n\t0x00, 0x06, 0x06, 0x36, 0x1E, 0x36, 0x66, 0x00, // Char 107 (k)\n\t0x00, 0x1C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // Char 108 (l)\n\t0x00, 0x00, 0x66, 0xFE, 0xFE, 0xD6, 0xC6, 0x00, // Char 109 (m)\n\t0x00, 0x00, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x00, // Char 110 (n)\n\t0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 111 (o)\n\t0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x00, // Char 112 (p)\n\t0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00, // Char 113 (q)\n\t0x00, 0x00, 0x3E, 0x66, 0x06, 0x06, 0x06, 0x00, // Char 114 (r)\n\t0x00, 0x00, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x00, // Char 115 (s)\n\t0x00, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x70, 0x00, // Char 116 (t)\n\t0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, // Char 117 (u)\n\t0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // Char 118 (v)\n\t0x00, 0x00, 0xC6, 0xD6, 0xFE, 0x7C, 0x6C, 0x00, // Char 119 (w)\n\t0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, // Char 120 (x)\n\t0x00, 0x00, 0x66, 0x66, 0x7C, 0x60, 0x3C, 0x00, // Char 121 (y)\n\t0x00, 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x7E, 0x00, // Char 122 (z)\n\t0x00, 0x18, 0x08, 0x08, 0x04, 0x08, 0x08, 0x18, // Char 123 ({)\n\t0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, // Char 124 (|)\n\t0x00, 0x0C, 0x08, 0x08, 0x10, 0x08, 0x08, 0x0C, // Char 125 (})\n\t0x00, 0x00, 0x00, 0x4C, 0x32, 0x00, 0x00, 0x00  // Char 126 (~)\n};\n\nvoid gfx_clear_grey(u8 color)\n{\n\tmemset(gfx_ctxt.fb, color, gfx_ctxt.width * gfx_ctxt.height * 4);\n}\n\nvoid gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height)\n{\n\tmemset(gfx_ctxt.fb + pos_x * gfx_ctxt.stride, color, height * 4 * gfx_ctxt.stride);\n}\n\nvoid gfx_clear_color(u32 color)\n{\n\tfor (u32 i = 0; i < gfx_ctxt.width * gfx_ctxt.height; i++)\n\t\tgfx_ctxt.fb[i] = color;\n}\n\nvoid gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride)\n{\n\tgfx_ctxt.fb = fb;\n\tgfx_ctxt.width = width;\n\tgfx_ctxt.height = height;\n\tgfx_ctxt.stride = stride;\n}\n\nvoid gfx_con_init()\n{\n\tgfx_con.gfx_ctxt = &gfx_ctxt;\n\tgfx_con.fntsz = 16;\n\tgfx_con.x = 0;\n\tgfx_con.y = 0;\n\tgfx_con.savedx = 0;\n\tgfx_con.savedy = 0;\n\tgfx_con.fgcol = 0xFFCCCCCC;\n\tgfx_con.fillbg = 1;\n\tgfx_con.bgcol = 0xFF1B1B1B;\n\tgfx_con.mute = 0;\n}\n\nvoid gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol)\n{\n\tgfx_con.fgcol = fgcol;\n\tgfx_con.fillbg = fillbg;\n\tgfx_con.bgcol = bgcol;\n}\n\nvoid gfx_con_getpos(u32 *x, u32 *y)\n{\n\t*x = gfx_con.x;\n\t*y = gfx_con.y;\n}\n\nvoid gfx_con_setpos(u32 x, u32 y)\n{\n\tgfx_con.x = x;\n\tgfx_con.y = y;\n}\n\nvoid gfx_putc(char c)\n{\n\t// Duplicate code for performance reasons.\n\tswitch (gfx_con.fntsz)\n\t{\n\tcase 16:\n\t\tif (c >= 32 && c <= 126)\n\t\t{\n\t\t\tu8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];\n\t\t\tu32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;\n\n\t\t\tfor (u32 i = 0; i < 16; i += 2)\n\t\t\t{\n\t\t\t\tu8 v = *cbuf;\n\t\t\t\tfor (u32 k = 0; k < 2; k++)\n\t\t\t\t{\n\t\t\t\t\tfor (u32 j = 0; j < 8; j++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (v & 1)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t*fb = gfx_con.fgcol;\n\t\t\t\t\t\t\tfb++;\n\t\t\t\t\t\t\t*fb = gfx_con.fgcol;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (gfx_con.fillbg)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t*fb = gfx_con.bgcol;\n\t\t\t\t\t\t\tfb++;\n\t\t\t\t\t\t\t*fb = gfx_con.bgcol;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tfb++;\n\t\t\t\t\t\tv >>= 1;\n\t\t\t\t\t\tfb++;\n\t\t\t\t\t}\n\t\t\t\t\tfb += gfx_ctxt.stride - 16;\n\t\t\t\t\tv = *cbuf;\n\t\t\t\t}\n\t\t\t\tcbuf++;\n\t\t\t}\n\t\t\tgfx_con.x += 16;\n\t\t}\n\t\telse if (c == '\\n')\n\t\t{\n\t\t\tgfx_con.x = 0;\n\t\t\tgfx_con.y += 16;\n\t\t\tif (gfx_con.y > gfx_ctxt.height - 16)\n\t\t\t\tgfx_con.y = 0;\n\t\t}\n\t\tbreak;\n\tcase 8:\n\tdefault:\n\t\tif (c >= 32 && c <= 126)\n\t\t{\n\t\t\tu8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];\n\t\t\tu32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;\n\t\t\tfor (u32 i = 0; i < 8; i++)\n\t\t\t{\n\t\t\t\tu8 v = *cbuf++;\n\t\t\t\tfor (u32 j = 0; j < 8; j++)\n\t\t\t\t{\n\t\t\t\t\tif (v & 1)\n\t\t\t\t\t\t*fb = gfx_con.fgcol;\n\t\t\t\t\telse if (gfx_con.fillbg)\n\t\t\t\t\t\t*fb = gfx_con.bgcol;\n\t\t\t\t\tv >>= 1;\n\t\t\t\t\tfb++;\n\t\t\t\t}\n\t\t\t\tfb += gfx_ctxt.stride - 8;\n\t\t\t}\n\t\t\tgfx_con.x += 8;\n\t\t}\n\t\telse if (c == '\\n')\n\t\t{\n\t\t\tgfx_con.x = 0;\n\t\t\tgfx_con.y += 8;\n\t\t\tif (gfx_con.y > gfx_ctxt.height - 8)\n\t\t\t\tgfx_con.y = 0;\n\t\t}\n\t\tbreak;\n\t}\n}\n\nvoid gfx_puts(char *s)\n{\n\tif (!s || gfx_con.mute)\n\t\treturn;\n\n\tfor (; *s; s++)\n\t\tgfx_putc(*s);\n}\n\nstatic void _gfx_putn(u32 v, int base, char fill, int fcnt)\n{\n\tchar buf[65];\n\tstatic const char digits[] = \"0123456789ABCDEFghijklmnopqrstuvwxyz\";\n\tchar *p;\n\tint c = fcnt;\n\n\tif (base > 36)\n\t\treturn;\n\n\tp = buf + 64;\n\t*p = 0;\n\tdo\n\t{\n\t\tc--;\n\t\t*--p = digits[v % base];\n\t\tv /= base;\n\t} while (v);\n\n\tif (fill != 0)\n\t{\n\t\twhile (c > 0)\n\t\t{\n\t\t\t*--p = fill;\n\t\t\tc--;\n\t\t}\n\t}\n\n\tgfx_puts(p);\n}\n\nvoid gfx_put_small_sep()\n{\n\tu8 prevFontSize = gfx_con.fntsz;\n\tgfx_con.fntsz = 8;\n\tgfx_putc('\\n');\n\tgfx_con.fntsz = prevFontSize;\n}\n\nvoid gfx_put_big_sep()\n{\n\tu8 prevFontSize = gfx_con.fntsz;\n\tgfx_con.fntsz = 16;\n\tgfx_putc('\\n');\n\tgfx_con.fntsz = prevFontSize;\n}\n\nvoid gfx_printf(const char *fmt, ...)\n{\n\tif (gfx_con.mute)\n\t\treturn;\n\n\tva_list ap;\n\tint fill, fcnt;\n\n\tva_start(ap, fmt);\n\twhile (*fmt)\n\t{\n\t\tif (*fmt == '%')\n\t\t{\n\t\t\tfmt++;\n\t\t\tfill = 0;\n\t\t\tfcnt = 0;\n\t\t\tif ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ')\n\t\t\t{\n\t\t\t\tfcnt = *fmt;\n\t\t\t\tfmt++;\n\t\t\t\tif (*fmt >= '0' && *fmt <= '9')\n\t\t\t\t{\n\t\t\t\t\tfill = fcnt;\n\t\t\t\t\tfcnt = *fmt - '0';\n\t\t\t\t\tfmt++;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfill = ' ';\n\t\t\t\t\tfcnt -= '0';\n\t\t\t\t}\n\t\t\t}\n\t\t\tswitch(*fmt)\n\t\t\t{\n\t\t\tcase 'c':\n\t\t\t\tgfx_putc(va_arg(ap, u32));\n\t\t\t\tbreak;\n\t\t\tcase 's':\n\t\t\t\tgfx_puts(va_arg(ap, char *));\n\t\t\t\tbreak;\n\t\t\tcase 'd':\n\t\t\t\t_gfx_putn(va_arg(ap, u32), 10, fill, fcnt);\n\t\t\t\tbreak;\n\t\t\tcase 'p':\n\t\t\tcase 'P':\n\t\t\tcase 'x':\n\t\t\tcase 'X':\n\t\t\t\t_gfx_putn(va_arg(ap, u32), 16, fill, fcnt);\n\t\t\t\tbreak;\n\t\t\tcase 'k':\n\t\t\t\tgfx_con.fgcol = va_arg(ap, u32);\n\t\t\t\tbreak;\n\t\t\tcase 'K':\n\t\t\t\tgfx_con.bgcol = va_arg(ap, u32);\n\t\t\t\tgfx_con.fillbg = 1;\n\t\t\t\tbreak;\n\t\t\tcase '%':\n\t\t\t\tgfx_putc('%');\n\t\t\t\tbreak;\n\t\t\tcase '\\0':\n\t\t\t\tgoto out;\n\t\t\tdefault:\n\t\t\t\tgfx_putc('%');\n\t\t\t\tgfx_putc(*fmt);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tgfx_putc(*fmt);\n\t\tfmt++;\n\t}\n\n\tout:\n\tva_end(ap);\n}\n\nvoid gfx_hexdump(u32 base, const u8 *buf, u32 len)\n{\n\tif (gfx_con.mute)\n\t\treturn;\n\n\tu8 prevFontSize = gfx_con.fntsz;\n\tgfx_con.fntsz = 8;\n\tfor (u32 i = 0; i < len; i++)\n\t{\n\t\tif (i % 0x10 == 0)\n\t\t{\n\t\t\tif (i != 0)\n\t\t\t{\n\t\t\t\tgfx_puts(\"| \");\n\t\t\t\tfor (u32 j = 0; j < 0x10; j++)\n\t\t\t\t{\n\t\t\t\t\tu8 c = buf[i - 0x10 + j];\n\t\t\t\t\tif (c >= 32 && c <= 126)\n\t\t\t\t\t\tgfx_putc(c);\n\t\t\t\t\telse\n\t\t\t\t\t\tgfx_putc('.');\n\t\t\t\t}\n\t\t\t\tgfx_putc('\\n');\n\t\t\t}\n\t\t\tgfx_printf(\"%08x: \", base + i);\n\t\t}\n\t\tgfx_printf(\"%02x \", buf[i]);\n\t\tif (i == len - 1)\n\t\t{\n\t\t\tint ln = len % 0x10 != 0;\n\t\t\tu32 k = 0x10 - 1;\n\t\t\tif (ln)\n\t\t\t{\n\t\t\t\tk = (len & 0xF) - 1;\n\t\t\t\tfor (u32 j = 0; j < 0x10 - k; j++)\n\t\t\t\t\tgfx_puts(\"   \");\n\t\t\t}\n\t\t\tgfx_puts(\"| \");\n\t\t\tfor (u32 j = 0; j < (ln ? k : k + 1); j++)\n\t\t\t{\n\t\t\t\tu8 c = buf[i - k + j];\n\t\t\t\tif (c >= 32 && c <= 126)\n\t\t\t\t\tgfx_putc(c);\n\t\t\t\telse\n\t\t\t\t\tgfx_putc('.');\n\t\t\t}\n\t\t\tgfx_putc('\\n');\n\t\t}\n\t}\n\tgfx_putc('\\n');\n\tgfx_con.fntsz = prevFontSize;\n}\n\nstatic int abs(int x)\n{\n\tif (x < 0)\n\t\treturn -x;\n\treturn x;\n}\n\nvoid gfx_set_pixel(u32 x, u32 y, u32 color)\n{\n\tgfx_ctxt.fb[x + y * gfx_ctxt.stride] = color;\n}\n\nvoid gfx_line(int x0, int y0, int x1, int y1, u32 color)\n{\n\tint dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;\n\tint dy = abs(y1 - y0), sy = y0 < y1 ? 1 : -1;\n\tint err = (dx > dy ? dx : -dy) / 2, e2;\n\n\twhile (1)\n\t{\n\t\tgfx_set_pixel(x0, y0, color);\n\t\tif (x0 == x1 && y0 == y1)\n\t\t\tbreak;\n\t\te2 = err;\n\t\tif (e2 >-dx)\n\t\t{\n\t\t\terr -= dy;\n\t\t\tx0 += sx;\n\t\t}\n\t\tif (e2 < dy)\n\t\t{\n\t\t\terr += dx;\n\t\t\ty0 += sy;\n\t\t}\n\t}\n}\n\nvoid gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)\n{\n\tu32 pos = 0;\n\tfor (u32 y = pos_y; y < (pos_y + size_y); y++)\n\t{\n\t\tfor (u32 x = pos_x; x < (pos_x + size_x); x++)\n\t\t{\n\t\t\tmemset(&gfx_ctxt.fb[x + y*gfx_ctxt.stride], buf[pos], 4);\n\t\t\tpos++;\n\t\t}\n\t}\n}\n\n\nvoid gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)\n{\n\tu32 pos = 0;\n\tfor (u32 y = pos_y; y < (pos_y + size_y); y++)\n\t{\n\t\tfor (u32 x = pos_x; x < (pos_x + size_x); x++)\n\t\t{\n\t\t\tgfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[pos + 2] | (buf[pos + 1] << 8) | (buf[pos] << 16);\n\t\t\tpos+=3;\n\t\t}\n\t}\n}\n\nvoid gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)\n{\n\tu32 *ptr = (u32 *)buf;\n\tfor (u32 y = pos_y; y < (pos_y + size_y); y++)\n\t\tfor (u32 x = pos_x; x < (pos_x + size_x); x++)\n\t\t\tgfx_ctxt.fb[x + y * gfx_ctxt.stride] = *ptr++;\n}\n\nvoid gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)\n{\n\tfor (u32 y = pos_y; y < (pos_y + size_y); y++)\n\t{\n\t\tfor (u32 x = pos_x; x < (pos_x + size_x); x++)\n\t\t\tgfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[(size_y + pos_y - 1 - y ) * size_x + x - pos_x];\n\t}\n}\n"
  },
  {
    "path": "modules/simple_sample/gfx/gfx.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2020 CTCaer\n * Copyright (c) 2018 M4xw\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _GFX_H_\n#define _GFX_H_\n\n#include <utils/types.h>\n\n#define EPRINTF(text) gfx_printf(\"%k\"text\"%k\\n\", 0xFFFF0000, 0xFFCCCCCC)\n#define EPRINTFARGS(text, args...) gfx_printf(\"%k\"text\"%k\\n\", 0xFFFF0000, args, 0xFFCCCCCC)\n#define WPRINTF(text) gfx_printf(\"%k\"text\"%k\\n\", 0xFFFFDD00, 0xFFCCCCCC)\n#define WPRINTFARGS(text, args...) gfx_printf(\"%k\"text\"%k\\n\", 0xFFFFDD00, args, 0xFFCCCCCC)\n\ntypedef struct _gfx_ctxt_t\n{\n\tu32 *fb;\n\tu32 width;\n\tu32 height;\n\tu32 stride;\n} gfx_ctxt_t;\n\ntypedef struct _gfx_con_t\n{\n\tgfx_ctxt_t *gfx_ctxt;\n\tu32 fntsz;\n\tu32 x;\n\tu32 y;\n\tu32 savedx;\n\tu32 savedy;\n\tu32 fgcol;\n\tint fillbg;\n\tu32 bgcol;\n\tbool mute;\n} gfx_con_t;\n\n// Global gfx console and context.\nextern gfx_ctxt_t gfx_ctxt;\nextern gfx_con_t gfx_con;\n\nvoid gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride);\nvoid gfx_clear_grey(u8 color);\nvoid gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height);\nvoid gfx_clear_color(u32 color);\nvoid gfx_con_init();\nvoid gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol);\nvoid gfx_con_getpos(u32 *x, u32 *y);\nvoid gfx_con_setpos(u32 x, u32 y);\nvoid gfx_putc(char c);\nvoid gfx_puts(char *s);\nvoid gfx_printf(const char *fmt, ...);\nvoid gfx_hexdump(u32 base, const u8 *buf, u32 len);\n\nvoid gfx_set_pixel(u32 x, u32 y, u32 color);\nvoid gfx_line(int x0, int y0, int x1, int y1, u32 color);\nvoid gfx_put_small_sep();\nvoid gfx_put_big_sep();\nvoid gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);\nvoid gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);\nvoid gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);\nvoid gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);\n\n#endif\n"
  },
  {
    "path": "modules/simple_sample/module_sample.c",
    "content": "/*  Sample Hekate Module\n\t2018 - M4xw\n*/\n\n#include <string.h>\n#include <module.h>\n#include <gfx_utils.h>\n\nvoid mod_entry(void *moduleConfig, bdk_params_t *bp)\n{\n\tmemcpy(&gfx_con, bp->gfx_con, sizeof(gfx_con_t));\n\tmemcpy(&gfx_ctxt, bp->gfx_ctx, sizeof(gfx_ctxt_t));\n\n\tgfx_puts(\"Hello World!\");\n\n\tmemcpy(bp->gfx_con, &gfx_con, sizeof(gfx_con_t));\n\tmemcpy(bp->gfx_ctx, &gfx_ctxt, sizeof(gfx_ctxt_t));\n}\n"
  },
  {
    "path": "nyx/Makefile",
    "content": "ifeq ($(strip $(DEVKITARM)),)\n$(error \"Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM\")\nendif\n\ninclude $(DEVKITARM)/base_rules\n\n################################################################################\n\nNYX_LOAD_ADDR := 0x81000000\nNYX_MAGIC := 0x43544347 #\"GCTC\"\ninclude ./../Versions.inc\n\n################################################################################\n\nTARGET := nyx\nBUILDDIR := ./../build/$(TARGET)\nOUTPUTDIR := ./../output\nSOURCEDIR = nyx_gui\nBDKDIR := bdk\nBDKINC := -I../$(BDKDIR)\nVPATH = $(dir $(wildcard ./$(SOURCEDIR)/)) $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/))\nVPATH += $(dir $(wildcard ./$(SOURCEDIR)/*/*/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/*/*/))\nVPATH += $(dir $(wildcard ../$(BDKDIR)/)) $(dir $(wildcard ../$(BDKDIR)/*/)) $(dir $(wildcard ../$(BDKDIR)/*/*/)) $(dir $(wildcard ../$(BDKDIR)/*/*/*/))\n\n# Track compiler flags\nTRACK_CFLAGS = $(BUILDDIR)/.cflags\nTRACK_LDFLAGS = $(BUILDDIR)/.ldflags\n\n# Main and graphics.\nOBJS =  start exception_handlers nyx heap gfx \\\n\t\tgui gui_info gui_tools gui_options gui_emmc_tools gui_emummc_tools gui_tools_partition_manager \\\n\t\tfe_emummc_tools fe_emmc_tools\n\n# Hardware.\nOBJS += actmon bpmp ccplex clock di vic i2c irq timer \\\n\t\tgpio  pinmux pmc se smmu tsec uart \\\n\t\tfuse kfuse \\\n\t\tmc sdram minerva ramdisk \\\n\t\tsdmmc sdmmc_driver emmc sd nx_emmc_bis \\\n\t\tbm92t36 bq24193 max17050 max7762x max77620-rtc regulator_5v \\\n\t\ttouch joycon tmp451 fan \\\n\t\tusbd xusbd usb_descriptors usb_gadget_ums usb_gadget_hid \\\n\t\thw_init\n\n# Utilities.\nOBJS += btn dirlist ianos ini util config sprintf\n\n# Horizon.\nOBJS += hos pkg1 pkg2\n\n# Libraries.\nOBJS += diskio ff ffunicode ffsystem \\\n\t\telfload elfreloc_arm blz \\\n\t\tlv_group lv_indev lv_obj lv_refr lv_style lv_vdb \\\n\t\tlv_draw lv_draw_rbasic lv_draw_vbasic lv_draw_arc lv_draw_img \\\n\t\tlv_draw_label lv_draw_line lv_draw_rect lv_draw_triangle \\\n\t\tlv_hal_disp lv_hal_indev lv_hal_tick \\\n\t\tinterui_20 interui_30 ubuntu_mono hekate_symbol_20 hekate_symbol_30 hekate_symbol_120 lv_font_builtin \\\n\t\tlv_anim lv_area lv_circ lv_color lv_font lv_ll lv_math lv_mem lv_task lv_txt lv_gc \\\n\t\tlv_bar lv_btn lv_btnm lv_cb lv_cont lv_ddlist lv_img lv_label lv_line lv_list lv_lmeter lv_mbox \\\n\t\tlv_page lv_roller lv_slider lv_sw lv_tabview lv_ta lv_win lv_log lv_imgbtn \\\n\t\tlv_theme lv_theme_hekate\n\nOBJS := $(addsuffix .o, $(OBJS))\nOBJS := $(addprefix $(BUILDDIR)/, $(OBJS))\n\nGFX_INC   := '\"../nyx/$(SOURCEDIR)/gfx/gfx.h\"'\nFFCFG_INC := '\"../nyx/$(SOURCEDIR)/libs/fatfs/ffconf.h\"'\n\n################################################################################\n\nCUSTOMDEFINES := -DNYX_LOAD_ADDR=$(NYX_LOAD_ADDR) -DNYX_MAGIC=$(NYX_MAGIC)\nCUSTOMDEFINES += -DNYX_VER_MJ=$(NYXVERSION_MAJOR) -DNYX_VER_MN=$(NYXVERSION_MINOR) -DNYX_VER_HF=$(NYXVERSION_HOTFX) -DNYX_VER_RL=$(NYXVERSION_REL)\n\n# BDK defines.\nCUSTOMDEFINES += -DBDK_MINERVA_CFG_FROM_RAM -DBDK_HW_EXTRA_DEINIT -DBDK_SDMMC_EXTRA_PRINT\nCUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC)\n\n#CUSTOMDEFINES += -DDEBUG\n\n# UART Logging: Max baudrate 12.5M. Disables Joycon on Nyx if UARTB or UARTC.\n# DEBUG_UART_PORT - 0: UART_A, 1: UART_B, 2: UART_C.\n#CUSTOMDEFINES += -DDEBUG_UART_BAUDRATE=115200 -DDEBUG_UART_INVERT=0 -DDEBUG_UART_PORT=0\n\n# LvGL UART LOG.\n#CUSTOMDEFINES += -DDEBUG_UART_LV_LOG\n\n#TODO: Considering reinstating some of these when pointer warnings have been fixed.\nWARNINGS := -Wall -Wsign-compare -Wtype-limits -Wno-array-bounds -Wno-stringop-overread -Wno-stringop-overflow\n#-fno-delete-null-pointer-checks\n#-Wstack-usage=byte-size -fstack-usage\n\nARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork $(WARNINGS)\nCFLAGS = $(ARCH) -O2 -g -gdwarf-4 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 $(CUSTOMDEFINES)\nLDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=NYX_LOAD_ADDR=$(NYX_LOAD_ADDR)\n\nifndef NYXECHO\nT := $(shell $(MAKE) $(BUILDDIR)/$(TARGET).elf --no-print-directory -nrRf $(firstword $(MAKEFILE_LIST)) NYXECHO=\"NYXOBJ\" | grep -c \"NYXOBJ\")\n\nN := x\nC = $(words $N)$(eval N := x $N)\nNYXECHO = echo -ne \"\\r`expr \"  [\\`expr $C '*' 100 / $T\\`\" : '.*\\(....\\)$$'`%]\\033[K\"\nendif\n\n################################################################################\n\n.PHONY: all clean\n\nall: $(TARGET).bin\n\t@echo \"--------------------------------------\"\n\t@echo -n \"Nyx size: \"\n\t$(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(TARGET).bin))\n\t@echo $(BIN_SIZE)\" Bytes\"\n\t@echo \"--------------------------------------\"\n\nclean:\n\t@rm -rf $(OBJS)\n\t@rm -rf $(BUILDDIR)\n\t@rm -rf $(OUTPUTDIR)\n\n$(TARGET).bin: $(BUILDDIR)/$(TARGET).elf\n\t@$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@\n\n$(BUILDDIR)/$(TARGET).elf: $(OBJS) $(TRACK_LDFLAGS)\n\t@echo -ne \"\\r[100%] Linking $(TARGET).elf\\033[K\"\n\t@$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $(OBJS) -o $@\n\t@printf \"\\n$(TARGET) was built with the following flags:\\nCFLAGS:  $(CFLAGS)\\nLDFLAGS: $(LDFLAGS)\\n\"\n\n$(BUILDDIR)/%.o: %.c $(TRACK_CFLAGS) | $(BUILDDIR)\n\t@$(NYXECHO) Building $@\n\t@$(CC) $(CFLAGS) $(BDKINC) -MMD -MP -c $< -o $@\n\n$(BUILDDIR)/%.o: %.S $(TRACK_CFLAGS) | $(BUILDDIR)\n\t@$(NYXECHO) Building $@\n\t@$(CC) $(CFLAGS) -MMD -MP -c $< -o $@\n\n$(BUILDDIR):\n\t@mkdir -p \"$(BUILDDIR)\"\n\t@mkdir -p \"$(OUTPUTDIR)\"\n\n# Non objects change detectors.\n$(TRACK_CFLAGS): $(BUILDDIR)\n\t@echo '$(CFLAGS)' | cmp -s - $@ || echo '$(CFLAGS)' > $@\n$(TRACK_LDFLAGS): $(BUILDDIR)\n\t@echo '$(LDFLAGS)' | cmp -s - $@ || echo '$(LDFLAGS)' > $@\n-include $(OBJS:.o=.d)\n"
  },
  {
    "path": "nyx/README_RES.md",
    "content": "# Nyx - Background - Icons\n\nThe background for Nyx, must be a 1280 x 720 32-bit BMP. Alpha blending is taken into account. For that reason, if a solid background is required, that value must be 0xFF. There are sites that can produce the correct bmp.\n\nThe icons supported are 192 x 192 32-bit BMP. You can utilize transparency at will and make nice mixes with the button background.\n\nAdditionally, using the `icon={sd path}`, the icon will get colorized if the name ends in `_hue.bmp`. That only works nicely if the icon is a white layout with transparency.\n\nIf `_nobox.bmp` is used then the button background is removed. Useful for icon themes that aim for a specific style.\n\nA combo of both can be enabled via `_hue_nobox.bmp` suffix.\n\nThe default system icons (`icon_switch.bmp` and `icon_payload.bmp`) can be replaced with white layouts that have transparency. They can also be replaced with normal icons if the following exist: `icon_switch_custom.bmp` or/and `icon_payload_custom.bmp`\n\n\n## How to configure\n\nThe background must go to /bootloader/res/background.bmp\n\nThe icons can be utilized either via `[boot entries names]` -> `boot entries names.bmp` or by using `icon={sd path}` (preferred method), which should point at a bmp.\n"
  },
  {
    "path": "nyx/nyx_gui/config.c",
    "content": "/*\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n#include <stdlib.h>\n\n#include <bdk.h>\n\n#include \"config.h\"\n#include <libs/fatfs/ff.h>\n\nvoid set_default_configuration()\n{\n\th_cfg.t210b01 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01;\n\th_cfg.devmode = fuse_read_hw_state();\n\n\th_cfg.autoboot      = 0;\n\th_cfg.autoboot_list = 0;\n\th_cfg.bootwait      = 3;\n\th_cfg.noticker      = 0; //! TODO: Add GUI option.\n\th_cfg.backlight     = 100;\n\th_cfg.autohosoff    = h_cfg.t210b01 ? 1 : 0;\n\th_cfg.autonogc      = 1;\n\th_cfg.updater2p     = 0;\n\th_cfg.bootprotect   = 0;\n\n\th_cfg.errors = 0;\n\th_cfg.eks = NULL;\n\th_cfg.rcm_patched = fuse_check_patched_rcm();\n\th_cfg.autorcm_enabled = false;\n\th_cfg.emummc_force_disable = false;\n\n\tsd_power_cycle_time_start = 0;\n}\n\nvoid set_nyx_default_configuration()\n{\n\tn_cfg.theme_bg       = 0x2D2D2D;\n\tn_cfg.theme_color    = 167;\n\tn_cfg.entries_5_col  = 0;\n\tn_cfg.timeoffset     = 0;\n\tn_cfg.timedst        = 1;\n\tn_cfg.home_screen    = 0;\n\tn_cfg.verification   = 1;\n\tn_cfg.ums_emmc_rw    = 0;\n\tn_cfg.jc_disable     = 0;\n\tn_cfg.jc_force_right = 0;\n\tn_cfg.bpmp_clock     = 0;\n}\n\nint create_config_entry()\n{\n\tchar lbuf[64];\n\tFIL fp;\n\tbool ini_found = false;\n\n\tLIST_INIT(ini_sections);\n\n\tif (!ini_parse(&ini_sections, \"bootloader/hekate_ipl.ini\", false))\n\t\tini_found = true;\n\telse\n\t{\n\t\tu8 res = f_open(&fp, \"bootloader/hekate_ipl.ini\", FA_READ);\n\t\tif (res == FR_NO_FILE || res == FR_NO_PATH)\n\t\t{\n\t\t\tf_mkdir(\"bootloader\");\n\t\t\tf_mkdir(\"bootloader/ini\");\n\t\t\tf_mkdir(\"bootloader/payloads\");\n\t\t\tf_mkdir(\"bootloader/sys\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (!res)\n\t\t\t\tf_close(&fp);\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\tif (f_open(&fp, \"bootloader/hekate_ipl.ini\", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)\n\t\treturn 1;\n\n\t// Add config entry.\n\tf_puts(\"[config]\\nautoboot=\", &fp);\n\titoa(h_cfg.autoboot, lbuf, 10);\n\tf_puts(lbuf, &fp);\n\n\tf_puts(\"\\nautoboot_list=\", &fp);\n\titoa(h_cfg.autoboot_list, lbuf, 10);\n\tf_puts(lbuf, &fp);\n\t/*\n\t * Clamp value to default if it exceeds 20s to protect against corruption.\n\t * Allow up to 20s though for use in cases where user needs lots of time.\n\t * For example dock-only use and r2p with enough time to reach dock and cancel it.\n\t*/\n\tif (h_cfg.bootwait > 20)\n\t\th_cfg.bootwait = 3;\n\tf_puts(\"\\nbootwait=\", &fp);\n\titoa(h_cfg.bootwait, lbuf, 10);\n\tf_puts(lbuf, &fp);\n\n\tf_puts(\"\\nbacklight=\", &fp);\n\titoa(h_cfg.backlight, lbuf, 10);\n\tf_puts(lbuf, &fp);\n\n\tf_puts(\"\\nnoticker=\", &fp);\n\titoa(h_cfg.noticker, lbuf, 10);\n\tf_puts(lbuf, &fp);\n\n\tf_puts(\"\\nautohosoff=\", &fp);\n\titoa(h_cfg.autohosoff, lbuf, 10);\n\tf_puts(lbuf, &fp);\n\n\tf_puts(\"\\nautonogc=\", &fp);\n\titoa(h_cfg.autonogc, lbuf, 10);\n\tf_puts(lbuf, &fp);\n\n\tf_puts(\"\\nupdater2p=\", &fp);\n\titoa(h_cfg.updater2p, lbuf, 10);\n\tf_puts(lbuf, &fp);\n\n\tf_puts(\"\\nbootprotect=\", &fp);\n\titoa(h_cfg.bootprotect, lbuf, 10);\n\tf_puts(lbuf, &fp);\n\n\tf_puts(\"\\n\", &fp);\n\n\tif (ini_found)\n\t{\n\t\t// Re-construct existing entries.\n\t\tLIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)\n\t\t{\n\t\t\tif (!strcmp(ini_sec->name, \"config\"))\n\t\t\t\tcontinue;\n\n\t\t\tswitch (ini_sec->type)\n\t\t\t{\n\t\t\tcase INI_CHOICE: // Re-construct Boot entry [ ].\n\t\t\t\tf_puts(\"[\", &fp);\n\t\t\t\tf_puts(ini_sec->name, &fp);\n\t\t\t\tf_puts(\"]\\n\", &fp);\n\t\t\t\t// Re-construct boot entry's config.\n\t\t\t\tLIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)\n\t\t\t\t{\n\t\t\t\t\tf_puts(kv->key, &fp);\n\t\t\t\t\tf_puts(\"=\", &fp);\n\t\t\t\t\tf_puts(kv->val, &fp);\n\t\t\t\t\tf_puts(\"\\n\", &fp);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase INI_CAPTION: // Re-construct caption entry { }.\n\t\t\t\tf_puts(\"{\", &fp);\n\t\t\t\tf_puts(ini_sec->name, &fp);\n\t\t\t\tf_puts(\"}\\n\", &fp);\n\t\t\t\tbreak;\n\t\t\tcase INI_NEWLINE: // Re-construct cosmetic newline \\n.\n\t\t\t\tf_puts(\"\\n\", &fp);\n\t\t\t\tbreak;\n\t\t\tcase INI_COMMENT: // Re-construct comment entry #.\n\t\t\t\tf_puts(\"#\", &fp);\n\t\t\t\tf_puts(ini_sec->name, &fp);\n\t\t\t\tf_puts(\"\\n\", &fp);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tini_free(&ini_sections);\n\t}\n\n\tf_close(&fp);\n\n\treturn 0;\n}\n\nint create_nyx_config_entry(bool force_unmount)\n{\n\tbool sd_mounted = sd_get_card_mounted();\n\n\tif (sd_mount())\n\t\treturn 1;\n\n\tchar lbuf[64];\n\tFIL fp;\n\n\t// Make sure that bootloader folder exists.\n\tf_mkdir(\"bootloader\");\n\n\tif (f_open(&fp, \"bootloader/nyx.ini\", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)\n\t\treturn 1;\n\n\t// Add config entry.\n\tf_puts(\"[config]\\nthemebg=\", &fp);\n\titoa(n_cfg.theme_bg, lbuf, 16);\n\tf_puts(lbuf, &fp);\n\n\tf_puts(\"\\nthemecolor=\", &fp);\n\titoa(n_cfg.theme_color, lbuf, 10);\n\tf_puts(lbuf, &fp);\n\n\tf_puts(\"\\nentries5col=\", &fp);\n\titoa(n_cfg.entries_5_col, lbuf, 10);\n\tf_puts(lbuf, &fp);\n\n\tf_puts(\"\\ntimeoffset=\", &fp);\n\titoa(n_cfg.timeoffset, lbuf, 16);\n\tf_puts(lbuf, &fp);\n\n\tf_puts(\"\\ntimedst=\", &fp);\n\titoa(n_cfg.timedst, lbuf, 10);\n\tf_puts(lbuf, &fp);\n\n\tf_puts(\"\\nhomescreen=\", &fp);\n\titoa(n_cfg.home_screen, lbuf, 10);\n\tf_puts(lbuf, &fp);\n\n\tf_puts(\"\\nverification=\", &fp);\n\titoa(n_cfg.verification, lbuf, 10);\n\tf_puts(lbuf, &fp);\n\n\tf_puts(\"\\numsemmcrw=\", &fp);\n\titoa(n_cfg.ums_emmc_rw, lbuf, 10);\n\tf_puts(lbuf, &fp);\n\n\tf_puts(\"\\njcdisable=\", &fp);\n\titoa(n_cfg.jc_disable, lbuf, 10);\n\tf_puts(lbuf, &fp);\n\n\tf_puts(\"\\njcforceright=\", &fp);\n\titoa(n_cfg.jc_force_right, lbuf, 10);\n\tf_puts(lbuf, &fp);\n\n\tf_puts(\"\\nbpmpclock=\", &fp);\n\titoa(n_cfg.bpmp_clock, lbuf, 10);\n\tf_puts(lbuf, &fp);\n\n\tf_puts(\"\\n\", &fp);\n\n\tf_close(&fp);\n\n\tif (force_unmount || !sd_mounted)\n\t\tsd_unmount();\n\n\treturn 0;\n}\n"
  },
  {
    "path": "nyx/nyx_gui/config.h",
    "content": "/*\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _CONFIG_H_\n#define _CONFIG_H_\n\n#include <bdk.h>\n\n#include \"hos/hos.h\"\n\ntypedef struct _hekate_config\n{\n\t// Non-volatile config.\n\tu32 autoboot;\n\tu32 autoboot_list;\n\tu32 bootwait;\n\tu32 noticker;\n\tu32 backlight;\n\tu32 autohosoff;\n\tu32 autonogc;\n\tu32 updater2p;\n\tu32 bootprotect;\n\t// Global temporary config.\n\tbool t210b01;\n\tbool devmode;\n\tbool emummc_force_disable;\n\tbool rcm_patched;\n\tbool autorcm_enabled;\n\tu32  errors;\n\thos_eks_mbr_t *eks;\n} hekate_config;\n\ntypedef struct _nyx_config\n{\n\tu32 theme_bg; // COLOR_BG_BASE_MIN - COLOR_BG_BASE_MAX.\n\tu32 theme_color;\n\tu32 entries_5_col;\n\tu32 timeoffset;\n\tu32 timedst;\n\tu32 home_screen;\n\tu32 verification;\n\tu32 ums_emmc_rw;\n\tu32 jc_disable;\n\tu32 jc_force_right;\n\tu32 bpmp_clock;\n} nyx_config;\n\nextern hekate_config h_cfg;\nextern nyx_config n_cfg;\n\nvoid set_default_configuration();\nvoid set_nyx_default_configuration();\nint create_config_entry();\nint create_nyx_config_entry(bool force_unmount);\n\n#endif /* _CONFIG_H_ */\n"
  },
  {
    "path": "nyx/nyx_gui/frontend/fe_emmc_tools.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018 Rajko Stojadinovic\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n//! fix the dram stuff and the pop ups\n\n#include <string.h>\n#include <stdlib.h>\n\n#include <bdk.h>\n\n#include \"gui.h\"\n#include \"fe_emmc_tools.h\"\n#include \"fe_emummc_tools.h\"\n#include \"../config.h\"\n#include <libs/fatfs/ff.h>\n\n#define VERIF_STATUS_OK    0\n#define VERIF_STATUS_ERROR 1\n#define VERIF_STATUS_ABORT 2\n\n#define NUM_SECTORS_PER_ITER 8192 // 4MB Cache.\n#define OUT_FILENAME_SZ 128\n#define HASH_FILENAME_SZ (OUT_FILENAME_SZ + 11) // 11 == strlen(\".sha256sums\")\n\nextern nyx_config n_cfg;\n\nextern char *emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);\n\nstatic void _get_valid_partition(u32 *sector_start, u32 *sector_size, u32 *part_idx, bool backup)\n{\n\tsd_mount();\n\tmbr_t *mbr = (mbr_t *)zalloc(sizeof(mbr_t));\n\tsdmmc_storage_read(&sd_storage, 0, 1, mbr);\n\n\t*part_idx = 0;\n\tint i = 0;\n\tu32 curr_part_size = 0;\n\t// Find first partition with emuMMC GPP.\n\tfor (i = 1; i < 4; i++)\n\t{\n\t\tcurr_part_size = mbr->partitions[i].size_sct;\n\t\t*sector_start = mbr->partitions[i].start_sct;\n\t\tu8 type = mbr->partitions[i].type;\n\t\tu32 sector_size_safe = backup ? 0x400000 : (*sector_size) + 0x8000; // 2GB min safe size for backup.\n\t\tif ((curr_part_size >= sector_size_safe) && (*sector_start) && type != 0x83 && (!backup || type == 0xE0))\n\t\t{\n\t\t\tif (backup)\n\t\t\t{\n\t\t\t\tu8 gpt_check[SD_BLOCKSIZE] = { 0 };\n\t\t\t\tsdmmc_storage_read(&sd_storage, (*sector_start) + 0xC001, 1, gpt_check);\n\t\t\t\tif (!memcmp(gpt_check, \"EFI PART\", 8))\n\t\t\t\t{\n\t\t\t\t\t*sector_size = curr_part_size;\n\t\t\t\t\t*sector_start = (*sector_start) + 0x8000;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tsdmmc_storage_read(&sd_storage, (*sector_start) + 0x4001, 1, gpt_check);\n\t\t\t\tif (!memcmp(gpt_check, \"EFI PART\", 8))\n\t\t\t\t{\n\t\t\t\t\t*sector_size = curr_part_size;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t}\n\tfree(mbr);\n\n\tif (i < 4)\n\t\t*part_idx = i;\n\telse\n\t{\n\t\t*sector_start = 0;\n\t\t*sector_size = 0;\n\t\t*part_idx = 0;\n\t}\n\n\t// Get emuMMC GPP size.\n\tif (backup && *part_idx && *sector_size)\n\t{\n\t\tgpt_t *gpt = (gpt_t *)zalloc(sizeof(gpt_t));\n\t\tsdmmc_storage_read(&sd_storage, (*sector_start) + 0x4001, 1, gpt);\n\n\t\tu32 new_size = gpt->header.alt_lba + 1;\n\t\tif (*sector_size > new_size)\n\t\t\t*sector_size = new_size;\n\t\telse\n\t\t\t*sector_size = 0;\n\n\t\tfree(gpt);\n\t}\n\telse if (!backup && *part_idx)\n\t\t*sector_start = (*sector_start) + 0x8000;\n}\n\nstatic lv_obj_t *create_mbox_text(const char *text, bool button_ok)\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_map[] = { \"\\251\", \"\\222OK\", \"\\251\", \"\" };\n\tlv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);\n\n\tlv_mbox_set_text(mbox, text);\n\tif (button_ok)\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\treturn dark_bg;\n}\n\nstatic void _update_filename(char *outFilename, u32 sdPathLen, u32 currPartIdx)\n{\n\tif (currPartIdx < 10)\n\t{\n\t\toutFilename[sdPathLen] = '0';\n\t\titoa(currPartIdx, &outFilename[sdPathLen + 1], 10);\n\t}\n\telse\n\t\titoa(currPartIdx, &outFilename[sdPathLen], 10);\n}\n\nstatic int _emmc_sd_copy_verify(emmc_tool_gui_t *gui, sdmmc_storage_t *storage, u32 lba_curr, const char *outFilename, const emmc_part_t *part)\n{\n\tFIL fp;\n\tFIL hashFp;\n\tu8 sparseShouldVerify = 4;\n\tu32 prevPct = 200;\n\tu32 sdFileSector = 0;\n\tint res = 0;\n\tstatic const char hexa[] = \"0123456789abcdef\";\n\tDWORD *clmt = NULL;\n\n\tu8 hashEm[SE_SHA_256_SIZE];\n\tu8 hashSd[SE_SHA_256_SIZE];\n\n\tif (f_open(&fp, outFilename, FA_READ) == FR_OK)\n\t{\n\t\tif (n_cfg.verification == 3)\n\t\t{\n\t\t\tchar hashFilename[HASH_FILENAME_SZ];\n\t\t\tstrncpy(hashFilename, outFilename, OUT_FILENAME_SZ - 1);\n\t\t\tstrcat(hashFilename, \".sha256sums\");\n\n\t\t\tres = f_open(&hashFp, hashFilename, FA_CREATE_ALWAYS | FA_WRITE);\n\t\t\tif (res)\n\t\t\t{\n\t\t\t\tf_close(&fp);\n\n\t\t\t\ts_printf(gui->txt_buf,\n\t\t\t\t\t\t\"\\n#FF0000 Hash file could not be written (error %d)!#\\n\"\n\t\t\t\t\t\t\"#FF0000 Aborting..#\\n\", res);\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\treturn VERIF_STATUS_ERROR;\n\t\t\t}\n\n\t\t\tchar chunkSizeAscii[10];\n\t\t\titoa(NUM_SECTORS_PER_ITER * EMMC_BLOCKSIZE, chunkSizeAscii, 10);\n\t\t\tchunkSizeAscii[9] = '\\0';\n\n\t\t\tf_puts(\"# chunksize: \", &hashFp);\n\t\t\tf_puts(chunkSizeAscii, &hashFp);\n\t\t\tf_puts(\"\\n\", &hashFp);\n\t\t}\n\n\t\tu32 totalSectorsVer = (u32)((u64)f_size(&fp) >> (u64)9);\n\n\t\tu8 *bufEm = (u8 *)EMMC_BUF_ALIGNED;\n\t\tu8 *bufSd = (u8 *)SDXC_BUF_ALIGNED;\n\n\t\tu32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);\n\t\tlv_bar_set_value(gui->bar, pct);\n\t\tlv_bar_set_style(gui->bar, LV_BAR_STYLE_BG, gui->bar_teal_bg);\n\t\tlv_bar_set_style(gui->bar, LV_BAR_STYLE_INDIC, gui->bar_teal_ind);\n\t\ts_printf(gui->txt_buf, \" \"SYMBOL_DOT\" %d%%\", pct);\n\t\tlv_label_set_text(gui->label_pct, gui->txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\tclmt = f_expand_cltbl(&fp, SZ_4M, 0);\n\n\t\tu32 num = 0;\n\t\twhile (totalSectorsVer > 0)\n\t\t{\n\t\t\tnum = MIN(totalSectorsVer, NUM_SECTORS_PER_ITER);\n\n\t\t\t// Check every time or every 4.\n\t\t\t// Every 4 protects from fake sd, sector corruption and frequent I/O corruption.\n\t\t\t// Full provides all that, plus protection from extremely rare I/O corruption.\n\t\t\tif ((n_cfg.verification >= 2) || !(sparseShouldVerify % 4))\n\t\t\t{\n\t\t\t\tif (sdmmc_storage_read(storage, lba_curr, num, bufEm))\n\t\t\t\t{\n\t\t\t\t\ts_printf(gui->txt_buf,\n\t\t\t\t\t\t\"\\n#FF0000 Failed to read %d blocks (@LBA %08X),#\\n\"\n\t\t\t\t\t\t\"#FF0000 from eMMC! Verification failed..#\\n\",\n\t\t\t\t\t\tnum, lba_curr);\n\t\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\t\tfree(clmt);\n\t\t\t\t\tf_close(&fp);\n\t\t\t\t\tif (n_cfg.verification == 3)\n\t\t\t\t\t\tf_close(&hashFp);\n\n\t\t\t\t\treturn VERIF_STATUS_ERROR;\n\t\t\t\t}\n\t\t\t\tmanual_system_maintenance(false);\n\n\t\t\t\tse_sha_hash_256_async(hashEm, bufEm, num << 9);\n\n\t\t\t\tf_lseek(&fp, (u64)sdFileSector << (u64)9);\n\t\t\t\tif (f_read_fast(&fp, bufSd, num << 9))\n\t\t\t\t{\n\t\t\t\t\ts_printf(gui->txt_buf,\n\t\t\t\t\t\t\"\\n#FF0000 Failed to read %d blocks (@LBA %08X),#\\n\"\n\t\t\t\t\t\t\"#FF0000 from SD card! Verification failed..#\\n\",\n\t\t\t\t\t\tnum, lba_curr);\n\t\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\t\tfree(clmt);\n\t\t\t\t\tf_close(&fp);\n\t\t\t\t\tif (n_cfg.verification == 3)\n\t\t\t\t\t\tf_close(&hashFp);\n\n\t\t\t\t\treturn VERIF_STATUS_ERROR;\n\t\t\t\t}\n\t\t\t\tmanual_system_maintenance(false);\n\t\t\t\tse_sha_hash_256_finalize(hashEm);\n\t\t\t\tse_sha_hash_256_oneshot(hashSd, bufSd, num << 9);\n\t\t\t\tres = memcmp(hashEm, hashSd, SE_SHA_256_SIZE / 2);\n\n\t\t\t\tif (res)\n\t\t\t\t{\n\t\t\t\t\ts_printf(gui->txt_buf,\n\t\t\t\t\t\t\"\\n#FF0000 SD & eMMC data (@LBA %08X) do not match!#\\n\"\n\t\t\t\t\t\t\"\\n#FF0000 Verification failed..#\\n\",\n\t\t\t\t\t\tlba_curr);\n\t\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\t\tfree(clmt);\n\t\t\t\t\tf_close(&fp);\n\t\t\t\t\tif (n_cfg.verification == 3)\n\t\t\t\t\t\tf_close(&hashFp);\n\n\t\t\t\t\treturn VERIF_STATUS_ERROR;\n\t\t\t\t}\n\n\t\t\t\tif (n_cfg.verification == 3)\n\t\t\t\t{\n\t\t\t\t\t// Transform computed hash to readable hexadecimal\n\t\t\t\t\tchar hashStr[SE_SHA_256_SIZE * 2 + 1];\n\t\t\t\t\tchar *hashStrPtr = hashStr;\n\t\t\t\t\tfor (int i = 0; i < SE_SHA_256_SIZE; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\t*(hashStrPtr++) = hexa[hashSd[i] >> 4];\n\t\t\t\t\t\t*(hashStrPtr++) = hexa[hashSd[i] & 0x0F];\n\t\t\t\t\t}\n\t\t\t\t\thashStr[SE_SHA_256_SIZE * 2] = '\\0';\n\n\t\t\t\t\tf_puts(hashStr, &hashFp);\n\t\t\t\t\tf_puts(\"\\n\", &hashFp);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);\n\t\t\tif (pct != prevPct)\n\t\t\t{\n\t\t\t\tlv_bar_set_value(gui->bar, pct);\n\t\t\t\ts_printf(gui->txt_buf, \" \"SYMBOL_DOT\" %d%%\", pct);\n\t\t\t\tlv_label_set_text(gui->label_pct, gui->txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\t\t\t\tprevPct = pct;\n\t\t\t}\n\n\t\t\tmanual_system_maintenance(false);\n\n\t\t\tlba_curr += num;\n\t\t\ttotalSectorsVer -= num;\n\t\t\tsdFileSector += num;\n\t\t\tsparseShouldVerify++;\n\n\t\t\t// Check for cancellation combo.\n\t\t\tif (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))\n\t\t\t{\n\t\t\t\tstrcpy(gui->txt_buf, \"#FFDD00 Verification was cancelled!#\\n\");\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\tmsleep(1000);\n\n\t\t\t\tfree(clmt);\n\t\t\t\tf_close(&fp);\n\t\t\t\tf_close(&hashFp);\n\n\t\t\t\treturn VERIF_STATUS_ABORT;\n\t\t\t}\n\t\t}\n\t\tfree(clmt);\n\t\tf_close(&fp);\n\t\tf_close(&hashFp);\n\n\t\tlv_bar_set_value(gui->bar, pct);\n\t\ts_printf(gui->txt_buf, \" \"SYMBOL_DOT\" %d%%\", pct);\n\t\tlv_label_set_text(gui->label_pct, gui->txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\treturn VERIF_STATUS_OK;\n\t}\n\telse\n\t{\n\t\tstrcpy(gui->txt_buf, \"\\n#FFDD00 File not found or could not be loaded!#\\n#FFDD00 Verification failed..#\\n\");\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\treturn VERIF_STATUS_ERROR;\n\t}\n}\n\nbool partial_sd_full_unmount = false;\n\nstatic int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_part, sdmmc_storage_t *storage, emmc_part_t *part)\n{\n\tstatic const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF;\n\tstatic const u32 SECTORS_TO_MIB_COEFF = 11;\n\n\tpartial_sd_full_unmount = false;\n\n\tu32 verification = n_cfg.verification;\n\tu32 multipartSplitSize = (1u << 31);\n\tu32 lba_end = part->lba_end;\n\tu32 totalSectors = part->lba_end - part->lba_start + 1;\n\tu32 currPartIdx = 0;\n\tu32 numSplitParts = 0;\n\tu32 maxSplitParts = 0;\n\tbool isSmallSdCard = false;\n\tbool partialDumpInProgress = false;\n\tint res = 0;\n\tchar *outFilename = sd_path;\n\tu32 sdPathLen = strlen(sd_path);\n\n\tu32 sector_start = 0, part_idx = 0;\n\tu32 sector_size = totalSectors;\n\tu32 sd_sector_off = 0;\n\n\tFIL partialIdxFp;\n\tchar partialIdxFilename[12];\n\tstrcpy(partialIdxFilename, \"partial.idx\");\n\n\tif (gui->raw_emummc)\n\t{\n\t\t_get_valid_partition(&sector_start, &sector_size, &part_idx, true);\n\t\tif (!part_idx || !sector_size)\n\t\t{\n\t\t\tstrcpy(gui->txt_buf, \"\\n#FFDD00 Failed to find a partition...#\\n\");\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\treturn 1;\n\t\t}\n\t\tsd_sector_off = sector_start + (0x2000 * active_part);\n\t\tif (active_part == 2)\n\t\t{\n\t\t\t// Set new total sectors and lba end sector for percentage calculations.\n\t\t\ttotalSectors = sector_size;\n\t\t\tlba_end = sector_size + part->lba_start - 1;\n\t\t}\n\t}\n\n\ts_printf(gui->txt_buf, \"#96FF00 SD Card free space:# %d MiB\\n#96FF00 Total backup size:# %d MiB\\n\\n\",\n\t\t(u32)(sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF),\n\t\ttotalSectors >> SECTORS_TO_MIB_COEFF);\n\tlv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);\n\tmanual_system_maintenance(true);\n\n\tlv_bar_set_value(gui->bar, 0);\n\tlv_label_set_text(gui->label_pct, \" \"SYMBOL_DOT\" 0%\");\n\tlv_bar_set_style(gui->bar, LV_BAR_STYLE_BG, gui->bar_white_bg);\n\tlv_bar_set_style(gui->bar, LV_BAR_STYLE_INDIC, gui->bar_white_ind);\n\tmanual_system_maintenance(true);\n\n\t// 1GB parts for sd cards 8GB and less.\n\tif ((sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits)) <= 8192)\n\t\tmultipartSplitSize = (1u << 30);\n\t// Maximum parts fitting the free space available.\n\tmaxSplitParts = (sd_fs.free_clst * sd_fs.csize) / (multipartSplitSize / EMMC_BLOCKSIZE);\n\n\t// Check if the USER partition or the RAW eMMC fits the sd card free space.\n\tif (totalSectors > (sd_fs.free_clst * sd_fs.csize))\n\t{\n\t\tisSmallSdCard = true;\n\n\t\tstrcpy(gui->txt_buf, \"\\n#FFBA00 Free space is smaller than backup size.#\\n\");\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\tif (!maxSplitParts)\n\t\t{\n\t\t\tstrcpy(gui->txt_buf, \"#FFDD00 Not enough free space for Partial Backup!#\\n\");\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\treturn 1;\n\t\t}\n\t}\n\t// Check if we are continuing a previous raw eMMC or USER partition backup in progress.\n\tif (f_open(&partialIdxFp, partialIdxFilename, FA_READ) == FR_OK && totalSectors > (FAT32_FILESIZE_LIMIT / EMMC_BLOCKSIZE))\n\t{\n\t\tstrcpy(gui->txt_buf, \"\\n#AEFD14 Partial Backup in progress. Continuing...#\\n\");\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\tpartialDumpInProgress = true;\n\t\t// Force partial dumping, even if the card is larger.\n\t\tisSmallSdCard = true;\n\n\t\tf_read(&partialIdxFp, &currPartIdx, 4, NULL);\n\t\tf_close(&partialIdxFp);\n\n\t\tif (!maxSplitParts)\n\t\t{\n\t\t\tstrcpy(gui->txt_buf, \"\\n#FFDD00 Not enough free space for Partial Backup!#\\n\");\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\treturn 1;\n\t\t}\n\n\t\t// Increase maxSplitParts to accommodate previously backed up parts.\n\t\tmaxSplitParts += currPartIdx;\n\t}\n\telse if (isSmallSdCard)\n\t{\n\t\ts_printf(gui->txt_buf, \"\\n#FFBA00 Partial Backup enabled (%d MiB parts)...#\\n\", multipartSplitSize >> 20);\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\tmanual_system_maintenance(true);\n\t}\n\n\t// Check if filesystem is FAT32 or the free space is smaller and backup in parts.\n\tif (((sd_fs.fs_type != FS_EXFAT) && totalSectors > (FAT32_FILESIZE_LIMIT / EMMC_BLOCKSIZE)) || isSmallSdCard)\n\t{\n\t\tu32 multipartSplitSectors = multipartSplitSize / EMMC_BLOCKSIZE;\n\t\tnumSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors;\n\n\t\toutFilename[sdPathLen++] = '.';\n\n\t\t// Continue from where we left, if Partial Backup in progress.\n\t\t_update_filename(outFilename, sdPathLen, partialDumpInProgress ? currPartIdx : 0);\n\t}\n\n\tFIL fp;\n\tif (!f_open(&fp, outFilename, FA_READ))\n\t{\n\t\tf_close(&fp);\n\n\t\tlv_obj_t *warn_mbox_bg = create_mbox_text(\n\t\t\t\"#FFDD00 An existing backup has been detected!#\\n\\n\"\n\t\t\t\"Press #FF8000 POWER# to Continue.\\nPress #FF8000 VOL# to abort.\", false);\n\t\tmanual_system_maintenance(true);\n\n\t\tif (!(btn_wait() & BTN_POWER))\n\t\t{\n\t\t\tlv_obj_del(warn_mbox_bg);\n\t\t\treturn 1;\n\t\t}\n\t\tlv_obj_del(warn_mbox_bg);\n\t}\n\n\ts_printf(gui->txt_buf, \"#96FF00 Filepath:#\\n%s\\n#96FF00 Filename:# #FF8000 %s#\",\n\t\tgui->base_path, outFilename + strlen(gui->base_path));\n\tlv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);\n\tmanual_system_maintenance(true);\n\n\tres = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);\n\tif (res)\n\t{\n\t\ts_printf(gui->txt_buf, \"\\n#FF0000 Error (%d) while creating#\\n#FFDD00 %s#\\n\", res, outFilename);\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\treturn 1;\n\t}\n\n\tu8 *buf = (u8 *)MIXD_BUF_ALIGNED;\n\n\tu32 lba_curr = part->lba_start;\n\tu32 lbaStartPart = part->lba_start;\n\tu32 bytesWritten = 0;\n\tu32 prevPct = 200;\n\tint retryCount = 0;\n\tDWORD *clmt = NULL;\n\n\t// Continue from where we left, if Partial Backup in progress.\n\tif (partialDumpInProgress)\n\t{\n\t\tlba_curr += currPartIdx * (multipartSplitSize / EMMC_BLOCKSIZE);\n\t\ttotalSectors -= currPartIdx * (multipartSplitSize / EMMC_BLOCKSIZE);\n\t\tlbaStartPart = lba_curr; // Update the start LBA for verification.\n\t}\n\tu64 totalSize = (u64)((u64)totalSectors << 9);\n\tif (!isSmallSdCard && (sd_fs.fs_type == FS_EXFAT || totalSize <= FAT32_FILESIZE_LIMIT))\n\t\tclmt = f_expand_cltbl(&fp, SZ_4M, totalSize);\n\telse\n\t\tclmt = f_expand_cltbl(&fp, SZ_4M, MIN(totalSize, multipartSplitSize));\n\n\tu32 num = 0;\n\tu32 pct = 0;\n\n\tlv_obj_set_opa_scale(gui->bar, LV_OPA_COVER);\n\tlv_obj_set_opa_scale(gui->label_pct, LV_OPA_COVER);\n\twhile (totalSectors > 0)\n\t{\n\t\tif (numSplitParts != 0 && bytesWritten >= multipartSplitSize)\n\t\t{\n\t\t\tf_close(&fp);\n\t\t\tfree(clmt);\n\t\t\tmemset(&fp, 0, sizeof(fp));\n\t\t\tcurrPartIdx++;\n\n\t\t\tif (verification && !gui->raw_emummc)\n\t\t\t{\n\t\t\t\t// Verify part.\n\t\t\t\tres = _emmc_sd_copy_verify(gui, storage, lbaStartPart, outFilename, part);\n\t\t\t\tswitch (res)\n\t\t\t\t{\n\t\t\t\tcase VERIF_STATUS_OK:\n\t\t\t\t\tbreak;\n\t\t\t\tcase VERIF_STATUS_ERROR:\n\t\t\t\t\tstrcpy(gui->txt_buf, \"\\n#FFDD00 Please try again...#\\n\");\n\t\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\t\tmanual_system_maintenance(true);\n\t\t\t\t\treturn 1;\n\t\t\t\tcase VERIF_STATUS_ABORT:\n\t\t\t\t\tverification = 0;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tlv_bar_set_style(gui->bar, LV_BAR_STYLE_BG, gui->bar_white_bg);\n\t\t\t\tlv_bar_set_style(gui->bar, LV_BAR_STYLE_INDIC, gui->bar_white_ind);\n\t\t\t}\n\n\t\t\t_update_filename(outFilename, sdPathLen, currPartIdx);\n\n\t\t\t// Always create partial.idx before next part, in case a fatal error occurs.\n\t\t\tif (isSmallSdCard)\n\t\t\t{\n\t\t\t\t// Create partial backup index file.\n\t\t\t\tif (f_open(&partialIdxFp, partialIdxFilename, FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)\n\t\t\t\t{\n\t\t\t\t\tf_write(&partialIdxFp, &currPartIdx, 4, NULL);\n\t\t\t\t\tf_close(&partialIdxFp);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tstrcpy(gui->txt_buf, \"\\n#FF0000 Error creating partial.idx file!#\\n\");\n\t\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\n\t\t\t\t// More parts to backup that do not currently fit the sd card free space or fatal error.\n\t\t\t\tif (currPartIdx >= maxSplitParts)\n\t\t\t\t{\n\t\t\t\t\tcreate_mbox_text(\n\t\t\t\t\t\t\"#96FF00 Partial Backup in progress!#\\n\\n\"\n\t\t\t\t\t\t\"#96FF00 1.# Press OK to unmount SD Card.\\n\"\n\t\t\t\t\t\t\"#96FF00 2.# Remove SD Card and move files to free space.\\n\"\n\t\t\t\t\t\t\"#FFDD00 Don\\'t move the partial.idx file!#\\n\"\n\t\t\t\t\t\t\"#96FF00 3.# Re-insert SD Card.\\n\"\n\t\t\t\t\t\t\"#96FF00 4.# Select the SAME option again to continue.\", true);\n\n\t\t\t\t\tpartial_sd_full_unmount = true;\n\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Create next part.\n\t\t\ts_printf(gui->txt_buf, \"%s#\", outFilename + strlen(gui->base_path));\n\t\t\tlv_label_cut_text(gui->label_info,\n\t\t\t\tstrlen(lv_label_get_text(gui->label_info)) - strlen(outFilename + strlen(gui->base_path)) - 1,\n\t\t\t\tstrlen(outFilename + strlen(gui->base_path)) + 1);\n\t\t\tlv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\t\t\tlbaStartPart = lba_curr;\n\t\t\tres = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);\n\t\t\tif (res)\n\t\t\t{\n\t\t\t\ts_printf(gui->txt_buf, \"\\n#FF0000 Error (%d) while creating#\\n#FFDD00 %s#\\n\", res, outFilename);\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tbytesWritten = 0;\n\n\t\t\ttotalSize = (u64)((u64)totalSectors << 9);\n\t\t\tclmt = f_expand_cltbl(&fp, SZ_4M, MIN(totalSize, multipartSplitSize));\n\t\t}\n\n\t\tretryCount = 0;\n\t\tnum = MIN(totalSectors, NUM_SECTORS_PER_ITER);\n\n\t\tint res_read;\n\t\tif (!gui->raw_emummc)\n\t\t\tres_read = sdmmc_storage_read(storage, lba_curr, num, buf);\n\t\telse\n\t\t\tres_read = sdmmc_storage_read(&sd_storage, lba_curr + sd_sector_off, num, buf);\n\n\t\twhile (res_read)\n\t\t{\n\t\t\tif (!gui->raw_emummc)\n\t\t\t{\n\t\t\t\ts_printf(gui->txt_buf,\n\t\t\t\t\t\"\\n#FFDD00 Error reading %d blocks @ LBA %08X,#\\n\"\n\t\t\t\t\t\"#FFDD00 from eMMC (try %d). #\",\n\t\t\t\t\tnum, lba_curr, ++retryCount);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ts_printf(gui->txt_buf,\n\t\t\t\t\t\"\\n#FFDD00 Error reading %d blocks @ LBA %08X,#\\n\"\n\t\t\t\t\t\"#FFDD00 from emuMMC @ %08X (try %d). #\",\n\t\t\t\t\tnum, lba_curr + sd_sector_off, lba_curr, ++retryCount);\n\t\t\t}\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tmsleep(150);\n\t\t\tif (retryCount >= 3)\n\t\t\t{\n\t\t\t\tstrcpy(gui->txt_buf, \"#FF0000 Aborting...#\\nPlease try again...\\n\");\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\tf_close(&fp);\n\t\t\t\tfree(clmt);\n\t\t\t\tf_unlink(outFilename);\n\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstrcpy(gui->txt_buf, \"#FFDD00 Retrying...#\\n\");\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\t\t\t}\n\n\t\t\tif (!gui->raw_emummc)\n\t\t\t\tres_read = sdmmc_storage_read(storage, lba_curr, num, buf);\n\t\t\telse\n\t\t\t\tres_read = sdmmc_storage_read(&sd_storage, lba_curr + sd_sector_off, num, buf);\n\t\t\tmanual_system_maintenance(false);\n\t\t}\n\n\t\tres = f_write_fast(&fp, buf, EMMC_BLOCKSIZE * num);\n\n\t\tif (res)\n\t\t{\n\t\t\ts_printf(gui->txt_buf, \"\\n#FF0000 Fatal error (%d) when writing to SD Card#\\nPlease try again...\\n\", res);\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tf_close(&fp);\n\t\t\tfree(clmt);\n\t\t\tf_unlink(outFilename);\n\n\t\t\treturn 1;\n\t\t}\n\n\t\tmanual_system_maintenance(false);\n\n\t\tpct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(lba_end - part->lba_start);\n\t\tif (pct != prevPct)\n\t\t{\n\t\t\tlv_bar_set_value(gui->bar, pct);\n\t\t\ts_printf(gui->txt_buf, \" \"SYMBOL_DOT\" %d%%\", pct);\n\t\t\tlv_label_set_text(gui->label_pct, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\t\t\tprevPct = pct;\n\t\t}\n\n\t\tlba_curr += num;\n\t\ttotalSectors -= num;\n\t\tbytesWritten += num * EMMC_BLOCKSIZE;\n\n\t\t// Force a flush after a lot of data if not splitting.\n\t\tif (numSplitParts == 0 && bytesWritten >= multipartSplitSize)\n\t\t{\n\t\t\tf_sync(&fp);\n\t\t\tbytesWritten = 0;\n\t\t}\n\n\t\t// Check for cancellation combo.\n\t\tif (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))\n\t\t{\n\t\t\tstrcpy(gui->txt_buf, \"\\n#FFDD00 The backup was cancelled!#\\n\");\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tmsleep(1500);\n\n\t\t\tf_close(&fp);\n\t\t\tfree(clmt);\n\t\t\tf_unlink(outFilename);\n\n\t\t\treturn 1;\n\t\t}\n\t}\n\tlv_bar_set_value(gui->bar, 100);\n\tlv_label_set_text(gui->label_pct, \" \"SYMBOL_DOT\" 100%\");\n\tmanual_system_maintenance(true);\n\n\t// Backup operation ended successfully.\n\tf_close(&fp);\n\tfree(clmt);\n\n\tif (verification && !gui->raw_emummc)\n\t{\n\t\t// Verify last part or single file backup.\n\t\tif (_emmc_sd_copy_verify(gui, storage, lbaStartPart, outFilename, part) == VERIF_STATUS_ERROR)\n\t\t{\n\t\t\tstrcpy(gui->txt_buf, \"\\n#FFDD00 Please try again...#\\n\");\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\treturn 1;\n\t\t}\n\t\tlv_bar_set_value(gui->bar, 100);\n\t\tlv_label_set_text(gui->label_pct, \" \"SYMBOL_DOT\" 100%\");\n\t\tmanual_system_maintenance(true);\n\t}\n\n\t// Remove partial backup index file if no fatal errors occurred.\n\tif (isSmallSdCard)\n\t{\n\t\tf_unlink(partialIdxFilename);\n\n\t\tcreate_mbox_text(\n\t\t\t\"#96FF00 Partial Backup done!#\\n\\n\"\n\t\t\t\"You can now join the files if needed\\nand get the complete eMMC RAW GPP backup.\", true);\n\n\t\tpartial_sd_full_unmount = true;\n\t}\n\n\treturn 0;\n}\n\nvoid dump_emmc_selected(emmcPartType_t dumpType, emmc_tool_gui_t *gui)\n{\n\tint res = 1;\n\tu32 timer = 0;\n\n\tchar *txt_buf = (char *)malloc(SZ_16K);\n\tgui->txt_buf = txt_buf;\n\n\ttxt_buf[0] = 0;\n\tlv_label_set_text(gui->label_log, txt_buf);\n\n\tlv_label_set_text(gui->label_info, \"Checking for available free space...\");\n\tmanual_system_maintenance(true);\n\n\tif (sd_mount())\n\t{\n\t\tlv_label_set_text(gui->label_info, \"#FFDD00 Failed to init SD!#\");\n\t\tgoto out;\n\t}\n\n\t// Get SD Card free space for Partial Backup.\n\tf_getfree(\"\", &sd_fs.free_clst, NULL);\n\n\tif (emmc_initialize(false))\n\t{\n\t\tlv_label_set_text(gui->label_info, \"#FFDD00 Failed to init eMMC!#\");\n\t\tgoto out;\n\t}\n\n\tint i = 0;\n\tchar sdPath[OUT_FILENAME_SZ];\n\t// Create Restore folders, if they do not exist.\n\temmcsn_path_impl(sdPath, \"/restore\", \"\", &emmc_storage);\n\temmcsn_path_impl(sdPath, \"/restore/emummc\", \"\", &emmc_storage);\n\temmcsn_path_impl(sdPath, \"/restore/partitions\", \"\", &emmc_storage);\n\n\t// Set folder to backup/{emmc_sn}.\n\temmcsn_path_impl(sdPath, \"\", \"\", &emmc_storage);\n\tgui->base_path = (char *)malloc(strlen(sdPath) + 1);\n\tstrcpy(gui->base_path, sdPath);\n\n\ttimer = get_tmr_s();\n\tif (dumpType & PART_BOOT)\n\t{\n\t\tconst u32 BOOT_PART_SIZE = emmc_storage.ext_csd.boot_mult << 17;\n\t\tconst u32 BOOT_PART_SECTORS = 0x2000; // Force 4 MiB for emuMMC.\n\n\t\temmc_part_t bootPart;\n\t\tmemset(&bootPart, 0, sizeof(bootPart));\n\t\tbootPart.lba_start = 0;\n\t\tif (!gui->raw_emummc)\n\t\t\tbootPart.lba_end = (BOOT_PART_SIZE / EMMC_BLOCKSIZE) - 1;\n\t\telse\n\t\t\tbootPart.lba_end = BOOT_PART_SECTORS - 1;\n\t\tfor (i = 0; i < 2; i++)\n\t\t{\n\t\t\tstrcpy(bootPart.name, \"BOOT\");\n\t\t\tbootPart.name[4] = (u8)('0' + i);\n\t\t\tbootPart.name[5] = 0;\n\n\t\t\ts_printf(txt_buf, \"#00DDFF %02d: %s#\\n#00DDFF Range: 0x%08X - 0x%08X#\\n\\n\",\n\t\t\t\ti, bootPart.name, bootPart.lba_start, bootPart.lba_end);\n\t\t\tlv_label_set_text(gui->label_info, txt_buf);\n\t\t\ts_printf(txt_buf, \"%02d: %s... \", i, bootPart.name);\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\temmc_set_partition(i + 1);\n\n\t\t\t// Set filename to backup/{emmc_sn}/BOOT0/1 or backup/{emmc_sn}/emummc/BOOT0/1.\n\t\t\tif (!gui->raw_emummc)\n\t\t\t\temmcsn_path_impl(sdPath, \"\",        bootPart.name, &emmc_storage);\n\t\t\telse\n\t\t\t\temmcsn_path_impl(sdPath, \"/emummc\", bootPart.name, &emmc_storage);\n\n\t\t\tres = _dump_emmc_part(gui, sdPath, i, &emmc_storage, &bootPart);\n\n\t\t\tif (res)\n\t\t\t\tstrcpy(txt_buf, \"#FFDD00 Failed!#\\n\");\n\t\t\telse\n\t\t\t\tstrcpy(txt_buf, \"Done!\\n\");\n\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\t\t}\n\t}\n\n\tif ((dumpType & PART_SYSTEM) || (dumpType & PART_USER) || (dumpType & PART_RAW))\n\t{\n\t\temmc_set_partition(EMMC_GPP);\n\n\t\tif ((dumpType & PART_SYSTEM) || (dumpType & PART_USER))\n\t\t{\n\t\t\temmcsn_path_impl(sdPath, \"/partitions\", \"\", &emmc_storage);\n\t\t\tgui->base_path = (char *)malloc(strlen(sdPath) + 1);\n\t\t\tstrcpy(gui->base_path, sdPath);\n\n\t\t\tLIST_INIT(gpt);\n\t\t\temmc_gpt_parse(&gpt);\n\t\t\tLIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)\n\t\t\t{\n\t\t\t\tif ((dumpType & PART_USER) == 0 && !strcmp(part->name, \"USER\"))\n\t\t\t\t\tcontinue;\n\t\t\t\tif ((dumpType & PART_SYSTEM) == 0 && strcmp(part->name, \"USER\"))\n\t\t\t\t\tcontinue;\n\n\t\t\t\ts_printf(txt_buf, \"#00DDFF %02d: %s#\\n#00DDFF Range: 0x%08X - 0x%08X#\\n\\n\",\n\t\t\t\t\ti, part->name, part->lba_start, part->lba_end);\n\t\t\t\tlv_label_set_text(gui->label_info, txt_buf);\n\t\t\t\ts_printf(txt_buf, \"%02d: %s... \", i, part->name);\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\t\t\t\ti++;\n\n\t\t\t\temmcsn_path_impl(sdPath, \"/partitions\", part->name, &emmc_storage);\n\t\t\t\tres = _dump_emmc_part(gui, sdPath, 0, &emmc_storage, part);\n\t\t\t\t// If a part failed, don't continue.\n\t\t\t\tif (res)\n\t\t\t\t{\n\t\t\t\t\tstrcpy(txt_buf, \"#FFDD00 Failed!#\\n\");\n\t\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tstrcpy(txt_buf, \"Done!\\n\");\n\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\t\t\t}\n\t\t\temmc_gpt_free(&gpt);\n\t\t}\n\n\t\tif (dumpType & PART_RAW)\n\t\t{\n\t\t\t// Get GP partition size dynamically.\n\t\t\tconst u32 RAW_AREA_NUM_SECTORS = emmc_storage.sec_cnt;\n\n\t\t\temmc_part_t rawPart;\n\t\t\tmemset(&rawPart, 0, sizeof(rawPart));\n\t\t\trawPart.lba_start = 0;\n\t\t\trawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;\n\t\t\tstrcpy(rawPart.name, \"rawnand.bin\");\n\t\t\t{\n\t\t\t\ts_printf(txt_buf, \"#00DDFF %02d: %s#\\n#00DDFF Range: 0x%08X - 0x%08X#\\n\\n\",\n\t\t\t\t\ti, rawPart.name, rawPart.lba_start, rawPart.lba_end);\n\t\t\t\tlv_label_set_text(gui->label_info, txt_buf);\n\t\t\t\ts_printf(txt_buf, \"%02d: %s... \", i, rawPart.name);\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\ti++;\n\n\t\t\t\t// Set filename to backup/{emmc_sn}/rawnand.bin or backup/{emmc_sn}/emummc/rawnand.bin.\n\t\t\t\tif (!gui->raw_emummc)\n\t\t\t\t\temmcsn_path_impl(sdPath, \"\",        rawPart.name, &emmc_storage);\n\t\t\t\telse\n\t\t\t\t\temmcsn_path_impl(sdPath, \"/emummc\", rawPart.name, &emmc_storage);\n\n\t\t\t\tres = _dump_emmc_part(gui, sdPath, 2, &emmc_storage, &rawPart);\n\n\t\t\t\tif (res)\n\t\t\t\t\tstrcpy(txt_buf, \"#FFDD00 Failed!#\\n\");\n\t\t\t\telse\n\t\t\t\t\tstrcpy(txt_buf, \"Done!\\n\");\n\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\t\t\t}\n\t\t}\n\t}\n\n\ttimer = get_tmr_s() - timer;\n\temmc_end();\n\n\tif (!res && n_cfg.verification && !gui->raw_emummc)\n\t\ts_printf(txt_buf, \"Time taken: %dm %ds.\\n#96FF00 Finished and verified!#\", timer / 60, timer % 60);\n\telse if (!res)\n\t\ts_printf(txt_buf, \"Time taken: %dm %ds.\\nFinished!\", timer / 60, timer % 60);\n\telse\n\t\ts_printf(txt_buf, \"Time taken: %dm %ds.\", timer / 60, timer % 60);\n\n\tlv_label_set_text(gui->label_finish, txt_buf);\n\nout:\n\tfree(txt_buf);\n\tfree(gui->base_path);\n\tif (!partial_sd_full_unmount)\n\t\tsd_unmount();\n\telse\n\t{\n\t\tpartial_sd_full_unmount = false;\n\t\tsd_end();\n\t}\n}\n\nstatic int _restore_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_part, sdmmc_storage_t *storage, emmc_part_t *part, bool allow_multi_part)\n{\n\tstatic const u32 SECTORS_TO_MIB_COEFF = 11;\n\n\tu32 verification = n_cfg.verification;\n\tu32 lba_end = part->lba_end;\n\tu32 totalSectors = part->lba_end - part->lba_start + 1;\n\tu32 currPartIdx = 0;\n\tu32 numSplitParts = 0;\n\tu32 lbaStartPart = part->lba_start;\n\tint res = 0;\n\tchar *outFilename = sd_path;\n\tu32 sdPathLen = strlen(sd_path);\n\tu64 fileSize = 0;\n\tu64 totalCheckFileSize = 0;\n\n\tFIL fp;\n\tFILINFO fno;\n\n\tlv_bar_set_value(gui->bar, 0);\n\tlv_label_set_text(gui->label_pct, \" \"SYMBOL_DOT\" 0%\");\n\tlv_bar_set_style(gui->bar, LV_BAR_STYLE_BG, gui->bar_orange_bg);\n\tlv_bar_set_style(gui->bar, LV_BAR_STYLE_INDIC, gui->bar_orange_ind);\n\tmanual_system_maintenance(true);\n\n\tbool use_multipart = false;\n\tbool check_4MB_aligned = true;\n\n\tif (!allow_multi_part)\n\t\tgoto multipart_not_allowed;\n\n\t// Check to see if there is a combined file and if so then use that.\n\tif (f_stat(outFilename, &fno))\n\t{\n\t\t// If not, check if there are partial files and the total size matches.\n\t\tstrcpy(gui->txt_buf, \"\\nNo single file, checking for part files...\\n\");\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\toutFilename[sdPathLen++] = '.';\n\n\t\t_update_filename(outFilename, sdPathLen, numSplitParts);\n\n\t\ts_printf(gui->txt_buf, \"#96FF00 Filepath:#\\n%s\\n#96FF00 Filename:# #FF8000 %s#\",\n\t\t\tgui->base_path, outFilename + strlen(gui->base_path));\n\t\tlv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);\n\n\t\t// Stat total size of the part files.\n\t\twhile ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors)\n\t\t{\n\t\t\t_update_filename(outFilename, sdPathLen, numSplitParts);\n\n\t\t\ts_printf(gui->txt_buf, \"%s#\", outFilename + strlen(gui->base_path));\n\t\t\tlv_label_cut_text(gui->label_info,\n\t\t\t\tstrlen(lv_label_get_text(gui->label_info)) - strlen(outFilename + strlen(gui->base_path)) - 1,\n\t\t\t\tstrlen(outFilename + strlen(gui->base_path)) + 1);\n\t\t\tlv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tif ((u32)((u64)totalCheckFileSize >> (u64)9) > totalSectors)\n\t\t\t{\n\t\t\t\tstrcpy(gui->txt_buf, \"\\n#FF8000 Size of SD Card split backup exceeds#\\n#FF8000 eMMC's selected part size!#\\n#FFDD00 Aborting...#\");\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\telse if (f_stat(outFilename, &fno))\n\t\t\t{\n\t\t\t\tif (!gui->raw_emummc)\n\t\t\t\t{\n\t\t\t\t\ts_printf(gui->txt_buf, \"\\n#FFDD00 Error file not found#\\n#FFDD00 %s.#\\n\\n\", outFilename);\n\t\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\t\t// Attempt a smaller restore.\n\t\t\t\t\tif (numSplitParts)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Set new total sectors and lba end sector for percentage calculations.\n\t\t\t\t\ttotalSectors = (u32)((u64)totalCheckFileSize >> (u64)9);\n\t\t\t\t\tpart->lba_end = totalSectors + part->lba_start - 1;\n\t\t\t\t\tlba_end = part->lba_end;\n\t\t\t\t}\n\n\t\t\t\t// Restore folder is empty.\n\t\t\t\tif (!numSplitParts)\n\t\t\t\t{\n\t\t\t\t\tstrcpy(gui->txt_buf, \"\\n#FFDD00 Restore folder is empty.#\\n\\n\");\n\t\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttotalCheckFileSize += (u64)fno.fsize;\n\n\t\t\t\tif (check_4MB_aligned && (((u64)fno.fsize) % SZ_4M))\n\t\t\t\t{\n\t\t\t\t\tstrcpy(gui->txt_buf, \"\\n#FFDD00 The split file must be a#\\n#FFDD00 multiple of 4 MiB.#\\n#FFDD00 Aborting...#\");\n\t\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\n\t\t\t\tcheck_4MB_aligned = false;\n\t\t\t}\n\n\t\t\tnumSplitParts++;\n\t\t}\n\n\t\ts_printf(gui->txt_buf, \"%X sectors total.\\n\", (u32)((u64)totalCheckFileSize >> (u64)9));\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\tif ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors)\n\t\t{\n\t\t\tlv_obj_t *warn_mbox_bg = create_mbox_text(\n\t\t\t\t\"#FF8000 Size of SD Card split backup does not match#\\n#FF8000 eMMC's selected part size!#\\n\\n\"\n\t\t\t\t\"#FFDD00 The backup might be corrupted,#\\n#FFDD00 or missing files!#\\n#FFDD00 Aborting is suggested!#\\n\\n\"\n\t\t\t\t\"Press #FF8000 POWER# to Continue.\\nPress #FF8000 VOL# to abort.\", false);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tif (!(btn_wait() & BTN_POWER))\n\t\t\t{\n\t\t\t\tlv_obj_del(warn_mbox_bg);\n\t\t\t\tstrcpy(gui->txt_buf, \"\\n#FF0000 Size of SD Card split backup does not match#\\n#FF0000 eMMC's selected part size!#\\n\");\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tlv_obj_del(warn_mbox_bg);\n\n\t\t\t// Set new total sectors and lba end sector for percentage calculations.\n\t\t\ttotalSectors = (u32)((u64)totalCheckFileSize >> (u64)9);\n\t\t\tpart->lba_end = totalSectors + part->lba_start - 1;\n\t\t\tlba_end = part->lba_end;\n\t\t}\n\t\tuse_multipart = true;\n\t\t_update_filename(outFilename, sdPathLen, 0);\n\t}\n\nmultipart_not_allowed:\n\tres = f_open(&fp, outFilename, FA_READ);\n\tif (use_multipart)\n\t{\n\t\ts_printf(gui->txt_buf, \"%s#\", outFilename + strlen(gui->base_path));\n\t\tlv_label_cut_text(gui->label_info,\n\t\t\tstrlen(lv_label_get_text(gui->label_info)) - strlen(outFilename + strlen(gui->base_path)) - 1,\n\t\t\tstrlen(outFilename + strlen(gui->base_path)) + 1);\n\t\tlv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\tmanual_system_maintenance(true);\n\t}\n\telse\n\t{\n\t\ts_printf(gui->txt_buf, \"#96FF00 Filepath:#\\n%s\\n#96FF00 Filename:# #FF8000 %s#\",\n\t\t\tgui->base_path, outFilename + strlen(gui->base_path));\n\t\t\tlv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);\n\t}\n\tmanual_system_maintenance(true);\n\tif (res)\n\t{\n\t\tif (res != FR_NO_FILE)\n\t\t{\n\t\t\ts_printf(gui->txt_buf, \"\\n#FF0000 Error (%d) while opening file. Continuing...#\\n\", res);\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\t\t}\n\t\telse\n\t\t{\n\t\t\ts_printf(gui->txt_buf, \"\\n#FFDD00 Error (%d) file not found. Continuing...#\\n\", res);\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\t\t}\n\n\t\treturn 2;\n\t}\n\telse if (!use_multipart && (((u32)((u64)f_size(&fp) >> (u64)9)) != totalSectors)) // Check total restore size vs emmc size.\n\t{\n\t\tif (((u32)((u64)f_size(&fp) >> (u64)9)) > totalSectors)\n\t\t{\n\t\t\tstrcpy(gui->txt_buf, \"\\n#FF8000 Size of SD Card backup exceeds#\\n#FF8000 eMMC's selected part size!#\\n#FFDD00 Aborting...#\");\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tf_close(&fp);\n\n\t\t\treturn 1;\n\t\t}\n\t\telse if (!gui->raw_emummc)\n\t\t{\n\t\t\tlv_obj_t *warn_mbox_bg = create_mbox_text(\n\t\t\t\t\"#FF8000 Size of the SD Card backup does not match#\\n#FF8000 eMMC's selected part size!#\\n\\n\"\n\t\t\t\t\"#FFDD00 The backup might be corrupted!#\\n#FFDD00 Aborting is suggested!#\\n\\n\"\n\t\t\t\t\"Press #FF8000 POWER# to Continue.\\nPress #FF8000 VOL# to abort.\", false);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tif (!(btn_wait() & BTN_POWER))\n\t\t\t{\n\t\t\t\tlv_obj_del(warn_mbox_bg);\n\t\t\t\tstrcpy(gui->txt_buf, \"\\n#FF0000 Size of the SD Card backup does not match#\\n#FF0000 eMMC's selected part size.#\\n\");\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\tf_close(&fp);\n\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tlv_obj_del(warn_mbox_bg);\n\t\t}\n\t\t// Set new total sectors and lba end sector for percentage calculations.\n\t\ttotalSectors = (u32)((u64)f_size(&fp) >> (u64)9);\n\t\tlba_end = totalSectors + part->lba_start - 1;\n\t}\n\telse\n\t{\n\t\tfileSize = (u64)f_size(&fp);\n\t\ts_printf(gui->txt_buf, \"\\nTotal restore size: %d MiB.\\n\",\n\t\t\t(u32)((use_multipart ? (u64)totalCheckFileSize : fileSize) >> (u64)9) >> SECTORS_TO_MIB_COEFF);\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\tmanual_system_maintenance(true);\n\t}\n\n\tu8 *buf = (u8 *)MIXD_BUF_ALIGNED;\n\n\tu32 lba_curr = part->lba_start;\n\tu32 bytesWritten = 0;\n\tu32 prevPct = 200;\n\tint retryCount = 0;\n\n\tu32 num = 0;\n\tu32 pct = 0;\n\n\tDWORD *clmt = f_expand_cltbl(&fp, SZ_4M, 0);\n\n\tu32 sector_start = 0, part_idx = 0;\n\tu32 sector_size = totalSectors;\n\tu32 sd_sector_off = 0;\n\n\tif (gui->raw_emummc)\n\t{\n\t\t_get_valid_partition(&sector_start, &sector_size, &part_idx, false);\n\t\tif (!part_idx || !sector_size)\n\t\t{\n\t\t\tstrcpy(gui->txt_buf, \"\\n#FFDD00 Failed to find a partition...#\\n\");\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\treturn 1;\n\t\t}\n\t\tsd_sector_off = sector_start + (0x2000 * active_part);\n\t}\n\n\tlv_obj_set_opa_scale(gui->bar, LV_OPA_COVER);\n\tlv_obj_set_opa_scale(gui->label_pct, LV_OPA_COVER);\n\twhile (totalSectors > 0)\n\t{\n\t\t// If we have more than one part, check the size for the split parts and make sure that the bytes written is not more than that.\n\t\tif (numSplitParts != 0 && bytesWritten >= fileSize)\n\t\t{\n\t\t\t// If we have more bytes written then close the file pointer and increase the part index we are using\n\t\t\tf_close(&fp);\n\t\t\tfree(clmt);\n\t\t\tmemset(&fp, 0, sizeof(fp));\n\t\t\tcurrPartIdx++;\n\n\t\t\tif (verification && !gui->raw_emummc)\n\t\t\t{\n\t\t\t\t// Verify part.\n\t\t\t\tres = _emmc_sd_copy_verify(gui, storage, lbaStartPart, outFilename, part);\n\t\t\t\tswitch (res)\n\t\t\t\t{\n\t\t\t\tcase VERIF_STATUS_OK:\n\t\t\t\t\tbreak;\n\t\t\t\tcase VERIF_STATUS_ERROR:\n\t\t\t\t\tstrcpy(gui->txt_buf, \"\\n#FFDD00 Please try again...#\\n\");\n\t\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\t\tmanual_system_maintenance(true);\n\t\t\t\t\treturn 1;\n\t\t\t\tcase VERIF_STATUS_ABORT:\n\t\t\t\t\tverification = 0;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tlv_bar_set_style(gui->bar, LV_BAR_STYLE_BG, gui->bar_orange_bg);\n\t\t\t\tlv_bar_set_style(gui->bar, LV_BAR_STYLE_INDIC, gui->bar_orange_ind);\n\t\t\t}\n\n\t\t\t_update_filename(outFilename, sdPathLen, currPartIdx);\n\n\t\t\t// Read from next part.\n\t\t\ts_printf(gui->txt_buf, \"%s#\", outFilename + strlen(gui->base_path));\n\t\t\tlv_label_cut_text(gui->label_info,\n\t\t\t\tstrlen(lv_label_get_text(gui->label_info)) - strlen(outFilename + strlen(gui->base_path)) - 1,\n\t\t\t\tstrlen(outFilename + strlen(gui->base_path)) + 1);\n\t\t\tlv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tlbaStartPart = lba_curr;\n\n\t\t\t// Try to open the next file part\n\t\t\tres = f_open(&fp, outFilename, FA_READ);\n\t\t\tif (res)\n\t\t\t{\n\t\t\t\ts_printf(gui->txt_buf, \"\\n#FF0000 Error (%d) while opening file#\\n#FFDD00 %s!#\\n\", res, outFilename);\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tfileSize = (u64)f_size(&fp);\n\t\t\tbytesWritten = 0;\n\t\t\tclmt = f_expand_cltbl(&fp, SZ_4M, 0);\n\t\t}\n\n\t\tretryCount = 0;\n\t\tnum = MIN(totalSectors, NUM_SECTORS_PER_ITER);\n\n\t\tres = f_read_fast(&fp, buf, num << 9);\n\t\tmanual_system_maintenance(false);\n\n\t\tif (res)\n\t\t{\n\t\t\ts_printf(gui->txt_buf,\n\t\t\t\t\"\\n#FF0000 Fatal error (%d) when reading from SD!#\\n\"\n\t\t\t\t\"#FF0000 This device may be in an inoperative state!#\\n\"\n\t\t\t\t\"#FFDD00 Please try again now!#\\n\", res);\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tf_close(&fp);\n\t\t\tfree(clmt);\n\t\t\treturn 1;\n\t\t}\n\t\tif (!gui->raw_emummc)\n\t\t\tres = sdmmc_storage_write(storage, lba_curr, num, buf);\n\t\telse\n\t\t\tres = sdmmc_storage_write(&sd_storage, lba_curr + sd_sector_off, num, buf);\n\n\t\tmanual_system_maintenance(false);\n\n\t\twhile (res)\n\t\t{\n\t\t\ts_printf(gui->txt_buf,\n\t\t\t\t\"\\n#FFDD00 Error writing %d blocks @ LBA %08X,#\\n\"\n\t\t\t\t\"#FFDD00 from eMMC (try %d). #\",\n\t\t\t\tnum, lba_curr, ++retryCount);\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tmsleep(150);\n\t\t\tif (retryCount >= 3)\n\t\t\t{\n\t\t\t\tstrcpy(gui->txt_buf, \"#FF0000 Aborting...#\\n\"\n\t\t\t\t\t\"#FF0000 This device may be in an inoperative state!#\\n\"\n\t\t\t\t\t\"#FFDD00 Please try again now!#\\n\");\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\tf_close(&fp);\n\t\t\t\tfree(clmt);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstrcpy(gui->txt_buf, \"#FFDD00 Retrying...#\\n\");\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\t\t\t}\n\t\t\tif (!gui->raw_emummc)\n\t\t\t\tres = sdmmc_storage_write(storage, lba_curr, num, buf);\n\t\t\telse\n\t\t\t\tres = sdmmc_storage_write(&sd_storage, lba_curr + sd_sector_off, num, buf);\n\t\t\tmanual_system_maintenance(false);\n\t\t}\n\t\tpct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(lba_end - part->lba_start);\n\t\tif (pct != prevPct)\n\t\t{\n\t\t\tlv_bar_set_value(gui->bar, pct);\n\t\t\ts_printf(gui->txt_buf, \" \"SYMBOL_DOT\" %d%%\", pct);\n\t\t\tlv_label_set_text(gui->label_pct, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\t\t\tprevPct = pct;\n\t\t}\n\n\t\tlba_curr += num;\n\t\ttotalSectors -= num;\n\t\tbytesWritten += num * EMMC_BLOCKSIZE;\n\t}\n\tlv_bar_set_value(gui->bar, 100);\n\tlv_label_set_text(gui->label_pct, \" \"SYMBOL_DOT\" 100%\");\n\tmanual_system_maintenance(true);\n\n\t// Restore operation ended successfully.\n\tf_close(&fp);\n\tfree(clmt);\n\n\tif (verification && !gui->raw_emummc)\n\t{\n\t\t// Verify restored data.\n\t\tif (_emmc_sd_copy_verify(gui, storage, lbaStartPart, outFilename, part) == VERIF_STATUS_ERROR)\n\t\t{\n\t\t\tstrcpy(gui->txt_buf, \"\\n#FFDD00 Please try again...#\\n\");\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\treturn 1;\n\t\t}\n\t\tlv_bar_set_value(gui->bar, 100);\n\t\tlv_label_set_text(gui->label_pct, \" \"SYMBOL_DOT\" 100%\");\n\t\tmanual_system_maintenance(true);\n\t}\n\n\tif (gui->raw_emummc)\n\t{\n\t\tchar sdPath[OUT_FILENAME_SZ];\n\t\t// Create Restore folders, if they do not exist.\n\t\tf_mkdir(\"emuMMC\");\n\t\ts_printf(sdPath, \"emuMMC/RAW%d\", part_idx);\n\t\tf_mkdir(sdPath);\n\t\tstrcat(sdPath, \"/raw_based\");\n\t\tFIL fp_raw;\n\t\tf_open(&fp_raw, sdPath, FA_CREATE_ALWAYS | FA_WRITE);\n\t\tf_write(&fp_raw, &sector_start, 4, NULL);\n\t\tf_close(&fp_raw);\n\n\t\ts_printf(sdPath, \"emuMMC/RAW%d\", part_idx);\n\t\tsave_emummc_cfg(part_idx, sector_start, sdPath);\n\t}\n\n\treturn 0;\n}\n\nvoid restore_emmc_selected(emmcPartType_t restoreType, emmc_tool_gui_t *gui)\n{\n\tint res = 0;\n\tu32 timer = 0;\n\n\tchar *txt_buf = (char *)malloc(SZ_16K);\n\tgui->txt_buf = txt_buf;\n\n\ttxt_buf[0] = 0;\n\tlv_label_set_text(gui->label_log, txt_buf);\n\n\tmanual_system_maintenance(true);\n\n\tif (!gui->raw_emummc)\n\t\tstrcpy(txt_buf, \"#FFDD00 This may render the device inoperative!#\");\n\telse\n\t\tstrcpy(txt_buf, \"#FFDD00 This may render the emuMMC inoperative!#\");\n\tstrcat(txt_buf, \"\\n\\n#FFDD00 Are you really sure?#\");\n\n\tif (gui->raw_emummc)\n\t\tstrcat(txt_buf, \"\\n\\nOnly the 1st emuMMC found can be restored!\");\n\n\tif ((restoreType & PART_BOOT) || (restoreType & PART_GP_ALL))\n\t{\n\t\tstrcat(txt_buf,\n\t\t\t\"\\n\\nThe mode you selected will only restore\\nthe partitions that it can find.\\n\"\n\t\t\t\"If it is not found, it will be skipped\\nand continue with the next.\");\n\t}\n\n\tu32 orig_msg_len = strlen(txt_buf);\n\n\tlv_obj_t *warn_mbox_bg = create_mbox_text(txt_buf, false);\n\tlv_obj_t *warn_mbox = lv_obj_get_child(warn_mbox_bg, NULL);\n\n\tu8 failsafe_wait = 6;\n\twhile (failsafe_wait > 0)\n\t{\n\t\ts_printf(txt_buf + orig_msg_len, \"\\n\\n#888888 Wait... (%ds)#\", failsafe_wait);\n\t\tlv_mbox_set_text(warn_mbox, txt_buf);\n\t\tmsleep(1000);\n\t\tmanual_system_maintenance(true);\n\t\tfailsafe_wait--;\n\t}\n\n\ts_printf(txt_buf + orig_msg_len, \"\\n\\nPress #FF8000 POWER# to Continue.\\nPress #FF8000 VOL# to abort.\");\n\tlv_mbox_set_text(warn_mbox, txt_buf);\n\tmanual_system_maintenance(true);\n\n\tif (!(btn_wait() & BTN_POWER))\n\t{\n\t\tlv_label_set_text(gui->label_info, \"#FFDD00 Restore operation was aborted!#\");\n\t\tlv_obj_del(warn_mbox_bg);\n\t\tgoto out;\n\t}\n\tlv_obj_del(warn_mbox_bg);\n\tmanual_system_maintenance(true);\n\n\tif (sd_mount())\n\t{\n\t\tlv_label_set_text(gui->label_info, \"#FFDD00 Failed to init SD!#\");\n\t\tgoto out;\n\t}\n\n\tif (emmc_initialize(false))\n\t{\n\t\tlv_label_set_text(gui->label_info, \"#FFDD00 Failed to init eMMC!#\");\n\t\tgoto out;\n\t}\n\n\tint i = 0;\n\tchar sdPath[OUT_FILENAME_SZ];\n\tif (!gui->raw_emummc)\n\t\temmcsn_path_impl(sdPath, \"/restore\", \"\", &emmc_storage);\n\telse\n\t\temmcsn_path_impl(sdPath, \"/restore/emummc\", \"\", &emmc_storage);\n\tgui->base_path = (char *)malloc(strlen(sdPath) + 1);\n\tstrcpy(gui->base_path, sdPath);\n\n\ttimer = get_tmr_s();\n\tif (restoreType & PART_BOOT)\n\t{\n\t\tconst u32 BOOT_PART_SIZE = emmc_storage.ext_csd.boot_mult << 17;\n\t\tconst u32 BOOT_PART_SECTORS = 0x2000; // Force 4 MiB for emuMMC.\n\n\t\temmc_part_t bootPart;\n\t\tmemset(&bootPart, 0, sizeof(bootPart));\n\t\tbootPart.lba_start = 0;\n\t\tif (!gui->raw_emummc)\n\t\t\tbootPart.lba_end = (BOOT_PART_SIZE / EMMC_BLOCKSIZE) - 1;\n\t\telse\n\t\t\tbootPart.lba_end = BOOT_PART_SECTORS - 1;\n\t\tfor (i = 0; i < 2; i++)\n\t\t{\n\t\t\tstrcpy(bootPart.name, \"BOOT\");\n\t\t\tbootPart.name[4] = (u8)('0' + i);\n\t\t\tbootPart.name[5] = 0;\n\n\t\t\ts_printf(txt_buf, \"#00DDFF %02d: %s#\\n#00DDFF Range: 0x%08X - 0x%08X#\\n\\n\\n\\n\\n\",\n\t\t\t\ti, bootPart.name, bootPart.lba_start, bootPart.lba_end);\n\t\t\tlv_label_set_text(gui->label_info, txt_buf);\n\t\t\ts_printf(txt_buf, \"%02d: %s... \", i, bootPart.name);\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\temmc_set_partition(i + 1);\n\n\t\t\tif (!gui->raw_emummc)\n\t\t\t\temmcsn_path_impl(sdPath, \"/restore\", bootPart.name, &emmc_storage);\n\t\t\telse\n\t\t\t\temmcsn_path_impl(sdPath, \"/restore/emummc\", bootPart.name, &emmc_storage);\n\t\t\tres = _restore_emmc_part(gui, sdPath, i, &emmc_storage, &bootPart, false);\n\n\t\t\tif (res == 1)\n\t\t\t\tstrcpy(txt_buf, \"#FFDD00 Failed!#\\n\");\n\t\t\telse if (!res)\n\t\t\t\tstrcpy(txt_buf, \"Done!\\n\");\n\n\t\t\tif (res <= 1)\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\n\t\t\tmanual_system_maintenance(true);\n\t\t}\n\t}\n\n\tif (restoreType & PART_GP_ALL)\n\t{\n\t\temmcsn_path_impl(sdPath, \"/restore/partitions\", \"\", &emmc_storage);\n\t\tgui->base_path = (char *)malloc(strlen(sdPath) + 1);\n\t\tstrcpy(gui->base_path, sdPath);\n\n\t\temmc_set_partition(EMMC_GPP);\n\n\t\tLIST_INIT(gpt);\n\t\temmc_gpt_parse(&gpt);\n\t\tLIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)\n\t\t{\n\t\t\ts_printf(txt_buf, \"#00DDFF %02d: %s#\\n#00DDFF Range: 0x%08X - 0x%08X#\\n\\n\\n\\n\\n\",\n\t\t\t\ti, part->name, part->lba_start, part->lba_end);\n\t\t\tlv_label_set_text(gui->label_info, txt_buf);\n\t\t\ts_printf(txt_buf, \"%02d: %s... \", i, part->name);\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\t\t\ti++;\n\n\t\t\temmcsn_path_impl(sdPath, \"/restore/partitions\", part->name, &emmc_storage);\n\t\t\tres = _restore_emmc_part(gui, sdPath, 0, &emmc_storage, part, false);\n\n\t\t\tif (res == 1)\n\t\t\t\tstrcpy(txt_buf, \"#FFDD00 Failed!#\\n\");\n\t\t\telse if (!res)\n\t\t\t\tstrcpy(txt_buf, \"Done!\\n\");\n\n\t\t\tif (res <= 1)\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\n\t\t\tmanual_system_maintenance(true);\n\t\t}\n\t\temmc_gpt_free(&gpt);\n\t}\n\n\tif (restoreType & PART_RAW)\n\t{\n\t\t// Get GP partition size dynamically.\n\t\tconst u32 RAW_AREA_NUM_SECTORS = emmc_storage.sec_cnt;\n\n\t\temmc_part_t rawPart;\n\t\tmemset(&rawPart, 0, sizeof(rawPart));\n\t\trawPart.lba_start = 0;\n\t\trawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;\n\t\tstrcpy(rawPart.name, \"rawnand.bin\");\n\t\t{\n\t\t\ts_printf(txt_buf, \"#00DDFF %02d: %s#\\n#00DDFF Range: 0x%08X - 0x%08X#\\n\\n\\n\\n\\n\",\n\t\t\t\ti, rawPart.name, rawPart.lba_start, rawPart.lba_end);\n\t\t\tlv_label_set_text(gui->label_info, txt_buf);\n\t\t\ts_printf(txt_buf, \"%02d: %s... \", i, rawPart.name);\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\t\t\ti++;\n\n\t\t\tif (!gui->raw_emummc)\n\t\t\t\temmcsn_path_impl(sdPath, \"/restore\", rawPart.name, &emmc_storage);\n\t\t\telse\n\t\t\t\temmcsn_path_impl(sdPath, \"/restore/emummc\", rawPart.name, &emmc_storage);\n\t\t\tres = _restore_emmc_part(gui, sdPath, 2, &emmc_storage, &rawPart, true);\n\n\t\t\tif (res == 1)\n\t\t\t\tstrcpy(txt_buf, \"#FFDD00 Failed!#\\n\");\n\t\t\telse if (!res)\n\t\t\t\tstrcpy(txt_buf, \"Done!\\n\");\n\n\t\t\tif (res <= 1)\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\n\t\t\tmanual_system_maintenance(true);\n\t\t}\n\t}\n\n\ttimer = get_tmr_s() - timer;\n\temmc_end();\n\n\tif (!res && n_cfg.verification && !gui->raw_emummc)\n\t\ts_printf(txt_buf, \"Time taken: %dm %ds.\\n#96FF00 Finished and verified!#\", timer / 60, timer % 60);\n\telse if (!res)\n\t\ts_printf(txt_buf, \"Time taken: %dm %ds.\\nFinished!\", timer / 60, timer % 60);\n\telse\n\t\ts_printf(txt_buf, \"Time taken: %dm %ds.\", timer / 60, timer % 60);\n\n\tlv_label_set_text(gui->label_finish, txt_buf);\n\nout:\n\tfree(txt_buf);\n\tfree(gui->base_path);\n\tsd_unmount();\n}\n"
  },
  {
    "path": "nyx/nyx_gui/frontend/fe_emmc_tools.h",
    "content": "/*\n * Copyright (c) 2018 Rajko Stojadinovic\n * Copyright (c) 2018 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _FE_EMMC_TOOLS_H_\n#define _FE_EMMC_TOOLS_H_\n\n#include \"gui.h\"\n\ntypedef enum\n{\n\tPART_BOOT =   BIT(0),\n\tPART_SYSTEM = BIT(1),\n\tPART_USER =   BIT(2),\n\tPART_RAW =    BIT(3),\n\tPART_GP_ALL = BIT(7)\n} emmcPartType_t;\n\nvoid dump_emmc_selected(emmcPartType_t dumpType, emmc_tool_gui_t *gui);\nvoid restore_emmc_selected(emmcPartType_t restoreType, emmc_tool_gui_t *gui);\n\n#endif\n"
  },
  {
    "path": "nyx/nyx_gui/frontend/fe_emummc_tools.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018 Rajko Stojadinovic\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n//! fix the dram stuff and the pop ups\n\n#include <string.h>\n#include <stdlib.h>\n\n#include <bdk.h>\n\n#include \"gui.h\"\n#include \"fe_emummc_tools.h\"\n#include \"../config.h\"\n#include \"../hos/hos.h\"\n#include <libs/fatfs/diskio.h>\n#include <libs/fatfs/ff.h>\n\n#define OUT_FILENAME_SZ      128\n#define NUM_SECTORS_PER_ITER 8192 // 4MB Cache.\n\nvoid load_emummc_cfg(emummc_cfg_t *emu_info)\n{\n\tmemset(emu_info, 0, sizeof(emummc_cfg_t));\n\n\t// Parse emuMMC configuration.\n\tLIST_INIT(ini_sections);\n\tif (ini_parse(&ini_sections, \"emuMMC/emummc.ini\", false))\n\t\treturn;\n\n\tLIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)\n\t{\n\t\tif (!strcmp(ini_sec->name, \"emummc\"))\n\t\t{\n\t\t\tLIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)\n\t\t\t{\n\t\t\t\tif (!strcmp(\"enabled\",     kv->key))\n\t\t\t\t\temu_info->enabled = atoi(kv->val);\n\t\t\t\telse if (!strcmp(\"sector\", kv->key))\n\t\t\t\t\temu_info->sector = strtol(kv->val, NULL, 16);\n\t\t\t\telse if (!strcmp(\"id\",     kv->key))\n\t\t\t\t\temu_info->id     = strtol(kv->val, NULL, 16);\n\t\t\t\telse if (!strcmp(\"path\",   kv->key))\n\t\t\t\t{\n\t\t\t\t\temu_info->path = (char *)malloc(strlen(kv->val) + 1);\n\t\t\t\t\tstrcpy(emu_info->path, kv->val);\n\t\t\t\t}\n\t\t\t\telse if (!strcmp(\"nintendo_path\", kv->key))\n\t\t\t\t{\n\t\t\t\t\temu_info->nintendo_path = (char *)malloc(strlen(kv->val) + 1);\n\t\t\t\t\tstrcpy(emu_info->nintendo_path, kv->val);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tini_free(&ini_sections);\n}\n\nvoid save_emummc_cfg(u32 part_idx, u32 sector_start, const char *path)\n{\n\tsd_mount();\n\n\tchar lbuf[16];\n\tFIL fp;\n\n\tif (f_open(&fp, \"emuMMC/emummc.ini\", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)\n\t\treturn;\n\n\t// Add config entry.\n\tf_puts(\"[emummc]\\nenabled=\", &fp);\n\tif (part_idx && sector_start)\n\t{\n\t\titoa(part_idx, lbuf, 10);\n\t\tf_puts(lbuf, &fp);\n\t}\n\telse if (path)\n\t\tf_puts(\"1\", &fp);\n\telse\n\t\tf_puts(\"0\", &fp);\n\n\tif (!sector_start)\n\t\tf_puts(\"\\nsector=0x0\", &fp);\n\telse\n\t{\n\t\tf_puts(\"\\nsector=0x\", &fp);\n\t\titoa(sector_start, lbuf, 16);\n\t\tf_puts(lbuf, &fp);\n\t}\n\tif (path)\n\t{\n\t\tf_puts(\"\\npath=\", &fp);\n\t\tf_puts(path, &fp);\n\t}\n\n\t// Get ID from path.\n\tu32 id_from_path = 0;\n\tif (path && strlen(path) >= 4)\n\t\tmemcpy(&id_from_path, path + strlen(path) - 4, 4);\n\tf_puts(\"\\nid=0x\", &fp);\n\titoa(id_from_path, lbuf, 16);\n\tf_puts(lbuf, &fp);\n\n\tf_puts(\"\\nnintendo_path=\", &fp);\n\tif (path)\n\t{\n\t\tf_puts(path, &fp);\n\t\tf_puts(\"/Nintendo\\n\", &fp);\n\t}\n\telse\n\t\tf_puts(\"\\n\", &fp);\n\n\tf_close(&fp);\n}\n\nvoid update_emummc_base_folder(char *outFilename, u32 sdPathLen, u32 currPartIdx)\n{\n\tif (currPartIdx < 10)\n\t{\n\t\toutFilename[sdPathLen] = '0';\n\t\titoa(currPartIdx, &outFilename[sdPathLen + 1], 10);\n\t}\n\telse\n\t\titoa(currPartIdx, &outFilename[sdPathLen], 10);\n}\n\nstatic int _dump_emummc_file_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t *storage, const emmc_part_t *part)\n{\n\tstatic const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF;\n\tstatic const u32 SECTORS_TO_MIB_COEFF = 11;\n\n\tu32 multipartSplitSize = 0xFE000000;\n\tu32 totalSectors = part->lba_end - part->lba_start + 1;\n\tu32 currPartIdx = 0;\n\tu32 numSplitParts = 0;\n\tint res = 0;\n\tchar *outFilename = sd_path;\n\tu32 sdPathLen = strlen(sd_path);\n\n\ts_printf(gui->txt_buf, \"#96FF00 SD Card free space:# %d MiB\\n#96FF00 Total size:# %d MiB\\n\\n\",\n\t\t(u32)(sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF),\n\t\ttotalSectors >> SECTORS_TO_MIB_COEFF);\n\tlv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);\n\tmanual_system_maintenance(true);\n\n\tlv_bar_set_value(gui->bar, 0);\n\tlv_label_set_text(gui->label_pct, \" \"SYMBOL_DOT\" 0%\");\n\tmanual_system_maintenance(true);\n\n\t// Check if the USER partition or the RAW eMMC fits the sd card free space.\n\tif (totalSectors > (sd_fs.free_clst * sd_fs.csize))\n\t{\n\t\ts_printf(gui->txt_buf, \"\\n#FFDD00 Not enough free space for file based emuMMC!#\\n\");\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\treturn 1;\n\t}\n\n\t// Check if filesystem is FAT32 or the free space is smaller and dump in parts.\n\tif (totalSectors > (FAT32_FILESIZE_LIMIT / EMMC_BLOCKSIZE))\n\t{\n\t\tu32 multipartSplitSectors = multipartSplitSize / EMMC_BLOCKSIZE;\n\t\tnumSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors;\n\n\t\t// Get first part filename.\n\t\tupdate_emummc_base_folder(outFilename, sdPathLen, 0);\n\t}\n\n\tFIL fp;\n\ts_printf(gui->txt_buf, \"#96FF00 Filepath:#\\n%s\\n#96FF00 Filename:# #FF8000 %s#\",\n\t\tgui->base_path, outFilename + strlen(gui->base_path));\n\tlv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);\n\tmanual_system_maintenance(true);\n\n\tres = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);\n\tif (res)\n\t{\n\t\ts_printf(gui->txt_buf, \"\\n#FF0000 Error (%d) while creating#\\n#FFDD00 %s#\\n\", res, outFilename);\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\treturn 1;\n\t}\n\n\tu8 *buf = (u8 *)MIXD_BUF_ALIGNED;\n\n\tu32 lba_curr = part->lba_start;\n\tu32 bytesWritten = 0;\n\tu32 prevPct = 200;\n\tint retryCount = 0;\n\tDWORD *clmt = NULL;\n\n\tu64 totalSize = (u64)((u64)totalSectors << 9);\n\tif (totalSize <= FAT32_FILESIZE_LIMIT)\n\t\tclmt = f_expand_cltbl(&fp, SZ_4M, totalSize);\n\telse\n\t\tclmt = f_expand_cltbl(&fp, SZ_4M, MIN(totalSize, multipartSplitSize));\n\n\tu32 num = 0;\n\tu32 pct = 0;\n\n\tlv_obj_set_opa_scale(gui->bar, LV_OPA_COVER);\n\tlv_obj_set_opa_scale(gui->label_pct, LV_OPA_COVER);\n\twhile (totalSectors > 0)\n\t{\n\t\tif (numSplitParts != 0 && bytesWritten >= multipartSplitSize)\n\t\t{\n\t\t\tf_close(&fp);\n\t\t\tfree(clmt);\n\t\t\tmemset(&fp, 0, sizeof(fp));\n\t\t\tcurrPartIdx++;\n\n\t\t\tupdate_emummc_base_folder(outFilename, sdPathLen, currPartIdx);\n\n\t\t\t// Create next part.\n\t\t\ts_printf(gui->txt_buf, \"%s#\", outFilename + strlen(gui->base_path));\n\t\t\tlv_label_cut_text(gui->label_info, strlen(lv_label_get_text(gui->label_info)) - 3, 3);\n\t\t\tlv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tres = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);\n\t\t\tif (res)\n\t\t\t{\n\t\t\t\ts_printf(gui->txt_buf, \"\\n#FF0000 Error (%d) while creating#\\n#FFDD00 %s#\\n\", res, outFilename);\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tbytesWritten = 0;\n\n\t\t\ttotalSize = (u64)((u64)totalSectors << 9);\n\t\t\tclmt = f_expand_cltbl(&fp, SZ_4M, MIN(totalSize, multipartSplitSize));\n\t\t}\n\n\t\t// Check for cancellation combo.\n\t\tif (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))\n\t\t{\n\t\t\ts_printf(gui->txt_buf, \"\\n#FFDD00 The emuMMC was cancelled!#\\n\");\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tf_close(&fp);\n\t\t\tfree(clmt);\n\t\t\tf_unlink(outFilename);\n\n\t\t\tmsleep(1000);\n\n\t\t\treturn 1;\n\t\t}\n\n\t\tretryCount = 0;\n\t\tnum = MIN(totalSectors, NUM_SECTORS_PER_ITER);\n\n\t\twhile (sdmmc_storage_read(storage, lba_curr, num, buf))\n\t\t{\n\t\t\ts_printf(gui->txt_buf,\n\t\t\t\t\"\\n#FFDD00 Error reading %d blocks @ LBA %08X,#\\n\"\n\t\t\t\t\"#FFDD00 from eMMC (try %d). #\",\n\t\t\t\tnum, lba_curr, ++retryCount);\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tmsleep(150);\n\t\t\tif (retryCount >= 3)\n\t\t\t{\n\t\t\t\ts_printf(gui->txt_buf, \"#FF0000 Aborting...#\\nPlease try again...\\n\");\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\tf_close(&fp);\n\t\t\t\tfree(clmt);\n\t\t\t\tf_unlink(outFilename);\n\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ts_printf(gui->txt_buf, \"#FFDD00 Retrying...#\");\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\t\t\t}\n\t\t}\n\n\t\tmanual_system_maintenance(false);\n\n\t\tres = f_write_fast(&fp, buf, EMMC_BLOCKSIZE * num);\n\n\t\tmanual_system_maintenance(false);\n\n\t\tif (res)\n\t\t{\n\t\t\ts_printf(gui->txt_buf, \"\\n#FF0000 Fatal error (%d) when writing to SD Card#\\nPlease try again...\\n\", res);\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tf_close(&fp);\n\t\t\tfree(clmt);\n\t\t\tf_unlink(outFilename);\n\n\t\t\treturn 1;\n\t\t}\n\t\tpct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);\n\t\tif (pct != prevPct)\n\t\t{\n\t\t\tlv_bar_set_value(gui->bar, pct);\n\t\t\ts_printf(gui->txt_buf, \" \"SYMBOL_DOT\" %d%%\", pct);\n\t\t\tlv_label_set_text(gui->label_pct, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tprevPct = pct;\n\t\t}\n\n\t\tlba_curr += num;\n\t\ttotalSectors -= num;\n\t\tbytesWritten += num * EMMC_BLOCKSIZE;\n\n\t\t// Force a flush after a lot of data if not splitting.\n\t\tif (numSplitParts == 0 && bytesWritten >= multipartSplitSize)\n\t\t{\n\t\t\tf_sync(&fp);\n\t\t\tbytesWritten = 0;\n\t\t}\n\n\t\tmanual_system_maintenance(false);\n\t}\n\tlv_bar_set_value(gui->bar, 100);\n\tlv_label_set_text(gui->label_pct, \" \"SYMBOL_DOT\" 100%\");\n\tmanual_system_maintenance(true);\n\n\t// Operation ended successfully.\n\tf_close(&fp);\n\tfree(clmt);\n\n\treturn 0;\n}\n\nvoid dump_emummc_file(emmc_tool_gui_t *gui)\n{\n\tint res = 1;\n\tint base_len = 0;\n\tu32 timer = 0;\n\n\tchar *txt_buf = (char *)malloc(SZ_16K);\n\tgui->base_path = (char *)malloc(OUT_FILENAME_SZ);\n\tgui->txt_buf = txt_buf;\n\n\ttxt_buf[0] = 0;\n\tlv_label_set_text(gui->label_log, txt_buf);\n\n\tmanual_system_maintenance(true);\n\n\tif (sd_mount())\n\t{\n\t\tlv_label_set_text(gui->label_info, \"#FFDD00 Failed to init SD!#\");\n\t\tgoto out;\n\t}\n\n\tlv_label_set_text(gui->label_info, \"Checking for available free space...\");\n\tmanual_system_maintenance(true);\n\n\t// Get SD Card free space for file based emuMMC.\n\tf_getfree(\"\", &sd_fs.free_clst, NULL);\n\n\tif (emmc_initialize(false))\n\t{\n\t\tlv_label_set_text(gui->label_info, \"#FFDD00 Failed to init eMMC!#\");\n\t\tgoto out;\n\t}\n\n\tint i = 0;\n\tchar sdPath[OUT_FILENAME_SZ];\n\t// Create Restore folders, if they do not exist.\n\tf_mkdir(\"emuMMC\");\n\tstrcpy(sdPath, \"emuMMC/SD\");\n\tbase_len = strlen(sdPath);\n\n\tfor (int j = 0; j < 100; j++)\n\t{\n\t\tupdate_emummc_base_folder(sdPath, base_len, j);\n\t\tif (f_stat(sdPath, NULL) == FR_NO_FILE)\n\t\t\tbreak;\n\t}\n\n\tf_mkdir(sdPath);\n\tstrcat(sdPath, \"/eMMC\");\n\tf_mkdir(sdPath);\n\tstrcat(sdPath, \"/\");\n\tstrcpy(gui->base_path, sdPath);\n\n\ttimer = get_tmr_s();\n\tconst u32 BOOT_PART_SECTORS = 0x2000; // Force 4 MiB.\n\n\temmc_part_t bootPart;\n\tmemset(&bootPart, 0, sizeof(bootPart));\n\tbootPart.lba_start = 0;\n\tbootPart.lba_end = BOOT_PART_SECTORS - 1;\n\n\tfor (i = 0; i < 2; i++)\n\t{\n\t\tstrcpy(bootPart.name, \"BOOT\");\n\t\tbootPart.name[4] = (u8)('0' + i);\n\t\tbootPart.name[5] = 0;\n\n\t\ts_printf(txt_buf, \"#00DDFF %02d: %s#\\n#00DDFF Range: 0x%08X - 0x%08X#\\n\\n\",\n\t\t\ti, bootPart.name, bootPart.lba_start, bootPart.lba_end);\n\t\tlv_label_set_text(gui->label_info, txt_buf);\n\t\ts_printf(txt_buf, \"%02d: %s... \", i, bootPart.name);\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\temmc_set_partition(i + 1);\n\n\t\tstrcat(sdPath, bootPart.name);\n\t\tres = _dump_emummc_file_part(gui, sdPath, &emmc_storage, &bootPart);\n\n\t\tif (res)\n\t\t{\n\t\t\ts_printf(txt_buf, \"#FFDD00 Failed!#\\n\");\n\t\t\tgoto out_failed;\n\t\t}\n\t\telse\n\t\t\ts_printf(txt_buf, \"Done!\\n\");\n\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\tstrcpy(sdPath, gui->base_path);\n\t}\n\n\t// Get GP partition size dynamically.\n\temmc_set_partition(EMMC_GPP);\n\n\t// Get GP partition size dynamically.\n\tconst u32 RAW_AREA_NUM_SECTORS = emmc_storage.sec_cnt;\n\n\temmc_part_t rawPart;\n\tmemset(&rawPart, 0, sizeof(rawPart));\n\trawPart.lba_start = 0;\n\trawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;\n\tstrcpy(rawPart.name, \"GPP\");\n\n\ts_printf(txt_buf, \"#00DDFF %02d: %s#\\n#00DDFF Range: 0x%08X - 0x%08X#\\n\\n\",\n\t\ti, rawPart.name, rawPart.lba_start, rawPart.lba_end);\n\tlv_label_set_text(gui->label_info, txt_buf);\n\ts_printf(txt_buf, \"%02d: %s... \", i, rawPart.name);\n\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\tmanual_system_maintenance(true);\n\n\tres = _dump_emummc_file_part(gui, sdPath, &emmc_storage, &rawPart);\n\n\tif (res)\n\t\ts_printf(txt_buf, \"#FFDD00 Failed!#\\n\");\n\telse\n\t\ts_printf(txt_buf, \"Done!\\n\");\n\n\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\tmanual_system_maintenance(true);\n\nout_failed:\n\ttimer = get_tmr_s() - timer;\n\temmc_end();\n\n\tif (!res)\n\t{\n\t\ts_printf(txt_buf, \"Time taken: %dm %ds.\\nFinished!\", timer / 60, timer % 60);\n\t\tgui->base_path[strlen(gui->base_path) - 5] = '\\0';\n\t\tstrcpy(sdPath, gui->base_path);\n\t\tstrcat(sdPath, \"file_based\");\n\t\tFIL fp;\n\t\tf_open(&fp, sdPath, FA_CREATE_ALWAYS | FA_WRITE);\n\t\tf_close(&fp);\n\n\t\tgui->base_path[strlen(gui->base_path) - 1] = 0;\n\t\tsave_emummc_cfg(0, 0, gui->base_path);\n\t}\n\telse\n\t\ts_printf(txt_buf, \"Time taken: %dm %ds.\", timer / 60, timer % 60);\n\n\tlv_label_set_text(gui->label_finish, txt_buf);\n\nout:\n\tfree(txt_buf);\n\tfree(gui->base_path);\n\tsd_unmount();\n}\n\nstatic int _dump_emummc_raw_part(emmc_tool_gui_t *gui, int active_part, int part_idx, u32 sd_part_off, emmc_part_t *part, u32 resized_count)\n{\n\tu32 num = 0;\n\tu32 pct = 0;\n\tu32 prevPct = 200;\n\tint retryCount = 0;\n\tu32 sd_sector_off = sd_part_off + (0x2000 * active_part);\n\tu32 lba_curr = part->lba_start;\n\tu8 *buf = (u8 *)MIXD_BUF_ALIGNED;\n\n\ts_printf(gui->txt_buf, \"\\n\\n\\n\");\n\tlv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);\n\tmanual_system_maintenance(true);\n\n\tlv_bar_set_value(gui->bar, 0);\n\tlv_label_set_text(gui->label_pct, \" \"SYMBOL_DOT\" 0%\");\n\tmanual_system_maintenance(true);\n\n\ts_printf(gui->txt_buf, \"#96FF00 Base folder:#\\n%s\\n#96FF00 Partition offset:# #FF8000 0x%08X#\",\n\t\tgui->base_path, sd_part_off);\n\tlv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);\n\tmanual_system_maintenance(true);\n\n\tlv_obj_set_opa_scale(gui->bar, LV_OPA_COVER);\n\tlv_obj_set_opa_scale(gui->label_pct, LV_OPA_COVER);\n\n\tu32 user_offset = 0;\n\n\tif (resized_count)\n\t{\n\t\t// Get USER partition info.\n\t\tLIST_INIT(gpt_parsed);\n\t\temmc_gpt_parse(&gpt_parsed);\n\t\temmc_part_t *user_part = emmc_part_find(&gpt_parsed, \"USER\");\n\t\tif (!user_part)\n\t\t{\n\t\t\ts_printf(gui->txt_buf, \"\\n#FFDD00 USER partition not found!#\\n\");\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\treturn 1;\n\t\t}\n\n\t\tuser_offset = user_part->lba_start;\n\t\tpart->lba_end = user_offset - 1;\n\t\temmc_gpt_free(&gpt_parsed);\n\t}\n\n\tu32 totalSectors = part->lba_end - part->lba_start + 1;\n\twhile (totalSectors > 0)\n\t{\n\t\t// Check for cancellation combo.\n\t\tif (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))\n\t\t{\n\t\t\ts_printf(gui->txt_buf, \"\\n#FFDD00 emuMMC creation was cancelled!#\\n\");\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tmsleep(1000);\n\n\t\t\treturn 1;\n\t\t}\n\n\t\tretryCount = 0;\n\t\tnum = MIN(totalSectors, NUM_SECTORS_PER_ITER);\n\n\t\t// Read data from eMMC.\n\t\twhile (sdmmc_storage_read(&emmc_storage, lba_curr, num, buf))\n\t\t{\n\t\t\ts_printf(gui->txt_buf,\n\t\t\t\t\"\\n#FFDD00 Error reading %d blocks @LBA %08X,#\\n\"\n\t\t\t\t\"#FFDD00 from eMMC (try %d). #\",\n\t\t\t\tnum, lba_curr, ++retryCount);\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tmsleep(150);\n\t\t\tif (retryCount >= 3)\n\t\t\t{\n\t\t\t\ts_printf(gui->txt_buf, \"#FF0000 Aborting...#\\nPlease try again...\\n\");\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ts_printf(gui->txt_buf, \"#FFDD00 Retrying...#\\n\");\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\t\t\t}\n\t\t}\n\n\t\tmanual_system_maintenance(false);\n\n\t\t// Write data to SD card.\n\t\tretryCount = 0;\n\t\twhile (sdmmc_storage_write(&sd_storage, sd_sector_off + lba_curr, num, buf))\n\t\t{\n\t\t\ts_printf(gui->txt_buf,\n\t\t\t\t\"\\n#FFDD00 Error writing %d blocks @LBA %08X,#\\n\"\n\t\t\t\t\"#FFDD00 to SD (try %d). #\",\n\t\t\t\tnum, lba_curr, ++retryCount);\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tmsleep(150);\n\t\t\tif (retryCount >= 3)\n\t\t\t{\n\t\t\t\ts_printf(gui->txt_buf, \"#FF0000 Aborting...#\\nPlease try again...\\n\");\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ts_printf(gui->txt_buf, \"#FFDD00 Retrying...#\\n\");\n\t\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\t\t\t}\n\t\t}\n\n\t\tmanual_system_maintenance(false);\n\n\t\tpct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);\n\t\tif (pct != prevPct)\n\t\t{\n\t\t\tlv_bar_set_value(gui->bar, pct);\n\t\t\ts_printf(gui->txt_buf, \" \"SYMBOL_DOT\" %d%%\", pct);\n\t\t\tlv_label_set_text(gui->label_pct, gui->txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tprevPct = pct;\n\t\t}\n\n\t\tlba_curr += num;\n\t\ttotalSectors -= num;\n\t}\n\tlv_bar_set_value(gui->bar, 100);\n\tlv_label_set_text(gui->label_pct, \" \"SYMBOL_DOT\" 100%\");\n\tmanual_system_maintenance(true);\n\n\t// Set partition type to emuMMC (0xE0).\n\tif (active_part == 2)\n\t{\n\t\tmbr_t mbr;\n\t\tsdmmc_storage_read(&sd_storage, 0, 1, &mbr);\n\t\tmbr.partitions[part_idx].type = 0xE0;\n\t\tsdmmc_storage_write(&sd_storage, 0, 1, &mbr);\n\t}\n\n\tif (resized_count)\n\t{\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, \"Done!\\n\");\n\n\t\t// Calculate USER size and set it for FatFS.\n\t\tu32 user_sectors = resized_count - user_offset - 33;\n\t\tuser_sectors = ALIGN_DOWN(user_sectors, 0x20); // Align down to cluster size.\n\t\tdisk_set_info(DRIVE_EMU, SET_SECTOR_COUNT, &user_sectors);\n\n\t\t// Initialize BIS for emuMMC. BIS keys should be already in place.\n\t\temmc_part_t user_part = {0};\n\t\tuser_part.lba_start = user_offset;\n\t\tuser_part.lba_end = user_offset + user_sectors - 1;\n\t\tstrcpy(user_part.name, \"USER\");\n\t\tnx_emmc_bis_init(&user_part, true, sd_sector_off);\n\n\t\ts_printf(gui->txt_buf, \"Formatting USER... \");\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\t// Format USER partition as FAT32 with 16KB cluster and PRF2SAFE.\n\t\tu8 *buff = malloc(SZ_4M);\n\t\tint mkfs_error = f_mkfs(\"emu:\", FM_FAT32 | FM_SFD | FM_PRF2, 16384, buff, SZ_4M);\n\t\tfree(buff);\n\n\t\t// Mount sd card back.\n\t\tsd_mount();\n\n\t\tif (mkfs_error)\n\t\t{\n\t\t\ts_printf(gui->txt_buf, \"#FF0000 Failed (%d)!#\\nPlease try again...\\n\", mkfs_error);\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\n\t\t\treturn 1;\n\t\t}\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, \"Done!\\n\");\n\n\t\t// Flush BIS cache, deinit, clear BIS keys slots and reinstate SBK.\n\t\tnx_emmc_bis_end();\n\t\thos_bis_keys_clear();\n\n\t\ts_printf(gui->txt_buf, \"Writing new GPT... \");\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\t// Read MBR, GPT and backup GPT.\n\t\tmbr_t mbr;\n\t\tgpt_t *gpt = zalloc(sizeof(gpt_t));\n\t\tgpt_header_t gpt_hdr_backup;\n\t\tsdmmc_storage_read(&emmc_storage, 0, 1, &mbr);\n\t\tsdmmc_storage_read(&emmc_storage, 1, sizeof(gpt_t) >> 9, gpt);\n\t\tsdmmc_storage_read(&emmc_storage, gpt->header.alt_lba, 1, &gpt_hdr_backup);\n\n\t\t// Find USER partition.\n\t\tu32 gpt_entry_idx = 0;\n\t\tfor (gpt_entry_idx = 0; gpt_entry_idx < gpt->header.num_part_ents; gpt_entry_idx++)\n\t\t\tif (!memcmp(gpt->entries[gpt_entry_idx].name, (char[]) { 'U', 0, 'S', 0, 'E', 0, 'R', 0 }, 8))\n\t\t\t\tbreak;\n\n\t\tif (gpt_entry_idx >= gpt->header.num_part_ents)\n\t\t{\n\t\t\ts_printf(gui->txt_buf, \"\\n#FF0000 No USER partition...#\\nPlease try again...\\n\");\n\t\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\t\tfree(gpt);\n\n\t\t\treturn 1;\n\t\t}\n\n\t\t// Set new emuMMC size and USER size.\n\t\tmbr.partitions[0].size_sct = resized_count - 1; // Exclude MBR sector.\n\t\tgpt->entries[gpt_entry_idx].lba_end = user_part.lba_end;\n\n\t\t// Update Main GPT.\n\t\tgpt->header.alt_lba = resized_count - 1;\n\t\tgpt->header.last_use_lba = resized_count - 34;\n\t\tgpt->header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt->entries, sizeof(gpt_entry_t) * gpt->header.num_part_ents);\n\t\tgpt->header.crc32 = 0; // Set to 0 for calculation.\n\t\tgpt->header.crc32 = crc32_calc(0, (const u8 *)&gpt->header, gpt->header.size);\n\n\t\t// Update Backup GPT.\n\t\tmemcpy(&gpt_hdr_backup, &gpt->header, sizeof(gpt_header_t));\n\t\tgpt_hdr_backup.my_lba = resized_count - 1;\n\t\tgpt_hdr_backup.alt_lba = 1;\n\t\tgpt_hdr_backup.part_ent_lba = resized_count - 33;\n\t\tgpt_hdr_backup.crc32 = 0; // Set to 0 for calculation.\n\t\tgpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size);\n\n\t\t// Write main GPT.\n\t\tsdmmc_storage_write(&sd_storage, sd_sector_off + gpt->header.my_lba, sizeof(gpt_t) >> 9, gpt);\n\n\t\t// Write backup GPT partition table.\n\t\tsdmmc_storage_write(&sd_storage, sd_sector_off + gpt_hdr_backup.part_ent_lba, ((sizeof(gpt_entry_t) * 128) >> 9), gpt->entries);\n\n\t\t// Write backup GPT header.\n\t\tsdmmc_storage_write(&sd_storage, sd_sector_off + gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup);\n\n\t\t// Write MBR.\n\t\tsdmmc_storage_write(&sd_storage, sd_sector_off, 1, &mbr);\n\n\t\t// Clear nand patrol.\n\t\tmemset(buf, 0, EMMC_BLOCKSIZE);\n\t\tsdmmc_storage_write(&sd_storage, sd_part_off + NAND_PATROL_SECTOR, 1, buf);\n\n\t\tfree(gpt);\n\t}\n\n\treturn 0;\n}\n\nint emummc_raw_derive_bis_keys()\n{\n\tu8 *cal0_buff = malloc(SZ_64K);\n\n\t// Generate BIS keys.\n\tif (hos_bis_keygen())\n\t\tgoto error;\n\n\t// Read and decrypt CAL0 for validation of working BIS keys.\n\temmc_set_partition(EMMC_GPP);\n\tLIST_INIT(gpt);\n\temmc_gpt_parse(&gpt);\n\temmc_part_t *cal0_part = emmc_part_find(&gpt, \"PRODINFO\"); // check if null\n\tnx_emmc_bis_init(cal0_part, false, 0);\n\tnx_emmc_bis_read(0, 0x40, cal0_buff);\n\tnx_emmc_bis_end();\n\temmc_gpt_free(&gpt);\n\n\tnx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)cal0_buff;\n\n\t// Check keys validity.\n\tif (memcmp(&cal0->magic, \"CAL0\", 4))\n\t{\nerror:\n\t\t// Clear EKS keys.\n\t\thos_eks_clear(HOS_MKEY_VER_MAX);\n\n\t\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\t\tlv_obj_set_style(dark_bg, &mbox_darken);\n\t\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\t\tstatic const char * mbox_btn_map[] = { \"\\251\", \"\\222Close\", \"\\251\", \"\" };\n\t\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\t\tlv_mbox_set_recolor_text(mbox, true);\n\t\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);\n\n\t\tlv_mbox_set_text(mbox, \"#C7EA46 BIS Keys Generation#\");\n\n\t\tlv_obj_t * lb_desc = lv_label_create(mbox, NULL);\n\t\tlv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);\n\t\tlv_label_set_recolor(lb_desc, true);\n\t\tlv_label_set_style(lb_desc, &monospace_text);\n\t\tlv_obj_set_width(lb_desc, LV_HOR_RES / 9 * 4);\n\n\t\tlv_label_set_text(lb_desc, \"#FFDD00 BIS keys validation failed!#\\n\");\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);\n\n\t\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\t\tlv_obj_set_top(mbox, true);\n\n\t\tfree(cal0_buff);\n\t\treturn 0;\n\t}\n\n\tfree(cal0_buff);\n\n\treturn 1;\n}\n\nvoid dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start, u32 resized_count)\n{\n\tint res = 1;\n\tu32 timer = 0;\n\n\tchar *txt_buf = (char *)malloc(SZ_16K);\n\tgui->base_path = (char *)malloc(OUT_FILENAME_SZ);\n\tgui->txt_buf = txt_buf;\n\n\ttxt_buf[0] = 0;\n\tlv_label_set_text(gui->label_log, txt_buf);\n\n\tmanual_system_maintenance(true);\n\n\tif (sd_mount())\n\t{\n\t\tlv_label_set_text(gui->label_info, \"#FFDD00 Failed to init SD!#\");\n\t\tgoto out;\n\t}\n\n\tif (emmc_initialize(false))\n\t{\n\t\tlv_label_set_text(gui->label_info, \"#FFDD00 Failed to init eMMC!#\");\n\t\tgoto out;\n\t}\n\n\tif (resized_count && !emummc_raw_derive_bis_keys())\n\t{\n\t\ts_printf(gui->txt_buf, \"#FFDD00 For formatting USER partition,#\\n#FFDD00 BIS keys are needed!#\\n\");\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);\n\t\temmc_end();\n\t\tgoto out;\n\t}\n\n\tint i = 0;\n\tchar sdPath[OUT_FILENAME_SZ];\n\t// Create Restore folders, if they do not exist.\n\tf_mkdir(\"emuMMC\");\n\ts_printf(sdPath, \"emuMMC/RAW%d\", part_idx);\n\tf_mkdir(sdPath);\n\tstrcat(sdPath, \"/\");\n\tstrcpy(gui->base_path, sdPath);\n\n\ttimer = get_tmr_s();\n\tconst u32 BOOT_PART_SECTORS = 0x2000; // Force 4 MiB.\n\n\temmc_part_t bootPart;\n\tmemset(&bootPart, 0, sizeof(bootPart));\n\tbootPart.lba_start = 0;\n\tbootPart.lba_end = BOOT_PART_SECTORS - 1;\n\n\t// Clear partition start.\n\tmemset((u8 *)MIXD_BUF_ALIGNED, 0, SZ_16M);\n\tsdmmc_storage_write(&sd_storage, sector_start - 0x8000, 0x8000, (u8 *)MIXD_BUF_ALIGNED);\n\n\tfor (i = 0; i < 2; i++)\n\t{\n\t\tstrcpy(bootPart.name, \"BOOT\");\n\t\tbootPart.name[4] = (u8)('0' + i);\n\t\tbootPart.name[5] = 0;\n\n\t\ts_printf(txt_buf, \"#00DDFF %02d: %s#\\n#00DDFF Range: 0x%08X - 0x%08X#\\n\\n\",\n\t\t\ti, bootPart.name, bootPart.lba_start, bootPart.lba_end);\n\t\tlv_label_set_text(gui->label_info, txt_buf);\n\t\ts_printf(txt_buf, \"%02d: %s... \", i, bootPart.name);\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\temmc_set_partition(i + 1);\n\n\t\tstrcat(sdPath, bootPart.name);\n\t\tres = _dump_emummc_raw_part(gui, i, part_idx, sector_start, &bootPart, 0);\n\n\t\tif (res)\n\t\t{\n\t\t\ts_printf(txt_buf, \"#FFDD00 Failed!#\\n\");\n\t\t\tgoto out_failed;\n\t\t}\n\t\telse\n\t\t\ts_printf(txt_buf, \"Done!\\n\");\n\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\tstrcpy(sdPath, gui->base_path);\n\t}\n\n\temmc_set_partition(EMMC_GPP);\n\n\t// Get GP partition size dynamically.\n\tconst u32 RAW_AREA_NUM_SECTORS = emmc_storage.sec_cnt;\n\n\temmc_part_t rawPart;\n\tmemset(&rawPart, 0, sizeof(rawPart));\n\trawPart.lba_start = 0;\n\trawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;\n\tstrcpy(rawPart.name, \"GPP\");\n\t{\n\t\ts_printf(txt_buf, \"#00DDFF %02d: %s#\\n#00DDFF Range: 0x%08X - 0x%08X#\\n\\n\",\n\t\t\ti, rawPart.name, rawPart.lba_start, rawPart.lba_end);\n\t\tlv_label_set_text(gui->label_info, txt_buf);\n\t\ts_printf(txt_buf, \"%02d: %s... \", i, rawPart.name);\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\tres = _dump_emummc_raw_part(gui, 2, part_idx, sector_start, &rawPart, resized_count);\n\n\t\tif (res)\n\t\t\ts_printf(txt_buf, \"#FFDD00 Failed!#\\n\");\n\t\telse\n\t\t\ts_printf(txt_buf, \"Done!\\n\");\n\n\t\tlv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);\n\t\tmanual_system_maintenance(true);\n\t}\n\nout_failed:\n\ttimer = get_tmr_s() - timer;\n\temmc_end();\n\n\tif (!res)\n\t{\n\t\ts_printf(txt_buf, \"Time taken: %dm %ds.\\nFinished!\", timer / 60, timer % 60);\n\t\tstrcpy(sdPath, gui->base_path);\n\t\tstrcat(sdPath, \"raw_based\");\n\t\tFIL fp;\n\t\tf_open(&fp, sdPath, FA_CREATE_ALWAYS | FA_WRITE);\n\t\tf_write(&fp, &sector_start, 4, NULL);\n\t\tf_close(&fp);\n\n\t\tgui->base_path[strlen(gui->base_path) - 1] = 0;\n\t\tsave_emummc_cfg(part_idx, sector_start, gui->base_path);\n\t}\n\telse\n\t\ts_printf(txt_buf, \"Time taken: %dm %ds.\", timer / 60, timer % 60);\n\n\tlv_label_set_text(gui->label_finish, txt_buf);\n\nout:\n\tfree(txt_buf);\n\tfree(gui->base_path);\n\tsd_unmount();\n}\n"
  },
  {
    "path": "nyx/nyx_gui/frontend/fe_emummc_tools.h",
    "content": "/*\n * Copyright (c) 2018 Rajko Stojadinovic\n * Copyright (c) 2018 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _FE_EMUMMC_TOOLS_H_\n#define _FE_EMUMMC_TOOLS_H_\n\n#include \"gui.h\"\n\ntypedef struct _emummc_cfg_t\n{\n\tint  enabled;\n\tu32  sector;\n\tu16  id;\n\tchar *path;\n\tchar *nintendo_path;\n} emummc_cfg_t;\n\nvoid load_emummc_cfg(emummc_cfg_t *emu_info);\nvoid save_emummc_cfg(u32 part_idx, u32 sector_start, const char *path);\nvoid dump_emummc_file(emmc_tool_gui_t *gui);\nvoid dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start, u32 resized_count);\nvoid update_emummc_base_folder(char *outFilename, u32 sdPathLen, u32 currPartIdx);\n\nint  emummc_raw_derive_bis_keys();\n\n#endif\n"
  },
  {
    "path": "nyx/nyx_gui/frontend/gui.c",
    "content": "/*\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <stdlib.h>\n\n#include <bdk.h>\n\n#include \"gui.h\"\n#include \"gui_emummc_tools.h\"\n#include \"gui_tools.h\"\n#include \"gui_info.h\"\n#include \"gui_options.h\"\n#include <libs/lvgl/lv_themes/lv_theme_hekate.h>\n#include <libs/lvgl/lvgl.h>\n#include \"../gfx/logos-gui.h\"\n\n#include \"../config.h\"\n#include <libs/fatfs/ff.h>\n\nextern volatile boot_cfg_t *b_cfg;\nextern volatile nyx_storage_t *nyx_str;\n\nextern lv_res_t launch_payload(lv_obj_t *list);\n\nstatic bool disp_init_done = false;\nstatic bool do_auto_reload = false;\n\nlv_style_t hint_small_style;\nlv_style_t hint_small_style_white;\nlv_style_t monospace_text;\n\nlv_obj_t *payload_list;\nlv_obj_t *autorcm_btn;\nlv_obj_t *close_btn;\n\nlv_img_dsc_t *icon_switch;\nlv_img_dsc_t *icon_payload;\nlv_img_dsc_t *icon_lakka;\n\nlv_img_dsc_t *hekate_bg;\n\nlv_style_t btn_transp_rel, btn_transp_pr, btn_transp_tgl_rel, btn_transp_tgl_pr, btn_transp_ina;\nlv_style_t ddlist_transp_bg, ddlist_transp_sel;\nlv_style_t tabview_btn_pr, tabview_btn_tgl_pr;\n\nlv_style_t mbox_darken;\n\nchar *text_color;\n\ntypedef struct _jc_lv_driver_t\n{\n\tlv_indev_t *indev_jc;\n\tlv_indev_t *indev_touch;\n// LV_INDEV_READ_PERIOD * JC_CAL_MAX_STEPS = 264 ms.\n#define JC_CAL_MAX_STEPS 8\n\tu32 calibration_step;\n\tu16 cx_max;\n\tu16 cx_min;\n\tu16 cy_max;\n\tu16 cy_min;\n\ts16 pos_x;\n\ts16 pos_y;\n\ts16 pos_last_x;\n\ts16 pos_last_y;\n\tlv_obj_t *cursor;\n\tu32 cursor_timeout;\n\tbool cursor_hidden;\n\tu32 console_timeout;\n} jc_lv_driver_t;\n\nstatic jc_lv_driver_t jc_drv_ctx;\n\ngui_status_bar_ctx status_bar;\n\nstatic void _nyx_disp_init()\n{\n\tvic_surface_t vic_sfc;\n\tvic_sfc.src_buf  = NYX_FB2_ADDRESS;\n\tvic_sfc.dst_buf  = NYX_FB_ADDRESS;\n\tvic_sfc.width    = 1280;\n\tvic_sfc.height   = 720;\n\tvic_sfc.pix_fmt  = VIC_PIX_FORMAT_X8R8G8B8;\n\tvic_sfc.rotation = VIC_ROTATION_270;\n\n\t// Set hardware rotation via VIC.\n\tvic_init();\n\tvic_set_surface(&vic_sfc);\n\n\t// Turn off backlight to hide the transition.\n\tdisplay_backlight_brightness(0, 1000);\n\n\t// Rotate and copy the first frame.\n\tvic_compose();\n\tvic_wait_idle();\n\n\t// Switch to new window configuration.\n\tdisplay_init_window_a_pitch_vic();\n\n\t// Enable logging on window D.\n\tdisplay_init_window_d_console();\n\n\t// Switch back the backlight.\n\tdisplay_backlight_brightness(h_cfg.backlight - 20, 1000);\n}\n\nstatic void _save_log_to_bmp(char *fname)\n{\n\tu32 *fb_ptr = (u32 *)LOG_FB_ADDRESS;\n\n\t// Check if there's log written.\n\tbool log_changed = false;\n\tfor (u32 i = 0; i < 0xCD000; i++)\n\t{\n\t\tif (fb_ptr[i] != 0)\n\t\t{\n\t\t\tlog_changed = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (!log_changed)\n\t\treturn;\n\n\tconst u32 file_size = LOG_FB_SZ + 0x36;\n\tu8 *bitmap = malloc(file_size);\n\n\t// Reconstruct FB for bottom-top, landscape bmp. Rotation: 656x1280 -> 1280x656.\n\tu32 *fb = malloc(LOG_FB_SZ);\n\tfor (int x = 1279; x > - 1; x--)\n\t{\n\t\tfor (int y = 655; y > -1; y--)\n\t\t\tfb[y * 1280 + x] = *fb_ptr++;\n\t}\n\n\tmanual_system_maintenance(true);\n\n\tmemcpy(bitmap + 0x36, fb, LOG_FB_SZ);\n\n\ttypedef struct _bmp_t\n\t{\n\t\tu16 magic;\n\t\tu32 size;\n\t\tu32 rsvd;\n\t\tu32 data_off;\n\t\tu32 hdr_size;\n\t\tu32 width;\n\t\tu32 height;\n\t\tu16 planes;\n\t\tu16 pxl_bits;\n\t\tu32 comp;\n\t\tu32 img_size;\n\t\tu32 res_h;\n\t\tu32 res_v;\n\t\tu64 rsvd2;\n\t} __attribute__((packed)) bmp_t;\n\n\tbmp_t *bmp = (bmp_t *)bitmap;\n\n\tbmp->magic    = 0x4D42;\n\tbmp->size     = file_size;\n\tbmp->rsvd     = 0;\n\tbmp->data_off = 0x36;\n\tbmp->hdr_size = 40;\n\tbmp->width    = 1280;\n\tbmp->height   = 656;\n\tbmp->planes   = 1;\n\tbmp->pxl_bits = 32;\n\tbmp->comp     = 0;\n\tbmp->img_size = LOG_FB_SZ;\n\tbmp->res_h    = 2834;\n\tbmp->res_v    = 2834;\n\tbmp->rsvd2    = 0;\n\n\tchar path[0x80];\n\tstrcpy(path, \"bootloader/screenshots\");\n\ts_printf(path + strlen(path), \"/nyx%s_log.bmp\", fname);\n\tsd_save_to_file(bitmap, file_size, path);\n\n\tfree(bitmap);\n\tfree(fb);\n}\n\nstatic void _save_fb_to_bmp()\n{\n\t// Disallow screenshots if less than 2s passed.\n\tstatic u32 timer = 0;\n\tif (get_tmr_ms() < timer)\n\t\treturn;\n\n\tif (do_auto_reload)\n\t\tgoto exit;\n\n\t// Invalidate data.\n\tbpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);\n\n\tconst u32 file_size = NYX_FB_SZ + 0x36;\n\tu8 *bitmap = malloc(file_size);\n\tu32 *fb = malloc(NYX_FB_SZ);\n\tu32 *fb_ptr = (u32 *)NYX_FB2_ADDRESS;\n\tu32 line_bytes = 1280 * sizeof(u32);\n\n\t// Reconstruct FB for bottom-top, landscape bmp. No rotation.\n\tfor (int y = 719; y > -1; y--)\n\t{\n\t\tmemcpy(&fb[y * 1280], fb_ptr, line_bytes);\n\t\tfb_ptr += line_bytes / sizeof(u32);\n\t}\n\n\t// Create notification box.\n\tlv_obj_t * mbox = lv_mbox_create(lv_layer_top(), NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_mbox_set_text(mbox, SYMBOL_CAMERA\"  #FFDD00 Saving screenshot...#\");\n\tlv_obj_set_width(mbox, LV_DPI * 4);\n\tlv_obj_set_top(mbox, true);\n\tlv_obj_align(mbox, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0);\n\n\t// Capture effect.\n\tdisplay_backlight_brightness(255, 100);\n\tmsleep(150);\n\tdisplay_backlight_brightness(h_cfg.backlight - 20, 100);\n\n\tmanual_system_maintenance(true);\n\n\tmemcpy(bitmap + 0x36, fb, NYX_FB_SZ);\n\n\ttypedef struct _bmp_t\n\t{\n\t\tu16 magic;\n\t\tu32 size;\n\t\tu32 rsvd;\n\t\tu32 data_off;\n\t\tu32 hdr_size;\n\t\tu32 width;\n\t\tu32 height;\n\t\tu16 planes;\n\t\tu16 pxl_bits;\n\t\tu32 comp;\n\t\tu32 img_size;\n\t\tu32 res_h;\n\t\tu32 res_v;\n\t\tu64 rsvd2;\n\t} __attribute__((packed)) bmp_t;\n\n\tbmp_t *bmp = (bmp_t *)bitmap;\n\n\tbmp->magic    = 0x4D42;\n\tbmp->size     = file_size;\n\tbmp->rsvd     = 0;\n\tbmp->data_off = 0x36;\n\tbmp->hdr_size = 40;\n\tbmp->width    = 1280;\n\tbmp->height   = 720;\n\tbmp->planes   = 1;\n\tbmp->pxl_bits = 32;\n\tbmp->comp     = 0;\n\tbmp->img_size = NYX_FB_SZ;\n\tbmp->res_h    = 2834;\n\tbmp->res_v    = 2834;\n\tbmp->rsvd2    = 0;\n\n\tsd_mount();\n\n\tchar path[0x80];\n\n\tstrcpy(path, \"bootloader\");\n\tf_mkdir(path);\n\tstrcat(path, \"/screenshots\");\n\tf_mkdir(path);\n\n\t// Create date/time name.\n\tchar fname[32];\n\trtc_time_t time;\n\tmax77620_rtc_get_time_adjusted(&time);\n\ts_printf(fname, \"%04d%02d%02d_%02d%02d%02d\", time.year, time.month, time.day, time.hour, time.min, time.sec);\n\ts_printf(path + strlen(path), \"/nyx%s.bmp\", fname);\n\n\t// Save screenshot and log.\n\tint res = sd_save_to_file(bitmap, file_size, path);\n\tif (!res)\n\t\t_save_log_to_bmp(fname);\n\n\tsd_unmount();\n\n\tfree(bitmap);\n\tfree(fb);\n\n\tif (!res)\n\t\tlv_mbox_set_text(mbox, SYMBOL_CAMERA\"  #96FF00 Screenshot saved!#\");\n\telse\n\t\tlv_mbox_set_text(mbox, SYMBOL_WARNING\"  #FFDD00 Screenshot failed!#\");\n\tmanual_system_maintenance(true);\n\tlv_mbox_start_auto_close(mbox, 4000);\n\nexit:\n\t// Set timer to 2s.\n\ttimer = get_tmr_ms() + 2000;\n}\n\nstatic void _disp_fb_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t *color_p)\n{\n\t// Draw to intermediate non-rotated framebuffer.\n\tgfx_set_rect_pitch((u32 *)NYX_FB2_ADDRESS, (u32 *)color_p, 1280, x1, y1, x2, y2);\n\n\t// Rotate and copy to visible framebuffer.\n\tif (disp_init_done)\n\t\tvic_compose();\n\n\t// Check if display init was done. If it's the first big draw, init.\n\tif (!disp_init_done && ((x2 - x1 + 1) > 600))\n\t{\n\t\tdisp_init_done = true;\n\t\t_nyx_disp_init();\n\t}\n\n\tlv_flush_ready();\n}\n\nstatic touch_event_t touchpad;\nstatic bool touch_enabled;\nstatic bool console_enabled = false;\n\nstatic bool _fts_touch_read(lv_indev_data_t *data)\n{\n\tif (!touch_enabled)\n\t\treturn false;\n\n\tint res = touch_poll(&touchpad);\n\n\t// Take a screenshot if 3rd finger.\n\tif (touchpad.finger > 2)\n\t{\n\t\t_save_fb_to_bmp();\n\n\t\tdata->state = LV_INDEV_STATE_REL;\n\t\treturn false;\n\t}\n\n\tif (console_enabled)\n\t{\n\t\t// If no event, keep last debug message.\n\t\tif (res)\n\t\t\treturn false;\n\n\t\t// Print input debugging in console.\n\t\tgfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy, &gfx_con.savedcol);\n\t\tgfx_con_setpos(32, 638, GFX_COL_AUTO);\n\t\tgfx_con.fntsz = 8;\n\t\tgfx_printf(\"x: %4d, y: %4d | z: %3d | \", touchpad.x, touchpad.y, touchpad.z);\n\t\tgfx_printf(\"0: %02X, 1: %02X, 2: %02X, \", touchpad.raw[0], touchpad.raw[1], touchpad.raw[2]);\n\t\tgfx_printf(\"3: %02X, 4: %02X, 5: %02X, 6: %02X\",\n\t\t\ttouchpad.raw[3], touchpad.raw[4], touchpad.raw[5], touchpad.raw[6]);\n\t\tgfx_con_setpos(gfx_con.savedx, gfx_con.savedy, gfx_con.savedcol);\n\t\tgfx_con.fntsz = 16;\n\n\t\treturn false;\n\t}\n\n\t// Always set touch points.\n\tdata->point.x = touchpad.x;\n\tdata->point.y = touchpad.y;\n\n\t// Decide touch enable.\n\tif (touchpad.touch)\n\t\tdata->state = LV_INDEV_STATE_PR;\n\telse\n\t\tdata->state = LV_INDEV_STATE_REL;\n\n\treturn false; // No buffering so no more data read.\n}\n\nstatic bool _jc_virt_mouse_read(lv_indev_data_t *data)\n{\n\t// Poll Joy-Con.\n\tjc_gamepad_rpt_t *jc_pad = joycon_poll();\n\n\tif (!jc_pad)\n\t{\n\t\tdata->state = LV_INDEV_STATE_REL;\n\t\treturn false;\n\t}\n\n\t// Take a screenshot if Capture button is pressed.\n\tif (jc_pad->cap)\n\t{\n\t\t_save_fb_to_bmp();\n\n\t\tdata->state = LV_INDEV_STATE_REL;\n\t\treturn false;\n\t}\n\n\t// Calibrate left stick.\n\tif (jc_drv_ctx.calibration_step != JC_CAL_MAX_STEPS)\n\t{\n\t\tif (n_cfg.jc_force_right)\n\t\t{\n\t\t\tif (jc_pad->conn_r\n\t\t\t\t&& jc_pad->rstick_x > 0x400 && jc_pad->rstick_y > 0x400\n\t\t\t\t&& jc_pad->rstick_x < 0xC00 && jc_pad->rstick_y < 0xC00)\n\t\t\t{\n\t\t\t\tjc_drv_ctx.calibration_step++;\n\t\t\t\tjc_drv_ctx.cx_max = jc_pad->rstick_x + 0x96;\n\t\t\t\tjc_drv_ctx.cx_min = jc_pad->rstick_x - 0x96;\n\t\t\t\tjc_drv_ctx.cy_max = jc_pad->rstick_y + 0x96;\n\t\t\t\tjc_drv_ctx.cy_min = jc_pad->rstick_y - 0x96;\n\t\t\t\tjc_drv_ctx.cursor_timeout = 0;\n\t\t\t}\n\t\t}\n\t\telse if (jc_pad->conn_l\n\t\t\t     && jc_pad->lstick_x > 0x400 && jc_pad->lstick_y > 0x400\n\t\t\t     && jc_pad->lstick_x < 0xC00 && jc_pad->lstick_y < 0xC00)\n\t\t{\n\t\t\tjc_drv_ctx.calibration_step++;\n\t\t\tjc_drv_ctx.cx_max = jc_pad->lstick_x + 0x96;\n\t\t\tjc_drv_ctx.cx_min = jc_pad->lstick_x - 0x96;\n\t\t\tjc_drv_ctx.cy_max = jc_pad->lstick_y + 0x96;\n\t\t\tjc_drv_ctx.cy_min = jc_pad->lstick_y - 0x96;\n\t\t\tjc_drv_ctx.cursor_timeout = 0;\n\t\t}\n\n\t\tif (jc_drv_ctx.calibration_step != JC_CAL_MAX_STEPS)\n\t\t{\n\t\t\tif (jc_pad->plus || jc_pad->minus)\n\t\t\t\tgoto handle_console;\n\n\t\t\tif (console_enabled)\n\t\t\t\tgoto console;\n\n\t\t\tdata->state = LV_INDEV_STATE_REL;\n\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t// Re-calibrate on disconnection.\n\tif (n_cfg.jc_force_right && !jc_pad->conn_r)\n\t\tjc_drv_ctx.calibration_step = 0;\n\telse if (!n_cfg.jc_force_right && !jc_pad->conn_l)\n\t\tjc_drv_ctx.calibration_step = 0;\n\n\t// Set button presses.\n\tif (jc_pad->a || jc_pad->zl || jc_pad->zr)\n\t\tdata->state = LV_INDEV_STATE_PR;\n\telse\n\t\tdata->state = LV_INDEV_STATE_REL;\n\n\t// Enable console.\n\tif (jc_pad->plus || jc_pad->minus)\n\t{\nhandle_console:\n\t\tif (((u32)get_tmr_ms() - jc_drv_ctx.console_timeout) > 1000)\n\t\t{\n\t\t\tif (!console_enabled)\n\t\t\t{\n\t\t\t\tdisplay_window_d_console_enable();\n\t\t\t\tconsole_enabled = true;\n\t\t\t\tgfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy, &gfx_con.savedcol);\n\t\t\t\tgfx_con_setpos(964, 630, GFX_COL_AUTO);\n\t\t\t\tgfx_printf(\"Press -/+ to close\");\n\t\t\t\tgfx_con_setpos(gfx_con.savedx, gfx_con.savedy, gfx_con.savedcol);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdisplay_window_d_console_disable();\n\t\t\t\tconsole_enabled = false;\n\t\t\t}\n\n\t\t\tjc_drv_ctx.console_timeout = get_tmr_ms();\n\t\t}\n\n\t\tdata->state = LV_INDEV_STATE_REL;\n\n\t\treturn false;\n\t}\n\n\tif (console_enabled)\n\t{\nconsole:\n\t\t// Print input debugging in console.\n\t\tgfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy, &gfx_con.savedcol);\n\t\tgfx_con_setpos(32, 630, GFX_COL_AUTO);\n\t\tgfx_con.fntsz = 8;\n\t\tgfx_printf(\"x: %4X, y: %4X | rx: %4X, ry: %4X | b: %06X | c: %d (%d), %d (%d)\",\n\t\t\tjc_pad->lstick_x, jc_pad->lstick_y, jc_pad->rstick_x, jc_pad->rstick_y,\n\t\t\tjc_pad->buttons, jc_pad->batt_info_l, jc_pad->batt_chrg_l,\n\t\t\tjc_pad->batt_info_r, jc_pad->batt_chrg_r);\n\t\tgfx_con_setpos(gfx_con.savedx, gfx_con.savedy, gfx_con.savedcol);\n\t\tgfx_con.fntsz = 16;\n\n\t\tdata->state = LV_INDEV_STATE_REL;\n\n\t\treturn false;\n\t}\n\n\t// Calculate new cursor position.\n\tif (!n_cfg.jc_force_right)\n\t{\n\t\t// Left stick X.\n\t\tif (jc_pad->lstick_x <= jc_drv_ctx.cx_max && jc_pad->lstick_x >= jc_drv_ctx.cx_min)\n\t\t\tjc_drv_ctx.pos_x += 0;\n\t\telse if (jc_pad->lstick_x > jc_drv_ctx.cx_max)\n\t\t\tjc_drv_ctx.pos_x += ((jc_pad->lstick_x - jc_drv_ctx.cx_max) / 30);\n\t\telse\n\t\t\tjc_drv_ctx.pos_x -= ((jc_drv_ctx.cx_min - jc_pad->lstick_x) / 30);\n\n\t\t// Left stick Y.\n\t\tif (jc_pad->lstick_y <= jc_drv_ctx.cy_max && jc_pad->lstick_y >= jc_drv_ctx.cy_min)\n\t\t\tjc_drv_ctx.pos_y += 0;\n\t\telse if (jc_pad->lstick_y > jc_drv_ctx.cy_max)\n\t\t{\n\t\t\ts16 val = (jc_pad->lstick_y - jc_drv_ctx.cy_max) / 30;\n\t\t\t// Hoag has inverted Y axis.\n\t\t\tif (jc_pad->sio_mode)\n\t\t\t\tval *= -1;\n\t\t\tjc_drv_ctx.pos_y -= val;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ts16 val = (jc_drv_ctx.cy_min - jc_pad->lstick_y) / 30;\n\t\t\t// Hoag has inverted Y axis.\n\t\t\tif (jc_pad->sio_mode)\n\t\t\t\tval *= -1;\n\t\t\tjc_drv_ctx.pos_y += val;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Right stick X.\n\t\tif (jc_pad->rstick_x <= jc_drv_ctx.cx_max && jc_pad->rstick_x >= jc_drv_ctx.cx_min)\n\t\t\tjc_drv_ctx.pos_x += 0;\n\t\telse if (jc_pad->rstick_x > jc_drv_ctx.cx_max)\n\t\t\tjc_drv_ctx.pos_x += ((jc_pad->rstick_x - jc_drv_ctx.cx_max) / 30);\n\t\telse\n\t\t\tjc_drv_ctx.pos_x -= ((jc_drv_ctx.cx_min - jc_pad->rstick_x) / 30);\n\n\t\t// Right stick Y.\n\t\tif (jc_pad->rstick_y <= jc_drv_ctx.cy_max && jc_pad->rstick_y >= jc_drv_ctx.cy_min)\n\t\t\tjc_drv_ctx.pos_y += 0;\n\t\telse if (jc_pad->rstick_y > jc_drv_ctx.cy_max)\n\t\t{\n\t\t\ts16 val = (jc_pad->rstick_y - jc_drv_ctx.cy_max) / 30;\n\t\t\t// Hoag has inverted Y axis.\n\t\t\tif (jc_pad->sio_mode)\n\t\t\t\tval *= -1;\n\t\t\tjc_drv_ctx.pos_y -= val;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ts16 val = (jc_drv_ctx.cy_min - jc_pad->rstick_y) / 30;\n\t\t\t// Hoag has inverted Y axis.\n\t\t\tif (jc_pad->sio_mode)\n\t\t\t\tval *= -1;\n\t\t\tjc_drv_ctx.pos_y += val;\n\t\t}\n\t}\n\n\t// Ensure value inside screen limits.\n\tif (jc_drv_ctx.pos_x < 0)\n\t\tjc_drv_ctx.pos_x = 0;\n\telse if (jc_drv_ctx.pos_x > 1279)\n\t\tjc_drv_ctx.pos_x = 1279;\n\n\tif (jc_drv_ctx.pos_y < 0)\n\t\tjc_drv_ctx.pos_y = 0;\n\telse if (jc_drv_ctx.pos_y > 719)\n\t\tjc_drv_ctx.pos_y = 719;\n\n\t// Set cursor position.\n\tdata->point.x = jc_drv_ctx.pos_x;\n\tdata->point.y = jc_drv_ctx.pos_y;\n\n\t// Auto hide cursor.\n\tif (jc_drv_ctx.pos_x != jc_drv_ctx.pos_last_x || jc_drv_ctx.pos_y != jc_drv_ctx.pos_last_y)\n\t{\n\t\tjc_drv_ctx.pos_last_x = jc_drv_ctx.pos_x;\n\t\tjc_drv_ctx.pos_last_y = jc_drv_ctx.pos_y;\n\n\t\tjc_drv_ctx.cursor_hidden = false;\n\t\tjc_drv_ctx.cursor_timeout = get_tmr_ms();\n\t\tlv_indev_set_cursor(jc_drv_ctx.indev_jc, jc_drv_ctx.cursor);\n\n\t\t// Un hide cursor.\n\t\tlv_obj_set_opa_scale_enable(jc_drv_ctx.cursor, false);\n\t}\n\telse\n\t{\n\t\tif (!jc_drv_ctx.cursor_hidden)\n\t\t{\n\t\t\tif (((u32)get_tmr_ms() - jc_drv_ctx.cursor_timeout) > 3000)\n\t\t\t{\n\t\t\t\t// Remove cursor and hide it.\n\t\t\t\tlv_indev_set_cursor(jc_drv_ctx.indev_jc, NULL);\n\t\t\t\tlv_obj_set_opa_scale_enable(jc_drv_ctx.cursor, true);\n\t\t\t\tlv_obj_set_opa_scale(jc_drv_ctx.cursor, LV_OPA_TRANSP);\n\n\t\t\t\tjc_drv_ctx.cursor_hidden = true;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tdata->state = LV_INDEV_STATE_REL; // Ensure that no clicks are allowed.\n\t}\n\n\tif (jc_pad->b && close_btn)\n\t{\n\t\tlv_action_t close_btn_action = lv_btn_get_action(close_btn, LV_BTN_ACTION_CLICK);\n\t\tclose_btn_action(close_btn);\n\t\tclose_btn = NULL;\n\t}\n\n\treturn false; // No buffering so no more data read.\n}\n\ntypedef struct _system_maintenance_tasks_t\n{\n\tunion\n\t{\n\t\tlv_task_t *tasks[2];\n\t\tstruct\n\t\t{\n\t\t\tlv_task_t *status_bar;\n\t\t\tlv_task_t *dram_periodic_comp;\n\t\t} task;\n\t};\n} system_maintenance_tasks_t;\n\nstatic system_maintenance_tasks_t system_tasks;\n\nvoid manual_system_maintenance(bool refresh)\n{\n\tfor (u32 task_idx = 0; task_idx < (sizeof(system_maintenance_tasks_t) / sizeof(lv_task_t *)); task_idx++)\n\t{\n\t\tlv_task_t *task = system_tasks.tasks[task_idx];\n\t\tif (task && (lv_tick_elaps(task->last_run) >= task->period))\n\t\t{\n\t\t\ttask->last_run = lv_tick_get();\n\t\t\ttask->task(task->param);\n\t\t}\n\t}\n\tif (refresh)\n\t\tlv_refr_now();\n}\n\nlv_img_dsc_t *bmp_to_lvimg_obj(const char *path)\n{\n\tu32 fsize;\n\tu8 *bitmap = sd_file_read(path, &fsize);\n\tif (!bitmap)\n\t\treturn NULL;\n\n\tstruct _bmp_data\n\t{\n\t\tu32 size;\n\t\tu32 size_x;\n\t\tu32 size_y;\n\t\tu32 offset;\n\t};\n\n\tstruct _bmp_data bmpData;\n\n\t// Get values manually to avoid unaligned access.\n\tbmpData.size = bitmap[2] | bitmap[3] << 8 |\n\t\tbitmap[4] << 16 | bitmap[5] << 24;\n\tbmpData.offset = bitmap[10] | bitmap[11] << 8 |\n\t\tbitmap[12] << 16 | bitmap[13] << 24;\n\tbmpData.size_x = bitmap[18] | bitmap[19] << 8 |\n\t\tbitmap[20] << 16 | bitmap[21] << 24;\n\tbmpData.size_y = bitmap[22] | bitmap[23] << 8 |\n\t\tbitmap[24] << 16 | bitmap[25] << 24;\n\t// Sanity check.\n\tif (bitmap[0] == 'B' &&\n\t\tbitmap[1] == 'M' &&\n\t\tbitmap[28] == 32 && // Only 32 bit BMPs allowed.\n\t\tbmpData.size <= fsize)\n\t{\n\t\t// Check if non-default Bottom-Top.\n\t\tbool flipped = false;\n\t\tif (bmpData.size_y & 0x80000000)\n\t\t{\n\t\t\tbmpData.size_y = ~(bmpData.size_y) + 1;\n\t\t\tflipped = true;\n\t\t}\n\n\t\tlv_img_dsc_t *img_desc = (lv_img_dsc_t *)bitmap;\n\t\tuptr offset_copy = ALIGN((uptr)bitmap + sizeof(lv_img_dsc_t), 0x10);\n\n\t\timg_desc->header.always_zero = 0;\n\t\timg_desc->header.w = bmpData.size_x;\n\t\timg_desc->header.h = bmpData.size_y;\n\t\timg_desc->header.cf = (bitmap[28] == 32) ? LV_IMG_CF_TRUE_COLOR_ALPHA : LV_IMG_CF_TRUE_COLOR; // Only LV_IMG_CF_TRUE_COLOR_ALPHA is actually allowed.\n\t\timg_desc->data_size = bmpData.size - bmpData.offset;\n\t\timg_desc->data = (u8 *)offset_copy;\n\n\t\tu32 *tmp = malloc(bmpData.size);\n\t\tu32 *tmp2 = (u32 *)offset_copy;\n\n\t\t// Copy the unaligned data to an aligned buffer.\n\t\tmemcpy((u8 *)tmp, bitmap + bmpData.offset, img_desc->data_size);\n\t\tu32 j = 0;\n\n\t\tif (!flipped)\n\t\t{\n\t\t\tfor (u32 y = 0; y < bmpData.size_y; y++)\n\t\t\t{\n\t\t\t\tfor (u32 x = 0; x < bmpData.size_x; x++)\n\t\t\t\t\ttmp2[j++] = tmp[(bmpData.size_y - 1 - y ) * bmpData.size_x + x];\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (u32 y = 0; y < bmpData.size_y; y++)\n\t\t\t{\n\t\t\t\tfor (u32 x = 0; x < bmpData.size_x; x++)\n\t\t\t\t\ttmp2[j++] = tmp[y * bmpData.size_x + x];\n\t\t\t}\n\t\t}\n\n\t\tfree(tmp);\n\t}\n\telse\n\t{\n\t\tfree(bitmap);\n\t\treturn NULL;\n\t}\n\n\treturn (lv_img_dsc_t *)bitmap;\n}\n\nlv_res_t nyx_generic_onoff_toggle(lv_obj_t *btn)\n{\n\tlv_obj_t *label_btn = lv_obj_get_child(btn, NULL);\n\tlv_obj_t *label_btn2 = lv_obj_get_child(btn, label_btn);\n\n\tchar label_text[64];\n\tif (!label_btn2)\n\t{\n\t\tstrcpy(label_text, lv_label_get_text(label_btn));\n\t\tlabel_text[strlen(label_text) - 15] = 0;\n\n\t\tif (!(lv_btn_get_state(btn) & LV_BTN_STATE_TGL_REL))\n\t\t{\n\t\t\tstrcat(label_text, \"#D0D0D0    OFF#\");\n\t\t\tlv_label_set_text(label_btn, label_text);\n\t\t}\n\t\telse\n\t\t{\n\t\t\ts_printf(label_text, \"%s%s%s\", label_text, text_color, \"    ON #\");\n\t\t\tlv_label_set_text(label_btn, label_text);\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (!(lv_btn_get_state(btn) & LV_BTN_STATE_TGL_REL))\n\t\t\tlv_label_set_text(label_btn, \"#D0D0D0 OFF#\");\n\t\telse\n\t\t{\n\t\t\ts_printf(label_text, \"%s%s\", text_color, \" ON #\");\n\t\t\tlv_label_set_text(label_btn, label_text);\n\t\t}\n\t}\n\n\treturn LV_RES_OK;\n}\n\nlv_res_t nyx_mbox_action(lv_obj_t *btns, const char *txt)\n{\n\tlv_obj_t *mbox = lv_mbox_get_from_btn(btns);\n\tlv_obj_t *dark_bg = lv_obj_get_parent(mbox);\n\n\tlv_obj_del(dark_bg); // Deletes children also (mbox).\n\n\treturn LV_RES_INV;\n}\n\nbool nyx_emmc_check_battery_enough()\n{\n\tif (h_cfg.devmode)\n\t\treturn true;\n\n\tint batt_volt = 0;\n\n\tmax17050_get_property(MAX17050_VCELL, &batt_volt);\n\n\tif (batt_volt && batt_volt < 3650)\n\t{\n\t\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\t\tlv_obj_set_style(dark_bg, &mbox_darken);\n\t\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\t\tstatic const char * mbox_btn_map[] = { \"\\251\", \"\\222OK\", \"\\251\", \"\" };\n\t\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\t\tlv_mbox_set_recolor_text(mbox, true);\n\n\t\tlv_mbox_set_text(mbox,\n\t\t\t\"#FF8000 Battery Check#\\n\\n\"\n\t\t\t\"#FFDD00 Battery is not enough to carry on#\\n\"\n\t\t\t\"#FFDD00 with selected operation!#\\n\\n\"\n\t\t\t\"Charge to at least #C7EA46 3650 mV#, and try again!\");\n\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);\n\t\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);\n\t\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\t\tlv_obj_set_top(mbox, true);\n\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nstatic void _nyx_sd_card_issues_warning(void *param)\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char * mbox_btn_map[] = { \"\\251\", \"\\222OK\", \"\\251\", \"\" };\n\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\n\tlv_mbox_set_text(mbox,\n\t\t\"#FF8000 SD Card Issues Warning#\\n\\n\"\n\t\t\"#FFDD00 The SD Card is initialized in 1-bit mode!#\\n\"\n\t\t\"#FFDD00 This might mean detached or broken connector!#\\n\\n\"\n\t\t\"You might want to check\\n#C7EA46 Console Info# -> #C7EA46 microSD#\");\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n}\n\nvoid nyx_window_toggle_buttons(lv_obj_t *win, bool disable)\n{\n\tlv_win_ext_t * ext = lv_obj_get_ext_attr(win);\n\tlv_obj_t * hbtn;\n\n\thbtn = lv_obj_get_child_back(ext->header, NULL);\n\thbtn = lv_obj_get_child_back(ext->header, hbtn); // Skip the title.\n\n\tif (disable)\n\t{\n\t\twhile (hbtn != NULL)\n\t\t{\n\t\t\tlv_obj_set_opa_scale(hbtn, LV_OPA_40);\n\t\t\tlv_obj_set_opa_scale_enable(hbtn, true);\n\t\t\tlv_obj_set_click(hbtn, false);\n\t\t\thbtn = lv_obj_get_child_back(ext->header, hbtn);\n\t\t}\n\t}\n\telse\n\t{\n\t\twhile (hbtn != NULL)\n\t\t{\n\t\t\tlv_obj_set_opa_scale(hbtn, LV_OPA_COVER);\n\t\t\tlv_obj_set_click(hbtn, true);\n\t\t\thbtn = lv_obj_get_child_back(ext->header, hbtn);\n\t\t}\n\t}\n}\n\nlv_res_t nyx_win_close_action(lv_obj_t * btn)\n{\n\tclose_btn = NULL;\n\n\treturn lv_win_close_action(btn);\n}\n\nlv_obj_t *nyx_create_standard_window(const char *win_title, lv_action_t close_action)\n{\n\tstatic lv_style_t win_bg_style;\n\n\tlv_style_copy(&win_bg_style, &lv_style_plain);\n\twin_bg_style.body.main_color = lv_theme_get_current()->bg->body.main_color;\n\twin_bg_style.body.grad_color = win_bg_style.body.main_color;\n\n\tlv_obj_t *win = lv_win_create(lv_scr_act(), NULL);\n\tlv_win_set_title(win, win_title);\n\tlv_win_set_style(win, LV_WIN_STYLE_BG, &win_bg_style);\n\tlv_obj_set_size(win, LV_HOR_RES, LV_VER_RES);\n\n\tif (!close_action)\n\t\tclose_btn = lv_win_add_btn(win, NULL, SYMBOL_CLOSE\" Close\", nyx_win_close_action);\n\telse\n\t\tclose_btn = lv_win_add_btn(win, NULL, SYMBOL_CLOSE\" Close\", close_action);\n\n\treturn win;\n}\n\nstatic bool launch_logs_enable = false;\n\nstatic void _launch_hos(u8 autoboot, u8 autoboot_list)\n{\n\tb_cfg->boot_cfg = BOOT_CFG_AUTOBOOT_EN;\n\tif (launch_logs_enable)\n\t\tb_cfg->boot_cfg |= BOOT_CFG_FROM_LAUNCH;\n\tb_cfg->autoboot = autoboot;\n\tb_cfg->autoboot_list = autoboot_list;\n\n\tvoid (*main_ptr)() = (void *)nyx_str->hekate;\n\n\tsd_end();\n\n\thw_deinit(false);\n\n\t(*main_ptr)();\n}\n\nvoid reload_nyx(lv_obj_t *obj, bool force)\n{\n\tif (!force)\n\t{\n\t\tsd_mount();\n\n\t\t// Check that Nyx still exists.\n\t\tif (f_stat(\"bootloader/sys/nyx.bin\", NULL))\n\t\t{\n\t\t\tsd_unmount();\n\n\t\t\t// Remove lvgl object in case of being invoked from a window.\n\t\t\tif (obj)\n\t\t\t\tlv_obj_del(obj);\n\n\t\t\tdo_auto_reload = false;\n\n\t\t\treturn;\n\t\t}\n\t}\n\n\tb_cfg->boot_cfg = BOOT_CFG_AUTOBOOT_EN;\n\tb_cfg->autoboot = 0;\n\tb_cfg->autoboot_list = 0;\n\tb_cfg->extra_cfg = 0;\n\n\tvoid (*main_ptr)() = (void *)nyx_str->hekate;\n\n\tsd_end();\n\n\thw_deinit(false);\n\n\t(*main_ptr)();\n}\n\nstatic lv_res_t reload_action(lv_obj_t *btns, const char *txt)\n{\n\tif (!lv_btnm_get_pressed(btns))\n\t\treload_nyx(NULL, false);\n\n\treturn nyx_mbox_action(btns, txt);\n}\n\nstatic lv_res_t _removed_sd_action(lv_obj_t *btns, const char *txt)\n{\n\tu32 btnidx = lv_btnm_get_pressed(btns);\n\n\tswitch (btnidx)\n\t{\n\tcase 0:\n\t\tif (h_cfg.rcm_patched)\n\t\t\tpower_set_state(POWER_OFF_REBOOT);\n\t\telse\n\t\t\tpower_set_state(REBOOT_RCM);\n\t\tbreak;\n\tcase 1:\n\t\tpower_set_state(POWER_OFF_RESET);\n\t\tbreak;\n\tcase 2:\n\t\tsd_end();\n\t\tdo_auto_reload = false;\n\t\tbreak;\n\t}\n\n\treturn nyx_mbox_action(btns, txt);\n}\n\nstatic void _check_sd_card_removed(void *params)\n{\n\tstatic lv_obj_t *dark_bg = NULL;\n\n\t// The following checks if SDMMC_1 is initialized.\n\t// If yes and card was removed, shows a message box,\n\t// that will reload Nyx, when the card is inserted again.\n\tif (!do_auto_reload && sd_get_card_removed())\n\t{\n\t\tdark_bg = lv_obj_create(lv_scr_act(), NULL);\n\t\tlv_obj_set_style(dark_bg, &mbox_darken);\n\t\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\t\tstatic const char * mbox_btn_map[] = { \"\\221Reboot (RCM)\", \"\\221Power Off\", \"\\221Do not reload\", \"\" };\n\t\tstatic const char * mbox_btn_map_rcm_patched[] = { \"\\221Reboot\", \"\\221Power Off\", \"\\221Do not reload\", \"\" };\n\t\tlv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);\n\t\tlv_mbox_set_recolor_text(mbox, true);\n\t\tlv_obj_set_width(mbox, LV_HOR_RES * 6 / 9);\n\n\t\tlv_mbox_set_text(mbox, \"\\n#FF8000 SD card was removed!#\\n\\n#96FF00 Nyx will reload after inserting it.#\\n\\nReminder that you can use UMS instead of removing it.\\n\");\n\t\tlv_mbox_add_btns(mbox, h_cfg.rcm_patched ? mbox_btn_map_rcm_patched : mbox_btn_map, _removed_sd_action);\n\n\t\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\t\tlv_obj_set_top(mbox, true);\n\n\t\tdo_auto_reload = true;\n\t}\n\n\t// If in reload state and card was inserted, reload nyx.\n\tif (do_auto_reload && !sd_get_card_removed())\n\t\treload_nyx(dark_bg, false);\n}\n\nlv_task_t *task_emmc_errors;\nstatic void _nyx_emmc_issues_warning(void *params)\n{\n\tif (emmc_get_mode() < EMMC_MMC_HS400)\n\t{\n\t\t// Remove task.\n\t\tlv_task_del(task_emmc_errors);\n\n\t\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\t\tlv_obj_set_style(dark_bg, &mbox_darken);\n\t\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\t\tstatic const char * mbox_btn_map[] = { \"\\251\", \"\\222OK\", \"\\251\", \"\" };\n\t\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\t\tlv_mbox_set_recolor_text(mbox, true);\n\n\t\tlv_mbox_set_text(mbox,\n\t\t\t\"#FF8000 eMMC Issues Warning#\\n\\n\"\n\t\t\t\"#FFDD00 Your eMMC is initialized in a slower mode!#\\n\"\n\t\t\t\"#FFDD00 This might mean hardware issues!#\\n\\n\"\n\t\t\t\"You might want to check\\n#C7EA46 Console Info# -> #C7EA46 eMMC#\");\n\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);\n\t\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);\n\t\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\t\tlv_obj_set_top(mbox, true);\n\t}\n}\n\nstatic lv_res_t _reboot_ofw_action(lv_obj_t *btns, const char *txt)\n{\n\tif (!lv_btnm_get_pressed(btns))\n\t\tpower_set_state(REBOOT_BYPASS_FUSES);\n\n\treturn nyx_mbox_action(btns, txt);\n}\n\nstatic lv_res_t _create_mbox_reboot_ofw()\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char * mbox_btn_map[] = { \"\\221OK\", \"\\221Cancel\", \"\" };\n\tlv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES * 2 / 3);\n\n\tlv_mbox_set_text(mbox,\n\t\t\"#FF8000 Warning#\\n\\n\"\n\t\t\"#FFDD00 Your real DRAM ID does not match your RAM!#\\n\"\n\t\t\"#FFDD00 Density and rank differ!#\\n\\n\"\n\t\t\"#FFDD00 Choosing to boot that way will cause #\\n\"\n\t\t\"#FFDD00 performance degradation or even crashes.#\\n\\n\"\n\t\t\"Do you really want to boot via OFW method?#\");\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map, _reboot_ofw_action);\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _reboot_action(lv_obj_t *btns, const char *txt)\n{\n\tu32 btnidx = lv_btnm_get_pressed(btns);\n\n\tu8 dram_id     = fuse_read_dramid(true);\n\tu8 dram_id_adj = fuse_read_dramid(false);\n\n\t// No OFW support if fuses burnt to 7. Custom secmon is mandatory.\n\tbool t210_8gb_dramid = !h_cfg.t210b01 && dram_id     == LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX;\n\t// Warn against OFW if T210B01 and dram id has the wrong density and ranks with actual ram.\n\tbool unmatched_fuses =  h_cfg.t210b01 && dram_id_adj == LPDDR4X_AULA_8GB_SAMSUNG_K4UBE3D4AA_MGCL && dram_id != dram_id_adj;\n\n\tswitch (btnidx)\n\t{\n\tcase 0:\n\t\tif (unmatched_fuses)\n\t\t\t_create_mbox_reboot_ofw();\n\t\telse\n\t\t\tpower_set_state(REBOOT_BYPASS_FUSES);\n\t\tbreak;\n\tcase 1:\n\t\tif (h_cfg.rcm_patched && !t210_8gb_dramid)\n\t\t\tpower_set_state(POWER_OFF_REBOOT);\n\t\telse\n\t\t\tpower_set_state(REBOOT_RCM);\n\t\tbreak;\n\t}\n\n\treturn nyx_mbox_action(btns, txt);\n}\n\nstatic lv_res_t _poweroff_action(lv_obj_t *btns, const char *txt)\n{\n\tif (!lv_btnm_get_pressed(btns))\n\t\tpower_set_state(POWER_OFF_RESET);\n\n\treturn nyx_mbox_action(btns, txt);\n}\n\nstatic lv_res_t _create_mbox_reload(lv_obj_t *btn)\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char * mbox_btn_map[] = { \"\\221Reload\", \"\\221Cancel\", \"\" };\n\tlv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES * 4 / 10);\n\n\tlv_mbox_set_text(mbox, \"#FF8000 Do you really want#\\n#FF8000 to reload hekate & Nyx?#\\n\\n\"\n\t\t\"This also checks\\n#96FF00 bootloader/update.bin#\\nfor hekate updates\");\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map, reload_action);\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _create_mbox_reboot(lv_obj_t *btn)\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char * mbox_btn_map[] = { \"\\221OFW\", \"\\221RCM\", \"\\221Cancel\", \"\" };\n\tstatic const char * mbox_btn_map_autorcm[] = { \"\\261OFW\", \"\\221RCM\", \"\\221Cancel\", \"\" };\n\tstatic const char * mbox_btn_map_patched[] = { \"\\221OFW\", \"\\221Normal\", \"\\221Cancel\", \"\" };\n\tlv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 2);\n\n\tlv_mbox_set_text(mbox, \"#FF8000 Choose where to reboot:#\");\n\n\t// No OFW support if fuses burnt to 7. Custom secmon is mandatory.\n\tbool t210_8gb_dramid = !h_cfg.t210b01 && fuse_read_dramid(true) == LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX;\n\n\tif (h_cfg.rcm_patched && !t210_8gb_dramid)\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map_patched, _reboot_action);\n\telse if (t210_8gb_dramid)\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map_autorcm, _reboot_action);\n\telse\n\t\tlv_mbox_add_btns(mbox, !h_cfg.autorcm_enabled ? mbox_btn_map : mbox_btn_map_autorcm, _reboot_action);\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _create_mbox_poweroff(lv_obj_t *btn)\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char * mbox_btn_map[] = { \"\\221Power Off\", \"\\221Cancel\", \"\" };\n\tlv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES * 4 / 10);\n\n\tlv_mbox_set_text(mbox, \"#FF8000 Do you really want#\\n#FF8000 to power off?#\");\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map, _poweroff_action);\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\treturn LV_RES_OK;\n}\n\nvoid nyx_create_onoff_button(lv_theme_t *th, lv_obj_t *parent, lv_obj_t *btn, const char *btn_name, lv_action_t action, bool transparent)\n{\n\t// Create buttons that are flat and text, plus On/Off switch.\n\tstatic lv_style_t btn_onoff_rel_hos_style, btn_onoff_pr_hos_style;\n\tlv_style_copy(&btn_onoff_rel_hos_style, th->btn.rel);\n\tbtn_onoff_rel_hos_style.body.shadow.width = 0;\n\tbtn_onoff_rel_hos_style.body.border.width = 0;\n\tbtn_onoff_rel_hos_style.body.padding.hor = 0;\n\tbtn_onoff_rel_hos_style.body.radius = 0;\n\tbtn_onoff_rel_hos_style.body.empty = 1;\n\n\tlv_style_copy(&btn_onoff_pr_hos_style, &btn_onoff_rel_hos_style);\n\tif (transparent)\n\t{\n\t\tbtn_onoff_pr_hos_style.body.main_color = LV_COLOR_HEX(0xFFFFFF);\n\t\tbtn_onoff_pr_hos_style.body.opa = 35;\n\t}\n\telse\n\t\tbtn_onoff_pr_hos_style.body.main_color = LV_COLOR_HEX(theme_bg_color ? (theme_bg_color + 0x101010) : 0x2D2D2D); // COLOR_HOS_BG_LIGHT.\n\tbtn_onoff_pr_hos_style.body.grad_color = btn_onoff_pr_hos_style.body.main_color;\n\tbtn_onoff_pr_hos_style.text.color = th->btn.pr->text.color;\n\tbtn_onoff_pr_hos_style.body.empty = 0;\n\n\tlv_obj_t *label_btn = lv_label_create(btn, NULL);\n\tlv_obj_t *label_btnsw = NULL;\n\n\tlv_label_set_recolor(label_btn, true);\n\tlabel_btnsw = lv_label_create(btn, NULL);\n\tlv_label_set_recolor(label_btnsw, true);\n\tlv_btn_set_layout(btn, LV_LAYOUT_OFF);\n\n\tlv_btn_set_style(btn, LV_BTN_STYLE_REL, &btn_onoff_rel_hos_style);\n\tlv_btn_set_style(btn, LV_BTN_STYLE_PR, &btn_onoff_pr_hos_style);\n\tlv_btn_set_style(btn, LV_BTN_STYLE_TGL_REL, &btn_onoff_rel_hos_style);\n\tlv_btn_set_style(btn, LV_BTN_STYLE_TGL_PR, &btn_onoff_pr_hos_style);\n\n\tlv_btn_set_fit(btn, false, true);\n\tlv_obj_set_width(btn, lv_obj_get_width(parent));\n\tlv_btn_set_toggle(btn, true);\n\n\tlv_label_set_text(label_btn, btn_name);\n\n\tlv_label_set_text(label_btnsw, \"#D0D0D0 OFF#\");\n\tlv_obj_align(label_btn, btn, LV_ALIGN_IN_LEFT_MID, LV_DPI / 4, 0);\n\tlv_obj_align(label_btnsw, btn, LV_ALIGN_IN_RIGHT_MID, -LV_DPI / 4, -LV_DPI / 10);\n\n\tif (action)\n\t\tlv_btn_set_action(btn, LV_BTN_ACTION_CLICK, action);\n}\n\nstatic void _create_text_button(lv_theme_t *th, lv_obj_t *parent, lv_obj_t *btn, const char *btn_name, lv_action_t action)\n{\n\t// Create buttons that are flat and only have a text label.\n\tstatic lv_style_t btn_onoff_rel_hos_style, btn_onoff_pr_hos_style;\n\tlv_style_copy(&btn_onoff_rel_hos_style, th->btn.rel);\n\tbtn_onoff_rel_hos_style.body.shadow.width = 0;\n\tbtn_onoff_rel_hos_style.body.border.width = 0;\n\tbtn_onoff_rel_hos_style.body.radius = 0;\n\tbtn_onoff_rel_hos_style.body.padding.hor = LV_DPI / 4;\n\tbtn_onoff_rel_hos_style.body.empty = 1;\n\n\tlv_style_copy(&btn_onoff_pr_hos_style, &btn_onoff_rel_hos_style);\n\tif (hekate_bg)\n\t{\n\t\tbtn_onoff_pr_hos_style.body.main_color = LV_COLOR_HEX(0xFFFFFF);\n\t\tbtn_onoff_pr_hos_style.body.opa = 35;\n\t}\n\telse\n\t\tbtn_onoff_pr_hos_style.body.main_color = LV_COLOR_HEX(theme_bg_color ? (theme_bg_color + 0x101010) : 0x2D2D2D); // COLOR_HOS_BG_LIGHT\n\tbtn_onoff_pr_hos_style.body.grad_color = btn_onoff_pr_hos_style.body.main_color;\n\tbtn_onoff_pr_hos_style.text.color = th->btn.pr->text.color;\n\tbtn_onoff_pr_hos_style.body.empty = 0;\n\n\tlv_obj_t *label_btn = lv_label_create(btn, NULL);\n\n\tlv_label_set_recolor(label_btn, true);\n\n\tlv_btn_set_style(btn, LV_BTN_STYLE_REL, &btn_onoff_rel_hos_style);\n\tlv_btn_set_style(btn, LV_BTN_STYLE_PR, &btn_onoff_pr_hos_style);\n\tlv_btn_set_style(btn, LV_BTN_STYLE_TGL_REL, &btn_onoff_rel_hos_style);\n\tlv_btn_set_style(btn, LV_BTN_STYLE_TGL_PR, &btn_onoff_pr_hos_style);\n\n\tlv_btn_set_fit(btn, true, true);\n\n\tlv_label_set_text(label_btn, btn_name);\n\n\tif (action)\n\t\tlv_btn_set_action(btn, LV_BTN_ACTION_CLICK, action);\n}\n\nstatic void _create_tab_about(lv_theme_t * th, lv_obj_t * parent)\n{\n\tlv_obj_t * lbl_credits = lv_label_create(parent, NULL);\n\n\tlv_obj_align(lbl_credits, NULL, LV_ALIGN_IN_TOP_LEFT, LV_DPI / 2, LV_DPI / 2);\n\tlv_label_set_style(lbl_credits, &monospace_text);\n\tlv_label_set_recolor(lbl_credits, true);\n\tlv_label_set_static_text(lbl_credits,\n\t\t\"#C7EA46 hekate# (c) 2018,      #C7EA46 naehrwert#, #C7EA46 st4rk#\\n\"\n\t\t\"       (c) 2018-2026, #C7EA46 CTCaer#\\n\"\n\t\t\"\\n\"\n\t\t\"#C7EA46 Nyx#    (c) 2019-2026, #C7EA46 CTCaer#\\n\"\n\t\t\"\\n\"\n\t\t\"Thanks to: #00CCFF derrek, nedwill, plutoo, #\\n\"\n\t\t\"           #00CCFF shuffle2, smea, thexyz, yellows8 #\\n\"\n\t\t\"\\n\"\n\t\t\"Greetings to: fincs, hexkyz, SciresM,\\n\"\n\t\t\"              Shiny Quagsire, WinterMute\\n\"\n\t\t\"\\n\"\n\t\t\"Open source and free packages used:                    \\n\" // Label width alignment padding.\n\t\t\" - Littlev Graphics Library,\\n\"\n\t\t\"   Copyright (c) 2016-2018, Gabor Kiss-Vamosi\\n\\n\"\n\t\t\" - FatFs R0.13c,\\n\"\n\t\t\"   Copyright (c) 2006-2018, ChaN\\n\"\n\t\t\"   Copyright (c) 2018-2022, CTCaer\\n\\n\"\n\t\t\" - bcl-1.2.0,\\n\"\n\t\t\"   Copyright (c) 2003-2006, Marcus Geelnard\\n\\n\"\n\t\t\" - blz,\\n\"\n\t\t\"   Copyright (c) 2018, SciresM\\n\\n\"\n\t\t\" - elfload,\\n\"\n\t\t\"   Copyright (c) 2014, Owen Shepherd\\n\"\n\t\t\"   Copyright (c) 2018, M4xw\"\n\t);\n\n\tlv_obj_t * lbl_octopus = lv_label_create(parent, NULL);\n\tlv_obj_align(lbl_octopus, lbl_credits, LV_ALIGN_OUT_RIGHT_TOP, -LV_DPI / 10, 0);\n\tlv_label_set_style(lbl_octopus, &monospace_text);\n\tlv_label_set_recolor(lbl_octopus, true);\n\n\tlv_label_set_static_text(lbl_octopus,\n\t\t\"\\n#00CCFF                          ___#\\n\"\n\t\t\"#00CCFF                       .-'   `'.#\\n\"\n\t\t\"#00CCFF                      /         \\\\#\\n\"\n\t\t\"#00CCFF                      |         ;#\\n\"\n\t\t\"#00CCFF                      |         |           ___.--,#\\n\"\n\t\t\"#00CCFF             _.._     |0) = (0) |    _.---'`__.-( (_.#\\n\"\n\t\t\"#00CCFF      __.--'`_.. '.__.\\\\    '--. \\\\_.-' ,.--'`     `\\\"\\\"`#\\n\"\n\t\t\"#00CCFF     ( ,.--'`   ',__ /./;   ;, '.__.'`    __#\\n\"\n\t\t\"#00CCFF     _`) )  .---.__.' / |   |\\\\   \\\\__..--\\\"\\\"  \\\"\\\"\\\"--.,_#\\n\"\n\t\t\"#00CCFF    `---' .'.''-._.-'`_./  /\\\\ '.  \\\\ _.--''````'''--._`-.__.'#\\n\"\n\t\t\"#00CCFF          | |  .' _.-' |  |  \\\\  \\\\  '.               `----`#\\n\"\n\t\t\"#00CCFF           \\\\ \\\\/ .'     \\\\  \\\\   '. '-._)#\\n\"\n\t\t\"#00CCFF            \\\\/ /        \\\\  \\\\    `=.__`'-.#\\n\"\n\t\t\"#00CCFF            / /\\\\         `) )    / / `\\\"\\\".`\\\\#\\n\"\n\t\t\"#00CCFF      , _.-'.'\\\\ \\\\        / /    ( (     / /#\\n\"\n\t\t\"#00CCFF       `--'`   ) )    .-'.'      '.'.  | (#\\n\"\n\t\t\"#00CCFF              (/`    ( (`          ) )  '-;    ##00FFCC [switchbrew]#\\n\"\n\t\t\"#00CCFF               `      '-;         (-'#\"\n\t);\n\n\tlv_obj_t *hekate_img = lv_img_create(parent, NULL);\n\tlv_img_set_src(hekate_img, &hekate_logo);\n\tlv_obj_align(hekate_img, lbl_octopus, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI * 2 / 3);\n\n\tlv_obj_t *ctcaer_img = lv_img_create(parent, NULL);\n\tlv_img_set_src(ctcaer_img, &ctcaer_logo);\n\tlv_obj_align(ctcaer_img, lbl_octopus, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, LV_DPI * 2 / 3);\n\n\tchar version[32];\n\ts_printf(version, \"Nyx %s%d.%d.%d%c\", NYX_VER_RL ? \"v\" : \"\", NYX_VER_MJ, NYX_VER_MN, NYX_VER_HF, NYX_VER_RL > 'A' ? NYX_VER_RL : 0);\n\tlv_obj_t * lbl_ver = lv_label_create(parent, NULL);\n\tlv_obj_align(lbl_ver, ctcaer_img, LV_ALIGN_OUT_BOTTOM_RIGHT, -LV_DPI / 20, LV_DPI / 4);\n\tlv_label_set_style(lbl_ver, &monospace_text);\n\tlv_label_set_text(lbl_ver, version);\n}\n\nstatic void _update_status_bar(void *params)\n{\n\tstatic char *label = NULL;\n\n\tu16 soc_temp = 0;\n\tu32 batt_percent = 0;\n\tint charge_status = 0;\n\tint batt_volt = 0;\n\tint batt_curr = 0;\n\trtc_time_t time;\n\n\t// Get sensor data.\n\tmax77620_rtc_get_time_adjusted(&time);\n\tsoc_temp = tmp451_get_soc_temp(false);\n\tbq24193_get_property(BQ24193_ChargeStatus, &charge_status);\n\tmax17050_get_property(MAX17050_RepSOC, (int *)&batt_percent);\n\tmax17050_get_property(MAX17050_VCELL, &batt_volt);\n\tmax17050_get_property(MAX17050_Current, &batt_curr);\n\n\t// Enable fan if more than 41 oC.\n\tu32 soc_temp_dec = soc_temp >> 8;\n\tfan_set_from_temp(soc_temp_dec);\n\n\tif (!label)\n\t\tlabel = (char *)malloc(512);\n\n\t// Set time and SoC temperature.\n\ts_printf(label, \"%02d:%02d \"SYMBOL_DOT\" \"SYMBOL_TEMPERATURE\" %02d.%d\",\n\t\ttime.hour, time.min, soc_temp_dec, (soc_temp & 0xFF) / 10);\n\n\tlv_label_set_text(status_bar.time_temp, label);\n\n\tlv_obj_realign(status_bar.temp_symbol);\n\tlv_obj_realign(status_bar.temp_degrees);\n\n\t// Set battery percent and charging symbol.\n\ts_printf(label, \" \"SYMBOL_DOT\" %d.%d%% \", (batt_percent >> 8) & 0xFF, (batt_percent & 0xFF) / 26);\n\n\tu8 batt_level = (batt_percent >> 8) & 0xFF;\n\tif (batt_level > 80)\n\t\tstrcat(label, SYMBOL_BATTERY_FULL);\n\telse if (batt_level > 60)\n\t\tstrcat(label, SYMBOL_BATTERY_3);\n\telse if (batt_level > 40)\n\t\tstrcat(label, SYMBOL_BATTERY_2);\n\telse if (batt_level > 15)\n\t\tstrcat(label, SYMBOL_BATTERY_1);\n\telse\n\t\tstrcat(label, \"#FF3C28 \"SYMBOL_BATTERY_EMPTY\"#\");\n\n\t// Set charging symbol.\n\tif (charge_status)\n\t\tstrcat(label, \" #FFDD00 \"SYMBOL_CHARGE\"#\");\n\n\tlv_label_set_text(status_bar.battery, label);\n\tlv_obj_realign(status_bar.battery);\n\n\t// Set battery current draw and voltage.\n\ts_printf(label, \"#%s%d\", batt_curr >= 0 ? \"96FF00 +\" : \"FF3C28 \", batt_curr / 1000);\n\n\tbool voltage_empty = batt_volt < 3200;\n\ts_printf(label + strlen(label), \" mA# (%s%d mV%s)\",\n\t\tvoltage_empty ? \"#FF8000 \" : \"\", batt_volt,  voltage_empty ? \" \"SYMBOL_WARNING\"#\" : \"\");\n\n\tlv_label_set_text(status_bar.battery_more, label);\n\tlv_obj_realign(status_bar.battery_more);\n}\n\nstatic lv_res_t _create_mbox_payloads(lv_obj_t *btn)\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char * mbox_btn_map[] = { \"\\251\", \"\\222Cancel\", \"\\251\", \"\" };\n\tlv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES * 5 / 9);\n\n\tlv_mbox_set_text(mbox, \"Select a payload to launch:\");\n\n\t// Create a list with all found payloads.\n\t//! TODO: SHould that be tabs with buttons? + Icon support?\n\tlv_obj_t *list = lv_list_create(mbox, NULL);\n\tpayload_list = list;\n\tlv_obj_set_size(list, LV_HOR_RES * 3 / 7, LV_VER_RES * 3 / 7);\n\tlv_list_set_single_mode(list, true);\n\n\tif (sd_mount())\n\t{\n\t\tlv_mbox_set_text(mbox, \"#FFDD00 Failed to init SD!#\");\n\n\t\tgoto out_end;\n\t}\n\n\tdirlist_t *filelist = dirlist(\"bootloader/payloads\", NULL, 0);\n\tsd_unmount();\n\n\tu32 i = 0;\n\tif (filelist)\n\t{\n\t\twhile (true)\n\t\t{\n\t\t\tif (!filelist->name[i])\n\t\t\t\tbreak;\n\t\t\tlv_list_add(list, NULL, filelist->name[i], launch_payload);\n\t\t\ti++;\n\t\t}\n\t\tfree(filelist);\n\t}\n\nout_end:\n\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\treturn LV_RES_OK;\n}\ntypedef struct _launch_menu_entries_t\n{\n\tlv_obj_t *btn[20];\n\tlv_obj_t *label[20];\n} launch_menu_entries_t;\n\nstatic launch_menu_entries_t launch_ctxt;\nstatic lv_obj_t *launch_bg = NULL;\nstatic bool launch_bg_done = false;\n\nstatic lv_res_t _launch_more_cfg_action(lv_obj_t *btn)\n{\n\tlv_btn_ext_t *ext = lv_obj_get_ext_attr(btn);\n\n\t_launch_hos(ext->idx, 1);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _win_launch_close_action(lv_obj_t * btn)\n{\n\t// Cleanup icons.\n\tfor (u32 i = 0; i < (n_cfg.entries_5_col ? 10 : 8); i++)\n\t{\n\t\tlv_obj_t *btns = launch_ctxt.btn[i];\n\t\tlv_btn_ext_t *ext = lv_obj_get_ext_attr(btns);\n\t\tif (ext->idx)\n\t\t{\n\t\t\t// This gets latest object, which is the button overlay. So iterate 2 times.\n\t\t\tlv_obj_t * img = lv_obj_get_child(btns, NULL);\n\t\t\timg = lv_obj_get_child(btns, img);\n\n\t\t\tlv_img_dsc_t *src = (lv_img_dsc_t *)lv_img_get_src(img);\n\n\t\t\t// Avoid freeing base icons.\n\t\t\tif ((src != icon_switch) && (src != icon_payload))\n\t\t\t\tfree(src);\n\t\t}\n\t}\n\n\tlv_obj_t * win = lv_win_get_from_btn(btn);\n\n\tlv_obj_del(win);\n\n\tif (n_cfg.home_screen && !launch_bg_done && hekate_bg)\n\t{\n\t\tlv_obj_set_opa_scale_enable(launch_bg, true);\n\t\tlv_obj_set_opa_scale(launch_bg, LV_OPA_TRANSP);\n\t\t//if (launch_bg)\n\t\t//\tlv_obj_del(launch_bg); //! TODO: Find why it hangs.\n\t\tlaunch_bg_done = true;\n\t}\n\n\tclose_btn = NULL;\n\n\treturn LV_RES_INV;\n}\n\nstatic lv_obj_t *create_window_launch(const char *win_title)\n{\n\tstatic lv_style_t win_bg_style, win_header;\n\n\tlv_style_copy(&win_bg_style, &lv_style_plain);\n\twin_bg_style.body.main_color = lv_theme_get_current()->bg->body.main_color;\n\twin_bg_style.body.grad_color = win_bg_style.body.main_color;\n\n\tif (n_cfg.home_screen && !launch_bg_done && hekate_bg)\n\t{\n\t\tlv_obj_t *img = lv_img_create(lv_scr_act(), NULL);\n\t\tlv_img_set_src(img, hekate_bg);\n\n\t\tlaunch_bg = img;\n\t}\n\n\tlv_obj_t *win = lv_win_create(lv_scr_act(), NULL);\n\tlv_win_set_title(win, win_title);\n\n\tlv_obj_set_size(win, LV_HOR_RES, LV_VER_RES);\n\n\tif (n_cfg.home_screen && !launch_bg_done && hekate_bg)\n\t{\n\t\tlv_style_copy(&win_header, lv_theme_get_current()->win.header);\n\t\twin_header.body.opa = LV_OPA_TRANSP;\n\n\t\twin_bg_style.body.opa = LV_OPA_TRANSP;\n\t\tlv_win_set_style(win, LV_WIN_STYLE_HEADER, &win_header);\n\t}\n\n\tlv_win_set_style(win, LV_WIN_STYLE_BG, &win_bg_style);\n\n\tclose_btn = lv_win_add_btn(win, NULL, SYMBOL_CLOSE\" Close\", _win_launch_close_action);\n\n\treturn win;\n}\n\nstatic lv_res_t _launch_action(lv_obj_t *btn)\n{\n\tlv_btn_ext_t *ext = lv_obj_get_ext_attr(btn);\n\n\t_launch_hos(ext->idx, 0);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t logs_onoff_toggle(lv_obj_t *btn)\n{\n\tlaunch_logs_enable = !launch_logs_enable;\n\n\tlv_obj_t *label_btn = lv_obj_get_child(btn, NULL);\n\n\tchar label_text[64];\n\tstrcpy(label_text, lv_label_get_text(label_btn));\n\tlabel_text[strlen(label_text) - 12] = 0;\n\n\tif (!launch_logs_enable)\n\t{\n\t\tstrcat(label_text, \"#D0D0D0 OFF#\");\n\t\tlv_label_set_text(label_btn, label_text);\n\t}\n\telse\n\t{\n\t\ts_printf(label_text, \"%s%s%s\", label_text, text_color, \" ON #\");\n\t\tlv_label_set_text(label_btn, label_text);\n\t}\n\n\treturn LV_RES_OK;\n}\n\ntypedef struct _launch_button_pos_t\n{\n\tu16 btn_x;\n\tu16 btn_y;\n\tu16 lbl_x;\n\tu16 lbl_y;\n} launch_button_pos_t;\n\nstatic const launch_button_pos_t launch_button_pos8[8] = {\n\t// First row.\n\t{  19,  36,   0, 245 },\n\t{ 340,  36, 321, 245 },\n\t{ 661,  36, 642, 245 },\n\t{ 982,  36, 963, 245 },\n\t// Second row.\n\t{  19, 313,   0, 522 },\n\t{ 340, 313, 321, 522 },\n\t{ 661, 313, 642, 522 },\n\t{ 982, 313, 963, 522 }\n};\n\nstatic const launch_button_pos_t launch_button_pos10[10] = {\n\t// First row.\n\t{ 19, 36,  0,  245},\n\t{260, 36, 241, 245},\n\t{501, 36, 482, 245},\n\t{742, 36, 723, 245},\n\t{983, 36, 964, 245},\n\t// Second row.\n\t{ 19, 313,   0, 522},\n\t{260, 313, 241, 522},\n\t{501, 313, 482, 522},\n\t{742, 313, 723, 522},\n\t{983, 313, 964, 522}\n};\n\nstatic lv_res_t _create_window_home_launch(lv_obj_t *btn)\n{\n\tconst u32 max_entries = n_cfg.entries_5_col ? 10 : 8;\n\tconst launch_button_pos_t *launch_button_pos = n_cfg.entries_5_col ? launch_button_pos10 : launch_button_pos8;\n\n\tchar *icon_path;\n\n\tstatic lv_style_t btn_home_noborder_rel;\n\tlv_style_copy(&btn_home_noborder_rel, lv_theme_get_current()->btn.rel);\n\tbtn_home_noborder_rel.body.opa = LV_OPA_0;\n\tbtn_home_noborder_rel.body.border.width = 4;\n\tbtn_home_noborder_rel.body.border.opa = LV_OPA_0;\n\n\tstatic lv_style_t btn_home_transp_rel;\n\tlv_style_copy(&btn_home_transp_rel, lv_theme_get_current()->btn.rel);\n\tbtn_home_transp_rel.body.opa = LV_OPA_0;\n\tbtn_home_transp_rel.body.border.width = 4;\n\n\tstatic lv_style_t btn_home_transp_pr;\n\tlv_style_copy(&btn_home_transp_pr, lv_theme_get_current()->btn.pr);\n\tbtn_home_transp_pr.body.main_color = LV_COLOR_HEX(0xFFFFFF);\n\tbtn_home_transp_pr.body.grad_color = btn_home_transp_pr.body.main_color;\n\tbtn_home_transp_pr.body.opa = LV_OPA_30;\n\n\tstatic lv_style_t btn_label_home_transp;\n\tlv_style_copy(&btn_label_home_transp, lv_theme_get_current()->cont);\n\tbtn_label_home_transp.body.opa = LV_OPA_TRANSP;\n\n\tlv_obj_t *win;\n\n\tbool more_cfg = false;\n\tbool combined_cfg = false;\n\tif (btn)\n\t{\n\t\tif (strcmp(lv_label_get_text(lv_obj_get_child(btn, NULL)) + 8,\"Launch#\"))\n\t\t\tmore_cfg = true;\n\t}\n\telse\n\t{\n\t\tswitch (n_cfg.home_screen)\n\t\t{\n\t\tcase 1: // All configs.\n\t\t\tcombined_cfg = true;\n\t\t\tbreak;\n\t\tcase 3: // More configs\n\t\t\tmore_cfg = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (!btn)\n\t\twin = create_window_launch(SYMBOL_GPS\" hekate - Launch\");\n\telse if (!more_cfg)\n\t\twin = create_window_launch(SYMBOL_GPS\" Launch\");\n\telse\n\t\twin = create_window_launch(SYMBOL_GPS\" More Configurations\");\n\n\tlv_win_add_btn(win, NULL, SYMBOL_LIST\" Logs #D0D0D0 OFF#\", logs_onoff_toggle);\n\tlaunch_logs_enable = false;\n\n\tlv_cont_set_fit(lv_page_get_scrl(lv_win_get_content(win)), false, false);\n\tlv_page_set_scrl_height(lv_win_get_content(win), 572);\n\n\tlv_btn_ext_t * ext;\n\tlv_obj_t *btn_boot_entry;\n\tlv_obj_t *boot_entry_lbl_cont;\n\tlv_obj_t *boot_entry_label;\n\tbool no_boot_entries = false;\n\n\t// Create Boot Entry buttons.\n\t// Buttons are 200 x 200 with 4 pixel borders.\n\t// Icons must be <= 192 x 192.\n\t// Create first Button.\n\tbtn_boot_entry = lv_btn_create(win, NULL);\n\tlaunch_ctxt.btn[0] = btn_boot_entry;\n\tlv_obj_set_size(btn_boot_entry, 200, 200);\n\tlv_obj_set_pos(btn_boot_entry, launch_button_pos[0].btn_x, launch_button_pos[0].btn_y);\n\tlv_obj_set_opa_scale(btn_boot_entry, LV_OPA_0);\n\tlv_obj_set_opa_scale_enable(btn_boot_entry, true);\n\tlv_btn_set_layout(btn_boot_entry, LV_LAYOUT_OFF);\n\n\tboot_entry_lbl_cont = lv_cont_create(win, NULL);\n\tboot_entry_label = lv_label_create(boot_entry_lbl_cont, NULL);\n\tlv_obj_set_style(boot_entry_label, &hint_small_style_white);\n\tlv_label_set_text(boot_entry_label, \"\");\n\tlaunch_ctxt.label[0] = boot_entry_label;\n\n\tlv_cont_set_fit(boot_entry_lbl_cont, false, false);\n\tlv_cont_set_layout(boot_entry_lbl_cont, LV_LAYOUT_CENTER);\n\tlv_obj_set_size(boot_entry_lbl_cont, 238, 20);\n\tlv_obj_set_pos(boot_entry_lbl_cont, launch_button_pos[0].lbl_x, launch_button_pos[0].lbl_y);\n\tlv_obj_set_style(boot_entry_lbl_cont, &btn_label_home_transp);\n\n\t// Create the rest of the buttons.\n\tfor (u32 btn_idx = 1; btn_idx < (n_cfg.entries_5_col ? 10 : 8); btn_idx++)\n\t{\n\t\tbtn_boot_entry = lv_btn_create(win, btn_boot_entry);\n\t\tlaunch_ctxt.btn[btn_idx] = btn_boot_entry;\n\t\tlv_obj_set_pos(btn_boot_entry, launch_button_pos[btn_idx].btn_x, launch_button_pos[btn_idx].btn_y);\n\n\t\tboot_entry_lbl_cont = lv_cont_create(win, boot_entry_lbl_cont);\n\t\tboot_entry_label = lv_label_create(boot_entry_lbl_cont, boot_entry_label);\n\t\tlv_obj_set_pos(boot_entry_lbl_cont, launch_button_pos[btn_idx].lbl_x, launch_button_pos[btn_idx].lbl_y);\n\t\tlaunch_ctxt.label[btn_idx] = boot_entry_label;\n\t}\n\n\t// Create colorized icon style based on its parent style.\n\tstatic lv_style_t img_style;\n\tlv_style_copy(&img_style, &lv_style_plain);\n\timg_style.image.color = COLOR_HOS_TURQUOISE_EX(n_cfg.theme_color);\n\timg_style.image.intense = LV_OPA_COVER;\n\n\t// Parse ini boot entries and set buttons/icons.\n\tchar *tmp_path = malloc(1024);\n\tu32 curr_btn_idx = 0; // Active buttons.\n\tLIST_INIT(ini_sections);\n\n\tif (sd_mount())\n\t\tgoto failed_sd_mount;\n\n\t// Check if we use custom system icons.\n\tbool icon_sw_custom = !f_stat(\"bootloader/res/icon_switch_custom.bmp\", NULL);\n\tbool icon_pl_custom = !f_stat(\"bootloader/res/icon_payload_custom.bmp\", NULL);\n\n\t// Choose what to parse.\n\tbool ini_parse_success = false;\n\tif (!more_cfg)\n\t\tini_parse_success = !ini_parse(&ini_sections, \"bootloader/hekate_ipl.ini\", false);\n\telse\n\t\tini_parse_success = !ini_parse(&ini_sections, \"bootloader/ini\", true);\n\n\tif (combined_cfg && !ini_parse_success)\n\t{\nini_parsing:\n\t\tlist_init(&ini_sections);\n\t\tini_parse_success = !ini_parse(&ini_sections, \"bootloader/ini\", true);\n\t\tmore_cfg = true;\n\t}\n\n\tif (!ini_parse_success)\n\t\tgoto ini_parse_failed;\n\n\t// Iterate to all boot entries and load icons.\n\tu32 entry_idx = 1;\n\tLIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)\n\t{\n\t\tif (!strcmp(ini_sec->name, \"config\") || (ini_sec->type != INI_CHOICE))\n\t\t\tcontinue;\n\n\t\ticon_path = NULL;\n\t\tbool payload = false;\n\t\tbool img_colorize = false;\n\t\tbool img_noborder = false;\n\t\tlv_img_dsc_t *bmp = NULL;\n\t\tlv_obj_t *img = NULL;\n\n\t\t// Check for icons.\n\t\tLIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)\n\t\t{\n\t\t\tif (!strcmp(\"icon\", kv->key))\n\t\t\t\ticon_path = kv->val;\n\t\t\telse if (!strcmp(\"payload\", kv->key))\n\t\t\t\tpayload = true;\n\t\t}\n\n\t\t// If icon not found, check res folder for section_name.bmp.\n\t\t// If not, use defaults.\n\t\tif (!icon_path)\n\t\t{\n\t\t\ts_printf(tmp_path, \"bootloader/res/%s.bmp\", ini_sec->name);\n\t\t\tbmp = bmp_to_lvimg_obj(tmp_path);\n\t\t\tif (!bmp)\n\t\t\t{\n\t\t\t\ts_printf(tmp_path, \"bootloader/res/%s_hue_nobox.bmp\", ini_sec->name);\n\t\t\t\tbmp = bmp_to_lvimg_obj(tmp_path);\n\t\t\t\tif (bmp)\n\t\t\t\t{\n\t\t\t\t\timg_noborder = true;\n\t\t\t\t\timg_colorize = true;\n\t\t\t\t}\n\t\t\t\tif (!bmp)\n\t\t\t\t{\n\t\t\t\t\ts_printf(tmp_path, \"bootloader/res/%s_hue.bmp\", ini_sec->name);\n\t\t\t\t\tbmp = bmp_to_lvimg_obj(tmp_path);\n\t\t\t\t\tif (bmp)\n\t\t\t\t\t\timg_colorize = true;\n\t\t\t\t}\n\t\t\t\tif (!bmp)\n\t\t\t\t{\n\t\t\t\t\ts_printf(tmp_path, \"bootloader/res/%s_nobox.bmp\", ini_sec->name);\n\t\t\t\t\tbmp = bmp_to_lvimg_obj(tmp_path);\n\t\t\t\t\tif (bmp)\n\t\t\t\t\t\timg_noborder = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!bmp && payload)\n\t\t\t{\n\t\t\t\tbmp = icon_payload;\n\n\t\t\t\tif (!icon_pl_custom)\n\t\t\t\t\timg_colorize = true;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbmp = bmp_to_lvimg_obj(icon_path);\n\n\t\t\t// Check if both colorization and border are enabled.\n\t\t\tif (bmp && strlen(icon_path) > 14 && !memcmp(icon_path + strlen(icon_path) - 14, \"_hue_nobox\", 10))\n\t\t\t{\n\t\t\t\timg_colorize = true;\n\t\t\t\timg_noborder = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Check if colorization is enabled.\n\t\t\t\tif (bmp && strlen(icon_path) > 8 && !memcmp(icon_path + strlen(icon_path) - 8, \"_hue\", 4))\n\t\t\t\t\timg_colorize = true;\n\n\t\t\t\t// Check if no border is enabled.\n\t\t\t\tif (bmp && strlen(icon_path) > 10 && !memcmp(icon_path + strlen(icon_path) - 10, \"_nobox\", 6))\n\t\t\t\t\timg_noborder = true;\n\t\t\t}\n\t\t}\n\n\t\t// Enable button.\n\t\tlv_obj_set_opa_scale(launch_ctxt.btn[curr_btn_idx], LV_OPA_COVER);\n\n\t\t// Default to switch logo if no icon found at all.\n\t\tif (!bmp)\n\t\t{\n\t\t\tbmp = icon_switch;\n\n\t\t\tif (!icon_sw_custom)\n\t\t\t\timg_colorize = true;\n\t\t}\n\n\t\t//Set icon.\n\t\tif (bmp)\n\t\t{\n\t\t\timg = lv_img_create(launch_ctxt.btn[curr_btn_idx], NULL);\n\n\t\t\tif (img_colorize)\n\t\t\t\tlv_img_set_style(img, &img_style);\n\n\t\t\tlv_img_set_src(img, bmp);\n\t\t}\n\n\t\t// Add button mask/radius and align icon.\n\t\tlv_obj_t *btns = lv_btn_create(launch_ctxt.btn[curr_btn_idx], NULL);\n\t\tu32 btn_width = 200;\n\t\tu32 btn_height = 200;\n\t\tif (img_noborder)\n\t\t{\n\t\t\tbtn_width = bmp->header.w + 4;\n\t\t\tbtn_height = bmp->header.h + 4;\n\n\t\t\tif (btn_width > 200)\n\t\t\t\tbtn_width = 200;\n\t\t\tif (btn_height > 200)\n\t\t\t\tbtn_height = 200;\n\n\t\t\tlv_btn_set_style(launch_ctxt.btn[curr_btn_idx], LV_BTN_STYLE_REL, &btn_home_noborder_rel);\n\t\t\tlv_btn_set_style(launch_ctxt.btn[curr_btn_idx], LV_BTN_STYLE_PR,  &btn_home_noborder_rel);\n\t\t}\n\t\tlv_obj_set_size(btns, btn_width, btn_height);\n\t\tlv_btn_set_style(btns, LV_BTN_STYLE_REL, img_noborder ? &btn_home_noborder_rel : &btn_home_transp_rel);\n\t\tlv_btn_set_style(btns, LV_BTN_STYLE_PR, &btn_home_transp_pr);\n\n\t\t// Button transparency if custom background, but loses color.\n\t\t// if (!btn && hekate_bg && !img_noborder)\n\t\t// {\n\t\t// \tlv_btn_set_style(launch_ctxt.btn[curr_btn_idx], LV_BTN_STYLE_REL, &btn_transp_rel);\n\t\t// \tlv_btn_set_style(launch_ctxt.btn[curr_btn_idx], LV_BTN_STYLE_PR,  &btn_transp_pr);\n\t\t// \tlv_btn_set_style(btns, LV_BTN_STYLE_REL, &btn_home_noborder_rel);\n\t\t// }\n\n\t\tif (img)\n\t\t\tlv_obj_align(img, NULL, LV_ALIGN_CENTER, 0, 0);\n\t\tif (img_noborder)\n\t\t\tlv_obj_align(btns, NULL, LV_ALIGN_CENTER, 0, 0);\n\n\t\t// Set autoboot index.\n\t\text = lv_obj_get_ext_attr(btns);\n\t\text->idx = entry_idx;\n\t\text = lv_obj_get_ext_attr(launch_ctxt.btn[curr_btn_idx]); // Redundancy.\n\t\text->idx = entry_idx;\n\n\t\t// Set action.\n\t\tif (!more_cfg)\n\t\t\tlv_btn_set_action(btns, LV_BTN_ACTION_CLICK, _launch_action);\n\t\telse\n\t\t\tlv_btn_set_action(btns, LV_BTN_ACTION_CLICK, _launch_more_cfg_action);\n\n\t\t// Set button's label text.\n\t\tlv_label_set_text(launch_ctxt.label[curr_btn_idx], ini_sec->name);\n\t\tlv_obj_set_opa_scale(launch_ctxt.label[curr_btn_idx], LV_OPA_COVER);\n\n\t\t// Set rolling text if name is too big.\n\t\tint max_label_size = 238 - (n_cfg.entries_5_col ? 12 : 0);\n\t\tif (lv_obj_get_width(launch_ctxt.label[curr_btn_idx]) > max_label_size)\n\t\t{\n\t\t\tlv_label_set_long_mode(launch_ctxt.label[curr_btn_idx], LV_LABEL_LONG_ROLL);\n\t\t\tlv_obj_set_width(launch_ctxt.label[curr_btn_idx], max_label_size);\n\t\t}\n\n\t\tentry_idx++;\n\t\tcurr_btn_idx++;\n\n\t\t// Check if we exceed max buttons.\n\t\tif (curr_btn_idx >= max_entries)\n\t\t\tbreak;\n\t}\n\n\tini_free(&ini_sections);\n\nini_parse_failed:\n\t// Reiterate the loop with more cfgs if combined.\n\tif (combined_cfg && (curr_btn_idx < (n_cfg.entries_5_col ? 10 : 8)) && !more_cfg)\n\t\tgoto ini_parsing;\n\nfailed_sd_mount:\n\tif (curr_btn_idx < 1)\n\t\tno_boot_entries = true;\n\n\tsd_unmount();\n\n\tfree(tmp_path);\n\n\t// No boot entries found.\n\tif (no_boot_entries)\n\t{\n\t\tlv_obj_t *label_error = lv_label_create(win, NULL);\n\t\tlv_label_set_recolor(label_error, true);\n\t\tif (!more_cfg)\n\t\t{\n\t\t\tlv_label_set_static_text(label_error,\n\t\t\t\t\"#FFDD00 No main boot entries found...#\\n\"\n\t\t\t\t\"Check that #96FF00 bootloader/hekate_ipl.ini# has boot entries\\n\"\n\t\t\t\t\"or use #C7EA46 More configs# button for more boot entries.\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlv_label_set_static_text(label_error,\n\t\t\t\t\"#FFDD00 No .ini or boot entries found...#\\n\"\n\t\t\t\t\"Check that a .ini file exists in #96FF00 bootloader/ini/#\\n\"\n\t\t\t\t\"and that it contains at least one entry.\");\n\t\t}\n\n\t\tlv_obj_set_pos(label_error, 19, 0);\n\t}\n\n\treturn LV_RES_OK;\n}\n\nstatic void _create_tab_home(lv_theme_t *th, lv_obj_t *parent)\n{\n\tlv_page_set_scrl_layout(parent, LV_LAYOUT_OFF);\n\tlv_page_set_scrl_fit(parent, false, false);\n\tlv_page_set_scrl_height(parent, 592);\n\n\tchar btn_colored_text[64];\n\n\t// Set brand label.\n\tlv_obj_t *label_brand = lv_label_create(parent, NULL);\n\tlv_label_set_recolor(label_brand, true);\n\ts_printf(btn_colored_text, \"%s%s\", text_color, \" hekate#\");\n\tlv_label_set_text(label_brand, btn_colored_text);\n\tlv_obj_set_pos(label_brand, 50, 48);\n\n\t// Set tagline label.\n\tlv_obj_t *label_tagline = lv_label_create(parent, NULL);\n\tlv_obj_set_style(label_tagline, &hint_small_style_white);\n\tlv_label_set_static_text(label_tagline, \"THE ALL IN ONE BOOTLOADER FOR ALL YOUR NEEDS\");\n\tlv_obj_set_pos(label_tagline, 50, 82);\n\n\tstatic lv_style_t icons;\n\tlv_style_copy(&icons, th->label.prim);\n\ticons.text.font = &hekate_symbol_120;\n\n\t// Launch button.\n\tlv_obj_t *btn_launch = lv_btn_create(parent, NULL);\n\tif (hekate_bg)\n\t{\n\t\tlv_btn_set_style(btn_launch, LV_BTN_STYLE_REL, &btn_transp_rel);\n\t\tlv_btn_set_style(btn_launch, LV_BTN_STYLE_PR, &btn_transp_pr);\n\t}\n\tlv_obj_t *label_btn = lv_label_create(btn_launch, NULL);\n\tlv_label_set_recolor(label_btn, true);\n\tlv_obj_set_style(label_btn, &icons);\n\ts_printf(btn_colored_text, \"%s%s\", text_color, \" \"SYMBOL_DOT\"#\");\n\tlv_label_set_text(label_btn, btn_colored_text);\n\tlv_btn_set_action(btn_launch, LV_BTN_ACTION_CLICK, _create_window_home_launch);\n\tlv_obj_set_size(btn_launch, 256, 256);\n\tlv_obj_set_pos(btn_launch, 50, 160);\n\tlv_btn_set_layout(btn_launch, LV_LAYOUT_OFF);\n\tlv_obj_align(label_btn, NULL, LV_ALIGN_CENTER, 0, -28);\n\tlv_obj_t *label_btn2 = lv_label_create(btn_launch, NULL);\n\tlv_label_set_recolor(label_btn2, true);\n\ts_printf(btn_colored_text, \"%s%s\", text_color, \" Launch#\");\n\tlv_label_set_text(label_btn2, btn_colored_text);\n\tlv_obj_align(label_btn2, NULL, LV_ALIGN_IN_TOP_MID, 0, 174);\n\n\t// More Configs button.\n\tlv_obj_t *btn_more_cfg = lv_btn_create(parent, btn_launch);\n\tlabel_btn = lv_label_create(btn_more_cfg, label_btn);\n\ts_printf(btn_colored_text, \"%s%s\", text_color, \" \"SYMBOL_CLOCK\"#\");\n\tlv_label_set_text(label_btn, btn_colored_text);\n\tlv_btn_set_action(btn_more_cfg, LV_BTN_ACTION_CLICK, _create_window_home_launch);\n\tlv_btn_set_layout(btn_more_cfg, LV_LAYOUT_OFF);\n\tlv_obj_align(label_btn, NULL, LV_ALIGN_CENTER, 0, -28);\n\tlabel_btn2 = lv_label_create(btn_more_cfg, label_btn2);\n\ts_printf(btn_colored_text, \"%s%s\", text_color, \" More Configs#\");\n\tlv_label_set_text(label_btn2, btn_colored_text);\n\tlv_obj_set_pos(btn_more_cfg, 341, 160);\n\tlv_obj_align(label_btn2, NULL, LV_ALIGN_IN_TOP_MID, 0, 174);\n\n\t// Quick Launch button.\n\t// lv_obj_t *btn_quick_launch = lv_btn_create(parent, NULL);\n\t// lv_obj_t *label_quick_launch = lv_label_create(btn_quick_launch, NULL);\n\t// lv_label_set_static_text(label_quick_launch, SYMBOL_EDIT\" Quick Launch\");\n\t// lv_obj_set_width(btn_quick_launch, 256);\n\t// lv_obj_set_pos(btn_quick_launch, 343, 448);\n\t// lv_btn_set_action(btn_quick_launch, LV_BTN_ACTION_CLICK, NULL);\n\t// if (hekate_bg)\n\t// {\n\t// \tlv_btn_set_style(btn_quick_launch, LV_BTN_STYLE_REL, &btn_transp_rel);\n\t// \tlv_btn_set_style(btn_quick_launch, LV_BTN_STYLE_PR, &btn_transp_pr);\n\t// \tlv_btn_set_style(btn_quick_launch, LV_BTN_STYLE_INA, &btn_transp_ina);\n\t// }\n\n\tlv_obj_t *btn_nyx_options = lv_btn_create(parent, NULL);\n\t_create_text_button(th, NULL, btn_nyx_options, SYMBOL_SETTINGS\" Nyx Settings\", NULL);\n\t//lv_obj_set_width(btn_nyx_options, 256);\n\tlv_btn_set_action(btn_nyx_options, LV_BTN_ACTION_CLICK, create_win_nyx_options);\n\tlv_obj_align(btn_nyx_options, NULL, LV_ALIGN_IN_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI / 12);\n\n\t// Payloads button.\n\tlv_obj_t *btn_payloads = lv_btn_create(parent, btn_launch);\n\tlabel_btn = lv_label_create(btn_payloads, label_btn);\n\ts_printf(btn_colored_text, \"%s%s\", text_color, \" \"SYMBOL_OK\"#\");\n\tlv_label_set_text(label_btn, btn_colored_text);\n\tlv_btn_set_action(btn_payloads, LV_BTN_ACTION_CLICK, _create_mbox_payloads);\n\tlv_btn_set_layout(btn_payloads, LV_LAYOUT_OFF);\n\tlv_obj_align(label_btn, NULL, LV_ALIGN_CENTER, 0, -28);\n\tlabel_btn2 = lv_label_create(btn_payloads, label_btn2);\n\ts_printf(btn_colored_text, \"%s%s\", text_color, \" Payloads#\");\n\tlv_label_set_text(label_btn2, btn_colored_text);\n\tlv_obj_set_pos(btn_payloads, 632, 160);\n\tlv_obj_align(label_btn2, NULL, LV_ALIGN_IN_TOP_MID, 0, 174);\n\n\tlv_obj_t *line_sep = lv_line_create(parent, NULL);\n\tstatic const lv_point_t line_pp[] = { {0, 0}, {0, LV_DPI * 3} };\n\tlv_line_set_points(line_sep, line_pp, 2);\n\tlv_line_set_style(line_sep, th->line.decor);\n\tlv_obj_align(line_sep, btn_payloads, LV_ALIGN_OUT_RIGHT_MID, 35, 0);\n\n\t// emuMMC manage button.\n\tlv_obj_t *btn_emummc = lv_btn_create(parent, btn_launch);\n\tlabel_btn = lv_label_create(btn_emummc, label_btn);\n\ts_printf(btn_colored_text, \"%s%s\", text_color, \" \"SYMBOL_LIST\"#\");\n\tlv_label_set_text(label_btn, btn_colored_text);\n\tlv_btn_set_action(btn_emummc, LV_BTN_ACTION_CLICK, create_win_emummc_tools);\n\tlv_btn_set_layout(btn_emummc, LV_LAYOUT_OFF);\n\tlv_obj_align(label_btn, NULL, LV_ALIGN_CENTER, 0, -28);\n\tlv_obj_set_pos(btn_emummc, 959, 160);\n\tlabel_btn2 = lv_label_create(btn_emummc, label_btn2);\n\ts_printf(btn_colored_text, \"%s%s\", text_color, \" emuMMC#\");\n\tlv_label_set_text(label_btn2, btn_colored_text);\n\tlv_obj_align(label_btn2, NULL, LV_ALIGN_IN_TOP_MID, 0, 174);\n\n\t// Create bottom right power buttons.\n\tlv_obj_t *btn_reboot = lv_btn_create(parent, NULL);\n\tlv_obj_t *btn_power_off = lv_btn_create(parent, NULL);\n\tlv_obj_t *btn_reload = lv_btn_create(parent, NULL);\n\n\t_create_text_button(th, NULL, btn_power_off, SYMBOL_POWER\" Power Off\", _create_mbox_poweroff);\n\tlv_obj_align(btn_power_off, NULL, LV_ALIGN_IN_BOTTOM_RIGHT, -LV_DPI / 4, -LV_DPI / 12);\n\n\t_create_text_button(th, NULL, btn_reboot, SYMBOL_REBOOT\" Reboot\", _create_mbox_reboot);\n\tlv_obj_align(btn_reboot, btn_power_off, LV_ALIGN_OUT_LEFT_MID, 0, 0);\n\n\t_create_text_button(th, NULL, btn_reload, SYMBOL_REFRESH\" Reload\", _create_mbox_reload);\n\tlv_obj_align(btn_reload, btn_reboot, LV_ALIGN_OUT_LEFT_MID, 0, 0);\n}\n\nstatic lv_res_t _save_options_action(lv_obj_t *btn)\n{\n\tstatic const char * mbox_btn_map[] = {\"\\251\", \"\\222OK!\", \"\\251\", \"\"};\n\tlv_obj_t * mbox = lv_mbox_create(lv_scr_act(), NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\n\tint res = 0;\n\n\tif (!sd_mount())\n\t\tres = create_config_entry();\n\n\tif (!res)\n\t\tlv_mbox_set_text(mbox, \"#FF8000 hekate Configuration#\\n\\n#96FF00 The configuration was saved to sd card!#\");\n\telse\n\t\tlv_mbox_set_text(mbox, \"#FF8000 hekate Configuration#\\n\\n#FFDD00 Failed to save the configuration#\\n#FFDD00 to sd card!#\");\n\tlv_mbox_add_btns(mbox, mbox_btn_map, NULL);\n\tlv_obj_set_top(mbox, true);\n\n\tnyx_options_clear_ini_changes_made();\n\n\tsd_unmount();\n\n\treturn LV_RES_OK;\n}\n\nstatic void _create_status_bar(lv_theme_t * th)\n{\n\tstatic lv_obj_t *status_bar_bg;\n\tstatus_bar_bg = lv_cont_create(lv_layer_top(), NULL);\n\tstatus_bar.bar_bg = status_bar_bg;\n\n\tstatic lv_style_t status_bar_style;\n\tlv_style_copy(&status_bar_style, &lv_style_plain_color);\n\tstatus_bar_style.body.opa = LV_OPA_0;\n\tstatus_bar_style.body.shadow.width = 0;\n\n\tlv_obj_set_style(status_bar_bg, &status_bar_style);\n\tlv_obj_set_size(status_bar_bg, LV_HOR_RES, LV_DPI * 9 / 14);\n\tlv_obj_align(status_bar_bg, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);\n\n\t// Battery percentages.\n\tlv_obj_t *lbl_battery = lv_label_create(status_bar_bg, NULL);\n\tlv_label_set_recolor(lbl_battery, true);\n\tlv_label_set_text(lbl_battery, \" \"SYMBOL_DOT\" 00.0% \"SYMBOL_BATTERY_1\" #FFDD00 \"SYMBOL_CHARGE\"#\");\n\tlv_obj_align(lbl_battery, NULL, LV_ALIGN_IN_RIGHT_MID, -LV_DPI * 6 / 11, 0);\n\tstatus_bar.battery = lbl_battery;\n\n\t// Amperages, voltages.\n\tlbl_battery = lv_label_create(status_bar_bg, lbl_battery);\n\tlv_obj_set_style(lbl_battery, &hint_small_style_white);\n\tlv_label_set_text(lbl_battery, \"#96FF00 +0 mA# (0 mV)\");\n\tlv_obj_align(lbl_battery, status_bar.battery, LV_ALIGN_OUT_LEFT_MID, -LV_DPI / 25, -1);\n\tstatus_bar.battery_more = lbl_battery;\n\n\tlv_obj_t *lbl_left = lv_label_create(status_bar_bg, NULL);\n\tlv_label_set_text(lbl_left, SYMBOL_CLOCK\" \");\n\tlv_obj_align(lbl_left, NULL, LV_ALIGN_IN_LEFT_MID, LV_DPI * 6 / 11, 0);\n\n\t// Time, temperature.\n\tlv_obj_t *lbl_time_temp = lv_label_create(status_bar_bg, NULL);\n\tlv_label_set_text(lbl_time_temp, \"00:00 \"SYMBOL_DOT\" \"SYMBOL_TEMPERATURE\" 00.0\");\n\tlv_obj_align(lbl_time_temp, lbl_left, LV_ALIGN_OUT_RIGHT_MID, 0, 0);\n\tstatus_bar.time_temp = lbl_time_temp;\n\n\tlbl_left = lv_label_create(status_bar_bg, NULL);\n\tlv_label_set_text(lbl_left, \" \"SYMBOL_DOT);\n\tlv_obj_align(lbl_left, lbl_time_temp, LV_ALIGN_OUT_RIGHT_MID, 0, -LV_DPI / 14);\n\tstatus_bar.temp_symbol = lbl_left;\n\n\tlv_obj_t *lbl_degrees = lv_label_create(status_bar_bg, NULL);\n\tlv_label_set_text(lbl_degrees, \"C\");\n\tlv_obj_align(lbl_degrees, lbl_left, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 50, LV_DPI / 14);\n\tstatus_bar.temp_degrees = lbl_degrees;\n\n\t// Middle button.\n\t//! TODO: Utilize it for more.\n\tlv_obj_t *btn_mid = lv_btn_create(status_bar_bg, NULL);\n\tlv_obj_t *lbl_mid = lv_label_create(btn_mid, NULL);\n\tlv_label_set_static_text(lbl_mid, \"Save Options\");\n\tlv_obj_set_size(btn_mid, LV_DPI * 17 / 8, LV_DPI / 2);\n\tlv_obj_align(btn_mid, NULL, LV_ALIGN_CENTER, 0, 0);\n\tstatus_bar.mid = btn_mid;\n\tlv_obj_set_opa_scale(btn_mid, LV_OPA_0);\n\tlv_obj_set_opa_scale_enable(btn_mid, true);\n\tlv_obj_set_click(btn_mid, false);\n\tlv_btn_set_action(btn_mid, LV_BTN_ACTION_CLICK, _save_options_action);\n}\n\nstatic lv_res_t _create_mbox_save_changes_action(lv_obj_t *btns, const char * txt)\n{\n\tint btn_idx = lv_btnm_get_pressed(btns);\n\n\tnyx_mbox_action(btns, txt);\n\n\tif (!btn_idx)\n\t\t_save_options_action(NULL);\n\n\treturn LV_RES_INV;\n}\n\nvoid nyx_check_ini_changes()\n{\n\tif (nyx_options_get_ini_changes_made())\n\t{\n\t\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\t\tlv_obj_set_style(dark_bg, &mbox_darken);\n\t\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\t\tstatic const char * mbox_btn_map[] = { \"\\222Save\", \"\\222Cancel\", \"\" };\n\t\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\t\tlv_mbox_set_recolor_text(mbox, true);\n\n\t\tlv_mbox_set_text(mbox,\n\t\t\t\"#FF8000 Main configuration#\\n\\n\"\n\t\t\t\"You changed the configuration!\\n\\n\"\n\t\t\t\"Do you want to save it?\");\n\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map, _create_mbox_save_changes_action);\n\t\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);\n\t\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\t\tlv_obj_set_top(mbox, true);\n\n\t\tnyx_options_clear_ini_changes_made();\n\t}\n}\n\nstatic lv_res_t _show_hide_save_button(lv_obj_t *tv, uint16_t tab_idx)\n{\n\tif (tab_idx == 4) // Options.\n\t{\n\t\tlv_btn_set_action(status_bar.mid, LV_BTN_ACTION_CLICK, _save_options_action);\n\t\tlv_obj_set_opa_scale(status_bar.mid, LV_OPA_COVER);\n\t\tlv_obj_set_click(status_bar.mid, true);\n\t}\n\telse\n\t{\n\t\tlv_obj_set_opa_scale(status_bar.mid, LV_OPA_0);\n\t\tlv_obj_set_click(status_bar.mid, false);\n\t}\n\n\tnyx_check_ini_changes();\n\n\treturn LV_RES_OK;\n}\n\nstatic void _nyx_set_default_styles(lv_theme_t * th)\n{\n\tlv_style_copy(&mbox_darken, &lv_style_plain);\n\tmbox_darken.body.main_color = LV_COLOR_BLACK;\n\tmbox_darken.body.grad_color = mbox_darken.body.main_color;\n\tmbox_darken.body.opa = LV_OPA_30;\n\n\tlv_style_copy(&hint_small_style, th->label.hint);\n\thint_small_style.text.letter_space = 1;\n\thint_small_style.text.font = &interui_20;\n\n\tlv_style_copy(&hint_small_style_white, th->label.prim);\n\thint_small_style_white.text.letter_space = 1;\n\thint_small_style_white.text.font = &interui_20;\n\n\tlv_style_copy(&monospace_text, &lv_style_plain);\n\tmonospace_text.body.main_color = COLOR_HOS_BG_DARKER;\n\tmonospace_text.body.grad_color = COLOR_HOS_BG_DARKER;\n\tmonospace_text.body.border.color = COLOR_HOS_BG_DARKER;\n\tmonospace_text.body.border.width = 0;\n\tmonospace_text.body.opa = LV_OPA_TRANSP;\n\tmonospace_text.text.color = LV_COLOR_HEX(0xD8D8D8);\n\tmonospace_text.text.font = &ubuntu_mono;\n\tmonospace_text.text.letter_space = 0;\n\tmonospace_text.text.line_space = 0;\n\n\tlv_style_copy(&btn_transp_rel, th->btn.rel);\n\tbtn_transp_rel.body.main_color = LV_COLOR_HEX(0x444444);\n\tbtn_transp_rel.body.grad_color = btn_transp_rel.body.main_color;\n\tbtn_transp_rel.body.shadow.color = LV_COLOR_HEX(0x0F0F0F);\n\tbtn_transp_rel.body.opa = LV_OPA_50;\n\n\tlv_style_copy(&btn_transp_pr, th->btn.pr);\n\tbtn_transp_pr.body.main_color = LV_COLOR_HEX(0x888888);\n\tbtn_transp_pr.body.grad_color = btn_transp_pr.body.main_color;\n\tbtn_transp_pr.body.shadow.color = LV_COLOR_HEX(0x0F0F0F);\n\tbtn_transp_pr.body.opa = LV_OPA_50;\n\n\tlv_style_copy(&btn_transp_tgl_rel, th->btn.tgl_rel);\n\tbtn_transp_tgl_rel.body.main_color = LV_COLOR_HEX(0x444444);\n\tbtn_transp_tgl_rel.body.grad_color = btn_transp_tgl_rel.body.main_color;\n\tbtn_transp_tgl_rel.body.shadow.color = LV_COLOR_HEX(0x0F0F0F);\n\tbtn_transp_tgl_rel.body.opa = LV_OPA_50;\n\n\tlv_style_copy(&btn_transp_tgl_pr, th->btn.tgl_pr);\n\tbtn_transp_tgl_pr.body.main_color = LV_COLOR_HEX(0x888888);\n\tbtn_transp_tgl_pr.body.grad_color = btn_transp_tgl_pr.body.main_color;\n\tbtn_transp_tgl_pr.body.shadow.color = LV_COLOR_HEX(0x0F0F0F);\n\tbtn_transp_tgl_pr.body.opa = LV_OPA_50;\n\n\tlv_style_copy(&btn_transp_ina, th->btn.ina);\n\tbtn_transp_ina.body.main_color = LV_COLOR_HEX(0x292929);\n\tbtn_transp_ina.body.grad_color = btn_transp_ina.body.main_color;\n\tbtn_transp_ina.body.border.color = LV_COLOR_HEX(0x444444);\n\tbtn_transp_ina.body.shadow.color = LV_COLOR_HEX(0x0F0F0F);\n\tbtn_transp_ina.body.opa = LV_OPA_50;\n\n\tlv_style_copy(&ddlist_transp_bg, th->ddlist.bg);\n\tddlist_transp_bg.body.main_color = LV_COLOR_HEX(0x2D2D2D);\n\tddlist_transp_bg.body.grad_color = ddlist_transp_bg.body.main_color;\n\tddlist_transp_bg.body.opa = 180; // 70.6%.\n\n\tlv_style_copy(&ddlist_transp_sel, th->ddlist.sel);\n\tddlist_transp_sel.body.main_color = LV_COLOR_HEX(0x4D4D4D);\n\tddlist_transp_sel.body.grad_color = ddlist_transp_sel.body.main_color;\n\tddlist_transp_sel.body.opa = 180; // 70.6%.\n\n\tlv_style_copy(&tabview_btn_pr, th->tabview.btn.pr);\n\ttabview_btn_pr.body.main_color = LV_COLOR_HEX(0xFFFFFF);\n\ttabview_btn_pr.body.grad_color = tabview_btn_pr.body.main_color;\n\ttabview_btn_pr.body.opa = 35; // 13.7%.\n\n\tlv_style_copy(&tabview_btn_tgl_pr, th->tabview.btn.tgl_pr);\n\ttabview_btn_tgl_pr.body.main_color = LV_COLOR_HEX(0xFFFFFF);\n\ttabview_btn_tgl_pr.body.grad_color = tabview_btn_tgl_pr.body.main_color;\n\ttabview_btn_tgl_pr.body.opa = 35; // 13.7%.\n\n\tlv_color_t tmp_color = COLOR_HOS_TURQUOISE_EX(n_cfg.theme_color);\n\ttext_color = malloc(32);\n\ts_printf(text_color, \"#%06X\", (u32)(tmp_color.full & 0xFFFFFF));\n}\n\nlv_task_t *task_bpmp_clock;\nvoid first_time_bpmp_clock(void *param)\n{\n\t// Remove task.\n\tlv_task_del(task_bpmp_clock);\n\n\t// Max clock seems fine. Save it.\n\tn_cfg.bpmp_clock = 1;\n\tcreate_nyx_config_entry(false);\n}\n\nstatic void _nyx_main_menu(lv_theme_t * th)\n{\n\tstatic lv_style_t no_padding;\n\tlv_style_copy(&no_padding, &lv_style_transp);\n\tno_padding.body.padding.hor = 0;\n\n\t// Initialize global styles.\n\t_nyx_set_default_styles(th);\n\n\t// Create screen container.\n\tlv_obj_t *scr = lv_cont_create(NULL, NULL);\n\tlv_scr_load(scr);\n\tlv_cont_set_style(scr, th->bg);\n\n\t// Create base background and add a custom one if exists.\n\tlv_obj_t *cnr = lv_cont_create(scr, NULL);\n\tstatic lv_style_t base_bg_style;\n\tlv_style_copy(&base_bg_style, &lv_style_plain_color);\n\tbase_bg_style.body.main_color = th->bg->body.main_color;\n\tbase_bg_style.body.grad_color = base_bg_style.body.main_color;\n\tlv_cont_set_style(cnr, &base_bg_style);\n\tlv_obj_set_size(cnr, LV_HOR_RES, LV_VER_RES);\n\n\tif (hekate_bg)\n\t{\n\t\tlv_obj_t *img = lv_img_create(cnr, NULL);\n\t\tlv_img_set_src(img, hekate_bg);\n\t}\n\n\t// Add tabview page to screen.\n\tlv_obj_t *tv = lv_tabview_create(scr, NULL);\n\tif (hekate_bg)\n\t{\n\t\tlv_tabview_set_style(tv, LV_TABVIEW_STYLE_BTN_PR, &tabview_btn_pr);\n\t\tlv_tabview_set_style(tv, LV_TABVIEW_STYLE_BTN_TGL_PR, &tabview_btn_tgl_pr);\n\t}\n\tlv_tabview_set_sliding(tv, false);\n\tlv_obj_set_size(tv, LV_HOR_RES, LV_VER_RES);\n\n\t// Add all tabs content.\n\tchar version[32];\n\tchar rel = (nyx_str->version >> 24) & 0xFF;\n\ts_printf(version, \"hekate %s%d.%d.%d%c%c\",\n\t\t\t rel ? \"v\" : \"\", nyx_str->version & 0xFF, (nyx_str->version >> 8) & 0xFF, (nyx_str->version >> 16) & 0xFF, rel > 'a' ? rel : 0,\n\t\t\t (nyx_str->info_ex.rsvd_flags & RSVD_FLAG_DRAM_8GB) ? '*' : 0);\n\tlv_obj_t *tab_about = lv_tabview_add_tab(tv, version);\n\n\tlv_obj_t *tab_home = lv_tabview_add_tab(tv, SYMBOL_HOME\" Home\");\n\n\tlv_obj_t *tab_tools = lv_tabview_add_tab(tv, SYMBOL_TOOLS\" Tools\");\n\tlv_page_set_style(tab_tools, LV_PAGE_STYLE_BG, &no_padding);\n\tlv_page_set_style(tab_tools, LV_PAGE_STYLE_SCRL, &no_padding);\n\n\tlv_obj_t *tab_info = lv_tabview_add_tab(tv, SYMBOL_INFO\" Console Info\");\n\tlv_page_set_style(tab_info, LV_PAGE_STYLE_BG, &no_padding);\n\tlv_page_set_style(tab_info, LV_PAGE_STYLE_SCRL, &no_padding);\n\n\tlv_obj_t *tab_options = lv_tabview_add_tab(tv, SYMBOL_SETTINGS\" Options\");\n\n\t_create_tab_about(th, tab_about);\n\t_create_tab_home(th, tab_home);\n\tcreate_tab_tools(th, tab_tools);\n\tcreate_tab_info(th, tab_info);\n\tcreate_tab_options(th, tab_options);\n\n\tlv_tabview_set_tab_act(tv, 1, false);\n\n\t// Create status bar.\n\t_create_status_bar(th);\n\n\t// Create tasks.\n\tsystem_tasks.task.dram_periodic_comp = lv_task_create(minerva_periodic_training, EMC_PERIODIC_TRAIN_MS, LV_TASK_PRIO_HIGHEST, NULL);\n\tlv_task_ready(system_tasks.task.dram_periodic_comp);\n\n\tsystem_tasks.task.status_bar = lv_task_create(_update_status_bar, 5000, LV_TASK_PRIO_LOW, NULL);\n\tlv_task_ready(system_tasks.task.status_bar);\n\n\tlv_task_create(_check_sd_card_removed, 2000, LV_TASK_PRIO_LOWEST, NULL);\n\n\ttask_emmc_errors = lv_task_create(_nyx_emmc_issues_warning, 2000, LV_TASK_PRIO_LOWEST, NULL);\n\tlv_task_ready(task_emmc_errors);\n\n\t// Create top level global line separators.\n\tlv_obj_t *line = lv_cont_create(lv_layer_top(), NULL);\n\n\tstatic lv_style_t line_style;\n\tlv_style_copy(&line_style, &lv_style_plain_color);\n\n\tline_style.body.main_color = LV_COLOR_HEX(0xDDDDDD); // 0x505050\n\tline_style.body.grad_color = line_style.body.main_color;\n\tline_style.body.shadow.width = 0;\n\n\tlv_cont_set_style(line, &line_style);\n\tlv_obj_set_size(line, LV_HOR_RES - LV_DPI * 3 / 5, 1);\n\tlv_obj_set_pos(line, LV_DPI * 3 / 10, 63);\n\n\tlv_obj_set_top(line, true);\n\n\tline = lv_cont_create(lv_layer_top(), line);\n\tlv_obj_set_pos(line, LV_DPI * 3 / 10, 656);\n\tlv_obj_set_top(line, true);\n\n\t// Option save button.\n\tlv_tabview_set_tab_load_action(tv, _show_hide_save_button);\n\n\t// Check if Nyx was launched with a function set.\n\tif (nyx_str->cfg & NYX_CFG_UMS)\n\t{\n\t\tnyx_str->cfg &= ~(NYX_CFG_UMS);\n\t\tlv_task_t *task_run_ums = lv_task_create(nyx_run_ums, LV_TASK_ONESHOT, LV_TASK_PRIO_LOWEST, (void *)&nyx_str->cfg);\n\t\tlv_task_once(task_run_ums);\n\t}\n\telse if (n_cfg.home_screen)\n\t\t_create_window_home_launch(NULL);\n\n\tif (!n_cfg.timeoffset)\n\t{\n\t\tlv_task_t *task_run_clock = lv_task_create(first_time_clock_edit, LV_TASK_ONESHOT, LV_TASK_PRIO_MID, NULL);\n\t\tlv_task_once(task_run_clock);\n\t}\n\n\tif (!n_cfg.bpmp_clock)\n\t\ttask_bpmp_clock = lv_task_create(first_time_bpmp_clock, 10000, LV_TASK_PRIO_LOWEST, NULL);\n}\n\nvoid nyx_load_and_run()\n{\n\tmemset(&system_tasks, 0, sizeof(system_maintenance_tasks_t));\n\n\tlv_init();\n\tgfx_con.fillbg = 1;\n\n\t// Initialize framebuffer drawing functions.\n\tlv_disp_drv_t disp_drv;\n\tlv_disp_drv_init(&disp_drv);\n\tdisp_drv.disp_flush = _disp_fb_flush;\n\tlv_disp_drv_register(&disp_drv);\n\n\t// Initialize Joy-Con.\n\tif (!n_cfg.jc_disable)\n\t{\n\t\tlv_task_t *task_jc_init_hw = lv_task_create(jc_init_hw, LV_TASK_ONESHOT, LV_TASK_PRIO_LOWEST, NULL);\n\t\tlv_task_once(task_jc_init_hw);\n\t}\n\tlv_indev_drv_t indev_drv_jc;\n\tlv_indev_drv_init(&indev_drv_jc);\n\tindev_drv_jc.type = LV_INDEV_TYPE_POINTER;\n\tindev_drv_jc.read = _jc_virt_mouse_read;\n\tmemset(&jc_drv_ctx, 0, sizeof(jc_lv_driver_t));\n\tjc_drv_ctx.indev_jc = lv_indev_drv_register(&indev_drv_jc);\n\tclose_btn = NULL;\n\n\t// Initialize touch.\n\ttouch_enabled = !touch_power_on();\n\tlv_indev_drv_t indev_drv_touch;\n\tlv_indev_drv_init(&indev_drv_touch);\n\tindev_drv_touch.type = LV_INDEV_TYPE_POINTER;\n\tindev_drv_touch.read = _fts_touch_read;\n\tjc_drv_ctx.indev_touch = lv_indev_drv_register(&indev_drv_touch);\n\ttouchpad.touch = false;\n\n\t// Initialize temperature sensor.\n\ttmp451_init();\n\n\t// Set hekate theme based on chosen hue.\n\tlv_theme_t *th = lv_theme_hekate_init(n_cfg.theme_bg, n_cfg.theme_color, NULL);\n\tlv_theme_set_current(th);\n\n\t// Create main menu\n\t_nyx_main_menu(th);\n\n\tjc_drv_ctx.cursor = lv_img_create(lv_scr_act(), NULL);\n\tlv_img_set_src(jc_drv_ctx.cursor, &touch_cursor);\n\tlv_obj_set_opa_scale(jc_drv_ctx.cursor, LV_OPA_TRANSP);\n\tlv_obj_set_opa_scale_enable(jc_drv_ctx.cursor, true);\n\n\t// Check if sd card issues.\n\tif (sd_get_mode() == SD_1BIT_HS25)\n\t{\n\t\tlv_task_t *task_run_sd_errors = lv_task_create(_nyx_sd_card_issues_warning, LV_TASK_ONESHOT, LV_TASK_PRIO_LOWEST, NULL);\n\t\tlv_task_once(task_run_sd_errors);\n\t}\n\n\t// Gui loop.\n\tif (h_cfg.t210b01)\n\t{\n\t\t// Minerva not supported on T210B01 yet. Slight power saving via spinlock.\n\t\twhile (true)\n\t\t{\n\t\t\tlv_task_handler();\n\t\t\tusleep(400);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Alternate DRAM frequencies. Total stall < 1ms. Saves 300+ mW.\n\t\twhile (true)\n\t\t{\n\t\t\tminerva_change_freq(FREQ_1600);  // Takes 295 us.\n\n\t\t\tlv_task_handler();\n\n\t\t\tminerva_change_freq(FREQ_800);   // Takes 80 us.\n\t\t\tusleep(125); // Min 20us.\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "nyx/nyx_gui/frontend/gui.h",
    "content": "/*\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _GUI_H_\n#define _GUI_H_\n\n#include <libs/lvgl/lvgl.h>\n\ntypedef struct _emmc_tool_gui_t\n{\n\tlv_obj_t *label_log;\n\tlv_obj_t *label_info;\n\tlv_obj_t *label_pct;\n\tlv_obj_t *label_finish;\n\tlv_obj_t *bar;\n\tlv_style_t *bar_teal_bg;\n\tlv_style_t *bar_teal_ind;\n\tlv_style_t *bar_white_bg;\n\tlv_style_t *bar_white_ind;\n\tlv_style_t *bar_orange_bg;\n\tlv_style_t *bar_orange_ind;\n\tchar *txt_buf;\n\tchar *base_path;\n\tbool raw_emummc;\n} emmc_tool_gui_t;\n\ntypedef struct _gui_status_bar_ctx\n{\n\tlv_obj_t *bar_bg;\n\tlv_obj_t *mid;\n\tlv_obj_t *time_temp;\n\tlv_obj_t *temp_symbol;\n\tlv_obj_t *temp_degrees;\n\tlv_obj_t *battery;\n\tlv_obj_t *battery_more;\n} gui_status_bar_ctx;\n\nextern lv_style_t hint_small_style;\nextern lv_style_t hint_small_style_white;\nextern lv_style_t monospace_text;\n\nextern lv_obj_t *payload_list;\nextern lv_obj_t *autorcm_btn;\nextern lv_obj_t *close_btn;\n\nextern lv_img_dsc_t *icon_switch;\nextern lv_img_dsc_t *icon_payload;\nextern lv_img_dsc_t *icon_lakka;\n\nextern lv_img_dsc_t *hekate_bg;\n\nextern lv_style_t btn_transp_rel, btn_transp_pr, btn_transp_tgl_rel, btn_transp_tgl_pr, btn_transp_ina;\nextern lv_style_t ddlist_transp_bg, ddlist_transp_sel;\nextern lv_style_t tabview_btn_pr, tabview_btn_tgl_pr;\n\nextern lv_style_t mbox_darken;\n\nextern char *text_color;\n\nextern gui_status_bar_ctx status_bar;\n\nvoid reload_nyx(lv_obj_t *obj, bool force);\nlv_img_dsc_t *bmp_to_lvimg_obj(const char *path);\nbool nyx_emmc_check_battery_enough();\nlv_res_t nyx_mbox_action(lv_obj_t * btns, const char * txt);\nlv_res_t nyx_win_close_action(lv_obj_t * btn);\nvoid nyx_window_toggle_buttons(lv_obj_t *win, bool disable);\nlv_obj_t *nyx_create_standard_window(const char *win_title, lv_action_t close_action);\nvoid nyx_create_onoff_button(lv_theme_t *th, lv_obj_t *parent, lv_obj_t *btn, const char *btn_name, lv_action_t action, bool transparent);\nlv_res_t nyx_generic_onoff_toggle(lv_obj_t *btn);\nvoid manual_system_maintenance(bool refresh);\nvoid nyx_load_and_run();\n\n#endif\n"
  },
  {
    "path": "nyx/nyx_gui/frontend/gui_emmc_tools.c",
    "content": "/*\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <stdlib.h>\n\n#include <bdk.h>\n\n#include \"gui.h\"\n#include \"gui_emmc_tools.h\"\n#include \"gui_tools.h\"\n#include \"fe_emmc_tools.h\"\n#include \"../config.h\"\n#include \"../hos/pkg1.h\"\n#include \"../hos/pkg2.h\"\n#include \"../hos/hos.h\"\n#include <libs/fatfs/ff.h>\n\nextern char *emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);\n\ntypedef struct _emmc_backup_buttons_t\n{\n\tlv_obj_t *emmc_boot;\n\tlv_obj_t *emmc_raw_gpp;\n\tlv_obj_t *emmc_sys;\n\tlv_obj_t *emmc_usr;\n\tbool raw_emummc;\n\tbool restore;\n} emmc_backup_buttons_t;\n\nstatic emmc_backup_buttons_t emmc_btn_ctxt;\n\nstatic void _create_window_backup_restore(emmcPartType_t type, const char* win_label)\n{\n\temmc_tool_gui_t emmc_tool_gui_ctxt;\n\n\temmc_tool_gui_ctxt.raw_emummc = emmc_btn_ctxt.raw_emummc;\n\n\tchar win_label_full[80];\n\n\ts_printf(win_label_full, \"%s%s\", emmc_btn_ctxt.restore ? SYMBOL_DOWNLOAD\"  Restore \" : SYMBOL_UPLOAD\"  Backup \", win_label+3);\n\n\tlv_obj_t *win = nyx_create_standard_window(win_label_full, NULL);\n\n\t//Disable buttons.\n\tnyx_window_toggle_buttons(win, true);\n\n\t// Create important info container.\n\tlv_obj_t *h1 = lv_cont_create(win, NULL);\n\tlv_cont_set_fit(h1, false, true);\n\tlv_obj_set_width(h1, (LV_HOR_RES / 9) * 5);\n\tlv_obj_set_click(h1, false);\n\tlv_cont_set_layout(h1, LV_LAYOUT_OFF);\n\n\tstatic lv_style_t h_style;\n\tlv_style_copy(&h_style, lv_cont_get_style(h1));\n\th_style.body.main_color = LV_COLOR_HEX(0x1d1d1d);\n\th_style.body.grad_color = h_style.body.main_color;\n\th_style.body.opa = LV_OPA_COVER;\n\n\t// Create log container.\n\tlv_obj_t *h2 = lv_cont_create(win, h1);\n\tlv_cont_set_style(h2, &h_style);\n\tlv_cont_set_fit(h2, false, false);\n\tlv_obj_set_size(h2, (LV_HOR_RES / 11) * 4, LV_DPI * 5);\n\tlv_cont_set_layout(h2, LV_LAYOUT_OFF);\n\tlv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, 0, LV_DPI / 5);\n\n\tlv_obj_t *label_log = lv_label_create(h2, NULL);\n\tlv_label_set_recolor(label_log, true);\n\tlv_obj_set_style(label_log, &monospace_text);\n\tlv_label_set_long_mode(label_log, LV_LABEL_LONG_BREAK);\n\tlv_label_set_static_text(label_log, \"\");\n\tlv_obj_set_width(label_log, lv_obj_get_width(h2));\n\tlv_obj_align(label_log, h2, LV_ALIGN_IN_TOP_LEFT, LV_DPI / 10, LV_DPI / 10);\n\temmc_tool_gui_ctxt.label_log = label_log;\n\n\tlv_obj_t *label_sep = lv_label_create(h1, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\t// Create info elements.\n\tlv_obj_t *label_info = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(label_info, true);\n\tlv_obj_set_width(label_info, lv_obj_get_width(h1));\n\tlv_label_set_static_text(label_info, \"\\n\\n\\n\\n\\n\\n\\n\\n\\n\");\n\tlv_obj_set_style(label_info, lv_theme_get_current()->label.prim);\n\tlv_obj_align(label_info, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 10);\n\temmc_tool_gui_ctxt.label_info = label_info;\n\n\tstatic lv_style_t bar_teal_bg, bar_teal_ind, bar_orange_bg, bar_orange_ind, bar_white_ind;\n\n\tlv_style_copy(&bar_teal_bg, lv_theme_get_current()->bar.bg);\n\tbar_teal_bg.body.main_color = LV_COLOR_HEX(0x005a47);\n\tbar_teal_bg.body.grad_color = bar_teal_bg.body.main_color;\n\n\tlv_style_copy(&bar_teal_ind, lv_theme_get_current()->bar.indic);\n\tbar_teal_ind.body.main_color = LV_COLOR_HEX(0x00FFC9);\n\tbar_teal_ind.body.grad_color = bar_teal_ind.body.main_color;\n\n\tlv_style_copy(&bar_orange_bg, lv_theme_get_current()->bar.bg);\n\tbar_orange_bg.body.main_color = LV_COLOR_HEX(0x755000);\n\tbar_orange_bg.body.grad_color = bar_orange_bg.body.main_color;\n\n\tlv_style_copy(&bar_orange_ind, lv_theme_get_current()->bar.indic);\n\tbar_orange_ind.body.main_color = LV_COLOR_HEX(0xFFAE00);\n\tbar_orange_ind.body.grad_color = bar_orange_ind.body.main_color;\n\n\tlv_style_copy(&bar_white_ind, lv_theme_get_current()->bar.indic);\n\tbar_white_ind.body.main_color = LV_COLOR_HEX(0xF0F0F0);\n\tbar_white_ind.body.grad_color = bar_white_ind.body.main_color;\n\n\temmc_tool_gui_ctxt.bar_teal_bg = &bar_teal_bg;\n\temmc_tool_gui_ctxt.bar_teal_ind = &bar_teal_ind;\n\temmc_tool_gui_ctxt.bar_orange_bg = &bar_orange_bg;\n\temmc_tool_gui_ctxt.bar_orange_ind = &bar_orange_ind;\n\temmc_tool_gui_ctxt.bar_white_bg = lv_theme_get_current()->bar.bg;\n\temmc_tool_gui_ctxt.bar_white_ind = &bar_white_ind;\n\n\tlv_obj_t *bar = lv_bar_create(h1, NULL);\n\tlv_obj_set_size(bar, LV_DPI * 38 / 10, LV_DPI / 5);\n\tlv_bar_set_range(bar, 0, 100);\n\tlv_bar_set_value(bar, 0);\n\tlv_obj_align(bar, label_info, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 8);\n\tlv_obj_set_opa_scale(bar, LV_OPA_0);\n\tlv_obj_set_opa_scale_enable(bar, true);\n\temmc_tool_gui_ctxt.bar = bar;\n\n\tlv_obj_t *label_pct= lv_label_create(h1, NULL);\n\tlv_label_set_recolor(label_pct, true);\n\tlv_label_set_static_text(label_pct, \" \"SYMBOL_DOT\" 0%\");\n\tlv_obj_set_style(label_pct, lv_theme_get_current()->label.prim);\n\tlv_obj_align(label_pct, bar, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 20, 0);\n\tlv_obj_set_opa_scale(label_pct, LV_OPA_0);\n\tlv_obj_set_opa_scale_enable(label_pct, true);\n\temmc_tool_gui_ctxt.label_pct = label_pct;\n\n\tlv_obj_t *label_finish = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(label_finish, true);\n\tlv_label_set_static_text(label_finish, \"\");\n\tlv_obj_set_style(label_finish, lv_theme_get_current()->label.prim);\n\tlv_obj_align(label_finish, bar, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI * 9 / 20);\n\temmc_tool_gui_ctxt.label_finish = label_finish;\n\n\tif (!emmc_btn_ctxt.restore)\n\t\tdump_emmc_selected(type, &emmc_tool_gui_ctxt);\n\telse\n\t\trestore_emmc_selected(type, &emmc_tool_gui_ctxt);\n\n\tnyx_window_toggle_buttons(win, false);\n\n\t// Refresh AutoRCM button.\n\tif (emmc_btn_ctxt.restore && (type == PART_BOOT) && !emmc_btn_ctxt.raw_emummc)\n\t{\n\t\tif (get_set_autorcm_status(false))\n\t\t\tlv_btn_set_state(autorcm_btn, LV_BTN_STATE_TGL_REL);\n\t\telse\n\t\t\tlv_btn_set_state(autorcm_btn, LV_BTN_STATE_REL);\n\t\tnyx_generic_onoff_toggle(autorcm_btn);\n\n\t\tif (h_cfg.rcm_patched)\n\t\t{\n\t\t\tlv_obj_set_click(autorcm_btn, false);\n\t\t\tlv_btn_set_state(autorcm_btn, LV_BTN_STATE_INA);\n\t\t}\n\t}\n}\n\nstatic lv_res_t _emmc_backup_buttons_decider(lv_obj_t *btn)\n{\n\tif (!nyx_emmc_check_battery_enough())\n\t\treturn LV_RES_OK;\n\n\tchar *win_label = lv_label_get_text(lv_obj_get_child(btn, NULL));\n\n\tif (emmc_btn_ctxt.emmc_boot == btn)\n\t\t_create_window_backup_restore(PART_BOOT, win_label);\n\telse if (emmc_btn_ctxt.emmc_raw_gpp == btn)\n\t\t_create_window_backup_restore(PART_RAW, win_label);\n\telse if (emmc_btn_ctxt.emmc_sys == btn)\n\t{\n\t\tif (!emmc_btn_ctxt.restore)\n\t\t\t_create_window_backup_restore(PART_SYSTEM, win_label);\n\t\telse\n\t\t\t_create_window_backup_restore(PART_GP_ALL, win_label);\n\t}\n\telse if (!emmc_btn_ctxt.restore && emmc_btn_ctxt.emmc_usr == btn)\n\t\t_create_window_backup_restore(PART_USER, win_label);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _emmc_backup_buttons_raw_toggle(lv_obj_t *btn)\n{\n\tnyx_generic_onoff_toggle(btn);\n\n\tlv_obj_set_click(emmc_btn_ctxt.emmc_boot, true);\n\tlv_btn_set_state(emmc_btn_ctxt.emmc_boot, LV_BTN_STATE_REL);\n\tlv_obj_set_click(emmc_btn_ctxt.emmc_raw_gpp, true);\n\tlv_btn_set_state(emmc_btn_ctxt.emmc_raw_gpp, LV_BTN_STATE_REL);\n\n\tlv_obj_set_click(emmc_btn_ctxt.emmc_sys, true);\n\tlv_btn_set_state(emmc_btn_ctxt.emmc_sys, LV_BTN_STATE_REL);\n\n\t// Backup/Restore from and to eMMC.\n\tif (!(lv_btn_get_state(btn) & LV_BTN_STATE_TGL_REL))\n\t{\n\t\tif (!emmc_btn_ctxt.restore)\n\t\t\tlv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_boot, NULL), SYMBOL_UPLOAD\"  eMMC BOOT0 & BOOT1\");\n\t\telse\n\t\t\tlv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_boot, NULL), SYMBOL_DOWNLOAD\"  eMMC BOOT0 & BOOT1\");\n\t\tlv_obj_realign(emmc_btn_ctxt.emmc_boot);\n\n\t\tif (!emmc_btn_ctxt.restore)\n\t\t\tlv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_raw_gpp, NULL), SYMBOL_UPLOAD\"  eMMC RAW GPP\");\n\t\telse\n\t\t\tlv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_raw_gpp, NULL), SYMBOL_DOWNLOAD\"  eMMC RAW GPP\");\n\t\tlv_obj_realign(emmc_btn_ctxt.emmc_raw_gpp);\n\n\t\tif (!emmc_btn_ctxt.restore)\n\t\t\tlv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_sys, NULL), SYMBOL_MODULES\"  eMMC SYS\");\n\t\telse\n\t\t\tlv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_sys, NULL), SYMBOL_MODULES\"  eMMC ALL\");\n\t\tlv_obj_realign(emmc_btn_ctxt.emmc_sys);\n\n\t\tif (!emmc_btn_ctxt.restore)\n\t\t{\n\t\t\tlv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_usr, NULL), SYMBOL_MODULES_ALT\"  eMMC USER\");\n\t\t\tlv_obj_realign(emmc_btn_ctxt.emmc_usr);\n\n\t\t\tlv_obj_set_click(emmc_btn_ctxt.emmc_usr, true);\n\t\t\tlv_btn_set_state(emmc_btn_ctxt.emmc_usr, LV_BTN_STATE_REL);\n\t\t}\n\n\t\temmc_btn_ctxt.raw_emummc = false;\n\t}\n\telse // Backup/Restore from and to emuMMC.\n\t{\n\t\tif (!emmc_btn_ctxt.restore)\n\t\t\tlv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_boot, NULL), SYMBOL_UPLOAD\"  SD emuMMC BOOT0 & BOOT1\");\n\t\telse\n\t\t\tlv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_boot, NULL), SYMBOL_DOWNLOAD\"  SD emuMMC BOOT0 & BOOT1\");\n\t\tlv_obj_realign(emmc_btn_ctxt.emmc_boot);\n\n\t\tif (!emmc_btn_ctxt.restore)\n\t\t\tlv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_raw_gpp, NULL), SYMBOL_UPLOAD\"  SD emuMMC RAW GPP\");\n\t\telse\n\t\t\tlv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_raw_gpp, NULL), SYMBOL_DOWNLOAD\"  SD emuMMC RAW GPP\");\n\t\tlv_obj_realign(emmc_btn_ctxt.emmc_raw_gpp);\n\n\t\tlv_obj_set_click(emmc_btn_ctxt.emmc_sys, false);\n\t\tlv_btn_set_state(emmc_btn_ctxt.emmc_sys, LV_BTN_STATE_INA);\n\n\t\tif (!emmc_btn_ctxt.restore)\n\t\t{\n\t\t\tlv_obj_set_click(emmc_btn_ctxt.emmc_usr, false);\n\t\t\tlv_btn_set_state(emmc_btn_ctxt.emmc_usr, LV_BTN_STATE_INA);\n\t\t}\n\n\t\temmc_btn_ctxt.raw_emummc = true;\n\t}\n\n\treturn LV_RES_OK;\n}\n\nlv_res_t create_window_backup_restore_tool(lv_obj_t *btn)\n{\n\tlv_obj_t *win;\n\n\temmc_btn_ctxt.restore = false;\n\tif (strcmp(lv_label_get_text(lv_obj_get_child(btn, NULL)), SYMBOL_UPLOAD\"  Backup eMMC\"))\n\t\temmc_btn_ctxt.restore = true;\n\n\tif (!emmc_btn_ctxt.restore)\n\t\twin = nyx_create_standard_window(SYMBOL_SD\" Backup\", NULL);\n\telse\n\t\twin = nyx_create_standard_window(SYMBOL_SD\" Restore\", NULL);\n\n\tstatic lv_style_t h_style;\n\tlv_style_copy(&h_style, &lv_style_transp);\n\th_style.body.padding.inner = 0;\n\th_style.body.padding.hor = LV_DPI - (LV_DPI / 4);\n\th_style.body.padding.ver = LV_DPI / 9;\n\n\t// Create Full container.\n\tlv_obj_t *h1 = lv_cont_create(win, NULL);\n\tlv_cont_set_style(h1, &h_style);\n\tlv_cont_set_fit(h1, false, true);\n\tlv_obj_set_width(h1, (LV_HOR_RES / 9) * 4);\n\tlv_obj_set_click(h1, false);\n\tlv_cont_set_layout(h1, LV_LAYOUT_OFF);\n\n\tlv_obj_t *label_sep = lv_label_create(h1, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\tlv_obj_t *label_txt = lv_label_create(h1, NULL);\n\tlv_label_set_static_text(label_txt, \"Full\");\n\tlv_obj_set_style(label_txt, lv_theme_get_current()->label.prim);\n\tlv_obj_align(label_txt, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI * 3 / 10);\n\n\tlv_obj_t *line_sep = lv_line_create(h1, NULL);\n\tstatic const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 2, 0} };\n\tlv_line_set_points(line_sep, line_pp, 2);\n\tlv_line_set_style(line_sep, lv_theme_get_current()->line.decor);\n\tlv_obj_align(line_sep, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);\n\n\t// Create BOOT0 & BOOT1 button.\n\tlv_obj_t *btn1 = lv_btn_create(h1, NULL);\n\tlv_obj_t *label_btn = lv_label_create(btn1, NULL);\n\tlv_btn_set_fit(btn1, true, true);\n\tif (!emmc_btn_ctxt.restore)\n\t\tlv_label_set_static_text(label_btn, SYMBOL_UPLOAD\"  eMMC BOOT0 & BOOT1\");\n\telse\n\t\tlv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD\"  eMMC BOOT0 & BOOT1\");\n\n\tlv_obj_align(btn1, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);\n\tlv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, _emmc_backup_buttons_decider);\n\temmc_btn_ctxt.emmc_boot = btn1;\n\n\tlv_obj_t *label_txt2 = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(label_txt2, true);\n\tif (!emmc_btn_ctxt.restore)\n\t{\n\t\tlv_label_set_static_text(label_txt2,\n\t\t\t\"Allows you to backup the BOOT physical partitions.\\n\"\n\t\t\t\"They contain the BCT, keys and various package1.\\n\"\n\t\t\t\"#FF8000 These are paired with the RAW GPP backup.#\");\n\t}\n\telse\n\t{\n\t\tlv_label_set_static_text(label_txt2,\n\t\t\t\"Allows you to restore the BOOT physical partitions.\\n\"\n\t\t\t\"They contain the BCT, keys and various package1.\\n\"\n\t\t\t\"#FF8000 These are paired with the RAW GPP restore.#\");\n\t}\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, btn1, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\t// Create RAW GPP button.\n\tlv_obj_t *btn2 = lv_btn_create(h1, btn1);\n\tlabel_btn = lv_label_create(btn2, NULL);\n\tif (!emmc_btn_ctxt.restore)\n\t\tlv_label_set_static_text(label_btn, SYMBOL_UPLOAD\"  eMMC RAW GPP\");\n\telse\n\t\tlv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD\"  eMMC RAW GPP\");\n\tlv_obj_align(btn2, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);\n\tlv_btn_set_action(btn2, LV_BTN_ACTION_CLICK, _emmc_backup_buttons_decider);\n\temmc_btn_ctxt.emmc_raw_gpp= btn2;\n\n\tlabel_txt2 = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(label_txt2, true);\n\tif (!emmc_btn_ctxt.restore)\n\t{\n\t\tlv_label_set_static_text(label_txt2,\n\t\t\t\"Allows you to backup the GPP physical partition.\\n\"\n\t\t\t\"It contains, CAL0, various package2, SYSTEM, USER, etc.\\n\"\n\t\t\t\"#FF8000 This is paired with the BOOT0/1 backups.#\");\n\t}\n\telse\n\t{\n\t\tlv_label_set_static_text(label_txt2,\n\t\t\t\"Allows you to restore the GPP physical partition.\\n\"\n\t\t\t\"It contains, CAL0, various package2, SYSTEM, USER, etc.\\n\"\n\t\t\t\"#FF8000 This is paired with the BOOT0/1 restore.#\");\n\t}\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, btn2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\t// Create GPP Partitions container.\n\tlv_obj_t *h2 = lv_cont_create(win, NULL);\n\tlv_cont_set_style(h2, &h_style);\n\tlv_cont_set_fit(h2, false, true);\n\tlv_obj_set_width(h2, (LV_HOR_RES / 9) * 4);\n\tlv_obj_set_click(h2, false);\n\tlv_cont_set_layout(h2, LV_LAYOUT_OFF);\n\tlv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 17 / 29, 0);\n\n\tlabel_sep = lv_label_create(h2, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\tlv_obj_t *label_txt3 = lv_label_create(h2, NULL);\n\tlv_label_set_static_text(label_txt3, \"GPP Partitions\");\n\tlv_obj_set_style(label_txt3, lv_theme_get_current()->label.prim);\n\tlv_obj_align(label_txt3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI * 4 / 21);\n\n\tline_sep = lv_line_create(h2, line_sep);\n\tlv_obj_align(line_sep, label_txt3, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);\n\n\t// Create SYS/ALL button.\n\tlv_obj_t *btn3 = lv_btn_create(h2, NULL);\n\tlabel_btn = lv_label_create(btn3, NULL);\n\tlv_btn_set_fit(btn3, true, true);\n\tif (!emmc_btn_ctxt.restore)\n\t\tlv_label_set_static_text(label_btn, SYMBOL_MODULES\"  eMMC SYS\");\n\telse\n\t\tlv_label_set_static_text(label_btn, SYMBOL_MODULES\"  eMMC ALL\");\n\tlv_obj_align(btn3, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);\n\tlv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, _emmc_backup_buttons_decider);\n\temmc_btn_ctxt.emmc_sys = btn3;\n\n\tlv_obj_t *label_txt4 = lv_label_create(h2, NULL);\n\tlv_label_set_recolor(label_txt4, true);\n\tif (!emmc_btn_ctxt.restore)\n\t{\n\t\tlv_label_set_static_text(label_txt4,\n\t\t\t\"Allows you to backup the partitions from RAW GPP except\\n\"\n\t\t\t\"USER. It contains, CAL0, various package2, SYSTEM, etc.\\n\"\n\t\t\t\"#FF8000 This is an incomplete backup.#\");\n\t}\n\telse\n\t{\n\t\tlv_label_set_static_text(label_txt4,\n\t\t\t\"Allows you to restore ALL partitions from RAW GPP\\n\"\n\t\t\t\"It contains, CAL0, various package2, SYSTEM, USER, etc.\\n\");\n\t}\n\n\tlv_obj_set_style(label_txt4, &hint_small_style);\n\tlv_obj_align(label_txt4, btn3, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\t// Create USER button.\n\tif (!emmc_btn_ctxt.restore)\n\t{\n\t\tlv_obj_t *btn4 = lv_btn_create(h2, btn1);\n\t\tlabel_btn = lv_label_create(btn4, NULL);\n\t\tlv_label_set_static_text(label_btn, SYMBOL_MODULES_ALT\"  eMMC USER\");\n\t\tlv_obj_align(btn4, label_txt4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);\n\t\tlv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, _emmc_backup_buttons_decider);\n\t\temmc_btn_ctxt.emmc_usr = btn4;\n\n\t\tlabel_txt4 = lv_label_create(h2, NULL);\n\t\tlv_label_set_recolor(label_txt4, true);\n\t\tlv_label_set_static_text(label_txt4,\n\t\t\t\"Allows you to backup the USER partition from RAW GPP.\\n\"\n\t\t\t\"#FF8000 This is an incomplete backup.#\\n\");\n\t\tlv_obj_set_style(label_txt4, &hint_small_style);\n\t\tlv_obj_align(label_txt4, btn4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\t}\n\telse\n\t{\n\t\temmc_btn_ctxt.emmc_usr = NULL;\n\t}\n\n\t// Create eMMC/emuMMC On/Off button.\n\tlv_obj_t *h3 = lv_cont_create(win, NULL);\n\tlv_cont_set_style(h3, &h_style);\n\tlv_cont_set_fit(h3, false, true);\n\tlv_obj_set_width(h3, (LV_HOR_RES / 10) * 4);\n\tlv_obj_set_click(h3, false);\n\tlv_cont_set_layout(h3, LV_LAYOUT_OFF);\n\tlv_obj_align(h3, h1, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI * 38 / 11, LV_DPI / 7);\n\n\tlv_obj_t *sd_emummc_raw = lv_btn_create(h3, NULL);\n\tnyx_create_onoff_button(lv_theme_get_current(), h3,\n\t\tsd_emummc_raw, SYMBOL_SD\" SD emuMMC Raw Partition\", _emmc_backup_buttons_raw_toggle, false);\n\temmc_btn_ctxt.raw_emummc = false;\n\n\treturn LV_RES_OK;\n}\n"
  },
  {
    "path": "nyx/nyx_gui/frontend/gui_emmc_tools.h",
    "content": "/*\n * Copyright (c) 2018-2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _GUI_EMMC_TOOLS_H_\n#define _GUI_EMMC_TOOLS_H_\n\n#include <libs/lvgl/lvgl.h>\n\nlv_res_t create_window_backup_restore_tool(lv_obj_t *btn);\n\n#endif\n"
  },
  {
    "path": "nyx/nyx_gui/frontend/gui_emummc_tools.c",
    "content": "/*\n * Copyright (c) 2019-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <stdlib.h>\n\n#include <bdk.h>\n\n#include \"gui.h\"\n#include \"fe_emummc_tools.h\"\n#include \"gui_tools_partition_manager.h\"\n#include <libs/fatfs/ff.h>\n\nextern char *emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);\n\ntypedef struct _mbr_ctxt_t\n{\n\tu32 available;\n\tu32 sector[3];\n\tu32 resized_cnt[3];\n\n\tint part_idx;\n\tu32 sector_start;\n} mbr_ctxt_t;\n\nstatic bool emummc_backup;\nstatic mbr_ctxt_t mbr_ctx;\nstatic lv_obj_t *emummc_manage_window;\nstatic lv_res_t (*emummc_tools)(lv_obj_t *btn);\n\nstatic lv_res_t _action_emummc_window_close(lv_obj_t *btn)\n{\n\tnyx_win_close_action(btn);\n\n\t// Delete and relaunch main emuMMC window.\n\tlv_obj_del(emummc_manage_window);\n\t(*emummc_tools)(NULL);\n\n\treturn LV_RES_INV;\n}\n\nstatic void _create_window_emummc()\n{\n\temmc_tool_gui_t emmc_tool_gui_ctxt;\n\n\tlv_obj_t *win;\n\tif (!mbr_ctx.part_idx)\n\t\twin = nyx_create_standard_window(SYMBOL_DRIVE\"  Create SD File emuMMC\", _action_emummc_window_close);\n\telse\n\t\twin = nyx_create_standard_window(SYMBOL_DRIVE\"  Create SD Partition emuMMC\", _action_emummc_window_close);\n\n\t//Disable buttons.\n\tnyx_window_toggle_buttons(win, true);\n\n\t// Create important info container.\n\tlv_obj_t *h1 = lv_cont_create(win, NULL);\n\tlv_cont_set_fit(h1, false, true);\n\tlv_obj_set_width(h1, (LV_HOR_RES / 9) * 5);\n\tlv_obj_set_click(h1, false);\n\tlv_cont_set_layout(h1, LV_LAYOUT_OFF);\n\n\tstatic lv_style_t h_style;\n\tlv_style_copy(&h_style, lv_cont_get_style(h1));\n\th_style.body.main_color = LV_COLOR_HEX(0x1d1d1d);\n\th_style.body.grad_color = h_style.body.main_color;\n\th_style.body.opa = LV_OPA_COVER;\n\n\t// Chreate log container.\n\tlv_obj_t *h2 = lv_cont_create(win, h1);\n\tlv_cont_set_style(h2, &h_style);\n\tlv_cont_set_fit(h2, false, false);\n\tlv_obj_set_size(h2, (LV_HOR_RES / 11) * 4, LV_DPI * 5);\n\tlv_cont_set_layout(h2, LV_LAYOUT_OFF);\n\tlv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, 0, LV_DPI / 5);\n\n\tlv_obj_t *label_log = lv_label_create(h2, NULL);\n\tlv_label_set_recolor(label_log, true);\n\tlv_obj_set_style(label_log, &monospace_text);\n\tlv_label_set_long_mode(label_log, LV_LABEL_LONG_BREAK);\n\tlv_label_set_static_text(label_log, \"\");\n\tlv_obj_set_width(label_log, lv_obj_get_width(h2));\n\tlv_obj_align(label_log, h2, LV_ALIGN_IN_TOP_LEFT, LV_DPI / 10, LV_DPI / 10);\n\temmc_tool_gui_ctxt.label_log = label_log;\n\n\t// Create elements for info container.\n\tlv_obj_t *label_sep = lv_label_create(h1, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\tlv_obj_t *label_info = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(label_info, true);\n\tlv_obj_set_width(label_info, lv_obj_get_width(h1));\n\tlv_label_set_static_text(label_info, \"\\n\\n\\n\\n\\n\\n\\n\\n\\n\");\n\tlv_obj_set_style(label_info, lv_theme_get_current()->label.prim);\n\tlv_obj_align(label_info, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 10);\n\temmc_tool_gui_ctxt.label_info = label_info;\n\n\tlv_obj_t *bar = lv_bar_create(h1, NULL);\n\tlv_obj_set_size(bar, LV_DPI * 38 / 10, LV_DPI / 5);\n\tlv_bar_set_range(bar, 0, 100);\n\tlv_bar_set_value(bar, 0);\n\tlv_obj_align(bar, label_info, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 8);\n\tlv_obj_set_opa_scale(bar, LV_OPA_0);\n\tlv_obj_set_opa_scale_enable(bar, true);\n\temmc_tool_gui_ctxt.bar = bar;\n\n\tlv_obj_t *label_pct= lv_label_create(h1, NULL);\n\tlv_label_set_recolor(label_pct, true);\n\tlv_label_set_static_text(label_pct, \" \"SYMBOL_DOT\" 0%\");\n\tlv_obj_set_style(label_pct, lv_theme_get_current()->label.prim);\n\tlv_obj_align(label_pct, bar, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 20, 0);\n\tlv_obj_set_opa_scale(label_pct, LV_OPA_0);\n\tlv_obj_set_opa_scale_enable(label_pct, true);\n\temmc_tool_gui_ctxt.label_pct = label_pct;\n\n\tlv_obj_t *label_finish = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(label_finish, true);\n\tlv_label_set_static_text(label_finish, \"\");\n\tlv_obj_set_style(label_finish, lv_theme_get_current()->label.prim);\n\tlv_obj_align(label_finish, bar, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI * 9 / 20);\n\temmc_tool_gui_ctxt.label_finish = label_finish;\n\n\tif (!mbr_ctx.part_idx)\n\t\tdump_emummc_file(&emmc_tool_gui_ctxt);\n\telse\n\t\tdump_emummc_raw(&emmc_tool_gui_ctxt, mbr_ctx.part_idx, mbr_ctx.sector_start, mbr_ctx.resized_cnt[mbr_ctx.part_idx - 1]);\n\n\tnyx_window_toggle_buttons(win, false);\n}\n\nstatic lv_res_t _create_emummc_raw_format(lv_obj_t * btns, const char * txt)\n{\n\tint btn_idx = lv_btnm_get_pressed(btns);\n\n\t// Delete parent mbox.\n\tnyx_mbox_action(btns, txt);\n\n\t// Create partition window.\n\tif (!btn_idx)\n\t\tcreate_window_sd_partition_manager(btns);\n\n\tmbr_ctx.part_idx = 0;\n\tmbr_ctx.sector_start = 0;\n\n\treturn LV_RES_INV;\n}\n\nstatic lv_res_t _create_emummc_raw_action(lv_obj_t * btns, const char * txt)\n{\n\tint btn_idx = lv_btnm_get_pressed(btns);\n\tlv_obj_t *bg = lv_obj_get_parent(lv_obj_get_parent(btns));\n\n\tmbr_ctx.sector_start = 0x8000; // Protective offset.\n\n\tswitch (btn_idx)\n\t{\n\tcase 0:\n\t\tmbr_ctx.part_idx = 1;\n\t\tmbr_ctx.sector_start += mbr_ctx.sector[0];\n\t\tbreak;\n\tcase 1:\n\t\tmbr_ctx.part_idx = 2;\n\t\tmbr_ctx.sector_start += mbr_ctx.sector[1];\n\t\tbreak;\n\tcase 2:\n\t\tmbr_ctx.part_idx = 3;\n\t\tmbr_ctx.sector_start += mbr_ctx.sector[2];\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\tif (btn_idx < 3)\n\t{\n\t\tlv_obj_set_style(bg, &lv_style_transp);\n\t\t_create_window_emummc();\n\t}\n\n\tmbr_ctx.part_idx = 0;\n\tmbr_ctx.sector_start = 0;\n\n\tnyx_mbox_action(btns, txt);\n\n\treturn LV_RES_INV;\n}\n\nstatic void _create_mbox_emummc_raw()\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_format[] = { \"\\222Continue\", \"\\222Cancel\", \"\" };\n\tstatic char *mbox_btn_parts[] = { \"\\262Part 1\", \"\\262Part 2\", \"\\262Part 3\", \"\\222Cancel\", \"\" };\n\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);\n\n\tchar *txt_buf = (char *)malloc(SZ_16K);\n\tmbr_t *mbr = (mbr_t *)malloc(sizeof(mbr_t));\n\n\tmemset(&mbr_ctx, 0, sizeof(mbr_ctxt_t));\n\n\tsd_mount();\n\tsdmmc_storage_read(&sd_storage, 0, 1, mbr);\n\tsd_unmount();\n\n\temmc_initialize(false);\n\n\tu32 emmc_size_safe = emmc_storage.sec_cnt + 0xC000; // eMMC GPP size + BOOT0/1.\n\n\temmc_end();\n\n\tfor (int i = 1; i < 4; i++)\n\t{\n\t\tu32 part_size = mbr->partitions[i].size_sct;\n\t\tu32 part_start = mbr->partitions[i].start_sct;\n\t\tu8  part_type = mbr->partitions[i].type;\n\n\t\t// Skip Linux, GPT (Android) and SFD partitions.\n\t\tbool valid_part = (part_type != 0x83) && (part_type != 0xEE) && (part_type != 0xFF);\n\n\t\t// Check if at least 4GB and start above 16MB.\n\t\tif ((part_size >= 0x80F000) && part_start > 0x8000 && valid_part)\n\t\t{\n\t\t\tmbr_ctx.available |= BIT(i - 1);\n\t\t\tmbr_ctx.sector[i - 1] = part_start;\n\n\t\t\t// Only allow up to 28GB resized emuMMC.\n\t\t\tif (part_size <= 0x3810000)\n\t\t\t\tmbr_ctx.resized_cnt[i - 1] = part_size - 0xC000; // Save sectors count without protective size and BOOT0/1.\n\t\t\telse if (part_size >= emmc_size_safe)\n\t\t\t\tmbr_ctx.resized_cnt[i - 1] = 0;\n\t\t\telse\n\t\t\t{\n\t\t\t\tmbr_ctx.available &= ~BIT(i - 1);\n\t\t\t\tmbr_ctx.sector[i - 1] = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (mbr_ctx.available)\n\t{\n\t\ts_printf(txt_buf,\n\t\t\t\"#C7EA46 Found applicable partition(s)!#\\n\"\n\t\t\t\"#FF8000 Choose a partition to continue:#\\n\\n\");\n\t}\n\telse\n\t\ts_printf(txt_buf, \"#FFDD00 Failed to find applicable partition!#\\n\\n\");\n\n\ts_printf(txt_buf + strlen(txt_buf),\n\t\t\"Partition table:\\n\"\n\t\t\"#C0C0C0 Part 0: Type: %02x, Start: %08x, Size: %08x#\\n\"\n\t\t\"#%s Part 1: Type: %02x, Start: %08x, Size: %08x#\\n\"\n\t\t\"#%s Part 2: Type: %02x, Start: %08x, Size: %08x#\\n\"\n\t\t\"#%s Part 3: Type: %02x, Start: %08x, Size: %08x#\",\n\t\tmbr->partitions[0].type, mbr->partitions[0].start_sct, mbr->partitions[0].size_sct,\n\t\t(mbr_ctx.available & BIT(0)) ? (mbr_ctx.resized_cnt[0] ? \"FFDD00\" : \"C7EA46\") : \"C0C0C0\",\n\t\t mbr->partitions[1].type, mbr->partitions[1].start_sct, mbr->partitions[1].size_sct,\n\t\t(mbr_ctx.available & BIT(1)) ? (mbr_ctx.resized_cnt[1] ? \"FFDD00\" : \"C7EA46\") : \"C0C0C0\",\n\t\t mbr->partitions[2].type, mbr->partitions[2].start_sct, mbr->partitions[2].size_sct,\n\t\t(mbr_ctx.available & BIT(2)) ? (mbr_ctx.resized_cnt[2] ? \"FFDD00\" : \"C7EA46\") : \"C0C0C0\",\n\t\t mbr->partitions[3].type, mbr->partitions[3].start_sct, mbr->partitions[3].size_sct);\n\n\tif (mbr_ctx.resized_cnt[0] || mbr_ctx.resized_cnt[1] || mbr_ctx.resized_cnt[2])\n\t\tstrcat(txt_buf, \"\\n\\n#FFDD00 Note:# Yellow entries have USER partition resized.\");\n\n\tif (!mbr_ctx.available)\n\t\tstrcat(txt_buf, \"\\n#FF8000 Do you want to partition the SD card?#\\n\"\n\t\t\t\t\t\t  \"#FF8000 (You will be asked on how to proceed)#\");\n\n\tlv_mbox_set_text(mbox, txt_buf);\n\tfree(txt_buf);\n\tfree(mbr);\n\n\tif (mbr_ctx.available)\n\t{\n\t\t// Check available partitions and enable the corresponding buttons.\n\t\tif (mbr_ctx.available & 1)\n\t\t\tmbox_btn_parts[0][0] = '\\222';\n\t\telse\n\t\t\tmbox_btn_parts[0][0] = '\\262';\n\t\tif (mbr_ctx.available & 2)\n\t\t\tmbox_btn_parts[1][0] = '\\222';\n\t\telse\n\t\t\tmbox_btn_parts[1][0] = '\\262';\n\t\tif (mbr_ctx.available & 4)\n\t\t\tmbox_btn_parts[2][0] = '\\222';\n\t\telse\n\t\t\tmbox_btn_parts[2][0] = '\\262';\n\n\t\tlv_mbox_add_btns(mbox, (const char **)mbox_btn_parts, _create_emummc_raw_action);\n\t}\n\telse\n\t\tlv_mbox_add_btns(mbox, mbox_btn_format, _create_emummc_raw_format);\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n}\n\nstatic lv_res_t _create_emummc_action(lv_obj_t * btns, const char * txt)\n{\n\tint btn_idx = lv_btnm_get_pressed(btns);\n\tlv_obj_t *bg = lv_obj_get_parent(lv_obj_get_parent(btns));\n\n\tmbr_ctx.part_idx = 0;\n\tmbr_ctx.sector_start = 0;\n\n\tswitch (btn_idx)\n\t{\n\tcase 0:\n\t\tlv_obj_set_style(bg, &lv_style_transp);\n\t\t_create_window_emummc();\n\t\tbreak;\n\tcase 1:\n\t\t_create_mbox_emummc_raw();\n\t\tbreak;\n\t}\n\n\tnyx_mbox_action(btns, txt);\n\n\treturn LV_RES_INV;\n}\n\nstatic lv_res_t _create_mbox_emummc_create(lv_obj_t *btn)\n{\n\tif (!nyx_emmc_check_battery_enough())\n\t\treturn LV_RES_OK;\n\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char * mbox_btn_map[] = { \"\\222SD File\", \"\\222SD Partition\", \"\\222Cancel\", \"\" };\n\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);\n\n\tlv_mbox_set_text(mbox,\n\t\t\"Welcome to #C7EA46 emuMMC# creation tool!\\n\\n\"\n\t\t\"Please choose what type of emuMMC you want to create.\\n\"\n\t\t\"#FF8000 SD File# is saved as files in the FAT partition.\\n\"\n\t\t\"#FF8000 SD Partition# is saved as raw image in an available partition.\");\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map, _create_emummc_action);\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\treturn LV_RES_OK;\n}\n\nstatic void _change_raw_emummc_part_type()\n{\n\tmbr_t *mbr = (mbr_t *)malloc(sizeof(mbr_t));\n\tsdmmc_storage_read(&sd_storage, 0, 1, mbr);\n\tmbr->partitions[mbr_ctx.part_idx].type = 0xE0;\n\tsdmmc_storage_write(&sd_storage, 0, 1, mbr);\n\tfree(mbr);\n}\n\nstatic lv_res_t _save_emummc_cfg_mig_mbox_action(lv_obj_t *btns, const char *txt)\n{\n\t// Delete main emuMMC and popup windows and relaunch main emuMMC window.\n\tlv_obj_del(emummc_manage_window);\n\tnyx_mbox_action(btns, txt);\n\n\t(*emummc_tools)(NULL);\n\n\treturn LV_RES_INV;\n}\n\nstatic void _create_emummc_migrated_mbox()\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_map[] = { \"\\251\", \"OK\", \"\\251\", \"\" };\n\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 4);\n\n\tlv_mbox_set_text(mbox,\n\t\t\"#FF8000 emuMMC Configuration#\\n\\n\"\n\t\t\"#96FF00 The emuMMC configuration#\\n#96FF00 was saved to sd card!#\");\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map, _save_emummc_cfg_mig_mbox_action);\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n}\n\nstatic void _migrate_sd_raw_emummc_based()\n{\n\tchar *tmp = (char *)malloc(0x80);\n\ts_printf(tmp, \"emuMMC/RAW%d\", mbr_ctx.part_idx);\n\n\tsd_mount();\n\tf_mkdir(\"emuMMC\");\n\tf_mkdir(tmp);\n\tstrcat(tmp, \"/raw_based\");\n\n\tFIL fp;\n\tif (!f_open(&fp, tmp, FA_CREATE_ALWAYS | FA_WRITE))\n\t{\n\t\tf_write(&fp, &mbr_ctx.sector_start, 4, NULL);\n\t\tf_close(&fp);\n\t}\n\n\ts_printf(tmp, \"emuMMC/RAW%d\", mbr_ctx.part_idx);\n\n\t_change_raw_emummc_part_type();\n\n\tsave_emummc_cfg(mbr_ctx.part_idx, mbr_ctx.sector_start, tmp);\n\t_create_emummc_migrated_mbox();\n\tfree(tmp);\n\n\tsd_unmount();\n}\n\nstatic void _migrate_sd_backup_file_based()\n{\n\tchar *emu_path = (char *)malloc(128);\n\tchar *parts_path = (char *)malloc(128);\n\tchar *backup_path = (char *)malloc(128);\n\tchar *backup_file_path = (char *)malloc(128);\n\n\tsd_mount();\n\tf_mkdir(\"emuMMC\");\n\n\tstrcpy(emu_path, \"emuMMC/BK\");\n\tu32 base_len = strlen(emu_path);\n\n\tfor (int j = 0; j < 100; j++)\n\t{\n\t\tupdate_emummc_base_folder(emu_path, base_len, j);\n\t\tif (f_stat(emu_path, NULL) == FR_NO_FILE)\n\t\t\tbreak;\n\t}\n\tbase_len = strlen(emu_path);\n\n\tf_mkdir(emu_path);\n\tstrcat(emu_path, \"/eMMC\");\n\tf_mkdir(emu_path);\n\n\tFIL fp;\n\t// Create file based flag.\n\tstrcpy(emu_path + base_len, \"/file_based\");\n\tf_open(&fp, \"emuMMC/BK00/file_based\", FA_CREATE_ALWAYS | FA_WRITE);\n\tf_close(&fp);\n\n\tif (!emummc_backup)\n\t\temmcsn_path_impl(backup_path, \"\", \"\", NULL);\n\telse\n\t\temmcsn_path_impl(backup_path, \"/emummc\", \"\", NULL);\n\n\t// Move BOOT0.\n\ts_printf(backup_file_path, \"%s/BOOT0\", backup_path);\n\tstrcpy(emu_path + base_len, \"/eMMC/BOOT0\");\n\tf_rename(backup_file_path, emu_path);\n\n\t// Move BOOT1.\n\ts_printf(backup_file_path, \"%s/BOOT1\", backup_path);\n\tstrcpy(emu_path + base_len, \"/eMMC/BOOT1\");\n\tf_rename(backup_file_path, emu_path);\n\n\t// Move raw GPP.\n\tbool multipart = false;\n\ts_printf(backup_file_path, \"%s/rawnand.bin\", backup_path);\n\n\tif (f_stat(backup_file_path, NULL))\n\t\tmultipart = true;\n\n\tif (!multipart)\n\t{\n\t\tstrcpy(emu_path + base_len, \"/eMMC/00\");\n\t\tf_rename(backup_file_path, emu_path);\n\t}\n\telse\n\t{\n\t\temu_path[base_len] = 0;\n\t\tfor (int i = 0; i < 32; i++)\n\t\t{\n\t\t\ts_printf(backup_file_path, \"%s/rawnand.bin.%02d\", backup_path, i);\n\t\t\ts_printf(parts_path, \"%s/eMMC/%02d\", emu_path, i);\n\t\t\tif (f_rename(backup_file_path, parts_path))\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tfree(emu_path);\n\tfree(parts_path);\n\tfree(backup_path);\n\tfree(backup_file_path);\n\n\tsave_emummc_cfg(0, 0, \"emuMMC/BK00\");\n\t_create_emummc_migrated_mbox();\n\tsd_unmount();\n}\n\nstatic lv_res_t _create_emummc_mig0_action(lv_obj_t * btns, const char * txt)\n{\n\tswitch (lv_btnm_get_pressed(btns))\n\t{\n\tcase 0:\n\t\t_migrate_sd_raw_emummc_based();\n\t\tbreak;\n\t}\n\n\tmbr_ctx.part_idx = 0;\n\tmbr_ctx.sector_start = 0;\n\n\tnyx_mbox_action(btns, txt);\n\n\treturn LV_RES_INV;\n}\n\nstatic lv_res_t _create_emummc_mig1_action(lv_obj_t * btns, const char * txt)\n{\n\tswitch (lv_btnm_get_pressed(btns))\n\t{\n\tcase 0:\n\t\t_migrate_sd_backup_file_based();\n\t\tbreak;\n\t}\n\n\tmbr_ctx.part_idx = 0;\n\tmbr_ctx.sector_start = 0;\n\n\tnyx_mbox_action(btns, txt);\n\n\treturn LV_RES_INV;\n}\n\nstatic lv_res_t _create_emummc_migrate_action(lv_obj_t * btns, const char * txt)\n{\n\tbool backup = false;\n\tbool emummc = false;\n\n\tswitch (lv_btnm_get_pressed(btns))\n\t{\n\tcase 0:\n\t\tbackup = true;\n\t\tbreak;\n\tcase 1:\n\t\temummc = true;\n\t\tbreak;\n\tcase 2:\n\t\tnyx_mbox_action(btns, txt);\n\t\treturn LV_RES_INV;\n\t}\n\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_map[] = { \"\\222Continue\", \"\\222Cancel\", \"\" };\n\tstatic const char *mbox_btn_map1[] = { \"\\251\", \"OK\", \"\\251\", \"\" };\n\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);\n\n\tchar *txt_buf = (char *)malloc(SZ_16K);\n\n\tif (backup)\n\t{\n\t\tif (!emummc_backup)\n\t\t\ts_printf(txt_buf,\n\t\t\t\t\"#C7EA46 Found suitable eMMC backup!#\\n\\n\"\n\t\t\t\t\"#FF8000 Do you want to migrate it?#\\n\");\n\t\telse\n\t\t\ts_printf(txt_buf,\n\t\t\t\t\"#C7EA46 Found suitable emuMMC backup!#\\n\\n\"\n\t\t\t\t\"#FF8000 Do you want to migrate it?#\\n\");\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map, _create_emummc_mig1_action);\n\t}\n\telse if (emummc)\n\t{\n\t\ts_printf(txt_buf,\n\t\t\t\"#C7EA46 Found SD Partition based emuMMC!#\\n\\n\"\n\t\t\t\"#FF8000 Do you want to repair the config and partition type for it?#\\n\");\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map, _create_emummc_mig0_action);\n\t}\n\telse\n\t{\n\t\ts_printf(txt_buf, \"No emuMMC found!\\n\");\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map1, nyx_mbox_action);\n\t}\n\n\tlv_mbox_set_text(mbox, txt_buf);\n\tfree(txt_buf);\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\tnyx_mbox_action(btns, txt);\n\n\treturn LV_RES_INV;\n}\n\ntypedef struct _emummc_images_t\n{\n\tdirlist_t *dirlist;\n\tu32 part_sector[3];\n\tu32 part_type[3];\n\tu32 part_end[3];\n\tchar part_path[3 * 128];\n\tlv_obj_t *win;\n} emummc_images_t;\n\nstatic lv_res_t _create_mbox_emummc_migrate(lv_obj_t *btn)\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic char *mbox_btn_map[] = { \"\\262Backup\", \"\\262Fix RAW\", \"\\222Cancel\", \"\" };\n\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);\n\n\tlv_mbox_set_text(mbox,\n\t\t\"Welcome to #C7EA46 emuMMC# migration tool!\\n\\n\"\n\t\t\"Please choose what type of migration you want to do.\\n\"\n\t\t\"Anything that was not found will have the button disabled.\");\n\n\tchar *path_buf = (char *)malloc(0x512);\n\tmbr_t *mbr = (mbr_t *)malloc(sizeof(mbr_t));\n\tu8 *efi_part = (u8 *)malloc(0x200);\n\n\tsd_mount();\n\tsdmmc_storage_read(&sd_storage, 0, 1, mbr);\n\n\temmc_initialize(false);\n\n\tbool backup = false;\n\tbool emummc = false;\n\tbool rawnand_backup = false;\n\n\tmbr_ctx.sector_start = 0;\n\tmbr_ctx.part_idx = 0;\n\n\t// Try to find a partition based emuMMC.\n\tfor (int i = 1; i < 4; i++)\n\t{\n\t\tmbr_ctx.sector_start = mbr->partitions[i].start_sct;\n\n\t\tif (!mbr_ctx.sector_start)\n\t\t\tcontinue;\n\n\t\tsdmmc_storage_read(&sd_storage, mbr_ctx.sector_start + 0xC001, 1, efi_part);\n\t\tif (!memcmp(efi_part, \"EFI PART\", 8))\n\t\t{\n\t\t\tmbr_ctx.sector_start += 0x8000;\n\t\t\temummc = true;\n\t\t\tmbr_ctx.part_idx = i;\n\t\t\tbreak;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsdmmc_storage_read(&sd_storage, mbr_ctx.sector_start + 0x4001, 1, efi_part);\n\t\t\tif (!memcmp(efi_part, \"EFI PART\", 8))\n\t\t\t{\n\t\t\t\temummc = true;\n\t\t\t\tmbr_ctx.part_idx = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\temummc_backup = false;\n\n\temmcsn_path_impl(path_buf, \"\", \"BOOT0\", &emmc_storage);\n\tif (!f_stat(path_buf, NULL))\n\t\tbackup = true;\n\n\temmcsn_path_impl(path_buf, \"\", \"rawnand.bin\", &emmc_storage);\n\tif (!f_stat(path_buf, NULL))\n\t\trawnand_backup = true;\n\n\temmcsn_path_impl(path_buf, \"\", \"rawnand.bin.00\", &emmc_storage);\n\tif (!f_stat(path_buf, NULL))\n\t\trawnand_backup = true;\n\n\tbackup = backup && rawnand_backup;\n\n\tif (!backup)\n\t{\n\t\trawnand_backup = false;\n\t\temummc_backup = true;\n\n\t\temmcsn_path_impl(path_buf, \"/emummc\", \"BOOT0\", &emmc_storage);\n\t\tif (!f_stat(path_buf, NULL))\n\t\t\tbackup = true;\n\n\t\temmcsn_path_impl(path_buf, \"/emummc\", \"rawnand.bin\", &emmc_storage);\n\t\tif (!f_stat(path_buf, NULL))\n\t\t\trawnand_backup = true;\n\n\t\temmcsn_path_impl(path_buf, \"/emummc\", \"rawnand.bin.00\", &emmc_storage);\n\t\tif (!f_stat(path_buf, NULL))\n\t\t\trawnand_backup = true;\n\n\t\tbackup = backup && rawnand_backup;\n\t}\n\n\tsd_unmount();\n\temmc_end();\n\n\t// Check available types and enable the corresponding buttons.\n\tif (backup)\n\t\tmbox_btn_map[0][0] = '\\222';\n\telse\n\t\tmbox_btn_map[0][0] = '\\262';\n\tif (emummc)\n\t\tmbox_btn_map[1][0] = '\\222';\n\telse\n\t\tmbox_btn_map[1][0] = '\\262';\n\n\tfree(path_buf);\n\tfree(mbr);\n\tfree(efi_part);\n\n\tlv_mbox_add_btns(mbox, (const char **)mbox_btn_map, _create_emummc_migrate_action);\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\treturn LV_RES_OK;\n}\n\nstatic emummc_images_t *emummc_img;\n\nstatic lv_res_t _save_emummc_cfg_mbox_action(lv_obj_t *btns, const char *txt)\n{\n\t// Free components, delete main emuMMC and popup windows and relaunch main emuMMC window.\n\tlv_obj_del(emummc_img->win);\n\tlv_obj_del(emummc_manage_window);\n\tfree(emummc_img->dirlist);\n\tfree(emummc_img);\n\n\tnyx_mbox_action(btns, txt);\n\n\t(*emummc_tools)(NULL);\n\n\treturn LV_RES_INV;\n}\n\nstatic void _create_emummc_saved_mbox()\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_map[] = { \"\\251\", \"OK\", \"\\251\", \"\" };\n\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 4);\n\n\tlv_mbox_set_text(mbox,\n\t\t\"#FF8000 emuMMC Configuration#\\n\\n\"\n\t\t\"#96FF00 The emuMMC configuration#\\n#96FF00 was saved to sd card!#\");\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map, _save_emummc_cfg_mbox_action);\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n}\n\nstatic lv_res_t _save_raw_emummc_cfg_action(lv_obj_t * btn)\n{\n\tlv_btn_ext_t *ext = lv_obj_get_ext_attr(btn);\n\tswitch (ext->idx)\n\t{\n\tcase 0:\n\t\tsave_emummc_cfg(1, emummc_img->part_sector[0], &emummc_img->part_path[0]);\n\t\tbreak;\n\tcase 1:\n\t\tsave_emummc_cfg(2, emummc_img->part_sector[1], &emummc_img->part_path[128]);\n\t\tbreak;\n\tcase 2:\n\t\tsave_emummc_cfg(3, emummc_img->part_sector[2], &emummc_img->part_path[256]);\n\t\tbreak;\n\t}\n\n\t_create_emummc_saved_mbox();\n\tsd_unmount();\n\n\treturn LV_RES_INV;\n}\n\nstatic lv_res_t _save_disable_emummc_cfg_action(lv_obj_t * btn)\n{\n\tsave_emummc_cfg(0, 0, NULL);\n\t_create_emummc_saved_mbox();\n\tsd_unmount();\n\n\treturn LV_RES_INV;\n}\n\nstatic lv_res_t _save_file_emummc_cfg_action(lv_obj_t *btn)\n{\n\tsave_emummc_cfg(0, 0, lv_list_get_btn_text(btn));\n\t_create_emummc_saved_mbox();\n\tsd_unmount();\n\n\treturn LV_RES_INV;\n}\n\nstatic lv_res_t _action_win_change_emummc_close(lv_obj_t *btn)\n{\n\tfree(emummc_img->dirlist);\n\tfree(emummc_img);\n\n\treturn nyx_win_close_action(btn);\n}\n\nstatic lv_res_t _create_change_emummc_window(lv_obj_t *btn_caller)\n{\n\tlv_obj_t *win = nyx_create_standard_window(SYMBOL_SETTINGS\"  Change emuMMC\", _action_win_change_emummc_close);\n\tlv_win_add_btn(win, NULL, SYMBOL_POWER\"  Disable\", _save_disable_emummc_cfg_action);\n\n\tsd_mount();\n\n\temummc_img = malloc(sizeof(emummc_images_t));\n\temummc_img->win = win;\n\n\tmbr_t *mbr = (mbr_t *)malloc(sizeof(mbr_t));\n\tchar *path = malloc(512);\n\n\tsdmmc_storage_read(&sd_storage, 0, 1, mbr);\n\n\tmemset(emummc_img->part_path, 0, 3 * 128);\n\n\tfor (int i = 1; i < 4; i++)\n\t{\n\t\temummc_img->part_sector[i - 1] = mbr->partitions[i].start_sct;\n\t\temummc_img->part_end[i - 1]    = emummc_img->part_sector[i - 1] + mbr->partitions[i].size_sct - 1;\n\t\temummc_img->part_type[i - 1]   = mbr->partitions[i].type;\n\t}\n\tfree(mbr);\n\n\temummc_img->dirlist = dirlist(\"emuMMC\", NULL, DIR_SHOW_DIRS);\n\n\tif (!emummc_img->dirlist)\n\t\tgoto out0;\n\n\tu32 emummc_idx = 0;\n\n\tFIL fp;\n\n\t// Check for sd raw partitions, based on the folders in /emuMMC.\n\twhile (emummc_img->dirlist->name[emummc_idx])\n\t{\n\t\ts_printf(path, \"emuMMC/%s/raw_based\", emummc_img->dirlist->name[emummc_idx]);\n\n\t\tif (!f_stat(path, NULL))\n\t\t{\n\t\t\tf_open(&fp, path, FA_READ);\n\t\t\tu32 curr_list_sector = 0;\n\t\t\tf_read(&fp, &curr_list_sector, 4, NULL);\n\t\t\tf_close(&fp);\n\n\t\t\t// Check if there's a HOS image there.\n\t\t\tif ((curr_list_sector == 2) || (emummc_img->part_sector[0] && curr_list_sector >= emummc_img->part_sector[0] &&\n\t\t\t\tcurr_list_sector < emummc_img->part_end[0] && emummc_img->part_type[0] != 0x83))\n\t\t\t{\n\t\t\t\ts_printf(&emummc_img->part_path[0], \"emuMMC/%s\", emummc_img->dirlist->name[emummc_idx]);\n\t\t\t\temummc_img->part_sector[0] = curr_list_sector;\n\t\t\t\temummc_img->part_end[0]    = 0;\n\t\t\t}\n\t\t\telse if (emummc_img->part_sector[1] && curr_list_sector >= emummc_img->part_sector[1] &&\n\t\t\t\tcurr_list_sector < emummc_img->part_end[1] && emummc_img->part_type[1] != 0x83)\n\t\t\t{\n\t\t\t\ts_printf(&emummc_img->part_path[1 * 128], \"emuMMC/%s\", emummc_img->dirlist->name[emummc_idx]);\n\t\t\t\temummc_img->part_sector[1] = curr_list_sector;\n\t\t\t\temummc_img->part_end[1]    = 0;\n\t\t\t}\n\t\t\telse if (emummc_img->part_sector[2] && curr_list_sector >= emummc_img->part_sector[2] &&\n\t\t\t\tcurr_list_sector < emummc_img->part_end[2] && emummc_img->part_type[2] != 0x83)\n\t\t\t{\n\t\t\t\ts_printf(&emummc_img->part_path[2 * 128], \"emuMMC/%s\", emummc_img->dirlist->name[emummc_idx]);\n\t\t\t\temummc_img->part_sector[2] = curr_list_sector;\n\t\t\t\temummc_img->part_end[2]    = 0;\n\t\t\t}\n\t\t}\n\t\temummc_idx++;\n\t}\n\n\temummc_idx = 0;\n\tu32 file_based_idx = 0;\n\n\t// Sanitize the directory list with sd file based ones.\n\twhile (emummc_img->dirlist->name[emummc_idx])\n\t{\n\t\ts_printf(path, \"emuMMC/%s/file_based\", emummc_img->dirlist->name[emummc_idx]);\n\n\t\tif (!f_stat(path, NULL))\n\t\t{\n\t\t\tchar *tmp = emummc_img->dirlist->name[emummc_idx];\n\t\t\tmemcpy(emummc_img->dirlist->name[file_based_idx], tmp, strlen(tmp) + 1);\n\t\t\tfile_based_idx++;\n\t\t}\n\t\temummc_idx++;\n\t}\n\temummc_img->dirlist->name[file_based_idx] = NULL;\n\nout0:;\n\tstatic lv_style_t h_style;\n\tlv_style_copy(&h_style, &lv_style_transp);\n\th_style.body.padding.inner = 0;\n\th_style.body.padding.hor = LV_DPI - (LV_DPI / 4);\n\th_style.body.padding.ver = LV_DPI / 6;\n\n\t// Create SD Raw Partitions container.\n\tlv_obj_t *h1 = lv_cont_create(win, NULL);\n\tlv_cont_set_style(h1, &h_style);\n\tlv_cont_set_fit(h1, false, true);\n\tlv_obj_set_width(h1, (LV_HOR_RES / 9) * 4);\n\tlv_obj_set_click(h1, false);\n\tlv_cont_set_layout(h1, LV_LAYOUT_OFF);\n\n\tlv_obj_t *label_sep = lv_label_create(h1, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\tlv_obj_t *label_txt = lv_label_create(h1, NULL);\n\tlv_label_set_static_text(label_txt, \"SD Raw Partitions\");\n\tlv_obj_set_style(label_txt, lv_theme_get_current()->label.prim);\n\tlv_obj_align(label_txt, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -(LV_DPI / 2));\n\n\tlv_obj_t *line_sep = lv_line_create(h1, NULL);\n\tstatic const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 2, 0} };\n\tlv_line_set_points(line_sep, line_pp, 2);\n\tlv_line_set_style(line_sep, lv_theme_get_current()->line.decor);\n\tlv_obj_align(line_sep, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);\n\n\tlv_obj_t *btn = NULL;\n\tlv_btn_ext_t *ext;\n\tlv_obj_t *btn_label = NULL;\n\tlv_obj_t *lv_desc = NULL;\n\tchar *txt_buf = malloc(SZ_16K);\n\n\t// Create RAW buttons.\n\tfor (u32 raw_btn_idx = 0; raw_btn_idx < 3; raw_btn_idx++)\n\t{\n\t\tbtn = lv_btn_create(h1, btn);\n\t\text = lv_obj_get_ext_attr(btn);\n\t\text->idx = raw_btn_idx;\n\t\tbtn_label = lv_label_create(btn, btn_label);\n\n\t\tlv_btn_set_state(btn, LV_BTN_STATE_REL);\n\t\tlv_obj_set_click(btn, true);\n\n\t\tif (emummc_img->part_type[raw_btn_idx] != 0x83)\n\t\t{\n\t\t\ts_printf(txt_buf, \"SD RAW %d\", raw_btn_idx + 1);\n\t\t\tlv_label_set_text(btn_label, txt_buf);\n\t\t}\n\n\t\tif (!emummc_img->part_sector[raw_btn_idx] || emummc_img->part_type[raw_btn_idx] == 0x83 || !emummc_img->part_path[raw_btn_idx * 128])\n\t\t{\n\t\t\tlv_btn_set_state(btn, LV_BTN_STATE_INA);\n\t\t\tlv_obj_set_click(btn, false);\n\n\t\t\tif (emummc_img->part_type[raw_btn_idx] == 0x83)\n\t\t\t\tlv_label_set_static_text(btn_label, \"Linux\");\n\t\t}\n\n\t\tif (!raw_btn_idx)\n\t\t{\n\t\t\tlv_btn_set_fit(btn, false, true);\n\t\t\tlv_obj_set_width(btn, LV_DPI * 3);\n\t\t\tlv_obj_align(btn, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 2, LV_DPI / 5);\n\t\t}\n\t\telse\n\t\t\tlv_obj_align(btn, lv_desc, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\t\tlv_btn_set_action(btn, LV_BTN_ACTION_CLICK, _save_raw_emummc_cfg_action);\n\n\t\tlv_desc = lv_label_create(h1, lv_desc);\n\t\tlv_label_set_recolor(lv_desc, true);\n\t\tlv_obj_set_style(lv_desc, &hint_small_style);\n\n\t\ts_printf(txt_buf, \"Sector start: 0x%08X\\nFolder: %s\", emummc_img->part_sector[raw_btn_idx], &emummc_img->part_path[raw_btn_idx * 128]);\n\t\tlv_label_set_text(lv_desc, txt_buf);\n\t\tlv_obj_align(lv_desc, btn, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 5);\n\t}\n\tfree(txt_buf);\n\n\t// Create SD File Based container.\n\tlv_obj_t *h2 = lv_cont_create(win, NULL);\n\tlv_cont_set_style(h2, &h_style);\n\tlv_cont_set_fit(h2, false, true);\n\tlv_obj_set_width(h2, (LV_HOR_RES / 9) * 4);\n\tlv_obj_set_click(h2, false);\n\tlv_cont_set_layout(h2, LV_LAYOUT_OFF);\n\tlv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 17 / 29, 0);\n\n\tlabel_sep = lv_label_create(h2, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\tlv_obj_t *label_txt3 = lv_label_create(h2, NULL);\n\tlv_label_set_static_text(label_txt3, \"SD File Based\");\n\tlv_obj_set_style(label_txt3, lv_theme_get_current()->label.prim);\n\tlv_obj_align(label_txt3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI / 7);\n\n\tline_sep = lv_line_create(h2, line_sep);\n\tlv_obj_align(line_sep, label_txt3, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 2), LV_DPI / 8);\n\tlv_line_set_style(line_sep, lv_theme_get_current()->line.decor);\n\n\tlv_obj_t *list_sd_based = lv_list_create(h2, NULL);\n\tlv_obj_align(list_sd_based, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 2, LV_DPI / 4);\n\n\tlv_obj_set_size(list_sd_based, LV_HOR_RES * 4 / 10, LV_VER_RES * 6 / 10);\n\tlv_list_set_single_mode(list_sd_based, true);\n\n\tif (!emummc_img->dirlist)\n\t\tgoto out1;\n\n\temummc_idx = 0;\n\n\t// Add file based to the list.\n\twhile (emummc_img->dirlist->name[emummc_idx])\n\t{\n\t\ts_printf(path, \"emuMMC/%s\", emummc_img->dirlist->name[emummc_idx]);\n\n\t\tlv_list_add(list_sd_based, NULL, path, _save_file_emummc_cfg_action);\n\n\t\temummc_idx++;\n\t}\n\nout1:\n\tfree(path);\n\tsd_unmount();\n\n\treturn LV_RES_OK;\n}\n\nlv_res_t create_win_emummc_tools(lv_obj_t *btn)\n{\n\tlv_obj_t *win = nyx_create_standard_window(SYMBOL_EDIT\"  emuMMC Manage\", NULL);\n\n\t// Set resources to be managed by other windows.\n\temummc_manage_window = win;\n\temummc_tools = (void *)create_win_emummc_tools;\n\n\tsd_mount();\n\n\temummc_cfg_t emu_info;\n\tload_emummc_cfg(&emu_info);\n\n\tsd_unmount();\n\n\tstatic lv_style_t h_style;\n\tlv_style_copy(&h_style, &lv_style_transp);\n\th_style.body.padding.inner = 0;\n\th_style.body.padding.hor = LV_DPI - (LV_DPI / 4);\n\th_style.body.padding.ver = LV_DPI / 9;\n\n\t// Create emuMMC Info & Selection container.\n\tlv_obj_t *h1 = lv_cont_create(win, NULL);\n\tlv_cont_set_style(h1, &h_style);\n\tlv_cont_set_fit(h1, false, true);\n\tlv_obj_set_width(h1, (LV_HOR_RES / 9) * 4);\n\tlv_obj_set_click(h1, false);\n\tlv_cont_set_layout(h1, LV_LAYOUT_OFF);\n\n\tlv_obj_t *label_sep = lv_label_create(h1, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\tlv_obj_t *label_txt = lv_label_create(h1, NULL);\n\tlv_label_set_static_text(label_txt, \"emuMMC Info & Selection\");\n\tlv_obj_set_style(label_txt, lv_theme_get_current()->label.prim);\n\tlv_obj_align(label_txt, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 11);\n\n\tlv_obj_t *line_sep = lv_line_create(h1, NULL);\n\tstatic const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 2, 0} };\n\tlv_line_set_points(line_sep, line_pp, 2);\n\tlv_line_set_style(line_sep, lv_theme_get_current()->line.decor);\n\tlv_obj_align(line_sep, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);\n\n\t// Create emuMMC info labels.\n\tlv_obj_t *label_btn = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(label_btn, true);\n\tlv_label_set_static_text(label_btn, emu_info.enabled ? \"#96FF00 \"SYMBOL_OK\"  Enabled!#\" : \"#FF8000 \"SYMBOL_CLOSE\"  Disabled!#\");\n\tlv_obj_align(label_btn, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);\n\n\tlv_obj_t *label_txt2 = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(label_txt2, true);\n\tchar *txt_buf = (char *)malloc(SZ_16K);\n\n\tif (emu_info.enabled)\n\t{\n\t\tif (emu_info.sector)\n\t\t\ts_printf(txt_buf, \"#00DDFF Type:# SD Raw Partition\\n#00DDFF Sector:# 0x%08X\\n#00DDFF Nintendo folder:# %s\\n\",\n\t\t\t\temu_info.sector, emu_info.nintendo_path ? emu_info.nintendo_path : \"\");\n\t\telse\n\t\t\ts_printf(txt_buf, \"#00DDFF Type:# SD File\\n#00DDFF Base folder:# %s\\n#00DDFF Nintendo folder:# %s\\n\",\n\t\t\t\temu_info.path ? emu_info.path : \"\", emu_info.nintendo_path ? emu_info.nintendo_path : \"\");\n\n\t\tlv_label_set_text(label_txt2, txt_buf);\n\t}\n\telse\n\t{\n\t\tlv_label_set_static_text(label_txt2, \"emuMMC is disabled and eMMC will be used for boot.\\n\\n\\n\");\n\t}\n\n\tif (emu_info.path)\n\t\tfree(emu_info.path);\n\tif (emu_info.nintendo_path)\n\t\tfree(emu_info.nintendo_path);\n\tfree(txt_buf);\n\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, label_btn, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\t// Create Change emuMMC button.\n\tlv_obj_t *btn2 = lv_btn_create(h1, NULL);\n\tlv_btn_set_fit(btn2, true, true);\n\tlabel_btn = lv_label_create(btn2, NULL);\n\tlv_label_set_static_text(label_btn, SYMBOL_SETTINGS\"  Change emuMMC\");\n\tlv_obj_align(btn2, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI * 6 / 10);\n\tlv_btn_set_action(btn2, LV_BTN_ACTION_CLICK, _create_change_emummc_window);\n\n\tlabel_txt2 = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(label_txt2, true);\n\tlv_label_set_static_text(label_txt2,\n\t\t\"Choose between images created in the emuMMC folder\\n\"\n\t\t\"or in SD card partitions. You can have at most 3 partition\\n\"\n\t\t\"based and countless file based.\");\n\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, btn2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\t// Create emuMMC Tools container.\n\tlv_obj_t *h2 = lv_cont_create(win, NULL);\n\tlv_cont_set_style(h2, &h_style);\n\tlv_cont_set_fit(h2, false, true);\n\tlv_obj_set_width(h2, (LV_HOR_RES / 9) * 4);\n\tlv_obj_set_click(h2, false);\n\tlv_cont_set_layout(h2, LV_LAYOUT_OFF);\n\tlv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 17 / 29, 0);\n\n\tlabel_sep = lv_label_create(h2, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\tlv_obj_t *label_txt3 = lv_label_create(h2, NULL);\n\tlv_label_set_static_text(label_txt3, \"emuMMC Tools\");\n\tlv_obj_set_style(label_txt3, lv_theme_get_current()->label.prim);\n\tlv_obj_align(label_txt3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 5);\n\n\tline_sep = lv_line_create(h2, line_sep);\n\tlv_obj_align(line_sep, label_txt3, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);\n\n\t// Create Create emuMMC button.\n\tlv_obj_t *btn3 = lv_btn_create(h2, btn2);\n\tlabel_btn = lv_label_create(btn3, NULL);\n\tlv_btn_set_fit(btn3, true, true);\n\tlv_label_set_static_text(label_btn, SYMBOL_DRIVE\"  Create emuMMC\");\n\tlv_obj_align(btn3, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);\n\tlv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, _create_mbox_emummc_create);\n\n\tlv_obj_t *label_txt4 = lv_label_create(h2, NULL);\n\tlv_label_set_recolor(label_txt4, true);\n\tlv_label_set_static_text(label_txt4,\n\t\t\"Allows you to create a new #C7EA46 SD File# or #C7EA46 SD Raw Partition#\\n\"\n\t\t\"emuMMC. You can create it from eMMC or a eMMC Backup.\\n\");\n\n\tlv_obj_set_style(label_txt4, &hint_small_style);\n\tlv_obj_align(label_txt4, btn3, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\t// Create Migrate emuMMC button.\n\tlv_obj_t *btn4 = lv_btn_create(h2, btn2);\n\tlabel_btn = lv_label_create(btn4, NULL);\n\tlv_label_set_static_text(label_btn, SYMBOL_SHUFFLE\"  Migrate emuMMC\");\n\tlv_obj_align(btn4, label_txt4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);\n\tlv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, NULL);\n\tlv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, _create_mbox_emummc_migrate);\n\n\tlabel_txt4 = lv_label_create(h2, NULL);\n\tlv_label_set_recolor(label_txt4, true);\n\tlv_label_set_static_text(label_txt4,\n\t\t\"Migrate a backup to a #C7EA46 SD File emuMMC# or repair an existing\\n#C7EA46 SD Raw Partition emuMMC#.\\n\");\n\tlv_obj_set_style(label_txt4, &hint_small_style);\n\tlv_obj_align(label_txt4, btn4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\treturn LV_RES_OK;\n}\n"
  },
  {
    "path": "nyx/nyx_gui/frontend/gui_emummc_tools.h",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _GUI_EMUMMC_TOOLS_H_\n#define _GUI_EMUMMC_TOOLS_H_\n\n#include <libs/lvgl/lvgl.h>\n\nlv_res_t create_win_emummc_tools(lv_obj_t *btn);\n\n#endif\n"
  },
  {
    "path": "nyx/nyx_gui/frontend/gui_info.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2026 CTCaer\n * Copyright (c) 2018 balika011\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <bdk.h>\n\n#include \"gui.h\"\n#include \"../config.h\"\n#include \"../hos/hos.h\"\n#include \"../hos/pkg1.h\"\n#include <libs/fatfs/ff.h>\n\n#include <stdlib.h>\n\n#define SECTORS_TO_MIB_COEFF 11\n\nstatic const char base36[37] = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\n\nextern volatile nyx_storage_t *nyx_str;\n\nextern lv_res_t launch_payload(lv_obj_t *list);\nextern char *emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);\n\nstatic lv_res_t _create_window_dump_done(int error, char *dump_filenames)\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char * mbox_btn_map[] = { \"\\251\", \"\\222OK\", \"\\251\", \"\" };\n\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);\n\n\tchar *txt_buf = (char *)malloc(SZ_4K);\n\n\tif (error)\n\t\ts_printf(txt_buf, \"#FFDD00 Failed to dump to# %s#FFDD00 !#\\nError: %d\", dump_filenames, error);\n\telse\n\t{\n\t\tchar *sn = emmcsn_path_impl(NULL, NULL, NULL, NULL);\n\t\ts_printf(txt_buf, \"Dumping to SD card finished!\\nFiles: #C7EA46 backup/%s/dumps/#\\n%s\", sn, dump_filenames);\n\t}\n\tlv_mbox_set_text(mbox, txt_buf);\n\tfree(txt_buf);\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action); // Important. After set_text.\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _cal0_dump_window_action(lv_obj_t *btns, const char * txt)\n{\n\tint btn_idx = lv_btnm_get_pressed(btns);\n\n\tnyx_mbox_action(btns, txt);\n\n\tif (btn_idx == 1)\n\t{\n\t\tint error = sd_mount();\n\n\t\tif (!error)\n\t\t{\n\t\t\tchar path[64];\n\t\t\temmcsn_path_impl(path, \"/dumps\", \"cal0.bin\", NULL);\n\t\t\terror = sd_save_to_file((u8 *)cal0_buf, SZ_32K, path);\n\n\t\t\tsd_unmount();\n\t\t}\n\n\t\t_create_window_dump_done(error, \"cal0.bin\");\n\t}\n\n\treturn LV_RES_INV;\n}\n\n\nstatic lv_res_t _battery_dump_window_action(lv_obj_t * btn)\n{\n\tint error = sd_mount();\n\n\tif (!error)\n\t{\n\t\tchar path[64];\n\t\tvoid *buf = malloc(0x100 * 2);\n\n\t\tmax17050_dump_regs(buf);\n\n\t\temmcsn_path_impl(path, \"/dumps\", \"fuel_gauge.bin\", NULL);\n\t\terror = sd_save_to_file((u8 *)buf, 0x200, path);\n\n\t\tsd_unmount();\n\t}\n\n\t_create_window_dump_done(error, \"fuel_gauge.bin\");\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _bootrom_dump_window_action(lv_obj_t * btn)\n{\n\tstatic const u32 BOOTROM_SIZE = 0x18000;\n\n\tint error = sd_mount();\n\tif (!error)\n\t{\n\t\tchar path[64];\n\t\tu32 iram_evp_thunks[0x200];\n\t\tu32 iram_evp_thunks_len = sizeof(iram_evp_thunks);\n\t\terror = fuse_read_evp_thunk(iram_evp_thunks, &iram_evp_thunks_len);\n\t\tif (!error)\n\t\t{\n\t\t\temmcsn_path_impl(path, \"/dumps\", \"evp_thunks.bin\", NULL);\n\t\t\terror = sd_save_to_file((u8 *)iram_evp_thunks, iram_evp_thunks_len, path);\n\t\t}\n\t\telse\n\t\t\terror = 255;\n\n\t\temmcsn_path_impl(path, \"/dumps\", \"bootrom_patched.bin\", NULL);\n\t\tint res = sd_save_to_file((u8 *)IROM_BASE, BOOTROM_SIZE, path);\n\t\tif (!error)\n\t\t\terror = res;\n\n\t\tu32 ipatch_cam[IPATCH_CAM_ENTRIES + 1];\n\t\tmemcpy(ipatch_cam, (void *)IPATCH_BASE, sizeof(ipatch_cam));\n\t\tmemset((void*)IPATCH_BASE, 0, sizeof(ipatch_cam)); // Zeroing valid entries is enough but zero everything.\n\n\t\temmcsn_path_impl(path, \"/dumps\", \"bootrom_unpatched.bin\", NULL);\n\t\tres = sd_save_to_file((u8 *)IROM_BASE, BOOTROM_SIZE, path);\n\t\tif (!error)\n\t\t\terror = res;\n\n\t\tmemcpy((void*)IPATCH_BASE, ipatch_cam, sizeof(ipatch_cam));\n\n\t\tsd_unmount();\n\t}\n\t_create_window_dump_done(error, \"evp_thunks.bin, bootrom_patched.bin, bootrom_unpatched.bin\");\n\n\treturn LV_RES_OK;\n}\n\nstatic u8 _ccplex_set_fuse_rd_tz[] = {\n\t0xC1, 0x00, 0x00, 0x18, // 0x00: LDR  W1, =APB_MISC_PP_FUSE_READ_TZ\n\t0xE0, 0x03, 0x80, 0xD2, // 0x04: MOV  X0, #0x1F\n\t0x20, 0x00, 0x00, 0xB9, // 0x08: STR  W0, [X1]\n\t0x1F, 0x71, 0x08, 0xD5, // 0x0C: IC   IALLUIS\n\t0x9F, 0x3B, 0x03, 0xD5, // 0x10: DSB  ISH\n\t0xFE, 0xFF, 0xFF, 0x17, // 0x14: B    loop\n\t0xA4, 0x00, 0x00, 0x70, // 0x18: APB_MISC_PP_FUSE_READ_TZ/////////////////////check default value for sure\n};\n\nstatic void _unlock_reserved_odm_fuses(bool lock)\n{\n\t_ccplex_set_fuse_rd_tz[4] = lock ? 0xE0 : 0x00;\n\t_ccplex_set_fuse_rd_tz[5] = lock ? 0x03 : 0x00;\n\n\t// Launch payload on CCPLEX EL3 in order to unlock reserved ODM8-29 fuses.\n\tccplex_boot_cpu0((u32)_ccplex_set_fuse_rd_tz, false);\n\tmsleep(100);\n\tccplex_powergate_cpu0();\n}\n\nstatic lv_res_t _fuse_dump_window_action(lv_obj_t * btn)\n{\n\tint error = sd_mount();\n\tif (!error)\n\t{\n\t\tchar path[128];\n\t\tif (!h_cfg.t210b01)\n\t\t{\n\t\t\temmcsn_path_impl(path, \"/dumps\", \"fuse_cached_t210.bin\", NULL);\n\t\t\terror = sd_save_to_file((u8 *)0x7000F900, 0x300, path);\n\t\t\temmcsn_path_impl(path, \"/dumps\", \"fuse_array_raw_t210.bin\", NULL);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Unlock all reserved ODM fuses.\n\t\t\t_unlock_reserved_odm_fuses(false);\n\n\t\t\temmcsn_path_impl(path, \"/dumps\", \"fuse_cached_t210b01_x898.bin\", NULL);\n\t\t\terror = sd_save_to_file((u8 *)0x7000F898, 0x68, path);\n\t\t\temmcsn_path_impl(path, \"/dumps\", \"fuse_cached_t210b01_x900.bin\", NULL);\n\t\t\tif (!error)\n\t\t\t\terror = sd_save_to_file((u8 *)0x7000F900, 0x300, path);\n\t\t\temmcsn_path_impl(path, \"/dumps\", \"fuse_array_raw_t210b01.bin\", NULL);\n\t\t}\n\n\t\tif (!error)\n\t\t{\n\t\t\tu32 words[FUSE_ARRAY_WORDS_NUM_B01];\n\t\t\tu32 array_size = fuse_read_array(words);\n\t\t\terror = sd_save_to_file((u8 *)words, array_size * sizeof(u32), path);\n\t\t}\n\n\t\t// Relock.\n\t\tif (h_cfg.t210b01)\n\t\t\t_unlock_reserved_odm_fuses(true);\n\n\t\tsd_unmount();\n\t}\n\n\tif (!h_cfg.t210b01)\n\t\t_create_window_dump_done(error, \"fuse_cached_t210.bin, fuse_array_raw_t210.bin\");\n\telse\n\t\t_create_window_dump_done(error, \"fuse_cached_t210b01_x*.bin, fuse_array_raw_t210b01.bin\");\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _kfuse_dump_window_action(lv_obj_t * btn)\n{\n\tu32 buf[KFUSE_NUM_WORDS];\n\tint error = kfuse_read(buf);\n\n\tif (!error)\n\t\terror = sd_mount();\n\n\tif (!error)\n\t{\n\t\tchar path[64];\n\t\temmcsn_path_impl(path, \"/dumps\", \"kfuses.bin\", NULL);\n\t\terror = sd_save_to_file((u8 *)buf, KFUSE_NUM_WORDS * 4, path);\n\n\t\tsd_unmount();\n\t}\n\n\t_create_window_dump_done(error, \"kfuses.bin\");\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _create_mbox_cal0(lv_obj_t *btn)\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char * mbox_btn_map[] = { \"\\251\", \"\\222Dump\", \"\\222Close\", \"\\251\", \"\" };\n\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);\n\n\tlv_mbox_set_text(mbox, \"#C7EA46 CAL0 Info#\");\n\n\tchar *txt_buf = (char *)malloc(SZ_16K);\n\ttxt_buf[0] = 0;\n\n\tlv_obj_t * lb_desc = lv_label_create(mbox, NULL);\n\tlv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);\n\tlv_label_set_recolor(lb_desc, true);\n\tlv_label_set_style(lb_desc, &monospace_text);\n\tlv_obj_set_width(lb_desc, LV_HOR_RES / 9 * 4);\n\n\tsd_mount();\n\n\t// Dump CAL0.\n\tint cal0_res = hos_dump_cal0();\n\n\t// Check result. Don't error if hash doesn't match.\n\tif (cal0_res == 1)\n\t{\n\t\tlv_label_set_text(lb_desc, \"#FFDD00 Failed to init eMMC!#\");\n\n\t\tgoto out;\n\t}\n\telse if (cal0_res == 2)\n\t{\n\t\tlv_label_set_text(lb_desc, \"#FFDD00 CAL0 is corrupt or wrong keys!#\\n\");\n\t\tgoto out;\n\t}\n\n\tnx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)cal0_buf;\n\n\tu32 hash[8];\n\tse_sha_hash_256_oneshot(hash, (u8 *)&cal0->cfg_id1, cal0->body_size);\n\n\ts_printf(txt_buf,\n\t\t\"#FF8000 CAL0 Version:#      %d\\n\"\n\t\t\"#FF8000 Update Count:#      %d\\n\"\n\t\t\"#FF8000 Serial Number:#     %s\\n\"\n\t\t\"#FF8000 WLAN MAC:#          %02X:%02X:%02X:%02X:%02X:%02X\\n\"\n\t\t\"#FF8000 Bluetooth MAC:#     %02X:%02X:%02X:%02X:%02X:%02X\\n\"\n\t\t\"#FF8000 Battery LOT:#       %s (%d)\\n\"\n\t\t\"#FF8000 LCD Vendor:#        \",\n\t\tcal0->version, cal0->update_cnt, cal0->serial_number,\n\t\tcal0->wlan_mac[0], cal0->wlan_mac[1], cal0->wlan_mac[2], cal0->wlan_mac[3], cal0->wlan_mac[4], cal0->wlan_mac[5],\n\t\tcal0->bd_mac[0], cal0->bd_mac[1], cal0->bd_mac[2], cal0->bd_mac[3], cal0->bd_mac[4], cal0->bd_mac[5],\n\t\tcal0->battery_lot, cal0->battery_ver);\n\n\t// Prepare display info.\n\tu32 display_id = (cal0->lcd_vendor & 0xFF) << 8 | (cal0->lcd_vendor & 0xFF0000) >> 16;\n\tswitch (display_id)\n\t{\n\tcase PANEL_JDI_LAM062M109A:\n\t\tstrcat(txt_buf, \"JDI LAM062M109A\");\n\t\tbreak;\n\tcase PANEL_JDI_LPM062M326A:\n\t\tstrcat(txt_buf, \"JDI LPM062M326A\");\n\t\tbreak;\n\tcase PANEL_INL_P062CCA_AZ1:\n\t\tstrcat(txt_buf, \"InnoLux P062CCA-AZX\");\n\t\tbreak;\n\tcase PANEL_AUO_A062TAN01:\n\t\tstrcat(txt_buf, \"AUO A062TAN0X\");\n\t\tbreak;\n\tcase PANEL_INL_2J055IA_27A:\n\t\tstrcat(txt_buf, \"InnoLux 2J055IA-27A\");\n\t\tbreak;\n\tcase PANEL_AUO_A055TAN01:\n\t\tstrcat(txt_buf, \"AUO A055TAN0X\");\n\t\tbreak;\n\tcase PANEL_SHP_LQ055T1SW10:\n\t\tstrcat(txt_buf, \"Sharp LQ055T1SW10\");\n\t\tbreak;\n\tcase PANEL_SAM_AMS699VC01:\n\t\tstrcat(txt_buf, \"Samsung AMS699VC01\");\n\t\tbreak;\n\tdefault:\n\t\tswitch (cal0->lcd_vendor & 0xFF)\n\t\t{\n\t\tcase 0:\n\t\tcase PANEL_JDI_XXX062M:\n\t\t\tstrcat(txt_buf, \"JDI \");\n\t\t\tbreak;\n\t\tcase (PANEL_INL_P062CCA_AZ1 & 0xFF):\n\t\t\tstrcat(txt_buf, \"InnoLux \");\n\t\t\tbreak;\n\t\tcase (PANEL_AUO_A062TAN01 & 0xFF):\n\t\t\tstrcat(txt_buf, \"AUO \");\n\t\t\tbreak;\n\t\tcase (PANEL_SAM_AMS699VC01 & 0xFF):\n\t\t\tstrcat(txt_buf, \"Samsung \");\n\t\t\tbreak;\n\t\t}\n\t\tstrcat(txt_buf, \"Unknown\");\n\t\tbreak;\n\t}\n\n\ts_printf(txt_buf + strlen(txt_buf),\n\t\t\" (%06X)\\n#FF8000 Touch Vendor:#      %d\\n\"\n\t\t\"#FF8000 IMU Type/Mount:#    %d / %d\\n\"\n\t\t\"#FF8000 Stick L/R Type:#    %02X / %02X\\n\",\n\t\tcal0->lcd_vendor, cal0->touch_ic_vendor_id,\n\t\tcal0->console_6axis_sensor_type, cal0->console_6axis_sensor_mount_type,\n\t\tcal0->analog_stick_type_l, cal0->analog_stick_type_r);\n\n\tbool valid_cal0 = !memcmp(hash, cal0->body_sha256, 0x20);\n\ts_printf(txt_buf + strlen(txt_buf), \"#FF8000 SHA256 Hash Match:# %s\", valid_cal0 ? \"Pass\" : \"Failed\");\n\n\tlv_label_set_text(lb_desc, txt_buf);\n\nout:\n\tfree(txt_buf);\n\tsd_unmount();\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map, _cal0_dump_window_action);\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\treturn LV_RES_OK;\n}\n\nu32 wafer16nm[] =\n{\n\t0x0003F800, 0x001FFF00, 0x007FFFC0, 0x00FFFFE0,\n\t0x01FFFFF0, 0x03FFFFF8, 0x07FFFFFC, 0x07FFFFFC,\n\t0x0FFFFFFE, 0x0FFFFFFE, 0x0FFFFFFE, 0x1FFFFFFF,\n\t0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF, 0x1FFFFFFF,\n\t0x1FFFFFFF, 0x1FFFFFFF, 0x0FFFFFFE, 0x0FFFFFFE,\n\t0x0FFFFFFE, 0x07FFFFFC, 0x07FFFFFC, 0x03FFFFF8,\n\t0x01FFFFF0, 0x00FFFFE0, 0x007FFFC0, 0x001FFF00,\n\t0x0000E000\n};\n\nu32 wafer20nm[] =\n{\n\t0x0001FE00, 0x0007FF80, 0x001FFFE0, 0x003FFFF0,\n\t0x007FFFF8, 0x00FFFFFC, 0x00FFFFFC, 0x01FFFFFE,\n\t0x01FFFFFE, 0x03FFFFFF, 0x03FFFFFF, 0x03FFFFFF,\n\t0x03FFFFFF, 0x03FFFFFF, 0x03FFFFFF, 0x03FFFFFF,\n\t0x03FFFFFF, 0x01FFFFFE, 0x01FFFFFE, 0x00FFFFFC,\n\t0x00FFFFFC, 0x007FFFF8, 0x003FFFF0, 0x001FFFE0,\n\t0x0007FF80,\n\t0x00000000,\n};\n\ntypedef struct _hw_info_t\n{\n\tlv_obj_t *ver;\n\tlv_obj_t *wafer_img;\n\tlv_obj_t *wafer_txt;\n} hw_info_t;\n\nhw_info_t *hw_info = NULL;\n\n//! TODO: Limits assumed based on known samples.\n#define WAFER_20NM_X_MIN  -9\n#define WAFER_20NM_X_MAX  15\n#define WAFER_20NM_Y_MIN   1\n#define WAFER_20NM_Y_MAX  24\n\n// Limits validated based on known samples.\n#define WAFER_16NM_X_MIN -11\n#define WAFER_16NM_X_MAX  17\n#define WAFER_16NM_Y_MIN   0\n#define WAFER_16NM_Y_MAX  28\n\nvoid _hw_info_wafer(int die_x, int die_y)\n{\n\tstatic lv_img_dsc_t wafer_desc = { 0 };\n\tint diameter;\n\n\tif (h_cfg.t210b01)\n\t{\n\t\tif (die_x < WAFER_16NM_X_MIN || die_x > WAFER_16NM_X_MAX ||\n\t\t\tdie_y < WAFER_16NM_Y_MIN || die_y > WAFER_16NM_Y_MAX)\n\t\t\tdie_x = WAFER_16NM_X_MIN - 1;\n\n\t\tdie_x   += -WAFER_16NM_X_MIN;\n\t\tdiameter = 29;\n\t}\n\telse\n\t{\n\t\tif (die_x < WAFER_20NM_X_MIN || die_x > WAFER_20NM_X_MAX ||\n\t\t\tdie_y < 0                || die_y > WAFER_20NM_Y_MAX)\n\t\t\tdie_x = WAFER_20NM_X_MIN - 1;\n\n\t\tdie_x   += -WAFER_20NM_X_MIN;\n\t\tdiameter = 26;\n\t}\n\n\tconst u32 die_size = 2;\n\tconst u32 die_side = die_size + 1;\n\tconst u32 die_line = die_side * diameter + 1;\n\tconst int align_off = (die_size - 2) * diameter;\n\tconst u32 die_color = (die_x == -1) ? 0xFFFF0000 : 0x30FFFFFF; // Red for OOB.\n\tconst u32 str_color = 0x10FFFFFF;\n\tconst u32 hit_color = 0xFFFF8000;\n\n\tu32 *wafer_map = zalloc(die_line * die_line * sizeof(u32));\n\n\tfor (int y = 0; y < diameter; y++)\n\t{\n\t\tu32 wafer_row_next = -1;\n\t\tu32 wafer_row      = h_cfg.t210b01 ? wafer16nm[y] : wafer20nm[y];\n\n\t\tif ((y + 1) < diameter)\n\t\t\twafer_row_next = h_cfg.t210b01 ? wafer16nm[y + 1] : wafer20nm[y + 1];\n\n\t\t// Paint the first row of dies.\n\t\tint pos_y = y * die_line * die_side + die_line;\n\t\tfor (int x = 0; x < diameter; x++)\n\t\t{\n\t\t\tbool in_wafer   = wafer_row & (1u << x);\n\t\t\tbool die_found  = x == die_x && die_y == y;\n\t\t\tu32  die_column = x * die_side;\n\n\t\t\t// Paint street rows;\n\t\t\tif (in_wafer)\n\t\t\t\tfor (u32 i = 0; i < die_size + 2; i++)\n\t\t\t\t{\n\t\t\t\t\twafer_map[pos_y - die_line + die_column + i] = str_color;\n\t\t\t\t\tif (wafer_row > wafer_row_next)\n\t\t\t\t\t\twafer_map[pos_y - die_line + die_column + i + die_line * die_side] = str_color;\n\t\t\t\t}\n\n\t\t\t// Paint street column;\n\t\t\tif (in_wafer)\n\t\t\t\twafer_map[pos_y + die_column] = str_color;\n\n\t\t\tu32 color;\n\t\t\tif (in_wafer && !die_found)\n\t\t\t\tcolor = die_color;\n\t\t\telse\n\t\t\t\tcolor = !die_found ? 0 : hit_color;\n\n\t\t\t// Paint die row0;\n\t\t\tfor (u32 i = 0; i < die_size; i++)\n\t\t\t\twafer_map[pos_y + die_column + 1 + i] = color;\n\n\t\t\t// Paint street column;\n\t\t\tif (in_wafer)\n\t\t\t\twafer_map[pos_y + die_column + 1 + die_size] = str_color;\n\t\t}\n\n\t\t// Paint the rest of die rows.\n\t\tfor (u32 i = 1; i < die_size; i++)\n\t\t\tmemcpy(&wafer_map[pos_y + die_line * i], &wafer_map[pos_y], die_line * sizeof(u32));\n\t}\n\n\twafer_desc.header.always_zero = 0;\n\twafer_desc.header.w = die_line;\n\twafer_desc.header.h = die_line;\n\twafer_desc.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA;\n\twafer_desc.data_size = die_line * die_line * sizeof(u32);\n\twafer_desc.data = (u8 *)wafer_map;\n\n\tlv_obj_t *wafer_img = lv_img_create(lv_scr_act(), NULL);\n\tlv_img_set_src(wafer_img, &wafer_desc);\n\tif (h_cfg.t210b01)\n\t\tlv_obj_align(wafer_img, NULL, LV_ALIGN_IN_TOP_LEFT, LV_DPI * 58 / 11 - align_off, LV_DPI * 44 / 9 - align_off / 2);\n\telse\n\t\tlv_obj_align(wafer_img, NULL, LV_ALIGN_IN_TOP_LEFT, LV_DPI * 59 / 11 - align_off, LV_DPI * 74 / 15 - align_off / 2);\n\thw_info->wafer_img = wafer_img;\n\n\tlv_obj_t *wafer_txt = lv_label_create(lv_scr_act(), NULL);\n\tlv_label_set_style(wafer_txt, &monospace_text);\n\tlv_label_set_static_text(wafer_txt, (die_x == -1) ? \"Error\" : \"Wafer\");\n\tlv_obj_align(wafer_txt, wafer_img, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);\n\thw_info->wafer_txt = wafer_txt;\n}\n\nstatic lv_res_t _action_win_hw_info_status_close(lv_obj_t *btn)\n{\n\tif (hw_info)\n\t{\n\t\tlv_img_dsc_t *wafer_dsc = (lv_img_dsc_t *)lv_img_get_src(hw_info->wafer_img);\n\t\tlv_obj_del(hw_info->ver);\n\t\tlv_obj_del(hw_info->wafer_img);\n\t\tlv_obj_del(hw_info->wafer_txt);\n\t\tfree((u32 *)wafer_dsc->data);\n\t\tfree(hw_info);\n\t\thw_info = NULL;\n\t}\n\n\treturn nyx_win_close_action(btn);\n}\n\nstatic lv_res_t _create_window_hw_info_status(lv_obj_t *btn)\n{\n\tu32 uptime_s = get_tmr_s();\n\n\tlv_obj_t *win = nyx_create_standard_window(SYMBOL_CHIP\" HW & Fuses Info\", _action_win_hw_info_status_close);\n\tlv_win_add_btn(win, NULL, SYMBOL_DOWNLOAD\" Dump fuses\", _fuse_dump_window_action);\n\tlv_win_add_btn(win, NULL, SYMBOL_INFO\" CAL0 Info\", _create_mbox_cal0);\n\n\tlv_obj_t *desc = lv_cont_create(win, NULL);\n\tlv_obj_set_size(desc, LV_HOR_RES / 2 / 5 * 2, LV_VER_RES - (LV_DPI * 11 / 7) - 5);\n\n\tlv_obj_t * lb_desc = lv_label_create(desc, NULL);\n\tlv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);\n\tlv_label_set_recolor(lb_desc, true);\n\tlv_label_set_style(lb_desc, &monospace_text);\n\n\tchar version[32];\n\ts_printf(version, \"%s%d.%d.%d%c\", NYX_VER_RL ? \"v\" : \"\", NYX_VER_MJ, NYX_VER_MN, NYX_VER_HF, NYX_VER_RL > 'a' ? NYX_VER_RL : 0);\n\tlv_obj_t * lbl_ver = lv_label_create(lv_scr_act(), NULL);\n\tlv_label_set_style(lbl_ver, &hint_small_style_white);\n\tlv_label_set_text(lbl_ver, version);\n\tlv_obj_align(lbl_ver, status_bar.bar_bg, LV_ALIGN_OUT_TOP_RIGHT, -LV_DPI * 9 / 23, -LV_DPI * 2 / 13);\n\n\thw_info = zalloc(sizeof(hw_info_t));\n\thw_info->ver = lbl_ver;\n\n\tlv_label_set_static_text(lb_desc,\n\t\t\"#FF8000 SoC:#\\n\"\n\t\t\"#FF8000 SKU:#\\n\"\n\t\t\"#FF8000 DRAM ID:#\\n\"\n\t\t\"#FF8000 Burnt Fuses (ODM 7/6):#\\n\"\n\t\t\"ODM Fields (4/6/7):\\n\"\n\t\t\"Secure Boot Key (SBK):\\n\"\n\t\t\"Device Key (DK):\\n\"\n\t\t\"Public Key (PK SHA256):\\n\\n\"\n\t\t\"HOS Keygen Revision:\\n\"\n\t\t\"USB Controller (BROM):\\n\"\n\t\t\"Final Test Revision:\\n\"\n\t\t\"Chip Probing Revision:\\n\"\n\t\t\"BootROM Revision:\\n\\n\"\n\t\t\"#FF8000 CPU/GPU/SoC Speedo:#\\n\"\n\t\t\"CPU/GPU/SoC IDDQ:\\n\"\n\t\t\"CPU Speedo 1:\\n\"\n\t\t\"SoC Speedo 2:\\n\\n\"\n\t\t\"Product Code:\\n\"\n\t\t\"Vendor Code:\\n\"\n\t\t\"FAB/LOT Code:\\n\"\n\t\t\"Wafer ID:\\n\"\n\t\t\"X Coordinate:\\n\"\n\t\t\"Y Coordinate:\\n\\n\"\n\t\t\"Uptime:\"\n\t);\n\n\tlv_obj_set_width(lb_desc, lv_obj_get_width(desc));\n\n\tlv_obj_t *val = lv_cont_create(win, NULL);\n\tlv_obj_set_size(val, LV_HOR_RES / 7 * 2 + LV_DPI / 11, LV_VER_RES - (LV_DPI * 11 / 7) - 5);\n\n\tlv_obj_t * lb_val = lv_label_create(val, lb_desc);\n\n\tchar *txt_buf = (char *)malloc(SZ_16K);\n\n\t// Decode fuses.\n\tchar *sku;\n\tchar dram_model[64];\n\tchar fuses_hos_version[64];\n\tu8 dram_id     = fuse_read_dramid(true);\n\tu8 dram_id_adj = fuse_read_dramid(false);\n\n\tswitch (fuse_read_hw_type())\n\t{\n\tcase FUSE_NX_HW_TYPE_ICOSA:\n\t\tsku = \"Icosa - Odin\";\n\t\tbreak;\n\tcase FUSE_NX_HW_TYPE_IOWA:\n\t\tsku = \"Iowa - Modin\";\n\t\tbreak;\n\tcase FUSE_NX_HW_TYPE_HOAG:\n\t\tsku = \"Hoag - Vali\";\n\t\tbreak;\n\tcase FUSE_NX_HW_TYPE_AULA:\n\t\tsku = \"Aula - Fric\";\n\t\tbreak;\n\tdefault:\n\t\tsku = \"#FF8000 Unknown#\";\n\t\tbreak;\n\t}\n\n\t// Prepare dram id info.\n\tif (!h_cfg.t210b01)\n\t{\n\t\tswitch (dram_id)\n\t\t{\n\t\t// LPDDR4 3200Mbps.\n\t\tcase LPDDR4_ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH:\n\t\t\tstrcpy(dram_model, \"Samsung K4F6E304HB-MGCH 4GB\");\n\t\t\tbreak;\n\t\tcase LPDDR4_ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE:\n\t\t\tstrcpy(dram_model, \"Hynix H9HCNNNBPUMLHR-NLE 4GB\");\n\t\t\tbreak;\n\t\tcase LPDDR4_ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WTC:\n\t\t\tstrcpy(dram_model, \"Micron MT53B512M32D2NP-062 WT:C\");\n\t\t\tbreak;\n\t\tcase LPDDR4_ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH:\n\t\t\tstrcpy(dram_model, \"Samsung K4FHE3D4HM-MGCH 6GB\");\n\t\t\tbreak;\n\t\tcase LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX:\n\t\t\tstrcpy(dram_model, \"Samsung K4FBE3D4HM-MGXX 8GB\");\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tstrcpy(dram_model, \"#FF8000 Unknown#\");\n\t\t\tbreak;\n\t\t}\n\t}\n\telse\n\t{\n\t\tswitch (dram_id)\n\t\t{\n\t\t// LPDDR4X 3733Mbps.\n\t\tcase LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AM_MGCJ:\n\t\tcase LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AM_MGCJ:\n\t\t\tstrcpy(dram_model, \"Samsung K4U6E3S4AM-MGCJ 4GB\");\n\t\t\tbreak;\n\t\tcase LPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AM_MGCJ:\n\t\tcase LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AM_MGCJ:\n\t\t\tstrcpy(dram_model, \"Samsung K4UBE3D4AM-MGCJ 8GB\");\n\t\t\tbreak;\n\t\tcase LPDDR4X_IOWA_4GB_HYNIX_H9HCNNNBKMMLHR_NME:\n\t\tcase LPDDR4X_HOAG_4GB_HYNIX_H9HCNNNBKMMLHR_NME:\n\t\t\tstrcpy(dram_model, \"Hynix H9HCNNNBKMMLHR-NME 4GB\");\n\t\t\tbreak;\n\t\tcase LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTE: // 4266Mbps.\n\t\tcase LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTE: // 4266Mbps.\n\t\t\tstrcpy(dram_model, \"Micron MT53E512M32D2NP-046 WT:E\");\n\t\t\tbreak;\n\n\t\t// LPDDR4X 4266Mbps\n\t\tcase LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AA_MGCL:\n\t\tcase LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AA_MGCL:\n\t\tcase LPDDR4X_AULA_4GB_SAMSUNG_K4U6E3S4AA_MGCL:\n\t\t\tstrcpy(dram_model, \"Samsung K4U6E3S4AA-MGCL 4GB\");\n\t\t\tbreak;\n\t\tcase LPDDR4X_IOWA_8GB_SAMSUNG_K4UBE3D4AA_MGCL:\n\t\tcase LPDDR4X_HOAG_8GB_SAMSUNG_K4UBE3D4AA_MGCL:\n\t\tcase LPDDR4X_AULA_8GB_SAMSUNG_K4UBE3D4AA_MGCL:\n\t\t\tstrcpy(dram_model, \"Samsung K4UBE3D4AA-MGCL 8GB\");\n\t\t\tbreak;\n\t\tcase LPDDR4X_IOWA_4GB_SAMSUNG_K4U6E3S4AB_MGCL:\n\t\tcase LPDDR4X_HOAG_4GB_SAMSUNG_K4U6E3S4AB_MGCL:\n\t\tcase LPDDR4X_AULA_4GB_SAMSUNG_K4U6E3S4AB_MGCL:\n\t\t\tstrcpy(dram_model, \"Samsung K4U6E3S4AB-MGCL 4GB\");\n\t\t\tbreak;\n\t\tcase LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D2NP_046_WTF:\n\t\tcase LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D2NP_046_WTF:\n\t\tcase LPDDR4X_AULA_4GB_MICRON_MT53E512M32D2NP_046_WTF:\n\t\t\tstrcpy(dram_model, \"Micron MT53E512M32D2NP-046 WT:F\");\n\t\t\tbreak;\n\t\tcase LPDDR4X_HOAG_4GB_HYNIX_H9HCNNNBKMMLXR_NEE: // Replaced from Copper.\n\t\tcase LPDDR4X_AULA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE: // Replaced from Copper.\n\t\tcase LPDDR4X_IOWA_4GB_HYNIX_H9HCNNNBKMMLXR_NEE: // Replaced from Copper.\n\t\t\tstrcpy(dram_model, \"Hynix H9HCNNNBKMMLXR-NEE 4GB\");\n\t\t\tbreak;\n\t\tcase LPDDR4X_IOWA_4GB_HYNIX_H54G46CYRBX267:\n\t\tcase LPDDR4X_HOAG_4GB_HYNIX_H54G46CYRBX267:\n\t\tcase LPDDR4X_AULA_4GB_HYNIX_H54G46CYRBX267:\n\t\t\tstrcpy(dram_model, \"Hynix H54G46CYRBX267 4GB\");\n\t\t\tbreak;\n\t\tcase LPDDR4X_IOWA_4GB_MICRON_MT53E512M32D1NP_046_WTB:\n\t\tcase LPDDR4X_HOAG_4GB_MICRON_MT53E512M32D1NP_046_WTB:\n\t\tcase LPDDR4X_AULA_4GB_MICRON_MT53E512M32D1NP_046_WTB:\n\t\t\tstrcpy(dram_model, \"Micron MT53E512M32D1NP-046 WT:B\");\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tstrcpy(dram_model, \"#FF8000 Contact me!#\");\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Check if DRAM config is forced to 8GB.\n\tif (dram_id != dram_id_adj &&\n\t\t((!h_cfg.t210b01 && dram_id_adj == LPDDR4_ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX) ||\n\t\t ( h_cfg.t210b01 && dram_id_adj == LPDDR4X_AULA_8GB_SAMSUNG_K4UBE3D4AA_MGCL))\n\t   )\n\t\tstrcpy(dram_model, \"#FF8000 Forced DRAM Config 8GB#\");\n\n\t// Count burnt fuses.\n\tu8 burnt_fuses_7 = bit_count(fuse_read_odm(7));\n\tu8 burnt_fuses_6 = bit_count(fuse_read_odm(6));\n\n\t// Check if overburnt.\n\tu8 burnt_fuses_hos = (fuse_read_odm(7) & ~bit_count_mask(burnt_fuses_7)) ? 255 : burnt_fuses_7;\n\n\t//! TODO: Update on anti-downgrade fuses change.\n\tswitch (burnt_fuses_hos)\n\t{\n\tcase 0:\n\t\tstrcpy(fuses_hos_version, \"#96FF00 Golden sample#\");\n\t\tbreak;\n\tcase 1:\n\t\tstrcpy(fuses_hos_version, \"1.0.0\");\n\t\tbreak;\n\tcase 2:\n\t\tstrcpy(fuses_hos_version, \"2.0.0 - 2.3.0\");\n\t\tbreak;\n\tcase 3:\n\t\tstrcpy(fuses_hos_version, \"3.0.0\");\n\t\tbreak;\n\tcase 4:\n\t\tstrcpy(fuses_hos_version, \"3.0.1 - 3.0.2\");\n\t\tbreak;\n\tcase 5:\n\t\tstrcpy(fuses_hos_version, \"4.0.0 - 4.1.0\");\n\t\tbreak;\n\tcase 6:\n\t\tstrcpy(fuses_hos_version, \"5.0.0 - 5.1.0\");\n\t\tbreak;\n\tcase 7:\n\t\tstrcpy(fuses_hos_version, \"6.0.0 - 6.1.0\");\n\t\tbreak;\n\tcase 8:\n\t\tstrcpy(fuses_hos_version, \"6.2.0\");\n\t\tbreak;\n\tcase 9:\n\t\tstrcpy(fuses_hos_version, \"7.0.0 - 8.0.1\");\n\t\tbreak;\n\tcase 10:\n\t\tstrcpy(fuses_hos_version, \"8.1.0 - 8.1.1\");\n\t\tbreak;\n\tcase 11:\n\t\tstrcpy(fuses_hos_version, \"9.0.0 - 9.0.1\");\n\t\tbreak;\n\tcase 12:\n\t\tstrcpy(fuses_hos_version, \"9.1.0 - 9.2.0\");\n\t\tbreak;\n\tcase 13:\n\t\tstrcpy(fuses_hos_version, \"10.0.0 - 10.2.0\");\n\t\tbreak;\n\tcase 14:\n\t\tstrcpy(fuses_hos_version, \"11.0.0 - 12.0.1\");\n\t\tbreak;\n\tcase 15:\n\t\tstrcpy(fuses_hos_version, \"12.0.2 - 13.2.0\");\n\t\tbreak;\n\tcase 16:\n\t\tstrcpy(fuses_hos_version, \"13.2.1 - 14.1.2\");\n\t\tbreak;\n\tcase 17:\n\t\tstrcpy(fuses_hos_version, \"15.0.0 - 15.0.1\");\n\t\tbreak;\n\tcase 18:\n\t\tstrcpy(fuses_hos_version, \"16.0.0 - 16.1.0\");\n\t\tbreak;\n\tcase 19:\n\t\tstrcpy(fuses_hos_version, \"17.0.0 - 18.1.0\");\n\t\tbreak;\n\tcase 20:\n\t\tstrcpy(fuses_hos_version, \"19.0.0 - 19.0.1\");\n\t\tbreak;\n\tcase 21:\n\t\tstrcpy(fuses_hos_version, \"20.0.0 - 20.5.0\");\n\t\tbreak;\n\tcase 22:\n\t\tstrcpy(fuses_hos_version, \"21.0.0 - 21.2.0\");\n\t\tbreak;\n\tcase 23:\n\t\tstrcpy(fuses_hos_version, \"22.0.0+\");\n\t\tbreak;\n\tcase 255:\n\t\tstrcpy(fuses_hos_version, \"#FFD000 Overburnt#\");\n\t\tbreak;\n\tdefault:\n\t\tstrcpy(fuses_hos_version, \"#FF8000 Unknown#\");\n\t\tbreak;\n\t}\n\n\tu32 fab = FUSE(FUSE_OPT_FAB_CODE);\n\n\t// Convert LOT from base36 BCD to binary.\n\tu32 lot_enc = FUSE(FUSE_OPT_LOT_CODE_0);\n\tu32 lot_dec = 0;\n\tchar lot_bcd[6] = {0};\n\n\tfor (int i = 0; i < 5; ++i)\n\t{\n\t\tu32 digit  = (lot_enc & 0x3F000000) >> 24;\n\t\tlot_dec   *= 36;\n\t\tlot_dec   += digit;\n\t\tlot_enc  <<= 6;\n\t\tlot_bcd[i] = base36[digit];\n\t}\n\n\tchar sbk_key[64];\n\tchar dev_key[32];\n\tif (FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF &&\n\t\tFUSE(FUSE_PRIVATE_KEY1) == 0xFFFFFFFF &&\n\t\tFUSE(FUSE_PRIVATE_KEY2) == 0xFFFFFFFF &&\n\t\tFUSE(FUSE_PRIVATE_KEY3) == 0xFFFFFFFF &&\n\t\tFUSE(FUSE_PRIVATE_KEY4) == 0xFFFFFFFF)\n\t{\n\t\tstrcpy(sbk_key, \"Can't be read (locked out)\");\n\t\tstrcpy(dev_key, \"Can't be read (locked out)\");\n\t}\n\telse\n\t{\n\t\ts_printf(sbk_key, \"%08X%08X%08X%08X\",\n\t\t\tbyte_swap_32(FUSE(FUSE_PRIVATE_KEY0)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY1)),\n\t\t\tbyte_swap_32(FUSE(FUSE_PRIVATE_KEY2)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY3)));\n\t\ts_printf(dev_key, \"%08X\",  byte_swap_32(FUSE(FUSE_PRIVATE_KEY4)));\n\t}\n\n\tu32 chip_id = APB_MISC(APB_MISC_GP_HIDREV);\n\tu32 chip_major = (chip_id >>  4) & 0xF;\n\tu32 chip_minor = (chip_id >> 16) & 0xF;\n\tchar *chip_name = !h_cfg.t210b01 ? \"T210 (Erista)\" : \"T210B01 (Mariko)\";\n\n\tu32 brom_rev = FUSE(FUSE_SOC_SPEEDO_1_CALIB);\n\tu32 prod_rev = !h_cfg.t210b01 ? (brom_rev < 0x7F ? 1 : 2) : 10;\n\tchar product_part[16];\n\ts_printf(product_part, \"ODNX%02d-A%d\", prod_rev, chip_minor);\n\n\tchar iddq[3][8];\n\ts_printf(iddq[0], \"%d\", FUSE(FUSE_CPU_IDDQ_CALIB) * 4);\n\ts_printf(iddq[1], \"%d\", FUSE(FUSE_GPU_IDDQ_CALIB) * 5);\n\ts_printf(iddq[2], \"%d\", FUSE(FUSE_SOC_IDDQ_CALIB) * 4);\n\n\tint die_x = FUSE(FUSE_OPT_X_COORDINATE);\n\tint die_y = FUSE(FUSE_OPT_Y_COORDINATE);\n\n\t// X Coordinate is 9-bit 2s complement.\n\tdie_x = (die_x & BIT(8)) ? (die_x - 512) : die_x;\n\n\t// Render the wafer.\n\t_hw_info_wafer(die_x, die_y);\n\n\t// Parse fuses and display them.\n\ts_printf(txt_buf,\n\t\t\"%02X - %s - M%d A%02d\\n\"\n\t\t\"%X - %s - %s\\n\"\n\t\t\"%02d - %s\\n\"\n\t\t\"%d | %d - HOS: %s\\n\"\n\t\t\"%08X %08X %08X\\n\"\n\t\t\"%s\\n%s\\n\"\n\t\t\"%08X%08X%08X%08X\\n\"\n\t\t\"%08X%08X%08X%08X\\n\"\n\t\t\"%d\\n\"\n\t\t\"%s\\n\"\n\t\t\"%d.%02d (0x%X)\\n\"\n\t\t\"%d.%02d (0x%X)\\n\"\n\t\t\"0x%X\\n\\n\"\n\t\t\"%4d %4d %4d\\n\"\n\t\t\"%.4s %.4s %.4s\\n\"\n\t\t\"%d\\n%d\\n\\n\"\n\t\t\"%s\\n%d\\n%c%s (%d/%d)\\n\"\n\t\t\"%d\\n%d\\n%d\\n\\n\"\n\t\t\"%dh %02dm %02ds\",\n\t\t(chip_id >> 8) & 0xFF, chip_name, chip_major, chip_minor,\n\t\tFUSE(FUSE_SKU_INFO), sku, fuse_read_hw_state() ? \"Dev\" : \"Retail\",\n\t\tdram_id, dram_model,\n\t\tburnt_fuses_7, burnt_fuses_6, fuses_hos_version,\n\t\tfuse_read_odm(4), fuse_read_odm(6), fuse_read_odm(7),\n\t\tsbk_key, dev_key,\n\t\tbyte_swap_32(FUSE(FUSE_PUBLIC_KEY0)), byte_swap_32(FUSE(FUSE_PUBLIC_KEY1)),\n\t\tbyte_swap_32(FUSE(FUSE_PUBLIC_KEY2)), byte_swap_32(FUSE(FUSE_PUBLIC_KEY3)),\n\t\tbyte_swap_32(FUSE(FUSE_PUBLIC_KEY4)), byte_swap_32(FUSE(FUSE_PUBLIC_KEY5)),\n\t\tbyte_swap_32(FUSE(FUSE_PUBLIC_KEY6)), byte_swap_32(FUSE(FUSE_PUBLIC_KEY7)),\n\t\tfuse_read_odm_keygen_rev(),\n\t\t((FUSE(FUSE_RESERVED_SW) & 0x80) || h_cfg.t210b01) ? \"XUSB\" : \"USB2\",\n\t\t(FUSE(FUSE_OPT_FT_REV)  >> 5) & 0x3F, FUSE(FUSE_OPT_FT_REV) & 0x1F, FUSE(FUSE_OPT_FT_REV),\n\t\t(FUSE(FUSE_OPT_CP_REV)  >> 5) & 0x3F, FUSE(FUSE_OPT_CP_REV) & 0x1F, FUSE(FUSE_OPT_CP_REV),\n\t\tbrom_rev,\n\t\tFUSE(FUSE_CPU_SPEEDO_0_CALIB), FUSE(FUSE_CPU_SPEEDO_2_CALIB), FUSE(FUSE_SOC_SPEEDO_0_CALIB),\n\t\tiddq[0], iddq[1], iddq[2],\n\t\tFUSE(FUSE_CPU_SPEEDO_1_CALIB),  FUSE(FUSE_SOC_SPEEDO_2_CALIB),\n\t\tproduct_part, FUSE(FUSE_OPT_VENDOR_CODE), base36[fab], lot_bcd, fab, lot_dec,\n\t\tFUSE(FUSE_OPT_WAFER_ID), die_x, die_y,\n\t\tuptime_s / 3600, (uptime_s / 60) % 60, uptime_s % 60);\n\n\tlv_label_set_text(lb_val, txt_buf);\n\n\tlv_obj_set_width(lb_val, lv_obj_get_width(val));\n\tlv_obj_align(val, desc, LV_ALIGN_OUT_RIGHT_MID, 0, 0);\n\n\tlv_obj_t *desc2 = lv_cont_create(win, NULL);\n\tlv_obj_set_size(desc2, LV_HOR_RES / 2 / 5 * 4, LV_VER_RES - (LV_DPI * 11 / 7) - 5);\n\n\tlv_obj_t * lb_desc2 = lv_label_create(desc2, NULL);\n\tlv_label_set_long_mode(lb_desc2, LV_LABEL_LONG_BREAK);\n\tlv_label_set_recolor(lb_desc2, true);\n\n\t// Prepare DRAM info.\n\temc_mr_data_t ram_vendor  = sdram_read_mrx(MR5_MAN_ID);\n\temc_mr_data_t ram_rev0    = sdram_read_mrx(MR6_REV_ID1);\n\temc_mr_data_t ram_rev1    = sdram_read_mrx(MR7_REV_ID2);\n\temc_mr_data_t ram_density = sdram_read_mrx(MR8_DENSITY);\n\tu32 ranks    = EMC(EMC_ADR_CFG) + 1;\n\tu32 channels = (EMC(EMC_FBIO_CFG7) >> 1) & 3;\n\tchannels = (channels & 1) + ((channels & 2) >> 1);\n\ts_printf(txt_buf, \"#00DDFF %s SDRAM ##FF8000 (Module 0 | 1):#\\n#FF8000 Vendor:# \", h_cfg.t210b01 ? \"LPDDR4X\" : \"LPDDR4\");\n\tswitch (ram_vendor.chip0.rank0_ch0)\n\t{\n\tcase 1:\n\t\tstrcat(txt_buf, \"Samsung\");\n\t\tbreak;\n/*\n\tcase 5:\n\t\tstrcat(txt_buf, \"Nanya\");\n\t\tbreak;\n*/\n\tcase 6:\n\t\tstrcat(txt_buf, \"Hynix\");\n\t\tbreak;\n/*\n\tcase 8:\n\t\tstrcat(txt_buf, \"Winbond\");\n\t\tbreak;\n\tcase 9:\n\t\tstrcat(txt_buf, \"ESMT\");\n\t\tbreak;\n\tcase 19:\n\t\tstrcat(txt_buf, \"CXMT\");\n\t\tbreak;\n\tcase 26:\n\t\tstrcat(txt_buf, \"Xi'an UniIC\");\n\t\tbreak;\n\tcase 27:\n\t\tstrcat(txt_buf, \"ISSI\");\n\t\tbreak;\n\tcase 28:\n\t\tstrcat(txt_buf, \"JSC\");\n\t\tbreak;\n\tcase 197:\n\t\tstrcat(txt_buf, \"SINKER\");\n\t\tbreak;\n\tcase 229:\n\t\tstrcat(txt_buf, \"Dosilicon\");\n\t\tbreak;\n\tcase 248:\n\t\tstrcat(txt_buf, \"Fidelix\");\n\t\tbreak;\n\tcase 249:\n\t\tstrcat(txt_buf, \"Ultra Memory\");\n\t\tbreak;\n\tcase 253:\n\t\tstrcat(txt_buf, \"AP Memory\");\n\t\tbreak;\n */\n\tcase 255:\n\t\tstrcat(txt_buf, \"Micron\");\n\t\tbreak;\n\tdefault:\n\t\ts_printf(txt_buf + strlen(txt_buf), \"#FF8000 Unknown# (%d)\", ram_vendor.chip0.rank0_ch0);\n\t\tbreak;\n\t}\n\tstrcat(txt_buf, \" #FF8000 |# \");\n\tswitch (ram_vendor.chip1.rank0_ch0)\n\t{\n\tcase 1:\n\t\tstrcat(txt_buf, \"Samsung\");\n\t\tbreak;\n\tcase 6:\n\t\tstrcat(txt_buf, \"Hynix\");\n\t\tbreak;\n\tcase 255:\n\t\tstrcat(txt_buf, \"Micron\");\n\t\tbreak;\n\tdefault:\n\t\ts_printf(txt_buf + strlen(txt_buf), \"#FF8000 Unknown# (%d)\", ram_vendor.chip1.rank0_ch0);\n\t\tbreak;\n\t}\n\n\ts_printf(txt_buf + strlen(txt_buf), \"\\n#FF8000 Rev ID:#  %X.%02X #FF8000 |# %X.%02X\\n#FF8000 Density:# \",\n\t\tram_rev0.chip0.rank0_ch0, ram_rev1.chip0.rank0_ch0, ram_rev0.chip1.rank0_ch0, ram_rev1.chip1.rank0_ch0);\n\n\tu32 actual_ranks = (ram_vendor.chip0.rank0_ch0 == ram_vendor.chip0.rank1_ch0 &&\n\t\t\t\t\t\tram_vendor.chip0.rank0_ch1 == ram_vendor.chip0.rank1_ch1 &&\n\t\t\t\t\t\tram_rev0.chip0.rank0_ch0 == ram_rev0.chip0.rank1_ch0 &&\n\t\t\t\t\t\tram_rev0.chip0.rank0_ch1 == ram_rev0.chip0.rank1_ch1 &&\n\t\t\t\t\t\tram_rev1.chip0.rank0_ch0 == ram_rev1.chip0.rank1_ch0 &&\n\t\t\t\t\t\tram_rev1.chip0.rank0_ch1 == ram_rev1.chip0.rank1_ch1 &&\n\t\t\t\t\t\tram_density.chip0.rank0_ch0 == ram_density.chip0.rank1_ch0 &&\n\t\t\t\t\t\tram_density.chip0.rank0_ch1 == ram_density.chip0.rank1_ch1)\n\t\t\t\t\t   ? 2 : 1;\n\tbool rank_bad = ranks != actual_ranks;\n\ts_printf(txt_buf + strlen(txt_buf), \"%s %d x %s\", rank_bad ? \"#FFDD00\" : \"\", actual_ranks * channels, rank_bad ? \"#\" : \"\");\n\n\tswitch ((ram_density.chip0.rank0_ch0 & 0x3C) >> 2)\n\t{\n\tcase 2:\n\t\tstrcat(txt_buf, \"512MB\");\n\t\tbreak;\n\tcase 3:\n\t\tstrcat(txt_buf, \"768MB\");\n\t\tbreak;\n\tcase 4:\n\t\tstrcat(txt_buf, \"1GB\");\n\t\tbreak;\n\tcase 5:\n\t\tstrcat(txt_buf, \"1.5GB\");\n\t\tbreak;\n\tcase 6:\n\t\tstrcat(txt_buf, \"2GB\");\n\t\tbreak;\n\tdefault:\n\t\ts_printf(txt_buf + strlen(txt_buf), \"Unk (%d)\", (ram_density.chip0.rank0_ch0 & 0x3C) >> 2);\n\t\tbreak;\n\t}\n\n\tactual_ranks = (ram_vendor.chip1.rank0_ch0 == ram_vendor.chip1.rank1_ch0 &&\n\t\t\t\t\tram_vendor.chip1.rank0_ch1 == ram_vendor.chip1.rank1_ch1 &&\n\t\t\t\t\tram_rev0.chip1.rank0_ch0 == ram_rev0.chip1.rank1_ch0 &&\n\t\t\t\t\tram_rev0.chip1.rank0_ch1 == ram_rev0.chip1.rank1_ch1 &&\n\t\t\t\t\tram_rev1.chip1.rank0_ch0 == ram_rev1.chip1.rank1_ch0 &&\n\t\t\t\t\tram_rev1.chip1.rank0_ch1 == ram_rev1.chip1.rank1_ch1 &&\n\t\t\t\t\tram_density.chip1.rank0_ch0 == ram_density.chip1.rank1_ch0 &&\n\t\t\t\t\tram_density.chip1.rank0_ch1 == ram_density.chip1.rank1_ch1)\n\t\t\t\t   ? 2 : 1;\n\trank_bad = ranks != actual_ranks;\n\n\ts_printf(txt_buf + strlen(txt_buf), \" #FF8000 |# %s %d x %s\", rank_bad ? \"#FFDD00\" : \"\", actual_ranks * channels, rank_bad ? \"#\" : \"\");\n\n\tswitch ((ram_density.chip1.rank0_ch0 & 0x3C) >> 2)\n\t{\n\tcase 2:\n\t\tstrcat(txt_buf, \"512MB\");\n\t\tbreak;\n\tcase 3:\n\t\tstrcat(txt_buf, \"768MB\");\n\t\tbreak;\n\tcase 4:\n\t\tstrcat(txt_buf, \"1GB\");\n\t\tbreak;\n\tcase 5:\n\t\tstrcat(txt_buf, \"1.5GB\");\n\t\tbreak;\n\tcase 6:\n\t\tstrcat(txt_buf, \"2GB\");\n\t\tbreak;\n\tdefault:\n\t\ts_printf(txt_buf + strlen(txt_buf), \"Unk (%d)\", (ram_density.chip1.rank0_ch0 & 0x3C) >> 2);\n\t\tbreak;\n\t}\n\tstrcat(txt_buf, \"\\n\\n\");\n\n\t// Prepare display info.\n\tu8  display_rev = (nyx_str->info.panel_id >> 8) & 0xFF;\n\tu32 display_id = ((nyx_str->info.panel_id >> 8) & 0xFF00) | (nyx_str->info.panel_id & 0xFF);\n\n\t// For OLED LCD 7\" OEM clone use touch to identify it.\n\ttouch_info_t *touch_info = touch_get_chip_info();\n\tbool touch_clone_oled = touch_info->chip_id == FTS4_I2C_CHIP_ID && touch_info->clone;\n\tif (touch_clone_oled)\n\t\tdisplay_id = 0x10000;\n\n\tstrcat(txt_buf, \"#00DDFF Display Panel:#\\n#FF8000 Model:# \");\n\n\tswitch (display_id)\n\t{\n\tcase PANEL_JDI_LAM062M109A:\n\t\tstrcat(txt_buf, \"JDI LAM062M109A\");\n\t\tbreak;\n\n\tcase PANEL_JDI_LPM062M326A:\n\t\tstrcat(txt_buf, \"JDI LPM062M326A\");\n\t\tbreak;\n\n\tcase PANEL_INL_P062CCA_AZ1:\n\t\tstrcat(txt_buf, \"InnoLux P062CCA\");\n\t\tswitch (display_rev)\n\t\t{\n\t\tcase 0x93:\n\t\t\tstrcat(txt_buf, \"-AZ1\");\n\t\t\tbreak;\n\t\tcase 0x95:\n\t\t\tstrcat(txt_buf, \"-AZ2\");\n\t\t\tbreak;\n\t\tcase 0x96:\n\t\t\tstrcat(txt_buf, \"-AZ3\");\n\t\t\tbreak;\n\t\tcase 0x97:\n\t\t\tstrcat(txt_buf, \"-???\");\n\t\t\tbreak;\n\t\tcase 0x98:\n\t\t\tstrcat(txt_buf, \"-???\");\n\t\t\tbreak;\n\t\tcase 0x99:\n\t\t\tstrcat(txt_buf, \"-???\");\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tstrcat(txt_buf, \" #FFDD00 Contact me!#\");\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\n\tcase PANEL_AUO_A062TAN01:\n\t\tstrcat(txt_buf, \"AUO A062TAN\");\n\t\tswitch (display_rev)\n\t\t{\n\t\tcase 0x93:\n\t\t\tstrcat(txt_buf, \"00\");\n\t\t\tbreak;\n\t\tcase 0x94:\n\t\t\tstrcat(txt_buf, \"01\");\n\t\t\tbreak;\n\t\tcase 0x95:\n\t\t\tstrcat(txt_buf, \"02\");\n\t\t\tbreak;\n\t\tcase 0x96:\n\t\t\tstrcat(txt_buf, \"??\");\n\t\t\tbreak;\n\t\tcase 0x97:\n\t\t\tstrcat(txt_buf, \"??\");\n\t\t\tbreak;\n\t\tcase 0x98:\n\t\t\tstrcat(txt_buf, \"??\");\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tstrcat(txt_buf, \" #FFDD00 Contact me!#\");\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\n\tcase PANEL_INL_2J055IA_27A:\n\t\tstrcat(txt_buf, \"InnoLux 2J055IA-27A\");\n\t\tbreak;\n\n\tcase PANEL_AUO_A055TAN01:\n\t\tstrcat(txt_buf, \"AUO A055TAN\");\n\t\ts_printf(txt_buf + strlen(txt_buf), \"%02d\", display_rev - 0x92);\n\t\tbreak;\n\n\tcase PANEL_SHP_LQ055T1SW10:\n\t\tstrcat(txt_buf, \"Sharp LQ055T1SW10\");\n\t\tbreak;\n\n\tcase PANEL_SAM_AMS699VC01:\n\t\tstrcat(txt_buf, \"Samsung AMS699VC01\");\n\t\tbreak;\n\n\tcase PANEL_OEM_CLONE_6_2:\n\t\tstrcat(txt_buf, \"#FFDD00 OEM Clone 6.2\\\"#\");\n\t\tbreak;\n\n\tcase PANEL_OEM_CLONE_5_5:\n\t\tstrcat(txt_buf, \"#FFDD00 OEM Clone 5.5\\\"#\");\n\t\tbreak;\n\n\tcase PANEL_OEM_CLONE:\n\t\tstrcat(txt_buf, \"#FFDD00 OEM Clone#\");\n\t\tbreak;\n\n\tcase 0xCCCC:\n\t\tstrcat(txt_buf, \"#FFDD00 Failed to get info!#\");\n\t\tbreak;\n\n\tcase 0x10000: // Custom ID for LCD OEM Clone for Switch OLED.\n\t\tstrcat(txt_buf, \"#FFDD00 LCD OEM Clone 7\\\"#\");\n\t\tbreak;\n\n\tdefault:\n\t\tswitch (display_id & 0xFF)\n\t\t{\n\t\tcase PANEL_JDI_XXX062M:\n\t\t\tstrcat(txt_buf, \"JDI \");\n\t\t\tbreak;\n\t\tcase (PANEL_INL_P062CCA_AZ1 & 0xFF):\n\t\t\tstrcat(txt_buf, \"InnoLux \");\n\t\t\tbreak;\n\t\tcase (PANEL_AUO_A062TAN01 & 0xFF):\n\t\t\tstrcat(txt_buf, \"AUO \");\n\t\t\tbreak;\n\t\tcase (PANEL_SAM_AMS699VC01 & 0xFF):\n\t\t\tstrcat(txt_buf, \"Samsung \");\n\t\t\tbreak;\n\t\t}\n\t\tstrcat(txt_buf, \"Unknown #FFDD00 Contact me!#\");\n\t\tbreak;\n\t}\n\n\ts_printf(txt_buf + strlen(txt_buf), \"\\n#FF8000 ID:# #96FF00 %02X# %02X #96FF00 %02X#\",\n\t\tnyx_str->info.panel_id & 0xFF, (nyx_str->info.panel_id >> 8) & 0xFF, (nyx_str->info.panel_id >> 16) & 0xFF);\n\n\t// Prepare touch panel/ic info.\n\ttouch_fw_info_t touch_fw;\n\tif (!touch_get_fw_info(&touch_fw))\n\t{\n\t\tstrcat(txt_buf, \"\\n\\n#00DDFF Touch Panel:#\\n#FF8000 Model:# \");\n\n\t\ttouch_panel_info_t *touch_panel = touch_get_panel_vendor();\n\t\tif (touch_clone_oled)\n\t\t\tstrcat(txt_buf, \"#FFDD00 OEM Clone TSP#\");\n\t\telse if (touch_panel)\n\t\t{\n\t\t\tif ((u8)touch_panel->idx == (u8)-2) // Touch panel not found, print gpios.\n\t\t\t{\n\t\t\t\ts_printf(txt_buf + strlen(txt_buf), \"%2X%2X%2X #FFDD00 Contact me!#\",\n\t\t\t\t\ttouch_panel->gpio0, touch_panel->gpio1, touch_panel->gpio2);\n\t\t\t\ttouch_panel = NULL;\n\t\t\t}\n\t\t\telse\n\t\t\t\tstrcat(txt_buf, touch_panel->vendor);\n\t\t}\n\t\telse\n\t\t\tstrcat(txt_buf, \"#FFDD00 Error!#\");\n\n\t\ts_printf(txt_buf + strlen(txt_buf), \"\\n#FF8000 ID:# %02X.%02X.%02X.%02X (\",\n\t\t\t(touch_fw.fw_id >> 24) & 0xFF, (touch_fw.fw_id >> 16) & 0xFF, (touch_fw.fw_id >> 8) & 0xFF, touch_fw.fw_id & 0xFF);\n\n\t\tif (touch_clone_oled)\n\t\t\ttouch_fw.fw_id = 0xFFFFFFFF;\n\n\t\t// Check panel pair info.\n\t\tbool panel_ic_paired = false;\n\t\tswitch (touch_fw.fw_id)\n\t\t{\n\t\tcase 0x00100100:\n\t\t\tstrcat(txt_buf, \"4CD60D/0\");\n\t\t\tif (touch_panel)\n\t\t\t\tpanel_ic_paired = (u8)touch_panel->idx == (u8)-1;\n\t\t\tbreak;\n\n\t\tcase 0x00100200: // 4CD 1602.\n\t\tcase 0x00120100:\n\t\tcase 0x32000001:\n\t\t\tstrcat(txt_buf, \"4CD60D/1\");\n\t\t\tif (touch_panel)\n\t\t\t\tpanel_ic_paired = touch_panel->idx == 0; // NISSHA NFT-K12D.\n\t\t\tbreak;\n\n\t\t// case 0x98000004: // New 6.2\" panel?\n\t\t// case 0x50000001:\n\t\t// case 0x50000002:\n\t\t// \tstrcat(txt_buf, \"FST2 UNK\");\n\t\t// \tif (touch_panel)\n\t\t// \t\tpanel_ic_paired = touch_panel->idx == 0;\n\t\t// \tbreak;\n\n\t\tcase 0x001A0300:\n\t\tcase 0x32000102:\n\t\t\tstrcat(txt_buf, \"4CD60D/2\");\n\t\t\tif (touch_panel)\n\t\t\t\tpanel_ic_paired = touch_panel->idx == 1; // GiS GGM6 B2X.\n\t\t\tbreak;\n\n\t\tcase 0x00290100:\n\t\tcase 0x32000302:\n\t\t\tstrcat(txt_buf, \"4CD60D/3\");\n\t\t\tif (touch_panel)\n\t\t\t\tpanel_ic_paired = touch_panel->idx == 2; // NISSHA NBF-K9A.\n\t\t\tbreak;\n\n\t\tcase 0x31051820:\n\t\tcase 0x32000402:\n\t\t\tstrcat(txt_buf, \"4CD60D/4\");\n\t\t\tif (touch_panel)\n\t\t\t\tpanel_ic_paired = touch_panel->idx == 3; // GiS 5.5\".\n\t\t\tbreak;\n\n\t\tcase 0x32000501:\n\t\tcase 0x33000502:\n\t\tcase 0x33000503:\n\t\tcase 0x33000510:\n\t\t\tstrcat(txt_buf, \"4CD60D/5\");\n\t\t\tif (touch_panel)\n\t\t\t\tpanel_ic_paired = touch_panel->idx == 4; // Samsung BH2109.\n\t\t\tbreak;\n\n\t\tcase 0xFFFFFFFF: // Custom for OLED clone.\n\t\t\tstrcat(txt_buf, \"Clone\");\n\t\t\tpanel_ic_paired = true;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tstrcat(txt_buf, \"#FF8000 Contact me#\");\n\t\t\tbreak;\n\t\t}\n\n\t\ts_printf(txt_buf + strlen(txt_buf), \" - %s)\\n#FF8000 FTB ver:# %04X\\n#FF8000 FW rev:# %04X\",\n\t\t\tpanel_ic_paired ? \"Paired\" : \"#FFDD00 Error#\",\n\t\t\ttouch_fw.ftb_ver,\n\t\t\tbyte_swap_16(touch_fw.fw_rev)); // Byte swapping makes more sense here.\n\t}\n\telse\n\t\tstrcat(txt_buf, \"\\n\\n#FFDD00 Failed to get touch info!#\");\n\n\t// Check if patched unit.\n\tif (!fuse_check_patched_rcm())\n\t\tstrcat(txt_buf, \"\\n\\n#96FF00 This unit is exploitable#\\n#96FF00 to the RCM bug!#\");\n\telse\n\t\tstrcat(txt_buf, \"\\n\\n#FF8000 This unit is patched#\\n#FF8000 to the RCM bug!#\");\n\n\tlv_label_set_text(lb_desc2, txt_buf);\n\n\tfree(txt_buf);\n\n\tlv_obj_set_width(lb_desc2, lv_obj_get_width(desc2));\n\tlv_obj_align(desc2, val, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 4, 0);\n\n\treturn LV_RES_OK;\n}\n\nstatic char *ipatches_txt;\nstatic void _ipatch_process(u32 offset, u32 value)\n{\n\ts_printf(ipatches_txt + strlen(ipatches_txt), \"%6X     %4X    \", IROM_BASE + offset, value);\n\tu8 lo = value & 0xFF;\n\tswitch (value >> 8)\n\t{\n\tcase 0x20:\n\t\ts_printf(ipatches_txt + strlen(ipatches_txt), \"MOVS R0, ##0x%02X\", lo);\n\t\tbreak;\n\tcase 0x21:\n\t\ts_printf(ipatches_txt + strlen(ipatches_txt), \"MOVS R1, ##0x%02X\", lo);\n\t\tbreak;\n\tcase 0xDF:\n\t\ts_printf(ipatches_txt + strlen(ipatches_txt), \"SVC ##0x%02X\", lo);\n\t\tbreak;\n\t}\n\tstrcat(ipatches_txt, \"\\n\");\n}\n\nstatic lv_res_t _create_window_bootrom_info_status(lv_obj_t *btn)\n{\n\tlv_obj_t *win = nyx_create_standard_window(SYMBOL_CHIP\" Bootrom Info\", NULL);\n\tlv_win_add_btn(win, NULL, SYMBOL_DOWNLOAD\" Dump Bootrom\", _bootrom_dump_window_action);\n\n\tlv_obj_t *desc = lv_cont_create(win, NULL);\n\tlv_obj_set_size(desc, LV_HOR_RES / 2 / 3 * 2, LV_VER_RES - (LV_DPI * 11 / 7) - 5);\n\n\tlv_obj_t * lb_desc = lv_label_create(desc, NULL);\n\tlv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);\n\tlv_label_set_recolor(lb_desc, true);\n\tlv_label_set_style(lb_desc, &monospace_text);\n\n\tchar *txt_buf = (char *)malloc(SZ_4K);\n\tipatches_txt = txt_buf;\n\ts_printf(txt_buf, \"#00DDFF Ipatches:#\\n#FF8000 Address  \"SYMBOL_DOT\"  Val  \"SYMBOL_DOT\"  Instruction#\\n\");\n\n\tu32 res = fuse_read_ipatch(_ipatch_process);\n\tif (res != 0)\n\t\ts_printf(txt_buf + strlen(txt_buf), \"#FFDD00 Failed to read ipatches. Error: %d#\", res);\n\n\tlv_label_set_text(lb_desc, txt_buf);\n\n\tfree(txt_buf);\n\n\tlv_obj_set_width(lb_desc, lv_obj_get_width(desc));\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _launch_lockpick_action(lv_obj_t *btns, const char * txt)\n{\n\tint btn_idx = lv_btnm_get_pressed(btns);\n\n\tnyx_mbox_action(btns, txt);\n\n\tif (btn_idx == 1)\n\t{\n\t\tlv_obj_t *list = lv_list_create(NULL, NULL);\n\t\tlv_obj_set_size(list, 1, 1);\n\t\tlv_list_set_single_mode(list, true);\n\t\tlv_list_add(list, NULL, \"Lockpick_RCM.bin\", NULL);\n\t\tlv_obj_t *btn;\n\t\tbtn = lv_list_get_prev_btn(list, NULL);\n\t\tlaunch_payload(btn);\n\t\tlv_obj_del(list);\n\t}\n\n\treturn LV_RES_INV;\n}\n\nstatic lv_res_t _create_mbox_lockpick(lv_obj_t *btn)\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char * mbox_btn_map[] = { \"\\251\", \"\\222Continue\", \"\\222Close\", \"\\251\", \"\" };\n\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\n\tlv_mbox_set_text(mbox, \"#FF8000 Lockpick RCM#\\n\\nThis will launch Lockpick RCM.\\nDo you want to continue?\\n\\n\"\n\t\t\"To return back from lockpick use\\n#96FF00 Reboot to hekate#.\");\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map, _launch_lockpick_action);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _create_mbox_emmc_sandisk_report(lv_obj_t * btn)\n{\n\tstatic lv_style_t h_style;\n\tlv_style_copy(&h_style, &lv_style_transp);\n\th_style.body.padding.inner = 0;\n\th_style.body.padding.hor = LV_DPI - (LV_DPI / 4);\n\th_style.body.padding.ver = LV_DPI / 6;\n\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char * mbox_btn_map[] = { \"\\251\", \"\\222Close\", \"\\251\", \"\" };\n\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 8);\n\n\tlv_mbox_set_text(mbox, \"#C7EA46 Sandisk Device Report#\");\n\n\tu8 *buf = zalloc(EMMC_BLOCKSIZE);\n\tchar *txt_buf = (char *)malloc(SZ_32K);\n\tchar *txt_buf2 = (char *)malloc(SZ_32K);\n\ttxt_buf[0] = 0;\n\ttxt_buf2[0] = 0;\n\n\t// Create SoC Info container.\n\tlv_obj_t *h1 = lv_cont_create(mbox, NULL);\n\tlv_cont_set_style(h1, &h_style);\n\tlv_cont_set_fit(h1, false, true);\n\tlv_obj_set_width(h1, (LV_HOR_RES / 9) * 7);\n\tlv_obj_set_click(h1, false);\n\tlv_cont_set_layout(h1, LV_LAYOUT_OFF);\n\n\tlv_obj_t * lb_desc = lv_label_create(h1, NULL);\n\tlv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);\n\tlv_label_set_recolor(lb_desc, true);\n\tlv_label_set_style(lb_desc, &monospace_text);\n\tlv_obj_set_width(lb_desc, LV_HOR_RES / 9 * 4);\n\n\tlv_obj_t * lb_desc2 = lv_label_create(h1, NULL);\n\tlv_label_set_long_mode(lb_desc2, LV_LABEL_LONG_BREAK);\n\tlv_label_set_recolor(lb_desc2, true);\n\tlv_label_set_style(lb_desc2, &monospace_text);\n\tlv_obj_set_width(lb_desc2, LV_HOR_RES / 9 * 3);\n\tlv_obj_align(lb_desc2, lb_desc, LV_ALIGN_OUT_RIGHT_TOP, 0, 0);\n\n\n\tif (emmc_initialize(false))\n\t{\n\t\tlv_label_set_text(lb_desc, \"#FFDD00 Failed to init eMMC!#\");\n\n\t\tgoto out;\n\t}\n\n\tint res = sdmmc_storage_vendor_sandisk_report(&emmc_storage, buf);\n\temmc_end();\n\n\tif (res)\n\t{\n\t\tlv_label_set_text(lb_desc, \"#FFDD00 Device Report not supported!#\");\n\t\tlv_label_set_text(lb_desc2, \" \");\n\n\t\tgoto out;\n\t}\n\n\tmmc_sandisk_report_t *rpt = (mmc_sandisk_report_t *)buf;\n\n\tu8  fw_update_date[13] = {0};\n\tu8  fw_update_time[9] = {0};\n\tmemcpy(fw_update_date, rpt->fw_update_date, sizeof(rpt->fw_update_date));\n\tmemcpy(fw_update_time, rpt->fw_update_time, sizeof(rpt->fw_update_time));\n\n\ts_printf(txt_buf,\n\t\t\"#00DDFF Device report#\\n\"\n\t\t//\"#FF8000 Average Erases SYS:#    %d\\n\"\n\t\t\"#FF8000 Average Erases SLC:#    %d\\n\"\n\t\t\"#FF8000 Average Erases MLC:#    %d\\n\"\n\t\t//\"#FF8000 Read Reclaims SYS:#     %d\\n\"\n\t\t\"#FF8000 Read Reclaims SLC:#     %d\\n\"\n\t\t\"#FF8000 Read Reclaims MLC:#     %d\\n\"\n\t\t\"#FF8000 Bad Blocks Factory:#    %d\\n\"\n\t\t\"#FF8000 Bad Blocks SYS:#        %d\\n\"\n\t\t\"#FF8000 Bad Blocks SLC:#        %d\\n\"\n\t\t\"#FF8000 Bad Blocks MLC:#        %d\\n\"\n\t\t\"#FF8000 FW Updates:#            %d\\n\"\n\t\t\"#FF8000 FW Buildtime:#          %s %s\\n\"\n\t\t\"#FF8000 Total Writes:#          %d MB\\n\"\n\t\t//\"#FF8000 Voltage Drops:#         %d\\n\"\n\t\t//\"#FF8000 Voltage Droops:#        %d\\n\"\n\t\t//\"#FF8000 VD Failed Recovers:#    %d\\n\"\n\t\t//\"#FF8000 VD Recover Operations:# %d\\n\"\n\t\t\"#FF8000 Total Writes SLC:#      %d MB\\n\"\n\t\t\"#FF8000 Total Writes MLC:#      %d MB\\n\"\n\t\t\"#FF8000 BigFile limit status:#  %d\\n\"\n\t\t\"#FF8000 Average Erases Hybrid:# %d\",\n\n\t\t//rpt->avg_erase_cycles_sys,\n\t\trpt->avg_erase_cycles_slc,\n\t\trpt->avg_erase_cycles_mlc,\n\t\t//rpt->read_reclaim_cnt_sys,\n\t\trpt->read_reclaim_cnt_slc,\n\t\trpt->read_reclaim_cnt_mlc,\n\t\trpt->bad_blocks_factory,\n\t\trpt->bad_blocks_sys,\n\t\trpt->bad_blocks_slc,\n\t\trpt->bad_blocks_mlc,\n\t\trpt->fw_updates_cnt,\n\t\tfw_update_date,\n\t\tfw_update_time,\n\t\trpt->total_writes_100mb * 100,\n\t\t//rpt->vdrops,\n\t\t//rpt->vdroops,\n\t\t//rpt->vdrops_failed_data_rec,\n\t\t//rpt->vdrops_data_rec_ops,\n\t\trpt->total_writes_slc_100mb * 100,\n\t\trpt->total_writes_mlc_100mb * 100,\n\t\trpt->mlc_bigfile_mode_limit_exceeded,\n\t\trpt->avg_erase_cycles_hybrid);\n\n\tu8 advanced_report = 0;\n\tfor (u32 i = 0; i < sizeof(mmc_sandisk_advanced_report_t); i++)\n\t\tadvanced_report |= *(u8 *)((u8 *)&rpt->advanced + i);\n\n\tif (advanced_report)\n\t{\n\t\ts_printf(txt_buf2,\n\t\t\t\"#00DDFF Advanced Health Status#\\n\"\n\t\t\t\"#FF8000 Power ups:#             %d\\n\"\n\t\t\t//\"#FF8000 Maximum Erases SYS:#    %d\\n\"\n\t\t\t\"#FF8000 Maximum Erases SLC:#    %d\\n\"\n\t\t\t\"#FF8000 Maximum Erases MLC:#    %d\\n\"\n\t\t\t//\"#FF8000 Minimum Erases SYS:#    %d\\n\"\n\t\t\t\"#FF8000 Minimum Erases SLC:#    %d\\n\"\n\t\t\t\"#FF8000 Minimum Erases MLC:#    %d\\n\"\n\t\t\t\"#FF8000 Maximum Erases EUDA:#   %d\\n\"\n\t\t\t\"#FF8000 Minimum Erases EUDA:#   %d\\n\"\n\t\t\t\"#FF8000 Average Erases EUDA:#   %d\\n\"\n\t\t\t\"#FF8000 Read Reclaims EUDA:#    %d\\n\"\n\t\t\t\"#FF8000 Bad Blocks EUDA:#       %d\\n\"\n\t\t\t//\"#FF8000 Pre EOL State EUDA:#    %d\\n\"\n\t\t\t//\"#FF8000 Pre EOL State SYS:#     %d\\n\"\n\t\t\t//\"#FF8000 Pre EOL State MLC:#     %d\\n\"\n\t\t\t\"#FF8000 Uncorrectable ECC:#     %d\\n\"\n\t\t\t\"#FF8000 Temperature Now:#       %d oC\\n\"\n\t\t\t//\"#FF8000 Temperature Min:#       %d oC\\n\"\n\t\t\t\"#FF8000 Temperature Max:#       %d oC\\n\"\n\t\t\t\"#FF8000 Health Level EUDA:#     %d%%\\n\"\n\t\t\t//\"#FF8000 Health Level SYS:#      %d%%\\n\"\n\t\t\t\"#FF8000 Health Level MLC:#      %d%%\",\n\n\t\t\trpt->advanced.power_inits,\n\t\t\t//rpt->advanced.max_erase_cycles_sys,\n\t\t\trpt->advanced.max_erase_cycles_slc,\n\t\t\trpt->advanced.max_erase_cycles_mlc,\n\t\t\t//rpt->advanced.min_erase_cycles_sys,\n\t\t\trpt->advanced.min_erase_cycles_slc,\n\t\t\trpt->advanced.min_erase_cycles_mlc,\n\t\t\trpt->advanced.max_erase_cycles_euda,\n\t\t\trpt->advanced.min_erase_cycles_euda,\n\t\t\trpt->advanced.avg_erase_cycles_euda,\n\t\t\trpt->advanced.read_reclaim_cnt_euda,\n\t\t\trpt->advanced.bad_blocks_euda,\n\t\t\t//rpt->advanced.pre_eol_euda,\n\t\t\t//rpt->advanced.pre_eol_sys,\n\t\t\t//rpt->advanced.pre_eol_mlc,\n\t\t\trpt->advanced.uncorrectable_ecc,\n\t\t\trpt->advanced.temperature_now,\n\t\t\t//rpt->advanced.temperature_min,\n\t\t\trpt->advanced.temperature_max,\n\t\t\trpt->advanced.health_pct_euda ? 101 - rpt->advanced.health_pct_euda : 0,\n\t\t\t//rpt->advanced.health_pct_sys ? 101 - rpt->advanced.health_pct_sys : 0,\n\t\t\trpt->advanced.health_pct_mlc ? 101 - rpt->advanced.health_pct_mlc : 0);\n\t}\n\telse\n\t\tstrcpy(txt_buf2, \"#00DDFF Advanced Health Status#\\n#FFDD00 Empty!#\");\n\n\tlv_label_set_text(lb_desc, txt_buf);\n\tlv_label_set_text(lb_desc2, txt_buf2);\n\nout:\n\tfree(buf);\n\tfree (txt_buf);\n\tfree (txt_buf2);\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action); // Important. After set_text.\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_obj_t *bench_sd_err_label = NULL;\n\nstatic lv_res_t _create_mbox_benchmark(bool sd_bench)\n{\n\tsdmmc_storage_t *storage;\n\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char * mbox_btn_map[] = { \"\\251\", \"\\222OK\", \"\\251\", \"\" };\n\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES * 3 / 7);\n\n\tchar *txt_buf = (char *)malloc(SZ_16K);\n\n\ts_printf(txt_buf, \"#FF8000 %s Benchmark#\\n[Raw Reads] Abort: VOL- & VOL+\", sd_bench ? \"SD Card\" : \"eMMC\");\n\n\tlv_mbox_set_text(mbox, txt_buf);\n\ttxt_buf[0] = 0;\n\n\tlv_obj_t *h1 = lv_cont_create(mbox, NULL);\n\tlv_cont_set_fit(h1, false, true);\n\tlv_cont_set_style(h1, &lv_style_transp_tight);\n\tlv_obj_set_width(h1, lv_obj_get_width(mbox) - LV_DPI / 10);\n\n\tlv_obj_t *lbl_status = lv_label_create(h1, NULL);\n\tlv_label_set_style(lbl_status, &monospace_text);\n\tlv_label_set_recolor(lbl_status, true);\n\tlv_label_set_text(lbl_status, \" \");\n\tlv_obj_align(lbl_status, h1, LV_ALIGN_IN_TOP_MID, 0, 0);\n\n\tlv_obj_t *bar = lv_bar_create(mbox, NULL);\n\tlv_obj_set_size(bar, LV_DPI * 2, LV_DPI / 5);\n\tlv_bar_set_range(bar, 0, 100);\n\tlv_bar_set_value(bar, 0);\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\tmanual_system_maintenance(true);\n\n\tint res = 0;\n\n\tif (sd_bench)\n\t{\n\t\tstorage = &sd_storage;\n\n\t\t// Re-initialize to update trimmers.\n\t\tsd_end();\n\t\tres = sd_mount();\n\t}\n\telse\n\t{\n\t\tstorage = &emmc_storage;\n\t\tres = emmc_initialize(false);\n\t\tif (!res)\n\t\t\temmc_set_partition(EMMC_GPP);\n\t}\n\n\tif (res)\n\t{\n\t\tlv_mbox_set_text(mbox, \"#FFDD00 Failed to init Storage!#\");\n\t\tgoto out;\n\t}\n\n\t// Set benchmark parameters.\n\tconst u32 sct_blk_seq = 0x8000;   // 16MB.  A2 spec denotes 4MB, but using older big AU.\n\tconst u32 sct_blk_4kb = 8;        // 4KB.\n\tconst u32 sct_rem_seq = 0x200000; // 1GB.   A2 spec.\n\tconst u32 sct_rem_4kb = 0x80000;  // 256MB. A2 spec.\n\tconst u32 sct_num_1mb = 0x800;    // 1MB.\n\tconst u32 size_bytes_seq = sct_rem_seq * SDMMC_DAT_BLOCKSIZE;\n\tconst u32 size_bytes_4kb = sct_rem_4kb * SDMMC_DAT_BLOCKSIZE;\n\n\t// Set calculation divider. 1000 or 1024. (Does not affect IOPS).\n\tu32 mb_div = 1000; // Unfortunately most software uses fake MB.\n\n\tchar *mbs_text;\n\tswitch (mb_div)\n\t{\n\tcase 1000:\n\t\tmbs_text = \"MB/s\";\n\t\tbreak;\n\tcase 1024:\n\t\tmbs_text = \"MiB/s\";\n\t\tbreak;\n\t}\n\n\t// Set actual div in MB/MiB.\n\tmb_div *= mb_div;\n\n\tint error = 0;\n\tu32 iters = 3;\n\tu32 offset_chunk_start = ALIGN_DOWN(storage->sec_cnt / 3, sct_blk_seq); // Align to block.\n\tif (storage->sec_cnt < 0xC00000)\n\t\titers -= 2; // 4GB card.\n\n\tu32  rnd_off_cnt    = sct_rem_4kb / sct_blk_4kb;\n\tu32 *random_offsets = malloc(rnd_off_cnt * sizeof(u32));\n\tu32 *times_taken_4k = malloc(rnd_off_cnt * sizeof(u32));\n\n\tfor (u32 iter_curr = 0; iter_curr < iters; iter_curr++)\n\t{\n\t\tu32 pct = 0;\n\t\tu32 prevPct = 200;\n\t\tu32 timer = 0;\n\t\tu32 lba_curr = 0;\n\t\tu32 sector_off = offset_chunk_start * iter_curr;\n\t\tu32 sector_num = sct_blk_seq;\n\t\tu32 data_remaining = sct_rem_seq;\n\n\t\ts_printf(txt_buf + strlen(txt_buf), \"#C7EA46 %d/3# - Sector Offset #C7EA46 %08X#:\\n\", iter_curr + 1, sector_off);\n\n\t\tu32 render_min_ms = 66;\n\t\tu32 render_timer  = get_tmr_ms() + render_min_ms;\n\t\twhile (data_remaining)\n\t\t{\n\t\t\tu32 time_taken = get_tmr_us();\n\t\t\terror = sdmmc_storage_read(storage, sector_off + lba_curr, sector_num, (u8 *)MIXD_BUF_ALIGNED);\n\t\t\ttime_taken = get_tmr_us() - time_taken;\n\t\t\ttimer += time_taken;\n\n\t\t\tmanual_system_maintenance(false);\n\t\t\tdata_remaining -= sector_num;\n\t\t\tlba_curr += sector_num;\n\n\t\t\tpct = (lba_curr * 100) / sct_rem_seq;\n\t\t\tif (pct != prevPct && render_timer < get_tmr_ms())\n\t\t\t{\n\t\t\t\tlv_bar_set_value(bar, pct);\n\t\t\t\tmanual_system_maintenance(true);\n\t\t\t\trender_timer = get_tmr_ms() + render_min_ms;\n\n\t\t\t\tprevPct = pct;\n\n\t\t\t\tif (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))\n\t\t\t\t\terror = -1;\n\t\t\t}\n\n\t\t\tif (error)\n\t\t\t\tgoto error;\n\t\t}\n\t\tlv_bar_set_value(bar, 100);\n\n\t\t// Calculate rate for transfer.\n\t\tu32 rate_1k = (u64)size_bytes_seq * 1000 * 1000 * 1000 / mb_div / timer;\n\t\ts_printf(txt_buf + strlen(txt_buf), \" SEQ 16MB - Rate: #C7EA46 %3d.%02d %s#\",\n\t\t\trate_1k / 1000, (rate_1k % 1000) / 10, mbs_text);\n\t\tlv_label_set_text(lbl_status, txt_buf);\n\t\tlv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0);\n\t\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\t\tmanual_system_maintenance(true);\n\n\t\tpct = 0;\n\t\tprevPct = 200;\n\t\ttimer = 0;\n\t\tlba_curr = 0;\n\t\tsector_num = sct_blk_4kb;\n\t\tdata_remaining = sct_rem_4kb;\n\n\t\tu32 loop_idx = 0;\n\t\trender_timer = get_tmr_ms() + render_min_ms;\n\t\twhile (data_remaining)\n\t\t{\n\t\t\tu32 time_taken = get_tmr_us();\n\t\t\terror = sdmmc_storage_read(storage, sector_off + lba_curr, sector_num, (u8 *)MIXD_BUF_ALIGNED);\n\t\t\ttime_taken = get_tmr_us() - time_taken;\n\n\t\t\ttimer += time_taken;\n\t\t\ttimes_taken_4k[loop_idx++] = time_taken;\n\n\t\t\tmanual_system_maintenance(false);\n\t\t\tdata_remaining -= sector_num;\n\t\t\tlba_curr += sector_num;\n\n\t\t\tpct = (lba_curr * 100) / sct_rem_4kb;\n\t\t\tif (pct != prevPct && render_timer < get_tmr_ms())\n\t\t\t{\n\t\t\t\tlv_bar_set_value(bar, pct);\n\t\t\t\tmanual_system_maintenance(true);\n\t\t\t\trender_timer = get_tmr_ms() + render_min_ms;\n\n\t\t\t\tprevPct = pct;\n\n\t\t\t\tif (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))\n\t\t\t\t\terror = -1;\n\t\t\t}\n\n\t\t\tif (error)\n\t\t\t\tgoto error;\n\t\t}\n\t\tlv_bar_set_value(bar, 100);\n\n\t\tqsort(times_taken_4k, loop_idx, sizeof(u32), qsort_compare_int); // Use int for faster compare. Value can't exceed 2s.\n\n\t\tu32 pct95 = 0;\n\t\tfor (u32 i = 0; i < loop_idx * 95 / 100; i++)\n\t\t\tpct95 += times_taken_4k[i];\n\t\tpct95 /= loop_idx * 95 / 100;\n\n\t\tu32 pct05 = 0;\n\t\tfor (u32 i = 0; i < loop_idx * 5 / 100; i++)\n\t\t\tpct05 += times_taken_4k[loop_idx - 1 - i];\n\t\tpct05 /= loop_idx * 5 / 100;\n\n\t\t// Calculate rate and IOPS for transfer.\n\t\trate_1k = (u64)size_bytes_4kb * 1000 * 1000 * 1000 / mb_div / timer;\n\t\tu32 iops = ((u64)(sct_rem_4kb / sct_num_1mb) * 1024 * 1000 * 1000 * 1000) / (4096 / 1024) / timer / 1000;\n\t\ts_printf(txt_buf + strlen(txt_buf), \"        AVG #C7EA46 95th#  #FF3C28 5th#\\n\");\n\t\ts_printf(txt_buf + strlen(txt_buf), \" SEQ  4KB - Rate: #C7EA46 %3d.%02d %s# IOPS: #C7EA46 %4d# %4d %4d \\n\",\n\t\t\trate_1k / 1000, (rate_1k % 1000) / 10, mbs_text, iops, 1000000 / pct95, 1000000 / pct05);\n\t\tlv_label_set_text(lbl_status, txt_buf);\n\t\tlv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0);\n\t\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\t\tmanual_system_maintenance(true);\n\n\t\tu32 lba_idx = 0;\n\t\tu32 random_numbers[4];\n\t\tfor (u32 i = 0; i < rnd_off_cnt; i += 4)\n\t\t{\n\t\t\t// Generate new random numbers.\n\t\t\twhile (se_rng_pseudo(random_numbers, SE_RNG_BLOCK_SIZE))\n\t\t\t\t;\n\t\t\t// Clamp offsets to 256MB range.\n\t\t\trandom_offsets[i + 0] = random_numbers[0] % sct_rem_4kb;\n\t\t\trandom_offsets[i + 1] = random_numbers[1] % sct_rem_4kb;\n\t\t\trandom_offsets[i + 2] = random_numbers[2] % sct_rem_4kb;\n\t\t\trandom_offsets[i + 3] = random_numbers[3] % sct_rem_4kb;\n\t\t}\n\n\t\tpct = 0;\n\t\tprevPct = 200;\n\t\ttimer = 0;\n\t\tdata_remaining = sct_rem_4kb;\n\n\t\tloop_idx = 0;\n\t\trender_timer = get_tmr_ms() + render_min_ms;\n\t\twhile (data_remaining)\n\t\t{\n\t\t\tu32 time_taken = get_tmr_us();\n\t\t\terror = sdmmc_storage_read(storage, sector_off + random_offsets[lba_idx], sector_num, (u8 *)MIXD_BUF_ALIGNED);\n\t\t\ttime_taken = get_tmr_us() - time_taken;\n\n\t\t\ttimer += time_taken;\n\t\t\ttimes_taken_4k[loop_idx++] = time_taken;\n\n\t\t\tmanual_system_maintenance(false);\n\t\t\tdata_remaining -= sector_num;\n\t\t\tlba_idx++;\n\n\t\t\tpct = (lba_idx * 100) / rnd_off_cnt;\n\t\t\tif (pct != prevPct && render_timer < get_tmr_ms())\n\t\t\t{\n\t\t\t\tlv_bar_set_value(bar, pct);\n\t\t\t\tmanual_system_maintenance(true);\n\t\t\t\trender_timer = get_tmr_ms() + render_min_ms;\n\n\t\t\t\tprevPct = pct;\n\n\t\t\t\tif (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))\n\t\t\t\t\terror = -1;\n\t\t\t}\n\n\t\t\tif (error)\n\t\t\t\tgoto error;\n\t\t}\n\t\tlv_bar_set_value(bar, 100);\n\n\t\tqsort(times_taken_4k, loop_idx, sizeof(u32), qsort_compare_int); // Use int for faster compare. Value can't exceed 2s.\n\n\t\tpct95 = 0;\n\t\tfor (u32 i = 0; i < loop_idx * 95 / 100; i++)\n\t\t\tpct95 += times_taken_4k[i];\n\t\tpct95 /= loop_idx * 95 / 100;\n\n\t\tpct05 = 0;\n\t\tfor (u32 i = 0; i < loop_idx * 5 / 100; i++)\n\t\t\tpct05 += times_taken_4k[loop_idx - 1 - i];\n\t\tpct05 /= loop_idx * 5 / 100;\n\n\t\t// Calculate rate and IOPS for transfer.\n\t\trate_1k = (u64)size_bytes_4kb * 1000 * 1000 * 1000 / mb_div / timer;\n\t\tiops = ((u64)(sct_rem_4kb / sct_num_1mb) * 1024 * 1000 * 1000 * 1000) / (4096 / 1024) / timer / 1000;\n\t\ts_printf(txt_buf + strlen(txt_buf), \" RND  4KB - Rate: #C7EA46 %3d.%02d %s# IOPS: #C7EA46 %4d# %4d %4d \\n\",\n\t\t\trate_1k / 1000, (rate_1k % 1000) / 10, mbs_text, iops, 1000000 / pct95, 1000000 / pct05);\n\t\tif (iter_curr == iters - 1)\n\t\t\ttxt_buf[strlen(txt_buf) - 1] = 0; // Cut off last new line.\n\t\tlv_label_set_text(lbl_status, txt_buf);\n\t\tlv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0);\n\t\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\t\tmanual_system_maintenance(true);\n\t}\n\nerror:\n\tfree(random_offsets);\n\tfree(times_taken_4k);\n\n\tif (error)\n\t{\n\t\tif (error == -1)\n\t\t\ts_printf(txt_buf + strlen(txt_buf), \"\\n#FFDD00                      Aborted!                     #\");\n\t\telse\n\t\t\ts_printf(txt_buf + strlen(txt_buf), \"\\n#FFDD00                 IO Error occurred!                #\");\n\n\t\tlv_label_set_text(lbl_status, txt_buf);\n\t\tlv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0);\n\t}\n\n\tlv_obj_del(bar);\n\n\tif (sd_bench && error && error != -1)\n\t\tsd_end();\n\tif (sd_bench)\n\t{\n\t\tif (error && error != -1)\n\t\t\tsd_end();\n\t\telse\n\t\t\tsd_unmount();\n\t}\n\telse\n\t\temmc_end();\n\nout:\n\ts_printf(txt_buf, \"#FF8000 %s Benchmark#\\n[Raw Reads]\", sd_bench ? \"SD Card\" : \"eMMC\");\n\tlv_mbox_set_text(mbox, txt_buf);\n\n\t// Update SDMMC error info in case it changed.\n\tif (sd_bench && bench_sd_err_label)\n\t{\n\t\tu16 *sd_errors = sd_get_error_count();\n\t\ts_printf(txt_buf, \"\\n%d (%d)\\n%d (%d)\\n%d (%d)\",\n\t\t\tsd_errors[SD_ERROR_INIT_FAIL], nyx_str->info.sd_errors[SD_ERROR_INIT_FAIL],\n\t\t\tsd_errors[SD_ERROR_RW_FAIL],   nyx_str->info.sd_errors[SD_ERROR_RW_FAIL],\n\t\t\tsd_errors[SD_ERROR_RW_RETRY],  nyx_str->info.sd_errors[SD_ERROR_RW_RETRY]);\n\t\tlv_label_set_text(bench_sd_err_label, txt_buf);\n\t}\n\n\tfree(txt_buf);\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action); // Important. After set_text.\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _create_mbox_emmc_bench(lv_obj_t * btn)\n{\n\t_create_mbox_benchmark(false);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _create_mbox_sd_bench(lv_obj_t * btn)\n{\n\t_create_mbox_benchmark(true);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _create_window_emmc_info_status(lv_obj_t *btn)\n{\n\tlv_obj_t *win = nyx_create_standard_window(SYMBOL_CHIP\" Internal eMMC Info\", NULL);\n\tlv_win_add_btn(win, NULL, SYMBOL_CHIP\" Benchmark\", _create_mbox_emmc_bench);\n\n\tlv_obj_t *desc = lv_cont_create(win, NULL);\n\tlv_obj_set_size(desc, LV_HOR_RES / 2 / 6 * 2, LV_VER_RES - (LV_DPI * 11 / 7) - 5);\n\n\tlv_obj_t * lb_desc = lv_label_create(desc, NULL);\n\tlv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);\n\tlv_label_set_recolor(lb_desc, true);\n\n\tchar *txt_buf = (char *)malloc(SZ_16K);\n\ttxt_buf[0] = '\\n';\n\ttxt_buf[1] = 0;\n\tu16 *emmc_errors;\n\n\tif (emmc_initialize(false))\n\t{\n\t\tlv_label_set_text(lb_desc, \"#FFDD00 Failed to init eMMC!#\");\n\t\tlv_obj_set_width(lb_desc, lv_obj_get_width(desc));\n\t\temmc_errors = emmc_get_error_count();\n\n\t\tgoto out_error;\n\t}\n\n\tu32 bus_clock = 0;\n\tchar *rsvd_blocks;\n\tchar life_a_txt[8];\n\tchar life_b_txt[8];\n\tchar bkops[64];\n\tu32 cache = emmc_storage.ext_csd.cache_size;\n\tu32 life_a = emmc_storage.ext_csd.dev_life_est_a;\n\tu32 life_b = emmc_storage.ext_csd.dev_life_est_b;\n\tu16 card_type = emmc_storage.ext_csd.card_type;\n\tchar *max_bus_support = \"Unknown\";\n\n\t// Identify manufacturer. Only official eMMCs.\n\tswitch (emmc_storage.cid.manfid)\n\t{\n\tcase 0x11:\n\t\tstrcat(txt_buf, \"Toshiba \");\n\t\tbreak;\n\tcase 0x15:\n\t\tstrcat(txt_buf, \"Samsung \");\n\t\tbreak;\n\tcase 0x45: // Unofficial.\n\t\tstrcat(txt_buf, \"SanDisk \");\n\t\tlv_win_add_btn(win, NULL, SYMBOL_FILE_ALT\" Device Report\", _create_mbox_emmc_sandisk_report);\n\t\tbreak;\n\tcase 0x89: // Unofficial.\n\t\tstrcat(txt_buf, \"Silicon Motion \");\n\t\tbreak;\n\tcase 0x90:\n\t\tstrcat(txt_buf, \"SK Hynix \");\n\t\tbreak;\n\tdefault:\n\t\tstrcat(txt_buf, \"Unknown \");\n\t\tbreak;\n\t}\n\n\ts_printf(txt_buf + strlen(txt_buf), \"(%02X)\\n%c%c%c%c%c%c (%02X)\\n%d.%d\\n%04X\\n%02d/%04d\\n\\n\",\n\t\temmc_storage.cid.manfid,\n\t\temmc_storage.cid.prod_name[0], emmc_storage.cid.prod_name[1], emmc_storage.cid.prod_name[2],\n\t\temmc_storage.cid.prod_name[3], emmc_storage.cid.prod_name[4], emmc_storage.cid.prod_name[5],\n\t\temmc_storage.cid.oemid,\n\t\temmc_storage.cid.prv & 0xF, emmc_storage.cid.prv >> 4,\n\t\temmc_storage.cid.serial, emmc_storage.cid.month, emmc_storage.cid.year);\n\n\tif (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)\n\t\tmax_bus_support = \"HS400\";\n\telse if (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)\n\t\tmax_bus_support = \"HS200\";\n\telse if (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)\n\t\tmax_bus_support = \"DDR52\";\n\telse if (card_type & EXT_CSD_CARD_TYPE_HS_52)\n\t\tmax_bus_support = \"HS52\";\n\telse if (card_type & EXT_CSD_CARD_TYPE_HS_26)\n\t\tmax_bus_support = \"HS26\";\n\n\tif (emmc_storage.csd.busspeed == 400)\n\t\tbus_clock = 200;\n\telse\n\t\tbus_clock = emmc_storage.csd.busspeed; // Except DDR52 where it's 26 MHz.\n\n\tstrcpy(bkops, \"-\");\n\tif (emmc_storage.ext_csd.bkops)\n\t{\n\t\tif (emmc_storage.ext_csd.bkops_en & EXT_CSD_BKOPS_AUTO)\n\t\t{\n\t\t\tstrcpy(bkops, \"Auto\");\n\t\t\tif (emmc_storage.ext_csd.bkops_en & EXT_CSD_BKOPS_MANUAL)\n\t\t\t\tstrcat(bkops, \" + Manual\");\n\t\t}\n\t\telse\n\t\t\tstrcpy(bkops, \"Off\");\n\t\tstrcat(bkops, \": \");\n\n\t\tswitch (emmc_storage.raw_ext_csd[EXT_CSD_BKOPS_STATUS])\n\t\t{\n\t\tcase 0:\n\t\t\tstrcat(bkops, \"OK\");\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tstrcat(bkops, \"Minor\");\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tstrcat(bkops, \"#FFDD00 Degraded#\");\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tstrcat(bkops, \"#FFDD00 Critical#\");\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tstrcpy(life_a_txt, \"-\");\n\tstrcpy(life_b_txt, \"-\");\n\n\t// Normalize cells life (Used -> Left).\n\tif (life_a) // If 0 no NAND Type A.\n\t{\n\t\tlife_a = (10 - (life_a - 1)) * 10;\n\t\ts_printf(life_a_txt, \"%d%%\", life_a);\n\t}\n\n\tif (life_b) // If 0 no NAND Type B.\n\t{\n\t\tlife_b = (10 - (life_b - 1)) * 10;\n\t\ts_printf(life_b_txt, \"%d%%\", life_b);\n\t}\n\n\t// Reserved blocks used.\n\tswitch (emmc_storage.ext_csd.pre_eol_info)\n\t{\n\tcase 1:\n\t\trsvd_blocks = \"Normal (< 80%)\";\n\t\tbreak;\n\tcase 2:\n\t\trsvd_blocks = \"Warning (> 80%)\";\n\t\tbreak;\n\tcase 3:\n\t\trsvd_blocks = \"Critical (> 90%)\";\n\t\tbreak;\n\tdefault:\n\t\trsvd_blocks = \"#FF8000 Unknown#\";\n\t\tbreak;\n\t}\n\n\ts_printf(txt_buf + strlen(txt_buf),\n\t\t\"#00DDFF V1.%d (rev 1.%d)#\\n%02X\\n%s\\n%d MB/s (%d MHz)\\n%d MiB\\n%d %s\\n\\n%s\\nA: %s, B: %s\\n%s\",\n\t\temmc_storage.ext_csd.ext_struct, emmc_storage.ext_csd.rev,\n\t\temmc_storage.csd.cmdclass, max_bus_support,\n\t\temmc_storage.csd.busspeed, bus_clock,\n\t\temmc_storage.ext_csd.max_enh_mult * EMMC_BLOCKSIZE / 1024,\n\t\t!(cache % 1024) ? (cache / 1024) : cache, !(cache % 1024) ? \"MiB\" : \"KiB\",\n\t\tbkops,\n\t\tlife_a_txt, life_b_txt, rsvd_blocks);\n\n\tlv_label_set_static_text(lb_desc,\n\t\t\"#00DDFF CID:#\\n\"\n\t\t\"Vendor ID:\\n\"\n\t\t\"Model:\\n\"\n\t\t\"Prod Rev:\\n\"\n\t\t\"S/N:\\n\"\n\t\t\"Month/Year:\\n\\n\"\n\t\t\"#00DDFF Ext CSD:#\\n\"\n\t\t\"Cmd Classes:\\n\"\n\t\t\"Max Bus Rate:\\n\"\n\t\t\"Current Rate:\\n\"\n\t\t\"Enhanced Area:\\n\"\n\t\t\"Write Cache:\\n\\n\"\n\t\t\"Maintenance:\\n\"\n\t\t\"Estimated Life:\\n\"\n\t\t\"Reserved Used:\"\n\t);\n\tlv_obj_set_width(lb_desc, lv_obj_get_width(desc));\n\n\tlv_obj_t *info = lv_cont_create(win, NULL);\n\tlv_obj_set_size(info, LV_HOR_RES / 11 * 3, LV_VER_RES - (LV_DPI * 11 / 7) - 5);\n\n\tlv_obj_t * lb_val = lv_label_create(info, lb_desc);\n\n\tlv_label_set_text(lb_val, txt_buf);\n\n\tlv_obj_set_width(lb_val, lv_obj_get_width(info));\n\tlv_obj_align(info, desc, LV_ALIGN_OUT_RIGHT_MID, 0, 0);\n\n\tlv_obj_t *desc2 = lv_cont_create(win, NULL);\n\tlv_obj_set_size(desc2, LV_HOR_RES / 2 / 4 * 4, LV_VER_RES - (LV_DPI * 11 / 7) - 5);\n\n\tlv_obj_t * lb_desc2 = lv_label_create(desc2, lb_desc);\n\tlv_label_set_style(lb_desc2, &monospace_text);\n\n\tu32 boot_size = emmc_storage.ext_csd.boot_mult << 17;\n\tu32 rpmb_size = emmc_storage.ext_csd.rpmb_mult << 17;\n\tstrcpy(txt_buf, \"#00DDFF eMMC Physical Partitions:#\\n\");\n\ts_printf(txt_buf + strlen(txt_buf), \"1: #96FF00 BOOT0#  Size: %6d KiB  Sectors: 0x%08X\\n\", boot_size / 1024, boot_size / EMMC_BLOCKSIZE);\n\ts_printf(txt_buf + strlen(txt_buf), \"2: #96FF00 BOOT1#  Size: %6d KiB  Sectors: 0x%08X\\n\", boot_size / 1024, boot_size / EMMC_BLOCKSIZE);\n\ts_printf(txt_buf + strlen(txt_buf), \"3: #96FF00 RPMB#   Size: %6d KiB  Sectors: 0x%08X\\n\", rpmb_size / 1024, rpmb_size / EMMC_BLOCKSIZE);\n\ts_printf(txt_buf + strlen(txt_buf), \"0: #96FF00 GPP#    Size: %6d MiB  Sectors: 0x%08X\\n\", emmc_storage.sec_cnt >> SECTORS_TO_MIB_COEFF, emmc_storage.sec_cnt);\n\tstrcat(txt_buf, \"\\n#00DDFF GPP (eMMC USER) Partition Table:#\\n\");\n\n\temmc_set_partition(EMMC_GPP);\n\tLIST_INIT(gpt);\n\temmc_gpt_parse(&gpt);\n\n\tu32 idx = 0;\n\tint lines_left = 20;\n\ts_printf(txt_buf + strlen(txt_buf), \"#FFBA00 Idx Name                            Size     Offset    Sectors#\\n\");\n\tLIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)\n\t{\n\t\tint lines = strlen(part->name) > 25 ? 2 : 1;\n\t\tif ((lines_left - lines) <= 0)\n\t\t{\n\t\t\tstrcat(txt_buf, \"#FFDD00 Table does not fit on screen...#\");\n\t\t\tbreak;\n\t\t}\n\n\t\tif (lines == 2)\n\t\t{\n\t\t\ts_printf(txt_buf + strlen(txt_buf), \"%02d: #96FF00 %s#\\n                              %6d MiB  %8Xh  %8Xh\\n\",\n\t\t\t\tpart->index, part->name, (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF,\n\t\t\t\tpart->lba_start, part->lba_end - part->lba_start + 1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\ts_printf(txt_buf + strlen(txt_buf), \"%02d: #96FF00 %.25s# %6d MiB  %8Xh  %8Xh\\n\",\n\t\t\t\tpart->index, part->name, (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF,\n\t\t\t\tpart->lba_start, part->lba_end - part->lba_start + 1);\n\t\t}\n\n\t\tlines_left -= lines;\n\t\tidx++;\n\t}\n\tif (!idx)\n\t\tstrcat(txt_buf, \"#FFDD00 Partition table is empty!#\");\n\n\temmc_gpt_free(&gpt);\n\n\tlv_label_set_text(lb_desc2, txt_buf);\n\tlv_obj_set_width(lb_desc2, lv_obj_get_width(desc2));\n\tlv_obj_align(desc2, info, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 6, 0);\n\n\temmc_errors = emmc_get_error_count();\n\tif (emmc_get_mode() < EMMC_MMC_HS400  ||\n\t\temmc_errors[EMMC_ERROR_INIT_FAIL] ||\n\t\temmc_errors[EMMC_ERROR_RW_FAIL]   ||\n\t\temmc_errors[EMMC_ERROR_RW_RETRY])\n\t{\nout_error:\n\t\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\t\tlv_obj_set_style(dark_bg, &mbox_darken);\n\t\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\t\tstatic const char * mbox_btn_map[] = { \"\\251\", \"\\222OK\", \"\\251\", \"\" };\n\t\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\t\tlv_mbox_set_recolor_text(mbox, true);\n\n\t\ts_printf(txt_buf,\n\t\t\t\"#FF8000 eMMC Issues Warning#\\n\\n\"\n\t\t\t\"#FFDD00 Your eMMC is initialized in a slower mode,#\\n\"\n\t\t\t\"#FFDD00 or init/read/write errors occurred!#\\n\"\n\t\t\t\"#FFDD00 This might mean hardware issues!#\\n\\n\"\n\t\t\t\"#00DDFF Bus Speed:# %d MB/s\\n\\n\"\n\t\t\t\"#00DDFF SDMMC4 Errors:#\\n\"\n\t\t\t\"Init fails: %d\\n\"\n\t\t\t\"Read/Write fails: %d\\n\"\n\t\t\t\"Read/Write errors: %d\",\n\t\t\temmc_storage.csd.busspeed,\n\t\t\temmc_errors[EMMC_ERROR_INIT_FAIL],\n\t\t\temmc_errors[EMMC_ERROR_RW_FAIL],\n\t\t\temmc_errors[EMMC_ERROR_RW_RETRY]);\n\n\t\tlv_mbox_set_text(mbox, txt_buf);\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);\n\t\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);\n\t\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\t\tlv_obj_set_top(mbox, true);\n\t}\n\n\temmc_end();\n\tfree(txt_buf);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _create_window_sdcard_info_status(lv_obj_t *btn)\n{\n\tlv_obj_t *win = nyx_create_standard_window(SYMBOL_SD\" microSD Card Info\", NULL);\n\tlv_win_add_btn(win, NULL, SYMBOL_SD\" Benchmark\", _create_mbox_sd_bench);\n\n\tlv_obj_t *desc = lv_cont_create(win, NULL);\n\tlv_obj_set_size(desc, LV_HOR_RES / 2 / 6 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 5 / 2);\n\n\tlv_obj_t * lb_desc = lv_label_create(desc, NULL);\n\tlv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);\n\tlv_label_set_recolor(lb_desc, true);\n\n\tlv_label_set_text(lb_desc, \"#D4FF00 Please wait...#\");\n\tlv_obj_set_width(lb_desc, lv_obj_get_width(desc));\n\n\t// Disable buttons.\n\tnyx_window_toggle_buttons(win, true);\n\n\tmanual_system_maintenance(true);\n\n\tif (sd_mount())\n\t{\n\t\tlv_label_set_text(lb_desc, \"#FFDD00 Failed to init SD!#\");\n\t\tgoto failed;\n\t}\n\n\tlv_label_set_text(lb_desc,\n\t\t\"#00DDFF Card ID:#\\n\"\n\t\t\"Vendor ID:\\n\"\n\t\t\"Model:\\n\"\n\t\t\"OEM ID:\\n\"\n\t\t\"HW rev:\\n\"\n\t\t\"FW rev:\\n\"\n\t\t\"S/N:\\n\"\n\t\t\"Month/Year:\\n\\n\"\n\t\t\"Max Power:\\n\"\n\t\t\"Initial bus:\"\n\t);\n\n\tlv_obj_t *val = lv_cont_create(win, NULL);\n\tlv_obj_set_size(val, LV_HOR_RES / 12 * 3, LV_VER_RES - (LV_DPI * 11 / 8) * 5 / 2);\n\n\tlv_obj_t * lb_val = lv_label_create(val, lb_desc);\n\n\tchar *txt_buf = (char *)malloc(SZ_16K);\n\ttxt_buf[0] = '\\n';\n\ttxt_buf[1] = 0;\n\n\t// Identify manufacturer.\n\tswitch (sd_storage.cid.manfid)\n\t{\n\tcase 0x00:\n\t\tstrcat(txt_buf, \"#FFDD00 Fake# \");\n\t\tbreak;\n\tcase 0x01:\n\t\tstrcat(txt_buf, \"Panasonic \");\n\t\tbreak;\n\tcase 0x02:\n\t\tstrcat(txt_buf, \"Toshiba \");\n\t\tbreak;\n\tcase 0x03:\n\t\tif (!memcmp(&sd_storage.cid.oemid, \"DW\", 2))\n\t\t\tstrcat(txt_buf, \"Western Digital \"); // WD.\n\t\telse\n\t\t\tstrcat(txt_buf, \"SanDisk \");\n\t\tbreak;\n\tcase 0x06:\n\t\tstrcat(txt_buf, \"Ritek \");\n\t\tbreak;\n\tcase 0x09:\n\t\tstrcat(txt_buf, \"ATP \");\n\t\tbreak;\n\tcase 0x13:\n\t\tstrcat(txt_buf, \"Kingmax \");\n\t\tbreak;\n\tcase 0x19:\n\t\tstrcat(txt_buf, \"Dynacard \");\n\t\tbreak;\n\tcase 0x1A:\n\t\tstrcat(txt_buf, \"Power Quotient \");\n\t\tbreak;\n\tcase 0x1B:\n\t\tstrcat(txt_buf, \"Samsung \");\n\t\tbreak;\n\tcase 0x1D:\n\t\tstrcat(txt_buf, \"AData \");\n\t\tbreak;\n\tcase 0x27:\n\t\tstrcat(txt_buf, \"Phison \");\n\t\tbreak;\n\tcase 0x28:\n\t\tstrcat(txt_buf, \"Barun Electronics \");\n\t\tbreak;\n\tcase 0x31:\n\t\tstrcat(txt_buf, \"Silicon Power \");\n\t\tbreak;\n\tcase 0x41:\n\t\tstrcat(txt_buf, \"Kingston \");\n\t\tbreak;\n\tcase 0x51:\n\t\tstrcat(txt_buf, \"STEC \");\n\t\tbreak;\n\tcase 0x5D:\n\t\tstrcat(txt_buf, \"SwissBit \");\n\t\tbreak;\n\tcase 0x61:\n\t\tstrcat(txt_buf, \"Netlist \");\n\t\tbreak;\n\tcase 0x63:\n\t\tstrcat(txt_buf, \"Cactus \");\n\t\tbreak;\n\tcase 0x73:\n\t\tstrcat(txt_buf, \"Bongiovi \");\n\t\tbreak;\n\tcase 0x74:\n\t\tstrcat(txt_buf, \"Jiaelec \");\n\t\tbreak;\n\tcase 0x76:\n\t\tstrcat(txt_buf, \"Patriot \");\n\t\tbreak;\n\tcase 0x82:\n\t\tstrcat(txt_buf, \"Jiang Tay \");\n\t\tbreak;\n\tcase 0x83:\n\t\tstrcat(txt_buf, \"Netcom \");\n\t\tbreak;\n\tcase 0x84:\n\t\tstrcat(txt_buf, \"Strontium \");\n\t\tbreak;\n\tcase 0x9C:\n\t\tif (!memcmp(&sd_storage.cid.oemid, \"OS\", 2))\n\t\t\tstrcat(txt_buf, \"Sony \"); // SO.\n\t\telse\n\t\t\tstrcat(txt_buf, \"Barun Electronics \"); // BE.\n\t\tbreak;\n\tcase 0x9F:\n\t\tstrcat(txt_buf, \"Taishin \");\n\t\tbreak;\n\tcase 0xAD:\n\t\tstrcat(txt_buf, \"Longsys \");\n\t\tbreak;\n\tdefault:\n\t\tstrcat(txt_buf, \"Unknown \");\n\t\tbreak;\n\t}\n\n\t// UHS-I max power limit is 400mA, no matter what the card says.\n\tu32 max_power_nominal = sd_storage.max_power > 400 ? 400 : sd_storage.max_power;\n\n\ts_printf(txt_buf + strlen(txt_buf), \"(%02X)\\n%c%c%c%c%c\\n%c%c (%04X)\\n%X\\n%X\\n%08x\\n%02d/%04d\\n\\n%d mW (%d mA)\\n\",\n\t\tsd_storage.cid.manfid,\n\t\tsd_storage.cid.prod_name[0], sd_storage.cid.prod_name[1], sd_storage.cid.prod_name[2],\n\t\tsd_storage.cid.prod_name[3], sd_storage.cid.prod_name[4],\n\t\t(sd_storage.cid.oemid >> 8) & 0xFF, sd_storage.cid.oemid & 0xFF, sd_storage.cid.oemid,\n\t\tsd_storage.cid.hwrev, sd_storage.cid.fwrev, sd_storage.cid.serial,\n\t\tsd_storage.cid.month, sd_storage.cid.year,\n\t\tmax_power_nominal * 3600 / 1000, sd_storage.max_power);\n\n\tswitch (nyx_str->info.sd_init)\n\t{\n\tcase SD_1BIT_HS25:\n\t\tstrcat(txt_buf, \"HS25 1bit\");\n\t\tbreak;\n\tcase SD_4BIT_HS25:\n\t\tstrcat(txt_buf, \"HS25\");\n\t\tbreak;\n\tcase SD_UHS_SDR82: // Report as SDR104.\n\tcase SD_UHS_SDR104:\n\t\tstrcat(txt_buf, \"SDR104\");\n\t\tbreak;\n\tcase 0:\n\tdefault:\n\t\tstrcat(txt_buf, \"Undefined\");\n\t\tbreak;\n\t}\n\n\tlv_label_set_text(lb_val, txt_buf);\n\n\tlv_obj_set_width(lb_val, lv_obj_get_width(val));\n\tlv_obj_align(val, desc, LV_ALIGN_OUT_RIGHT_MID, 0, 0);\n\n\tlv_obj_t *desc2 = lv_cont_create(win, NULL);\n\tlv_obj_set_size(desc2, LV_HOR_RES / 2 / 11 * 5, LV_VER_RES - (LV_DPI * 11 / 8) * 5 / 2);\n\n\tlv_obj_t * lb_desc2 = lv_label_create(desc2, lb_desc);\n\n\tlv_label_set_static_text(lb_desc2,\n\t\t\"#00DDFF Card-Specific Data#\\n\"\n\t\t\"Cmd Classes:\\n\"\n\t\t\"Capacity:\\n\"\n\t\t\"Capacity (LBA):\\n\"\n\t\t\"Bus Width:\\n\"\n\t\t\"Current Rate:\\n\"\n\t\t\"Speed Class:\\n\"\n\t\t\"UHS Classes:\\n\"\n\t\t\"Max Bus Speed:\\n\\n\"\n\t\t\"Write Protect:\"\n\t);\n\tlv_obj_set_width(lb_desc2, lv_obj_get_width(desc2));\n\tlv_obj_align(desc2, val, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 5 * 3, 0);\n\n\tlv_obj_t *val2 = lv_cont_create(win, NULL);\n\tlv_obj_set_size(val2, LV_HOR_RES / 4, LV_VER_RES - (LV_DPI * 11 / 8) * 5 / 2);\n\n\tlv_obj_t * lb_val2 = lv_label_create(val2, lb_desc);\n\n\tchar *wp_info;\n\tswitch (sd_storage.csd.write_protect)\n\t{\n\tcase 1:\n\t\twp_info = \"Temporary\";\n\t\tbreak;\n\tcase 2:\n\tcase 3:\n\t\twp_info = \"Permanent\";\n\t\tbreak;\n\tdefault:\n\t\twp_info = \"None\";\n\t\tbreak;\n\t}\n\n\tbool uhs_au_mb = false;\n\tu32 uhs_au_size = sd_storage_get_ssr_au(&sd_storage);\n\tif (uhs_au_size >= 1024)\n\t{\n\t\tuhs_au_mb = true;\n\t\tuhs_au_size /= 1024;\n\t}\n\n\tsd_func_modes_t fmodes = { 0 };\n\tsd_storage_get_fmodes(&sd_storage, NULL, &fmodes);\n\n\tchar *bus_speed;\n\tif      (fmodes.cmd_system  & SD_MODE_UHS_DDR200)\n\t\tbus_speed = \"DDR200\";\n\telse if (fmodes.access_mode & SD_MODE_UHS_SDR104)\n\t\tbus_speed = \"SDR104\";\n\telse if (fmodes.access_mode & SD_MODE_UHS_SDR50)\n\t\tbus_speed = \"SDR50\";\n\telse if (fmodes.access_mode & SD_MODE_UHS_DDR50)\n\t\tbus_speed = \"DDR50\";\n\telse if (fmodes.access_mode & SD_MODE_UHS_SDR25)\n\t\tbus_speed = \"SDR25\";\n\telse\n\t\tbus_speed = \"SDR12\";\n\n\tchar *cpe = NULL;\n\tif (sd_storage.ssr.app_class == 2)\n\t{\n\t\tu8 *buf = zalloc(512);\n\n\t\t// Directly get and parse ext reg for performance enhance.\n\t\tsd_storage_parse_perf_enhance(&sd_storage, 2, 0, 0, buf);\n\n\t\tbool has_perf_enhance = sd_storage.ser.cache &&\n\t\t\t\t\t\t\tsd_storage.ser.cmdq  &&\n\t\t\t\t\t\t\tsd_storage.ser.cache == sd_storage.ser.cache_ext &&\n\t\t\t\t\t\t\tsd_storage.ser.cmdq  == sd_storage.ser.cmdq_ext;\n\t\tif (has_perf_enhance)\n\t\t\tcpe = \"#FFDD00 \"; // CMDQ/CACHE support via a quirk.\n\t\telse\n\t\t\tcpe = \"#FF3C28 \"; // Broken.\n\n\t\t// Get and parse ext reg for performance enhance in spec.\n\t\tsd_storage_get_ext_regs(&sd_storage, buf);\n\n\t\tif (sd_storage.ser.valid)\n\t\t{\n\t\t\thas_perf_enhance = sd_storage.ser.cache &&\n\t\t\t\t\t\t\t   sd_storage.ser.cmdq  &&\n\t\t\t\t\t\t\t   sd_storage.ser.cache == sd_storage.ser.cache_ext &&\n\t\t\t\t\t\t\t   sd_storage.ser.cmdq  == sd_storage.ser.cmdq_ext;\n\n\t\t\tif (has_perf_enhance)\n\t\t\t\tcpe = NULL; // CMDQ/CACHE support in spec.\n\t\t\telse\n\t\t\t\tcpe = \"#FF3C28 \"; // Broken.\n\t\t}\n\n\t\tfree(buf);\n\t}\n\n\ts_printf(txt_buf,\n\t\t\"#00DDFF v%d.0#\\n\"\n\t\t\"%02X\\n\"\n\t\t\"%d MiB\\n\"\n\t\t\"%X (CP %X)\\n\"\n\t\t\"%d\\n\"\n\t\t\"%d MB/s (%d MHz)\\n\"\n\t\t\"%d (AU: %d %s\\n\"\n\t\t\"U%d V%d %sA%d%s\\n\"\n\t\t\"%s\\n\\n\"\n\t\t\"%s\",\n\t\tsd_storage.csd.structure + 1,\n\t\tsd_storage.csd.cmdclass,\n\t\tsd_storage.sec_cnt >> 11,\n\t\tsd_storage.sec_cnt, sd_storage.ssr.protected_size >> 9,\n\t\tsd_storage.ssr.bus_width,\n\t\tsd_storage.csd.busspeed,\n\t\t(sd_storage.csd.busspeed > 10) ? (sd_storage.csd.busspeed * 2) : 50,\n\t\tsd_storage.ssr.speed_class, uhs_au_size, uhs_au_mb ? \"MiB)\" : \"KiB)\",\n\t\tsd_storage.ssr.uhs_grade, sd_storage.ssr.video_class, cpe ? cpe : \"\", sd_storage.ssr.app_class, cpe ? \"#\" : \"\",\n\t\tbus_speed,\n\t\twp_info);\n\n\tlv_label_set_text(lb_val2, txt_buf);\n\n\tlv_obj_set_width(lb_val2, lv_obj_get_width(val2));\n\tlv_obj_align(val2, desc2, LV_ALIGN_OUT_RIGHT_MID, 0, 0);\n\n\tlv_obj_t *line_sep = lv_line_create(win, NULL);\n\tstatic const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 12, 0} };\n\tlv_line_set_points(line_sep, line_pp, 2);\n\tlv_line_set_style(line_sep, lv_theme_get_current()->line.decor);\n\tlv_obj_align(line_sep, desc, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI * 410 / 100, LV_DPI / 7);\n\n\tlv_obj_t *desc3 = lv_cont_create(win, NULL);\n\tlv_obj_set_size(desc3, LV_HOR_RES / 2 / 2 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 4);\n\n\tlv_obj_t * lb_desc3 = lv_label_create(desc3, lb_desc);\n\tlv_label_set_text(lb_desc3, \"#D4FF00 Acquiring info...#\");\n\tlv_obj_set_width(lb_desc3, lv_obj_get_width(desc3));\n\n\tlv_obj_align(desc3, desc, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);\n\n\tmanual_system_maintenance(true);\n\n\tlv_obj_set_size(desc3, LV_HOR_RES / 2 / 6 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 4);\n\tlv_obj_align(desc3, desc, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);\n\n\tlv_obj_t *val3 = lv_cont_create(win, NULL);\n\tlv_obj_set_size(val3, LV_HOR_RES / 12 * 3, LV_VER_RES - (LV_DPI * 11 / 8) * 4);\n\n\tlv_obj_t * lb_val3 = lv_label_create(val3, lb_desc);\n\tlv_label_set_text(lb_val3, \"\");\n\n\tlv_obj_align(val3, desc3, LV_ALIGN_OUT_RIGHT_MID, 0, 0);\n\n\tlv_obj_t *desc4 = lv_cont_create(win, NULL);\n\tlv_obj_set_size(desc4, LV_HOR_RES / 2 / 2 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 4);\n\n\tlv_obj_t * lb_desc4 = lv_label_create(desc4, lb_desc);\n\tlv_label_set_text(lb_desc4, \"                             \");\n\tlv_obj_set_width(lb_desc4, lv_obj_get_width(desc4));\n\n\tlv_label_set_text(lb_desc4,\n\t\t\"#00DDFF SDMMC1 Errors:#\\n\"\n\t\t\"Init fails:\\n\"\n\t\t\"Read/Write fails:\\n\"\n\t\t\"Read/Write errors:\"\n\t);\n\tlv_obj_set_size(desc4, LV_HOR_RES / 2 / 11 * 5, LV_VER_RES - (LV_DPI * 11 / 8) * 4);\n\tlv_obj_set_width(lb_desc4, lv_obj_get_width(desc4));\n\tlv_obj_align(desc4, val3, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 5 * 3, 0);\n\n\tlv_obj_t *val4 = lv_cont_create(win, NULL);\n\tlv_obj_set_size(val4, LV_HOR_RES / 4, LV_VER_RES - (LV_DPI * 11 / 8) * 4);\n\n\tlv_obj_t *lb_val4 = lv_label_create(val4, lb_desc);\n\tbench_sd_err_label = lb_val4;\n\n\tu16 *sd_errors = sd_get_error_count();\n\ts_printf(txt_buf, \"\\n%d (%d)\\n%d (%d)\\n%d (%d)\",\n\t\tsd_errors[SD_ERROR_INIT_FAIL], nyx_str->info.sd_errors[SD_ERROR_INIT_FAIL],\n\t\tsd_errors[SD_ERROR_RW_FAIL],   nyx_str->info.sd_errors[SD_ERROR_RW_FAIL],\n\t\tsd_errors[SD_ERROR_RW_RETRY],  nyx_str->info.sd_errors[SD_ERROR_RW_RETRY]);\n\n\tlv_label_set_text(lb_val4, txt_buf);\n\n\tlv_obj_set_width(lb_val4, lv_obj_get_width(val4));\n\tlv_obj_align(val4, desc4, LV_ALIGN_OUT_RIGHT_MID, 0, 0);\n\n\tmanual_system_maintenance(true);\n\n\tf_getfree(\"\", &sd_fs.free_clst, NULL);\n\n\tlv_label_set_text(lb_desc3,\n\t\t\"#00DDFF Found FAT FS:#\\n\"\n\t\t\"Filesystem:\\n\"\n\t\t\"Cluster:\\n\"\n\t\t\"Size free/total:\"\n\t);\n\n\tlv_obj_set_width(lb_desc3, lv_obj_get_width(desc3));\n\n\ts_printf(txt_buf, \"\\n%s\\n%d %s\\n%d/%d MiB\",\n\t\tsd_fs.fs_type == FS_EXFAT ? (\"exFAT  \"SYMBOL_SHRK) : (\"FAT32\"),\n\t\t(sd_fs.csize > 1) ? (sd_fs.csize >> 1) : SD_BLOCKSIZE,\n\t\t(sd_fs.csize > 1) ? \"KiB\" : \"B\",\n\t\t(u32)(sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF),\n\t\t(u32)(sd_fs.n_fatent  * sd_fs.csize >> SECTORS_TO_MIB_COEFF));\n\n\tlv_label_set_text(lb_val3, txt_buf);\n\n\tlv_obj_set_width(lb_val3, lv_obj_get_width(val3));\n\n\tfree(txt_buf);\n\tsd_unmount();\n\nfailed:\n\tnyx_window_toggle_buttons(win, false);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _create_window_battery_status(lv_obj_t *btn)\n{\n\tlv_obj_t *win = nyx_create_standard_window(SYMBOL_BATTERY_FULL\" Battery Info\", NULL);\n\tlv_win_add_btn(win, NULL, SYMBOL_DOWNLOAD\" Dump Fuel Regs\", _battery_dump_window_action);\n\n\tlv_obj_t *desc = lv_cont_create(win, NULL);\n\tlv_obj_set_size(desc, LV_HOR_RES / 2 / 4 * 2, LV_VER_RES - (LV_DPI * 11 / 7) - 5);\n\n\tlv_obj_t * lb_desc = lv_label_create(desc, NULL);\n\tlv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);\n\tlv_label_set_recolor(lb_desc, true);\n\n\tlv_label_set_static_text(lb_desc,\n\t\t\"#00DDFF Fuel Gauge IC Info:#\\n\"\n\t\t\"Capacity now:\\n\"\n\t\t\"Capacity full:\\n\"\n\t\t\"Capacity (design):\\n\"\n\t\t\"Current now:\\n\"\n\t\t\"Current average:\\n\"\n\t\t\"Voltage now:\\n\"\n\t\t\"Voltage open-circuit:\\n\"\n\t\t\"Min voltage reached:\\n\"\n\t\t\"Max voltage reached:\\n\"\n\t\t\"Empty voltage:\\n\"\n\t\t\"Battery temp:\\n\\n\"\n\t\t\"#00DDFF PMIC IC Info:#\\n\"\n\t\t\"Main PMIC:\\n\\n\"\n\t\t\"CPU/GPU PMIC:\\n\"\n\t);\n\tlv_obj_set_width(lb_desc, lv_obj_get_width(desc));\n\n\tlv_obj_t *val = lv_cont_create(win, NULL);\n\tlv_obj_set_size(val, LV_HOR_RES / 5, LV_VER_RES - (LV_DPI * 11 / 7));\n\n\tlv_obj_t * lb_val = lv_label_create(val, lb_desc);\n\n\tchar *txt_buf = (char *)malloc(SZ_16K);\n\tint value = 0;\n\n\t// Fuel gauge IC info.\n\tif (!max17050_get_version(NULL))\n\t{\n\t\tint cap_pct = 0;\n\t\tmax17050_get_property(MAX17050_RepSOC, &cap_pct);\n\t\tmax17050_get_property(MAX17050_RepCap, &value);\n\t\ts_printf(txt_buf, \"\\n%d mAh [%d %%]\\n\", value, cap_pct >> 8);\n\n\t\tmax17050_get_property(MAX17050_FullCAP, &value);\n\t\ts_printf(txt_buf + strlen(txt_buf), \"%d mAh\\n\", value);\n\n\t\tmax17050_get_property(MAX17050_DesignCap, &value);\n\t\tbool design_cap_init = value == 1000;\n\t\ts_printf(txt_buf + strlen(txt_buf), \"%s%d mAh%s\\n\",\n\t\t\tdesign_cap_init ? \"#FF8000 \" : \"\", value,  design_cap_init ? \" - Init \"SYMBOL_WARNING\"#\" : \"\");\n\n\t\tmax17050_get_property(MAX17050_Current, &value);\n\t\ts_printf(txt_buf + strlen(txt_buf), \"%d mA\\n\", value / 1000);\n\n\t\tmax17050_get_property(MAX17050_AvgCurrent, &value);\n\t\ts_printf(txt_buf + strlen(txt_buf), \"%d mA\\n\", value / 1000);\n\n\t\tmax17050_get_property(MAX17050_VCELL, &value);\n\t\tbool voltage_empty = value < 3200;\n\t\ts_printf(txt_buf + strlen(txt_buf), \"%s%d mV%s\\n\",\n\t\t\tvoltage_empty ? \"#FF8000 \" : \"\", value,  voltage_empty ? \" - Low \"SYMBOL_WARNING\"#\" : \"\");\n\n\t\tmax17050_get_property(MAX17050_OCVInternal, &value);\n\t\ts_printf(txt_buf + strlen(txt_buf), \"%d mV\\n\", value);\n\n\t\tmax17050_get_property(MAX17050_MinVolt, &value);\n\t\ts_printf(txt_buf + strlen(txt_buf), \"%d mV\\n\", value);\n\n\t\tmax17050_get_property(MAX17050_MaxVolt, &value);\n\t\ts_printf(txt_buf + strlen(txt_buf), \"%d mV\\n\", value);\n\n\t\tmax17050_get_property(MAX17050_V_empty, &value);\n\t\ts_printf(txt_buf + strlen(txt_buf), \"%d mV\\n\", value);\n\n\t\tmax17050_get_property(MAX17050_TEMP, &value);\n\t\ts_printf(txt_buf + strlen(txt_buf), \"%d.%d oC\\n\\n\\n\", value / 10, (value >= 0 ? value : (~value + 1)) % 10);\n\t}\n\telse\n\t\tstrcpy(txt_buf, \"\\n#FF8000 \"SYMBOL_WARNING\" Error!#\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\");\n\n\t// Main Pmic IC info.\n\tvalue = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CID4);\n\tu32 main_pmic_version = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CID3) & 0xF;\n\n\tif (value == 0x35)\n\t\ts_printf(txt_buf + strlen(txt_buf), \"max77620 v%d\\nErista OTP\\n\", main_pmic_version);\n\telse if (value == 0x53)\n\t\ts_printf(txt_buf + strlen(txt_buf), \"max77620 v%d\\nMariko OTP\\n\", main_pmic_version);\n\telse\n\t\ts_printf(txt_buf + strlen(txt_buf), \"max77620 v%d\\n#FF8000 Unknown OTP# (%02X)\\n\", main_pmic_version, value);\n\n\t// CPU/GPU/DRAM Pmic IC info.\n\tu32 cpu_gpu_pmic_type = h_cfg.t210b01 ? (FUSE(FUSE_RESERVED_ODM28_B01) & 1) + 1 : 0;\n\tswitch (cpu_gpu_pmic_type)\n\t{\n\tcase 0:\n\t\ts_printf(txt_buf + strlen(txt_buf), \"max77621 v%d\",\n\t\t\ti2c_recv_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_REG_CHIPID1));\n\t\tbreak;\n\tcase 1:\n\t\ts_printf(txt_buf + strlen(txt_buf), \"max77812-2 v%d\",   // High power GPU. 2 Outputs, phases 3 1.\n\t\t\ti2c_recv_byte(I2C_5, MAX77812_PHASE31_CPU_I2C_ADDR, MAX77812_REG_VERSION) & 7);\n\t\tbreak;\n\tcase 2:\n\t\ts_printf(txt_buf + strlen(txt_buf), \"max77812-3 v%d.0\", // Low  power GPU. 3 Outputs, phases 2 1 1.\n\t\t\ti2c_recv_byte(I2C_5, MAX77812_PHASE211_CPU_I2C_ADDR, MAX77812_REG_VERSION) & 7);\n\t\tbreak;\n\t}\n\n\tlv_label_set_text(lb_val, txt_buf);\n\n\tlv_obj_set_width(lb_val, lv_obj_get_width(val));\n\tlv_obj_align(val, desc, LV_ALIGN_OUT_RIGHT_MID, 0, 0);\n\n\tlv_obj_t *desc2 = lv_cont_create(win, NULL);\n\tlv_obj_set_size(desc2, LV_HOR_RES / 2 / 7 * 4, LV_VER_RES - (LV_DPI * 11 / 7) - 5);\n\n\tlv_obj_t * lb_desc2 = lv_label_create(desc2, lb_desc);\n\n\tlv_label_set_static_text(lb_desc2,\n\t\t\"#00DDFF Battery Charger IC Info:#\\n\"\n\t\t\"Input current limit:\\n\"\n\t\t\"System voltage limit:\\n\"\n\t\t\"Charge current limit:\\n\"\n\t\t\"Charge voltage limit:\\n\"\n\t\t\"Charge status:\\n\"\n\t\t\"Temperature status:\\n\\n\"\n\t\t\"#00DDFF USB-PD IC Info:#\\n\"\n\t\t\"Connection status:\\n\"\n\t\t\"Input Wattage Limit:\\n\"\n\t\t\"USB-PD Profiles:\"\n\t);\n\tlv_obj_set_width(lb_desc2, lv_obj_get_width(desc2));\n\tlv_obj_align(desc2, val, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 2, 0);\n\n\tlv_obj_t *val2 = lv_cont_create(win, NULL);\n\tlv_obj_set_size(val2, LV_HOR_RES / 2 / 3, LV_VER_RES - (LV_DPI * 11 / 7) - 5);\n\n\tlv_obj_t * lb_val2 = lv_label_create(val2, lb_desc);\n\tint iinlim = 0;\n\n\t// Charger IC info.\n\tif (!bq24193_get_version(NULL))\n\t{\n\t\tbq24193_get_property(BQ24193_InputCurrentLimit, &iinlim);\n\t\ts_printf(txt_buf, \"\\n%d mA\\n\", iinlim);\n\n\t\tbq24193_get_property(BQ24193_SystemMinimumVoltage, &value);\n\t\ts_printf(txt_buf + strlen(txt_buf), \"%d mV\\n\", value);\n\n\t\tbq24193_get_property(BQ24193_FastChargeCurrentLimit, &value);\n\t\ts_printf(txt_buf + strlen(txt_buf), \"%d mA\\n\", value);\n\n\t\tbq24193_get_property(BQ24193_ChargeVoltageLimit, &value);\n\t\ts_printf(txt_buf + strlen(txt_buf), \"%d mV\\n\", value);\n\n\t\tbq24193_get_property(BQ24193_ChargeStatus, &value);\n\t\tswitch (value)\n\t\t{\n\t\tcase 0:\n\t\t\tstrcat(txt_buf, \"Not charging\\n\");\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tstrcat(txt_buf, \"Pre-charging\\n\");\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tstrcat(txt_buf, \"Fast charging\\n\");\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tstrcat(txt_buf, \"Charge terminated\\n\");\n\t\t\tbreak;\n\t\tdefault:\n\t\t\ts_printf(txt_buf + strlen(txt_buf), \"Unknown (%d)\\n\", value);\n\t\t\tbreak;\n\t\t}\n\n\t\tbq24193_get_property(BQ24193_TempStatus, &value);\n\t\tswitch (value)\n\t\t{\n\t\tcase 0:\n\t\t\tstrcat(txt_buf, \"Normal\");\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tstrcat(txt_buf, \"Warm\");\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tstrcat(txt_buf, \"Cool\");\n\t\t\tbreak;\n\t\tcase 5:\n\t\t\tstrcat(txt_buf, \"#FF8000 Cold#\");\n\t\t\tbreak;\n\t\tcase 6:\n\t\t\tstrcat(txt_buf, \"#FF8000 Hot#\");\n\t\t\tbreak;\n\t\tdefault:\n\t\t\ts_printf(txt_buf + strlen(txt_buf), \"Unknown (%d)\", value);\n\t\t\tbreak;\n\t\t}\n\t}\n\telse\n\t\tstrcpy(txt_buf, \"\\n#FF8000 \"SYMBOL_WARNING\" Error!#\\n\\n\\n\\n\\n\");\n\n\tstrcat(txt_buf, \"\\n\\n\\n\");\n\n\t// USB-PD IC info.\n\tif (!bm92t36_get_version(NULL))\n\t{\n\t\tbool inserted;\n\t\tu32 wattage = 0;\n\t\tusb_pd_objects_t usb_pd;\n\t\tbm92t36_get_source_info(&inserted, &usb_pd);\n\t\tstrcat(txt_buf, inserted ? \"Connected\" : \"Disconnected\");\n\n\t\t// Select 5V is no PD contract.\n\t\twattage = iinlim * (usb_pd.pdo_no ? usb_pd.selected_pdo.voltage : 5);\n\n\t\ts_printf(txt_buf + strlen(txt_buf), \"\\n%d.%d W\", wattage / 1000, (wattage % 1000) / 100);\n\n\t\tif (!usb_pd.pdo_no)\n\t\t\tstrcat(txt_buf, \"\\nNon PD\");\n\n\t\t// Show 6 profiles max so they can fit.\n\t\tusb_pd.pdo_no = MIN(usb_pd.pdo_no, 6);\n\t\tfor (u32 i = 0; i < usb_pd.pdo_no; i++)\n\t\t{\n\t\t\tbool selected =\n\t\t\t\tusb_pd.pdos[i].amperage == usb_pd.selected_pdo.amperage &&\n\t\t\t\tusb_pd.pdos[i].voltage == usb_pd.selected_pdo.voltage;\n\t\t\ts_printf(txt_buf + strlen(txt_buf), \"\\n%s%d mA, %2d V%s\",\n\t\t\t\tselected ? \"#D4FF00 \" : \"\",\n\t\t\t\tusb_pd.pdos[i].amperage, usb_pd.pdos[i].voltage,\n\t\t\t\tselected ? \"#\" : \"\");\n\t\t}\n\t}\n\telse\n\t\tstrcat(txt_buf, \"#FF8000 \"SYMBOL_WARNING\" Error!#\");\n\n\tlv_label_set_text(lb_val2, txt_buf);\n\n\tlv_obj_set_width(lb_val2, lv_obj_get_width(val2));\n\tlv_obj_align(val2, desc2, LV_ALIGN_OUT_RIGHT_MID, 0, 0);\n\n\tfree(txt_buf);\n\n\treturn LV_RES_OK;\n}\n\nstatic bool _lockpick_exists_check()\n{\n\t#define LOCKPICK_MAGIC_OFFSET   0x118\n\t#define LOCKPICK_VERSION_OFFSET 0x11C\n\t#define LOCKPICK_MAGIC          0x4B434F4C // LOCK.\n\t#define LOCKPICK_MIN_VERSION    0x1090500  // 1.9.5.\n\n\tbool found = false;\n\tvoid *buf = malloc(0x200);\n\tif (!sd_mount())\n\t{\n\t\tFIL fp;\n\t\tif (f_open(&fp, \"bootloader/payloads/Lockpick_RCM.bin\", FA_READ))\n\t\t\tgoto out;\n\n\t\t// Read Lockpick payload and check versioning.\n\t\tif (f_read(&fp, buf, 0x200, NULL))\n\t\t{\n\t\t\tf_close(&fp);\n\n\t\t\tgoto out;\n\t\t}\n\n\t\tu32 magic = *(u32 *)(buf + LOCKPICK_MAGIC_OFFSET);\n\t\tu32 version = byte_swap_32(*(u32 *)(buf + LOCKPICK_VERSION_OFFSET) - 0x303030);\n\n\t\tif (magic == LOCKPICK_MAGIC && version >= LOCKPICK_MIN_VERSION)\n\t\t\tfound = true;\n\n\t\tf_close(&fp);\n\t}\n\nout:\n\tfree(buf);\n\tsd_unmount();\n\n\treturn found;\n}\n\nvoid create_tab_info(lv_theme_t *th, lv_obj_t *parent)\n{\n\tlv_page_set_scrl_layout(parent, LV_LAYOUT_PRETTY);\n\n\tstatic lv_style_t h_style;\n\tlv_style_copy(&h_style, &lv_style_transp);\n\th_style.body.padding.inner = 0;\n\th_style.body.padding.hor = LV_DPI - (LV_DPI / 4);\n\th_style.body.padding.ver = LV_DPI / 6;\n\n\t// Create SoC Info container.\n\tlv_obj_t *h1 = lv_cont_create(parent, NULL);\n\tlv_cont_set_style(h1, &h_style);\n\tlv_cont_set_fit(h1, false, true);\n\tlv_obj_set_width(h1, (LV_HOR_RES / 9) * 4);\n\tlv_obj_set_click(h1, false);\n\tlv_cont_set_layout(h1, LV_LAYOUT_OFF);\n\n\tlv_obj_t *label_sep = lv_label_create(h1, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\tlv_obj_t *label_txt = lv_label_create(h1, NULL);\n\tlv_label_set_static_text(label_txt, \"SoC & HW Info\");\n\tlv_obj_set_style(label_txt, th->label.prim);\n\tlv_obj_align(label_txt, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, 0);\n\n\tlv_obj_t *line_sep = lv_line_create(h1, NULL);\n\tstatic const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 2, 0} };\n\tlv_line_set_points(line_sep, line_pp, 2);\n\tlv_line_set_style(line_sep, th->line.decor);\n\tlv_obj_align(line_sep, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);\n\n\t// Create Bootrom button.\n\tlv_obj_t *btn = lv_btn_create(h1, NULL);\n\tif (hekate_bg)\n\t{\n\t\tlv_btn_set_style(btn, LV_BTN_STYLE_REL, &btn_transp_rel);\n\t\tlv_btn_set_style(btn, LV_BTN_STYLE_PR,  &btn_transp_pr);\n\t\tlv_btn_set_style(btn, LV_BTN_STYLE_INA, &btn_transp_ina);\n\t}\n\tlv_obj_t *label_btn = lv_label_create(btn, NULL);\n\tlv_btn_set_fit(btn, true, true);\n\tlv_label_set_static_text(label_btn, SYMBOL_CHIP\"  Bootrom\");\n\tlv_obj_align(btn, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);\n\tlv_btn_set_action(btn, LV_BTN_ACTION_CLICK, _create_window_bootrom_info_status);\n\n\t// Create TSEC Keys button.\n\tlv_obj_t *btn2 = lv_btn_create(h1, btn);\n\tlabel_btn = lv_label_create(btn2, NULL);\n\tlv_label_set_static_text(label_btn, SYMBOL_KEY\"  Lockpick\");\n\tlv_obj_align(btn2, btn, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 11 / 15, 0);\n\tlv_btn_set_action(btn2, LV_BTN_ACTION_CLICK, _create_mbox_lockpick);\n\n\tbool lockpick_found = _lockpick_exists_check();\n\tif (!lockpick_found)\n\t\tlv_btn_set_state(btn2, LV_BTN_STATE_INA);\n\n\tlv_obj_t *label_txt2 = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(label_txt2, true);\n\n\tif (lockpick_found)\n\t{\n\t\tlv_label_set_static_text(label_txt2,\n\t\t\t\"View Ipatches and dump the unpatched and patched versions\\nof BootROM.\\n\"\n\t\t\t\"Or dump every single key via #C7EA46 Lockpick RCM#.\\n\");\n\t}\n\telse\n\t{\n\t\tlv_label_set_static_text(label_txt2,\n\t\t\t\"View Ipatches and dump the unpatched and patched versions\\nof BootROM. Or dump every single key via #C7EA46 Lockpick RCM#.\\n\"\n\t\t\t\"#FFDD00 bootloader/payloads/Lockpick_RCM.bin is missing or old!#\\n\");\n\t}\n\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, btn, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\tstatic lv_style_t line_style;\n\tlv_style_copy(&line_style, th->line.decor);\n\tline_style.line.color = LV_COLOR_HEX(theme_bg_color ? (theme_bg_color + 0x171717) : 0x343434);\n\n\tline_sep = lv_line_create(h1, line_sep);\n\tlv_obj_align(line_sep, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 16);\n\tlv_line_set_style(line_sep, &line_style);\n\n\t// Create HW info button.\n\tlv_obj_t *btn3 = lv_btn_create(h1, btn);\n\tlabel_btn = lv_label_create(btn3, NULL);\n\tlv_btn_set_fit(btn3, true, true);\n\tlv_label_set_static_text(label_btn, SYMBOL_CIRCUIT\"  HW & Fuses\");\n\tlv_obj_align(btn3, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 2);\n\tlv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, _create_window_hw_info_status);\n\n\t// Create KFuses button.\n\tlv_obj_t *btn4 = lv_btn_create(h1, btn);\n\tlabel_btn = lv_label_create(btn4, NULL);\n\tlv_label_set_static_text(label_btn, SYMBOL_SHUFFLE\"  KFuses\");\n\tlv_obj_align(btn4, btn3, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 46 / 100, 0);\n\tlv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, _kfuse_dump_window_action);\n\n\tlv_obj_t *label_txt4 = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(label_txt4, true);\n\tlv_label_set_static_text(label_txt4,\n\t\t\"View and dump the cached #C7EA46 Fuses# and #C7EA46 KFuses#.\\n\"\n\t\t\"Fuses contain info about the SoC/SKU and KFuses HDCP keys.\\n\"\n\t\t\"You can also see info about #C7EA46 DRAM#, #C7EA46 Screen# and #C7EA46 Touch panel#.\");\n\tlv_obj_set_style(label_txt4, &hint_small_style);\n\tlv_obj_align(label_txt4, btn3, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\t// Create Storage & Battery Info container.\n\tlv_obj_t *h2 = lv_cont_create(parent, NULL);\n\tlv_cont_set_style(h2, &h_style);\n\tlv_cont_set_fit(h2, false, true);\n\tlv_obj_set_width(h2, (LV_HOR_RES / 9) * 4);\n\tlv_obj_set_click(h2, false);\n\tlv_cont_set_layout(h2, LV_LAYOUT_OFF);\n\tlv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, 0, 0);\n\n\tlabel_sep = lv_label_create(h2, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\tlv_obj_t *label_txt3 = lv_label_create(h2, NULL);\n\tlv_label_set_static_text(label_txt3, \"Storage & Battery Info\");\n\tlv_obj_set_style(label_txt3, th->label.prim);\n\tlv_obj_align(label_txt3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, 0);\n\n\tline_sep = lv_line_create(h2, line_sep);\n\tlv_obj_align(line_sep, label_txt3, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 2), LV_DPI / 8);\n\tlv_line_set_style(line_sep, th->line.decor);\n\n\t// Create eMMC button.\n\tlv_obj_t *btn5 = lv_btn_create(h2, NULL);\n\tif (hekate_bg)\n\t{\n\t\tlv_btn_set_style(btn5, LV_BTN_STYLE_REL, &btn_transp_rel);\n\t\tlv_btn_set_style(btn5, LV_BTN_STYLE_PR, &btn_transp_pr);\n\t}\n\tlabel_btn = lv_label_create(btn5, NULL);\n\tlv_btn_set_fit(btn5, true, true);\n\tlv_label_set_static_text(label_btn, SYMBOL_CHIP\"  eMMC  \");\n\tlv_obj_align(btn5, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 2, LV_DPI / 4);\n\tlv_btn_set_action(btn5, LV_BTN_ACTION_CLICK, _create_window_emmc_info_status);\n\n\t// Create microSD button.\n\tlv_obj_t *btn6 = lv_btn_create(h2, btn);\n\tlabel_btn = lv_label_create(btn6, NULL);\n\tlv_label_set_static_text(label_btn, SYMBOL_SD\"  microSD \");\n\tlv_obj_align(btn6, btn5, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 3 / 4, 0);\n\tlv_btn_set_action(btn6, LV_BTN_ACTION_CLICK, _create_window_sdcard_info_status);\n\n\tlv_obj_t *label_txt5 = lv_label_create(h2, NULL);\n\tlv_label_set_recolor(label_txt5, true);\n\tlv_label_set_static_text(label_txt5,\n\t\t\"View info about the eMMC or microSD and their partition list.\\n\"\n\t\t\"Additionally you can benchmark read speeds.\");\n\tlv_obj_set_style(label_txt5, &hint_small_style);\n\tlv_obj_align(label_txt5, btn5, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\tline_sep = lv_line_create(h2, line_sep);\n\tlv_obj_align(line_sep, label_txt5, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 2);\n\tlv_line_set_style(line_sep, &line_style);\n\n\t// Create Battery button.\n\tlv_obj_t *btn7 = lv_btn_create(h2, NULL);\n\tif (hekate_bg)\n\t{\n\t\tlv_btn_set_style(btn7, LV_BTN_STYLE_REL, &btn_transp_rel);\n\t\tlv_btn_set_style(btn7, LV_BTN_STYLE_PR, &btn_transp_pr);\n\t}\n\tlabel_btn = lv_label_create(btn7, NULL);\n\tlv_btn_set_fit(btn7, true, true);\n\tlv_label_set_static_text(label_btn, SYMBOL_BATTERY_FULL\"  Battery\");\n\tlv_obj_align(btn7, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 2);\n\tlv_btn_set_action(btn7, LV_BTN_ACTION_CLICK, _create_window_battery_status);\n\n\tlv_obj_t *label_txt6 = lv_label_create(h2, NULL);\n\tlv_label_set_recolor(label_txt6, true);\n\tlv_label_set_static_text(label_txt6,\n\t\t\"View battery and battery charger related info.\\n\"\n\t\t\"Additionally you can dump battery charger's registers.\\n\");\n\tlv_obj_set_style(label_txt6, &hint_small_style);\n\tlv_obj_align(label_txt6, btn7, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n}\n"
  },
  {
    "path": "nyx/nyx_gui/frontend/gui_info.h",
    "content": "/*\n * Copyright (c) 2018-2021 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _GUI_INFO_H_\n#define _GUI_INFO_H_\n\n#include <libs/lvgl/lvgl.h>\n\nvoid create_tab_info(lv_theme_t *th, lv_obj_t *parent);\nint  dump_cal0();\n\n#endif\n"
  },
  {
    "path": "nyx/nyx_gui/frontend/gui_options.c",
    "content": "/*\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <stdlib.h>\n\n#include <bdk.h>\n\n#include \"gui.h\"\n#include \"gui_info.h\"\n#include \"../config.h\"\n#include <libs/lvgl/lv_themes/lv_theme_hekate.h>\n#include <libs/lvgl/lvgl.h>\n\n#define CLOCK_MIN_YEAR 2025\n#define CLOCK_MAX_YEAR (CLOCK_MIN_YEAR + 10)\n#define CLOCK_YEARLIST \"2025\\n2026\\n2027\\n2028\\n2029\\n2030\\n2031\\n2032\\n2033\\n2034\\n2035\"\n\nstatic lv_obj_t *autoboot_btn;\nstatic bool autoboot_first_time = true;\n\nstatic bool ini_changes_made = false;\nstatic bool nyx_changes_made = false;\n\nvoid nyx_options_clear_ini_changes_made()\n{\n\tini_changes_made = false;\n}\n\nbool nyx_options_get_ini_changes_made()\n{\n\treturn ini_changes_made;\n}\n\nstatic lv_res_t auto_hos_poweroff_toggle(lv_obj_t *btn)\n{\n\th_cfg.autohosoff = !h_cfg.autohosoff;\n\tini_changes_made = true;\n\n\tif (!h_cfg.autohosoff)\n\t\tlv_btn_set_state(btn, LV_BTN_STATE_REL);\n\telse\n\t\tlv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);\n\n\tnyx_generic_onoff_toggle(btn);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t auto_nogc_toggle(lv_obj_t *btn)\n{\n\th_cfg.autonogc = !h_cfg.autonogc;\n\tini_changes_made = true;\n\n\tif (!h_cfg.autonogc)\n\t\tlv_btn_set_state(btn, LV_BTN_STATE_REL);\n\telse\n\t\tlv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);\n\n\tnyx_generic_onoff_toggle(btn);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _update_r2p_action(lv_obj_t *btn)\n{\n\th_cfg.updater2p = !h_cfg.updater2p;\n\tini_changes_made = true;\n\n\tif (!h_cfg.updater2p)\n\t\tlv_btn_set_state(btn, LV_BTN_STATE_REL);\n\telse\n\t\tlv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);\n\n\tnyx_generic_onoff_toggle(btn);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _win_autoboot_close_action(lv_obj_t * btn)\n{\n\tif (!h_cfg.autoboot)\n\t\tlv_btn_set_state(autoboot_btn, LV_BTN_STATE_REL);\n\telse\n\t\tlv_btn_set_state(autoboot_btn, LV_BTN_STATE_TGL_REL);\n\n\tnyx_generic_onoff_toggle(autoboot_btn);\n\n\tlv_obj_t * win = lv_win_get_from_btn(btn);\n\n\tlv_obj_del(win);\n\n\tclose_btn = NULL;\n\n\treturn LV_RES_INV;\n}\n\nlv_obj_t *create_window_autoboot(const char *win_title)\n{\n\tstatic lv_style_t win_bg_style;\n\n\tlv_style_copy(&win_bg_style, &lv_style_plain);\n\twin_bg_style.body.main_color = LV_COLOR_HEX(theme_bg_color);\n\twin_bg_style.body.grad_color = win_bg_style.body.main_color;\n\n\tlv_obj_t *win = lv_win_create(lv_scr_act(), NULL);\n\tlv_win_set_title(win, win_title);\n\tlv_win_set_style(win, LV_WIN_STYLE_BG, &win_bg_style);\n\tlv_obj_set_size(win, LV_HOR_RES, LV_VER_RES);\n\n\tclose_btn = lv_win_add_btn(win, NULL, SYMBOL_CLOSE\" Close\", _win_autoboot_close_action);\n\n\treturn win;\n}\n\nstatic lv_res_t _autoboot_disable_action(lv_obj_t *btn)\n{\n\th_cfg.autoboot = 0;\n\th_cfg.autoboot_list = 0;\n\tini_changes_made = true;\n\n\tlv_btn_set_state(autoboot_btn, LV_BTN_STATE_REL);\n\tnyx_generic_onoff_toggle(autoboot_btn);\n\n\tlv_obj_t * win = lv_win_get_from_btn(btn);\n\n\tlv_obj_del(win);\n\n\tclose_btn = NULL;\n\n\treturn LV_RES_OK;\n}\n\nlv_obj_t *auto_main_list;\nlv_obj_t *auto_more_list;\nstatic lv_res_t _autoboot_enable_main_action(lv_obj_t *btn)\n{\n\th_cfg.autoboot = lv_list_get_btn_index(auto_main_list, btn) + 1;\n\th_cfg.autoboot_list = 0;\n\tini_changes_made = true;\n\n\tlv_btn_set_state(autoboot_btn, LV_BTN_STATE_TGL_REL);\n\tnyx_generic_onoff_toggle(autoboot_btn);\n\n\tlv_obj_t *obj = lv_obj_get_parent(btn);\n\tfor (int i = 0; i < 5; i++)\n\t\tobj = lv_obj_get_parent(obj);\n\tlv_obj_del(obj);\n\n\tclose_btn = NULL;\n\n\treturn LV_RES_INV;\n}\n\nstatic lv_res_t _autoboot_enable_more_action(lv_obj_t *btn)\n{\n\th_cfg.autoboot = lv_list_get_btn_index(auto_more_list, btn) + 1;\n\th_cfg.autoboot_list = 1;\n\tini_changes_made = true;\n\n\tlv_btn_set_state(autoboot_btn, LV_BTN_STATE_TGL_REL);\n\tnyx_generic_onoff_toggle(autoboot_btn);\n\n\tlv_obj_t *obj = lv_obj_get_parent(btn);\n\tfor (int i = 0; i < 5; i++)\n\t\tobj = lv_obj_get_parent(obj);\n\tlv_obj_del(obj);\n\n\tclose_btn = NULL;\n\n\treturn LV_RES_INV;\n}\n\nstatic void _create_autoboot_window()\n{\n\tlv_obj_t *win = create_window_autoboot(SYMBOL_GPS\" Auto Boot\");\n\tlv_win_add_btn(win, NULL, SYMBOL_POWER\" Disable\", _autoboot_disable_action);\n\n\tstatic lv_style_t h_style;\n\tlv_style_copy(&h_style, &lv_style_transp);\n\th_style.body.padding.inner = 0;\n\th_style.body.padding.hor = LV_DPI - (LV_DPI / 4);\n\th_style.body.padding.ver = LV_DPI / 6;\n\n\t// Main configurations container.\n\tlv_obj_t *h1 = lv_cont_create(win, NULL);\n\tlv_cont_set_style(h1, &h_style);\n\tlv_cont_set_fit(h1, false, true);\n\tlv_obj_set_width(h1, (LV_HOR_RES / 9) * 4);\n\tlv_obj_set_click(h1, false);\n\tlv_cont_set_layout(h1, LV_LAYOUT_OFF);\n\n\tlv_obj_t *label_sep = lv_label_create(h1, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\tlv_obj_t *label_txt = lv_label_create(h1, NULL);\n\tlv_label_set_static_text(label_txt, \"Main configurations\");\n\tlv_obj_set_style(label_txt, lv_theme_get_current()->label.prim);\n\tlv_obj_align(label_txt, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -(LV_DPI / 4));\n\n\tlv_obj_t *line_sep = lv_line_create(h1, NULL);\n\tstatic const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 2, 0} };\n\tlv_line_set_points(line_sep, line_pp, 2);\n\tlv_line_set_style(line_sep, lv_theme_get_current()->line.decor);\n\tlv_obj_align(line_sep, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);\n\n\t// Create list and populate it with Main boot entries.\n\tlv_obj_t *list_main = lv_list_create(h1, NULL);\n\tauto_main_list = list_main;\n\tlv_obj_align(list_main, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);\n\n\tlv_obj_set_size(list_main, LV_HOR_RES * 4 / 10, LV_VER_RES * 4 / 7);\n\tlv_list_set_single_mode(list_main, true);\n\n\tsd_mount();\n\n\t// Parse hekate main configuration.\n\tLIST_INIT(ini_sections);\n\tif (!ini_parse(&ini_sections, \"bootloader/hekate_ipl.ini\", false))\n\t{\n\t\tLIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)\n\t\t{\n\t\t\tif (!strcmp(ini_sec->name, \"config\") || (ini_sec->type != INI_CHOICE))\n\t\t\t\tcontinue;\n\n\t\t\tlv_list_add(list_main, NULL, ini_sec->name, _autoboot_enable_main_action);\n\t\t}\n\n\t\tini_free(&ini_sections);\n\t}\n\n\t// More configuration container.\n\tlv_obj_t *h2 = lv_cont_create(win, NULL);\n\tlv_cont_set_style(h2, &h_style);\n\tlv_cont_set_fit(h2, false, true);\n\tlv_obj_set_width(h2, (LV_HOR_RES / 9) * 4);\n\tlv_obj_set_click(h2, false);\n\tlv_cont_set_layout(h2, LV_LAYOUT_OFF);\n\tlv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 17 / 29, 0);\n\n\tlabel_sep = lv_label_create(h2, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\tlv_obj_t *label_txt3 = lv_label_create(h2, NULL);\n\tlv_label_set_static_text(label_txt3, \"Ini folder configurations\");\n\tlv_obj_set_style(label_txt3, lv_theme_get_current()->label.prim);\n\tlv_obj_align(label_txt3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI / 11);\n\n\tline_sep = lv_line_create(h2, line_sep);\n\tlv_obj_align(line_sep, label_txt3, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 2), LV_DPI / 8);\n\tlv_line_set_style(line_sep, lv_theme_get_current()->line.decor);\n\n\t// Create list and populate it with more cfg boot entries.\n\tlv_obj_t *list_more_cfg = lv_list_create(h2, NULL);\n\tauto_more_list = list_more_cfg;\n\tlv_obj_align(list_more_cfg, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 2, LV_DPI / 4);\n\n\tlv_obj_set_size(list_more_cfg, LV_HOR_RES * 4 / 10, LV_VER_RES * 4 / 7);\n\tlv_list_set_single_mode(list_more_cfg, true);\n\n\t// Parse all .ini files in ini folder.\n\tLIST_INIT(ini_list_sections);\n\tif (!ini_parse(&ini_list_sections, \"bootloader/ini\", true))\n\t{\n\t\tLIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_list_sections, link)\n\t\t{\n\t\t\tif (!strcmp(ini_sec->name, \"config\") || (ini_sec->type != INI_CHOICE))\n\t\t\t\tcontinue;\n\n\t\t\tlv_list_add(list_more_cfg, NULL, ini_sec->name, _autoboot_enable_more_action);\n\t\t}\n\n\t\tini_free(&ini_list_sections);\n\t}\n\n\tsd_unmount();\n}\n\nstatic lv_res_t _autoboot_hide_delay_action(lv_obj_t *btn)\n{\n\tif (!autoboot_first_time)\n\t\t_create_autoboot_window();\n\n\tif (!h_cfg.autoboot && autoboot_first_time)\n\t\tlv_btn_set_state(btn, LV_BTN_STATE_REL);\n\telse\n\t\tlv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);\n\tautoboot_first_time = false;\n\n\tnyx_generic_onoff_toggle(btn);\n\n\treturn LV_RES_INV;\n}\n\nstatic lv_res_t _autoboot_delay_action(lv_obj_t *ddlist)\n{\n\tu32 new_selection = lv_ddlist_get_selected(ddlist);\n\tif (h_cfg.bootwait != new_selection)\n\t{\n\t\th_cfg.bootwait = new_selection;\n\t\tini_changes_made = true;\n\t}\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _slider_brightness_action(lv_obj_t * slider)\n{\n\tdisplay_backlight_brightness(lv_slider_get_value(slider) - 20, 0);\n\th_cfg.backlight = lv_slider_get_value(slider);\n\tini_changes_made = true;\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _data_verification_action(lv_obj_t *ddlist)\n{\n\tu32 new_selection = lv_ddlist_get_selected(ddlist);\n\tif (n_cfg.verification != new_selection)\n\t{\n\t\tn_cfg.verification = new_selection;\n\t\tnyx_changes_made = true;\n\t}\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _entries_columns_action(lv_obj_t *btn)\n{\n\tn_cfg.entries_5_col = !n_cfg.entries_5_col;\n\tnyx_changes_made = true;\n\n\tif (!n_cfg.entries_5_col)\n\t\tlv_btn_set_state(btn, LV_BTN_STATE_REL);\n\telse\n\t\tlv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);\n\n\tnyx_generic_onoff_toggle(btn);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _save_nyx_options_action(lv_obj_t *btn)\n{\n\tstatic const char * mbox_btn_map[] = {\"\\251\", \"\\222OK!\", \"\\251\", \"\"};\n\tlv_obj_t * mbox = lv_mbox_create(lv_scr_act(), NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\n\tint res = !create_nyx_config_entry(true);\n\n\tnyx_changes_made = false;\n\n\tif (res)\n\t\tlv_mbox_set_text(mbox, \"#FF8000 Nyx Configuration#\\n\\n#96FF00 The configuration was saved to sd card!#\");\n\telse\n\t\tlv_mbox_set_text(mbox, \"#FF8000 Nyx Configuration#\\n\\n#FFDD00 Failed to save the configuration#\\n#FFDD00 to sd card!#\");\n\tlv_mbox_add_btns(mbox, mbox_btn_map, NULL);\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\treturn LV_RES_OK;\n}\n\nvoid create_flat_button(lv_obj_t *btn, int color_idx, lv_action_t action)\n{\n\tlv_color_t color = color_idx ? lv_color_hsv_to_rgb(color_idx, 100, 100) : lv_color_hsv_to_rgb(53, 8, 90);\n\tlv_style_t *btn_onoff_rel_hos_style = malloc(sizeof(lv_style_t));\n\tlv_style_t *btn_onoff_pr_hos_style  = malloc(sizeof(lv_style_t));\n\tlv_style_copy(btn_onoff_rel_hos_style, lv_theme_get_current()->btn.rel);\n\tbtn_onoff_rel_hos_style->body.main_color  = color;\n\tbtn_onoff_rel_hos_style->body.grad_color  = btn_onoff_rel_hos_style->body.main_color;\n\tbtn_onoff_rel_hos_style->body.padding.hor = 0;\n\tbtn_onoff_rel_hos_style->body.radius      = 0;\n\n\tif (color_idx == 167)\n\t{\n\t\tbtn_onoff_rel_hos_style->body.border.color = LV_COLOR_HEX(0x000000);\n\t\tbtn_onoff_rel_hos_style->body.border.opa = LV_OPA_20;\n\t\tbtn_onoff_rel_hos_style->body.border.width = 3;\n\t}\n\n\tlv_style_copy(btn_onoff_pr_hos_style, lv_theme_get_current()->btn.pr);\n\tbtn_onoff_pr_hos_style->body.main_color   = color;\n\tbtn_onoff_pr_hos_style->body.grad_color   = btn_onoff_pr_hos_style->body.main_color;\n\tbtn_onoff_pr_hos_style->body.padding.hor  = 0;\n\tbtn_onoff_pr_hos_style->body.border.color = LV_COLOR_HEX(0xFFFFFF);\n\tbtn_onoff_pr_hos_style->body.border.opa   = LV_OPA_50;\n\tbtn_onoff_pr_hos_style->body.border.width = 4;\n\tbtn_onoff_pr_hos_style->body.radius       = 0;\n\n\tlv_btn_set_style(btn, LV_BTN_STYLE_REL,     btn_onoff_rel_hos_style);\n\tlv_btn_set_style(btn, LV_BTN_STYLE_PR,      btn_onoff_pr_hos_style);\n\tlv_btn_set_style(btn, LV_BTN_STYLE_TGL_REL, btn_onoff_rel_hos_style);\n\tlv_btn_set_style(btn, LV_BTN_STYLE_TGL_PR,  btn_onoff_pr_hos_style);\n\n\tlv_btn_set_fit(btn, false, false);\n\tlv_obj_set_size(btn, LV_DPI * 7 / 11, LV_DPI * 7 / 11);\n\tlv_btn_set_toggle(btn, true);\n\n\tif (action)\n\t\tlv_btn_set_action(btn, LV_BTN_ACTION_CLICK, action);\n}\n\ntypedef struct _color_test_ctxt\n{\n\tu32 bg;\n\tu16 hue;\n\tu8 r;\n\tu8 g;\n\tu8 b;\n\n\tlv_obj_t *window;\n\tlv_obj_t *header1;\n\tlv_obj_t *header2;\n\tlv_obj_t *label;\n\tlv_obj_t *icons;\n\tlv_obj_t *slider;\n\tlv_obj_t *button;\n\tlv_obj_t *hue_slider;\n\tlv_obj_t *hue_label;\n\n\tlv_obj_t *r_slider;\n\tlv_obj_t *r_label;\n\tlv_obj_t *g_slider;\n\tlv_obj_t *g_label;\n\tlv_obj_t *b_slider;\n\tlv_obj_t *b_label;\n\n\tlv_style_t box_style;\n\tlv_obj_t *box;\n\n\tlv_obj_t *btn_reset;\n\tlv_obj_t *btn_apply;\n\tlv_obj_t *btn_black;\n} color_test_ctxt;\n\ncolor_test_ctxt color_test;\n\nstatic lv_res_t _action_win_nyx_colors_save(lv_obj_t *btn)\n{\n\tn_cfg.theme_bg    = color_test.bg;\n\tn_cfg.theme_color = color_test.hue;\n\n\t// Save nyx config.\n\tcreate_nyx_config_entry(true);\n\n\treload_nyx(NULL, false);\n\n\treturn LV_RES_OK;\n}\n\nstatic void _show_new_nyx_color(bool update_bg)\n{\n\tu32 bg = color_test.bg;\n\tu16 hue = color_test.hue;\n\n\tlv_color_t bgc       = LV_COLOR_HEX(bg);                              // COLOR_HOS_BG.\n\tlv_color_t bgc_light = LV_COLOR_HEX(bg ? (bg + 0x101010) : 0x2D2D2D); // COLOR_HOS_BG_LIGHT.\n\tlv_color_t bgc_press = LV_COLOR_HEX(bg ? (bg + 0x232323) : 0x404040); // 0x505050.\n\tlv_color_t bg_border = LV_COLOR_HEX(bg ? (bg + 0x202020) : 0x3D3D3D); // COLOR_HOS_BG_LIGHTER.\n\tlv_color_t color     = hue ? lv_color_hsv_to_rgb(hue, 100, 100) : lv_color_hsv_to_rgb(53, 8, 90);\n\n\tstatic lv_style_t btn_tgl_pr_test;\n\tlv_style_copy(&btn_tgl_pr_test, lv_btn_get_style(color_test.button, LV_BTN_STATE_TGL_PR));\n\tbtn_tgl_pr_test.body.main_color = bgc_press;\n\tbtn_tgl_pr_test.body.grad_color = btn_tgl_pr_test.body.main_color;\n\tbtn_tgl_pr_test.body.border.color = color;\n\tbtn_tgl_pr_test.text.color = color;\n\n\tif (update_bg)\n\t{\n\t\tstatic lv_style_t win_bg_test;\n\t\tlv_style_copy(&win_bg_test, lv_win_get_style(color_test.window, LV_WIN_STYLE_BG));\n\t\twin_bg_test.body.main_color = bgc;\n\t\twin_bg_test.body.grad_color = win_bg_test.body.main_color;\n\t\tlv_win_set_style(color_test.window, LV_WIN_STYLE_BG, &win_bg_test);\n\n\t\tstatic lv_style_t win_hdr_test;\n\t\tlv_style_copy(&win_hdr_test, lv_win_get_style(color_test.window, LV_WIN_STYLE_HEADER));\n\t\twin_hdr_test.body.main_color = bgc;\n\t\twin_hdr_test.body.grad_color = win_hdr_test.body.main_color;\n\t\tlv_win_set_style(color_test.window, LV_WIN_STYLE_HEADER, &win_hdr_test);\n\n\t\tstatic lv_style_t hdr1_bg_test;\n\t\tlv_style_copy(&hdr1_bg_test, lv_cont_get_style(color_test.header1));\n\t\thdr1_bg_test.body.main_color = bgc;\n\t\thdr1_bg_test.body.grad_color = hdr1_bg_test.body.main_color;\n\t\tlv_cont_set_style(color_test.header1, &hdr1_bg_test);\n\n\t\tstatic lv_style_t hdr2_bg_test;\n\t\tlv_style_copy(&hdr2_bg_test, lv_cont_get_style(color_test.header2));\n\t\thdr2_bg_test.body.main_color = bgc;\n\t\thdr2_bg_test.body.grad_color = hdr2_bg_test.body.main_color;\n\t\tlv_cont_set_style(color_test.header2, &hdr2_bg_test);\n\n\t\tstatic lv_style_t btn_tgl_rel_test;\n\t\tlv_style_copy(&btn_tgl_rel_test, lv_btn_get_style(color_test.btn_reset, LV_BTN_STATE_REL));\n\t\tbtn_tgl_rel_test.body.main_color = bgc_light;\n\t\tbtn_tgl_rel_test.body.grad_color = btn_tgl_rel_test.body.main_color;\n\t\tlv_btn_set_style(color_test.btn_reset, LV_BTN_STATE_REL, &btn_tgl_rel_test);\n\t\tlv_btn_set_style(color_test.btn_reset, LV_BTN_STATE_PR, &btn_tgl_pr_test);\n\t\tlv_btn_set_style(color_test.btn_apply, LV_BTN_STATE_REL, &btn_tgl_rel_test);\n\t\tlv_btn_set_style(color_test.btn_apply, LV_BTN_STATE_PR, &btn_tgl_pr_test);\n\t\tlv_btn_set_style(color_test.btn_black, LV_BTN_STATE_REL, &btn_tgl_rel_test);\n\t\tlv_btn_set_style(color_test.btn_black, LV_BTN_STATE_PR, &btn_tgl_pr_test);\n\n\t\tstatic lv_style_t slider_bg;\n\t\tlv_style_copy(&slider_bg, lv_slider_get_style(color_test.slider, LV_SLIDER_STYLE_BG));\n\t\tslider_bg.body.main_color = bg_border;\n\t\tslider_bg.body.grad_color = slider_bg.body.main_color;\n\t\tlv_slider_set_style(color_test.hue_slider, LV_SLIDER_STYLE_BG, &slider_bg);\n\t\tlv_slider_set_style(color_test.slider,     LV_SLIDER_STYLE_BG, &slider_bg);\n\t\tlv_slider_set_style(color_test.r_slider,   LV_SLIDER_STYLE_BG, &slider_bg);\n\t\tlv_slider_set_style(color_test.g_slider,   LV_SLIDER_STYLE_BG, &slider_bg);\n\t\tlv_slider_set_style(color_test.b_slider,   LV_SLIDER_STYLE_BG, &slider_bg);\n\t}\n\telse\n\t{\n\t\tstatic lv_style_t txt_test;\n\t\tlv_style_copy(&txt_test, lv_label_get_style(color_test.label));\n\t\ttxt_test.text.color = color;\n\t\tlv_obj_set_style(color_test.label, &txt_test);\n\t\tlv_obj_set_style(color_test.icons, &txt_test);\n\n\t\tstatic lv_style_t slider_knb;\n\t\tlv_style_copy(&slider_knb, lv_slider_get_style(color_test.slider, LV_SLIDER_STYLE_KNOB));\n\t\tslider_knb.body.main_color = color;\n\t\tslider_knb.body.grad_color = slider_knb.body.main_color;\n\t\tlv_slider_set_style(color_test.hue_slider, LV_SLIDER_STYLE_KNOB, &slider_knb);\n\t\tlv_slider_set_style(color_test.slider,     LV_SLIDER_STYLE_KNOB, &slider_knb);\n\t\tlv_slider_set_style(color_test.r_slider,   LV_SLIDER_STYLE_KNOB, &slider_knb);\n\t\tlv_slider_set_style(color_test.g_slider,   LV_SLIDER_STYLE_KNOB, &slider_knb);\n\t\tlv_slider_set_style(color_test.b_slider,   LV_SLIDER_STYLE_KNOB, &slider_knb);\n\n\t\tstatic lv_style_t slider_ind;\n\t\tlv_style_copy(&slider_ind, lv_slider_get_style(color_test.slider, LV_SLIDER_STYLE_INDIC));\n\t\tslider_ind.body.main_color = hue ? lv_color_hsv_to_rgb(hue, 100, 72) : lv_color_hsv_to_rgb(53, 8, 65);\n\t\tslider_ind.body.grad_color = slider_ind.body.main_color;\n\t\tlv_slider_set_style(color_test.hue_slider, LV_SLIDER_STYLE_INDIC, &slider_ind);\n\t\tlv_slider_set_style(color_test.slider,     LV_SLIDER_STYLE_INDIC, &slider_ind);\n\t\tlv_slider_set_style(color_test.r_slider,   LV_SLIDER_STYLE_INDIC, &slider_ind);\n\t\tlv_slider_set_style(color_test.g_slider,   LV_SLIDER_STYLE_INDIC, &slider_ind);\n\t\tlv_slider_set_style(color_test.b_slider,   LV_SLIDER_STYLE_INDIC, &slider_ind);\n\t}\n\n\tlv_btn_set_style(color_test.button, LV_BTN_STATE_TGL_PR, &btn_tgl_pr_test);\n}\n\nstatic lv_res_t _slider_hue_action(lv_obj_t *slider)\n{\n\tif (color_test.hue != lv_slider_get_value(slider))\n\t{\n\t\tcolor_test.hue = lv_slider_get_value(slider);\n\n\t\t_show_new_nyx_color(false);\n\n\t\tchar hue[8];\n\t\ts_printf(hue, \"%03d\", color_test.hue);\n\t\tlv_label_set_text(color_test.hue_label, hue);\n\t}\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _slider_r_action(lv_obj_t *slider)\n{\n\tif (color_test.r != lv_slider_get_value(slider))\n\t{\n\t\tcolor_test.r = lv_slider_get_value(slider);\n\t\tcolor_test.box_style.body.main_color = LV_COLOR_HEX((color_test.r << 16) | (color_test.g << 8) | color_test.b);\n\t\tcolor_test.box_style.body.grad_color = color_test.box_style.body.main_color;\n\t\tlv_obj_set_style(color_test.box, &color_test.box_style);\n\n\t\tchar shade[8];\n\t\ts_printf(shade, \"%03d\", color_test.r);\n\t\tlv_label_set_text(color_test.r_label, shade);\n\t}\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _slider_g_action(lv_obj_t *slider)\n{\n\tif (color_test.g != lv_slider_get_value(slider))\n\t{\n\t\tcolor_test.g = lv_slider_get_value(slider);\n\t\tcolor_test.box_style.body.main_color = LV_COLOR_HEX((color_test.r << 16) | (color_test.g << 8) | color_test.b);\n\t\tcolor_test.box_style.body.grad_color = color_test.box_style.body.main_color;\n\t\tlv_obj_set_style(color_test.box, &color_test.box_style);\n\n\t\tchar shade[8];\n\t\ts_printf(shade, \"%03d\", color_test.g);\n\t\tlv_label_set_text(color_test.g_label, shade);\n\t}\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _slider_b_action(lv_obj_t *slider)\n{\n\tif (color_test.b != lv_slider_get_value(slider))\n\t{\n\t\tcolor_test.b = lv_slider_get_value(slider);\n\t\tcolor_test.box_style.body.main_color = LV_COLOR_HEX((color_test.r << 16) | (color_test.g << 8) | color_test.b);\n\t\tcolor_test.box_style.body.grad_color = color_test.box_style.body.main_color;\n\t\tlv_obj_set_style(color_test.box, &color_test.box_style);\n\n\t\tchar shade[8];\n\t\ts_printf(shade, \"%03d\", color_test.b);\n\t\tlv_label_set_text(color_test.b_label, shade);\n\t}\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _preset_bg_apply(lv_obj_t *btn)\n{\n\tcolor_test.bg = (color_test.r << 16) | (color_test.g << 8) | color_test.b;\n\n\t_show_new_nyx_color(true);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _preset_bg_black(lv_obj_t *btn)\n{\n\tcolor_test.bg = 0;\n\n\t_show_new_nyx_color(true);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _preset_bg_reset(lv_obj_t *btn)\n{\n\tcolor_test.r = 0x2D;\n\tcolor_test.g = 0x2D;\n\tcolor_test.b = 0x2D;\n\tcolor_test.bg = 0x2D2D2D;\n\n\tcolor_test.box_style.body.main_color = LV_COLOR_HEX(color_test.bg);\n\tcolor_test.box_style.body.grad_color = color_test.box_style.body.main_color;\n\tlv_obj_set_style(color_test.box, &color_test.box_style);\n\n\tlv_bar_set_value(color_test.r_slider, color_test.r);\n\tlv_bar_set_value(color_test.g_slider, color_test.g);\n\tlv_bar_set_value(color_test.b_slider, color_test.b);\n\n\tchar shade[8];\n\ts_printf(shade, \"%03d\", color_test.r);\n\tlv_label_set_text(color_test.r_label, shade);\n\tlv_label_set_text(color_test.g_label, shade);\n\tlv_label_set_text(color_test.b_label, shade);\n\n\t_show_new_nyx_color(true);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _preset_hue_action(lv_obj_t *btn)\n{\n\tlv_btn_ext_t *ext = lv_obj_get_ext_attr(btn);\n\n\tif (color_test.hue != ext->idx)\n\t{\n\t\tcolor_test.hue = ext->idx;\n\n\t\tchar hue[8];\n\t\ts_printf(hue, \"%03d\", color_test.hue);\n\t\tlv_label_set_text(color_test.hue_label, hue);\n\t\tlv_bar_set_value(color_test.hue_slider, color_test.hue);\n\n\t\t_show_new_nyx_color(false);\n\t}\n\n\treturn LV_RES_OK;\n}\n\nstatic const u16 theme_colors[18] = {\n\t0, 4, 13, 23, 33, 43, 54, 66, 89, 124, 167, 187, 200, 208, 231, 261, 291, 341\n};\n\nlv_res_t _action_win_nyx_colors_close(lv_obj_t * btn)\n{\n\tlv_obj_set_opa_scale(status_bar.mid, LV_OPA_COVER);\n\tlv_obj_set_click(status_bar.mid, true);\n\n\treturn nyx_win_close_action(btn);\n}\n\nstatic lv_res_t _create_window_nyx_colors(lv_obj_t *btn)\n{\n\tlv_obj_t *win = nyx_create_standard_window(SYMBOL_COPY\" Nyx Color Theme\", _action_win_nyx_colors_close);\n\tlv_win_add_btn(win, NULL, SYMBOL_SAVE\" Save & Reload\", _action_win_nyx_colors_save);\n\tcolor_test.window = win;\n\n\t// Set current theme colors.\n\tcolor_test.bg  = n_cfg.theme_bg;\n\tcolor_test.hue = n_cfg.theme_color;\n\tu32 bg = n_cfg.theme_bg ? n_cfg.theme_bg : 0x2D2D2D;\n\tcolor_test.r = (bg >> 16) & 0xFF;\n\tcolor_test.g = (bg >>  8) & 0xFF;\n\tcolor_test.b = (bg >>  0) & 0xFF;\n\n\tlv_style_copy(&color_test.box_style, &lv_style_plain_color);\n\tcolor_test.box_style.body.main_color = LV_COLOR_HEX(color_test.bg);\n\tcolor_test.box_style.body.grad_color = color_test.box_style.body.main_color;\n\tcolor_test.box_style.body.border.color = LV_COLOR_HEX(0xFFFFFF);\n\tcolor_test.box_style.body.border.opa   = LV_OPA_20;\n\tcolor_test.box_style.body.border.width = 2;\n\n\t// Create container to keep content inside.\n\tlv_obj_t *h1 = lv_cont_create(win, NULL);\n\tlv_obj_set_size(h1, LV_DPI * 299 / 25, LV_DPI * 27 / 26);\n\tcolor_test.header1 = h1;\n\n\tlv_obj_t *acc_label = lv_label_create(h1, NULL);\n\tlv_label_set_static_text(acc_label, \"Accent color:\");\n\n\t// Create color preset buttons.\n\tlv_obj_t *color_btn = lv_btn_create(h1, NULL);\n\tlv_btn_ext_t *ext = lv_obj_get_ext_attr(color_btn);\n\text->idx = theme_colors[0];\n\tcreate_flat_button(color_btn, ext->idx, _preset_hue_action);\n\tlv_obj_align(color_btn, acc_label, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 10);\n\tlv_obj_t *color_btn2;\n\n\tfor (u32 i = 1; i < ARRAY_SIZE(theme_colors); i++)\n\t{\n\t\tcolor_btn2 = lv_btn_create(h1, NULL);\n\t\text = lv_obj_get_ext_attr(color_btn2);\n\t\text->idx = theme_colors[i];\n\t\tcreate_flat_button(color_btn2, ext->idx, _preset_hue_action);\n\t\tlv_obj_align(color_btn2, color_btn, LV_ALIGN_OUT_RIGHT_MID, 0, 0);\n\t\tcolor_btn = color_btn2;\n\t}\n\n\tlv_obj_align(h1, NULL, LV_ALIGN_IN_TOP_MID, 0, LV_DPI / 5);\n\n\t// Create hue slider.\n\tlv_obj_t *h_slider = lv_slider_create(win, NULL);\n\tlv_obj_set_width(h_slider, LV_DPI * 213 / 20);\n\tlv_obj_set_height(h_slider, LV_DPI * 4 / 10);\n\tlv_bar_set_range(h_slider, 0, 359);\n\tlv_bar_set_value(h_slider, color_test.hue);\n\tlv_slider_set_action(h_slider, _slider_hue_action);\n\tlv_obj_align(h_slider, h1, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 5);\n\tcolor_test.hue_slider = h_slider;\n\n\t// Create hue label.\n\tlv_obj_t *hue_text_label = lv_label_create(win, NULL);\n\tlv_obj_align(hue_text_label, h_slider, LV_ALIGN_OUT_RIGHT_MID, LV_DPI * 24 / 100, 0);\n\tchar txt[8];\n\ts_printf(txt, \"%03d\", color_test.hue);\n\tlv_label_set_text(hue_text_label, txt);\n\tcolor_test.hue_label = hue_text_label;\n\n\tlv_obj_t *bg_label = lv_label_create(win, NULL);\n\tlv_label_set_static_text(bg_label, \"Theme color:\");\n\tlv_obj_align(bg_label, h_slider, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI * 6 / 25);\n\n\t// Create red slider.\n\tlv_obj_t *r_slider = lv_slider_create(win, NULL);\n\tlv_obj_set_width(r_slider, LV_DPI * 85 / 16);\n\tlv_obj_set_height(r_slider, LV_DPI * 4 / 10);\n\tlv_bar_set_range(r_slider, 11, 100);\n\tlv_bar_set_value(r_slider, color_test.r);\n\tlv_slider_set_action(r_slider, _slider_r_action);\n\tlv_obj_align(r_slider, bg_label, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 21);\n\tcolor_test.r_slider = r_slider;\n\n\t// Create red label.\n\tlv_obj_t *r_text_label = lv_label_create(win, NULL);\n\tlv_obj_align(r_text_label, r_slider, LV_ALIGN_OUT_RIGHT_MID, LV_DPI * 24 / 100, 0);\n\ts_printf(txt, \"%03d\", color_test.r);\n\tlv_label_set_text(r_text_label, txt);\n\tcolor_test.r_label = r_text_label;\n\n\t// Create green slider.\n\tlv_obj_t *g_slider = lv_slider_create(win, r_slider);\n\tlv_bar_set_value(g_slider, color_test.g);\n\tlv_slider_set_action(g_slider, _slider_g_action);\n\tlv_obj_align(g_slider, r_slider, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 7);\n\tcolor_test.g_slider = g_slider;\n\n\t// Create green label.\n\tlv_obj_t *g_text_label = lv_label_create(win, NULL);\n\tlv_obj_align(g_text_label, g_slider, LV_ALIGN_OUT_RIGHT_MID, LV_DPI * 24 / 100, 0);\n\ts_printf(txt, \"%03d\", color_test.g);\n\tlv_label_set_text(g_text_label, txt);\n\tcolor_test.g_label = g_text_label;\n\n\t// Create blue slider.\n\tlv_obj_t *b_slider = lv_slider_create(win, r_slider);\n\tlv_bar_set_value(b_slider, color_test.b);\n\tlv_slider_set_action(b_slider, _slider_b_action);\n\tlv_obj_align(b_slider, g_slider, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 7);\n\tcolor_test.b_slider = b_slider;\n\n\t// Create blue label.\n\tlv_obj_t *b_text_label = lv_label_create(win, NULL);\n\tlv_obj_align(b_text_label, b_slider, LV_ALIGN_OUT_RIGHT_MID, LV_DPI * 24 / 100, 0);\n\ts_printf(txt, \"%03d\", color_test.b);\n\tlv_label_set_text(b_text_label, txt);\n\tcolor_test.b_label = b_text_label;\n\n\t// Create theme color box.\n\tlv_obj_t * bg_box = lv_obj_create(win, NULL);\n\tlv_obj_set_size(bg_box, LV_DPI * 10 / 7, LV_DPI * 18 / 13);\n\tlv_obj_align(bg_box, r_text_label, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI / 4, 0);\n\tlv_obj_set_style(bg_box, &color_test.box_style);\n\tcolor_test.box = bg_box;\n\n\t// Create theme color buttons.\n\tlv_obj_t *btn_reset = lv_btn_create(win, NULL);\n\tlv_obj_t *label_btn = lv_label_create(btn_reset, NULL);\n\tlv_label_set_static_text(label_btn, SYMBOL_REFRESH\" Grey\");\n\tlv_btn_set_fit(btn_reset, false, true);\n\tlv_obj_set_width(btn_reset, LV_DPI * 5 / 3);\n\tlv_btn_set_action(btn_reset, LV_BTN_ACTION_CLICK, _preset_bg_reset);\n\tlv_obj_align(btn_reset, bg_box, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI / 5, 0);\n\tcolor_test.btn_reset = btn_reset;\n\n\tlv_obj_t *btn_black = lv_btn_create(win, btn_reset);\n\tlabel_btn = lv_label_create(btn_black, NULL);\n\tlv_label_set_static_text(label_btn, SYMBOL_BRIGHTNESS\" Black\");\n\tlv_btn_set_action(btn_black, LV_BTN_ACTION_CLICK, _preset_bg_black);\n\tlv_obj_align(btn_black, btn_reset, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI / 5, 0);\n\tcolor_test.btn_black = btn_black;\n\n\tlv_obj_t *btn_apply = lv_btn_create(win, btn_reset);\n\tlabel_btn = lv_label_create(btn_apply, NULL);\n\tlv_label_set_static_text(label_btn, SYMBOL_LIST\" Custom Color\");\n\tlv_obj_set_width(btn_apply, LV_DPI * 10 / 3 + LV_DPI / 5);\n\tlv_btn_set_action(btn_apply, LV_BTN_ACTION_CLICK, _preset_bg_apply);\n\tlv_obj_align(btn_apply, btn_reset, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 7);\n\tcolor_test.btn_apply = btn_apply;\n\n\t// Create sample text.\n\tlv_obj_t *h2 = lv_cont_create(win, NULL);\n\tlv_obj_set_size(h2, LV_DPI * 12, LV_DPI * 18 / 10);\n\tlv_obj_align(h2, b_slider, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI * 6 / 25);\n\tcolor_test.header2 = h2;\n\n\tlv_obj_t *lbl_sample = lv_label_create(h2, NULL);\n\tlv_label_set_static_text(lbl_sample, \"Accent sample:\");\n\n\tlv_obj_t *lbl_test = lv_label_create(h2, NULL);\n\tlv_label_set_long_mode(lbl_test, LV_LABEL_LONG_BREAK);\n\tlv_label_set_static_text(lbl_test,\n\t\t\"Lorem ipsum dolor sit amet, consectetur adipisicing elit, \"\n\t\t\"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\");\n\tlv_obj_set_width(lbl_test, LV_DPI * 261 / 23);\n\tlv_obj_align(lbl_test, lbl_sample, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 34);\n\tcolor_test.label = lbl_test;\n\n\t// Create sample icons.\n\tlv_obj_t *lbl_icons = lv_label_create(h2, NULL);\n\tlv_label_set_static_text(lbl_icons,\n\t\tSYMBOL_BRIGHTNESS SYMBOL_CHARGE SYMBOL_FILE SYMBOL_DRIVE SYMBOL_FILE_CODE\n\t\tSYMBOL_EDIT SYMBOL_HINT SYMBOL_DRIVE SYMBOL_KEYBOARD SYMBOL_POWER);\n\tlv_obj_align(lbl_icons, lbl_test, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 5);\n\tcolor_test.icons = lbl_icons;\n\n\t// Create sample slider.\n\tlv_obj_t *slider_test = lv_slider_create(h2, NULL);\n\tlv_obj_align(slider_test, lbl_test, LV_ALIGN_OUT_BOTTOM_MID, 0, LV_DPI / 5);\n\tlv_obj_set_click(slider_test, false);\n\tlv_bar_set_value(slider_test, 60);\n\tcolor_test.slider = slider_test;\n\n\t// Create sample button.\n\tlv_obj_t *btn_test = lv_btn_create(h2, NULL);\n\tlv_btn_set_state(btn_test, LV_BTN_STATE_TGL_PR);\n\tlv_label_create(btn_test, NULL);\n\tlv_btn_set_fit(btn_test, false, true);\n\tlv_obj_set_width(btn_test, LV_DPI * 5 / 3);\n\tlv_obj_align(btn_test, lbl_test, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, LV_DPI / 20);\n\tlv_obj_set_click(btn_test, false);\n\tcolor_test.button = btn_test;\n\n\t_show_new_nyx_color(false);\n\n\tlv_obj_set_opa_scale(status_bar.mid, LV_OPA_0);\n\tlv_obj_set_click(status_bar.mid, false);\n\n\treturn LV_RES_OK;\n}\n\ntypedef struct _time_edit_obj_t\n{\n\tlv_obj_t *year;\n\tlv_obj_t *month;\n\tlv_obj_t *day;\n\tlv_obj_t *hour;\n\tlv_obj_t *min;\n} time_edit_obj_t;\n\ntime_edit_obj_t clock_ctxt;\n\nstatic lv_res_t _action_clock_edit(lv_obj_t *btns, const char * txt)\n{\n\tint btn_idx = lv_btnm_get_pressed(btns);\n\n\tif (btn_idx == 1)\n\t{\n\t\trtc_time_t time;\n\t\tmax77620_rtc_get_time(&time);\n\t\tu32 epoch = max77620_rtc_date_to_epoch(&time);\n\n\t\tu32 year  = lv_roller_get_selected(clock_ctxt.year) + CLOCK_MIN_YEAR;\n\t\tu32 month = lv_roller_get_selected(clock_ctxt.month) + 1;\n\t\tu32 day   = lv_roller_get_selected(clock_ctxt.day) + 1;\n\t\tu32 hour  = lv_roller_get_selected(clock_ctxt.hour);\n\t\tu32 min   = lv_roller_get_selected(clock_ctxt.min);\n\n\t\tswitch (month)\n\t\t{\n\t\tcase 2:\n\t\t\tif (!(year % 4) && day > 29)\n\t\t\t\tday = 29;\n\t\t\telse if (day > 28)\n\t\t\t\tday = 28;\n\t\t\tbreak;\n\t\tcase 4:\n\t\tcase 6:\n\t\tcase 9:\n\t\tcase 11:\n\t\t\tif (day > 30)\n\t\t\t\tday = 30;\n\t\t\tbreak;\n\t\t}\n\n\t\ttime.year  = year;\n\t\ttime.month = month;\n\t\ttime.day   = day;\n\t\ttime.hour  = hour;\n\t\ttime.min   = min;\n\n\t\tu32 new_epoch = max77620_rtc_date_to_epoch(&time);\n\n\t\t// Stored in u32 and allow overflow for integer offset casting.\n\t\tn_cfg.timeoffset = new_epoch - epoch;\n\n\t\t// If canceled set 1 for invalidating first boot clock edit.\n\t\tif (!n_cfg.timeoffset)\n\t\t\tn_cfg.timeoffset = 1;\n\t\telse\n\t\t{\n\t\t\t// Adjust for DST between 28 march and 28 october.\n\t\t\t// Good enough to cover all years as week info is not valid.\n\t\t\tu16 md = (time.month << 8) | time.day;\n\t\t\tif (n_cfg.timedst && md >= 0x31C && md < 0xA1C)\n\t\t\t\tn_cfg.timeoffset -= 3600; // Store time in non DST.\n\t\t\tmax77620_rtc_set_epoch_offset((int)n_cfg.timeoffset);\n\t\t}\n\n\t\tnyx_changes_made = true;\n\t}\n\n\tnyx_mbox_action(btns, txt);\n\n\treturn LV_RES_INV;\n}\n\nstatic lv_res_t _action_clock_edit_save(lv_obj_t *btns, const char * txt)\n{\n\t_action_clock_edit(btns, txt);\n\n\t// Save if changes were made.\n\tif (nyx_changes_made)\n\t\t_save_nyx_options_action(NULL);\n\n\treturn LV_RES_INV;\n}\n\nstatic lv_res_t _action_auto_dst_toggle(lv_obj_t *btn)\n{\n\tn_cfg.timedst = !n_cfg.timedst;\n\tmax77620_rtc_set_auto_dst(n_cfg.timedst);\n\n\tif (!n_cfg.timedst)\n\t\tlv_btn_set_state(btn, LV_BTN_STATE_REL);\n\telse\n\t\tlv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);\n\n\tnyx_generic_onoff_toggle(btn);\n\n\treturn LV_RES_OK;\n}\n\nstatic const u32 month_days[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\n\nstatic lv_res_t _action_date_validation(lv_obj_t *roller)\n{\n\tu32 year  = lv_roller_get_selected(clock_ctxt.year) + CLOCK_MIN_YEAR;\n\tu32 month = lv_roller_get_selected(clock_ctxt.month) + 1;\n\tu32 day   = lv_roller_get_selected(clock_ctxt.day) + 1;\n\n\t// Adjust max day based on year and month.\n\tu32 max_mon_day = month_days[month - 1];\n\tu32 max_feb_day = !(year % 4) ? 29 : 28;\n\tif (month == 2 && day > max_feb_day)\n\t\tlv_roller_set_selected(clock_ctxt.day, max_feb_day - 1, false);\n\telse if (day > max_mon_day)\n\t\tlv_roller_set_selected(clock_ctxt.day, max_mon_day - 1, false);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _create_mbox_clock_edit(lv_obj_t *btn)\n{\n\tstatic lv_style_t mbox_style;\n\tlv_theme_t *th = lv_theme_get_current();\n\tlv_style_copy(&mbox_style, th->mbox.bg);\n\tmbox_style.body.padding.inner = LV_DPI / 10;\n\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_map[] = { \"\\251\", \"\\222Done\", \"\\222Cancel\", \"\\251\", \"\" };\n\tlv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_style(mbox, LV_MBOX_STYLE_BG, &mbox_style);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);\n\n\tlv_mbox_set_text(mbox, \"Enter #C7EA46 Date# and #C7EA46 Time# for Nyx\\n\"\n\t\t\t\t\t\t   \"Used in all file operations and menu.\\n\"\n\t\t\t\t\t\t   \"This doesn't alter the actual HW clock!\");\n\n\tlv_obj_t *padding = lv_cont_create(mbox, NULL);\n\tlv_cont_set_fit(padding, true, false);\n\tlv_cont_set_style(padding, &lv_style_transp);\n\tlv_obj_set_height(padding, LV_DPI / 10);\n\n\t// Get current time.\n\trtc_time_t time;\n\tmax77620_rtc_get_time_adjusted(&time);\n\n\t// Normalize year if out of range.\n\tif (time.year < CLOCK_MIN_YEAR)\n\t\ttime.year = CLOCK_MIN_YEAR;\n\telse if (time.year > CLOCK_MAX_YEAR)\n\t\ttime.year = CLOCK_MAX_YEAR;\n\n\ttime.year -= CLOCK_MIN_YEAR;\n\n\tlv_obj_t *h1 = lv_cont_create(mbox, NULL);\n\tlv_cont_set_fit(h1, true, true);\n\n\t// Create year roller.\n\tlv_obj_t *roller_year = lv_roller_create(h1, NULL);\n\tlv_roller_set_options(roller_year, CLOCK_YEARLIST);\n\tlv_roller_set_selected(roller_year, time.year, false);\n\tlv_roller_set_visible_row_count(roller_year, 3);\n\tlv_roller_set_action(roller_year, _action_date_validation);\n\tclock_ctxt.year = roller_year;\n\n\t// Create month roller.\n\tlv_obj_t *roller_month = lv_roller_create(h1, roller_year);\n\tlv_roller_set_options(roller_month,\n\t\t\"January\\n\"\n\t\t\"February\\n\"\n\t\t\"March\\n\"\n\t\t\"April\\n\"\n\t\t\"May\\n\"\n\t\t\"June\\n\"\n\t\t\"July\\n\"\n\t\t\"August\\n\"\n\t\t\"September\\n\"\n\t\t\"October\\n\"\n\t\t\"November\\n\"\n\t\t\"December\");\n\tlv_roller_set_selected(roller_month, time.month - 1, false);\n\tlv_obj_align(roller_month, roller_year, LV_ALIGN_OUT_RIGHT_MID, 0, 0);\n\tlv_roller_set_action(roller_month, _action_date_validation);\n\tclock_ctxt.month = roller_month;\n\n\t// Create day roller.\n\tstatic char days[256];\n\tdays[0] = 0;\n\tfor (u32 i = 1; i < 32; i++)\n\t\ts_printf(days + strlen(days), \" %d \\n\", i);\n\tdays[strlen(days) - 1] = 0;\n\tlv_obj_t *roller_day = lv_roller_create(h1, roller_year);\n\tlv_roller_set_options(roller_day, days);\n\tlv_roller_set_selected(roller_day, time.day - 1, false);\n\tlv_roller_set_action(roller_day, _action_date_validation);\n\tlv_obj_align(roller_day, roller_month, LV_ALIGN_OUT_RIGHT_MID, 0, 0);\n\tclock_ctxt.day = roller_day;\n\n\t// Create hours roller.\n\tstatic char hours[256];\n\thours[0] = 0;\n\tfor (u32 i = 0; i < 24; i++)\n\t\ts_printf(hours + strlen(hours), \" %d \\n\", i);\n\thours[strlen(hours) - 1] = 0;\n\tlv_obj_t *roller_hour = lv_roller_create(h1, roller_year);\n\tlv_roller_set_options(roller_hour, hours);\n\tlv_roller_set_selected(roller_hour, time.hour, false);\n\tlv_obj_align(roller_hour, roller_day, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 2, 0);\n\tclock_ctxt.hour = roller_hour;\n\n\t// Create minutes roller.\n\tstatic char minutes[512];\n\tminutes[0] = 0;\n\tfor (u32 i = 0; i < 60; i++)\n\t\ts_printf(minutes + strlen(minutes), \" %02d \\n\", i);\n\tminutes[strlen(minutes) - 1] = 0;\n\tlv_obj_t *roller_minute = lv_roller_create(h1, roller_year);\n\tlv_roller_set_options(roller_minute, minutes);\n\tlv_roller_set_selected(roller_minute, time.min, false);\n\tlv_obj_align(roller_minute, roller_hour, LV_ALIGN_OUT_RIGHT_MID, 0, 0);\n\tclock_ctxt.min = roller_minute;\n\n\t// Add DST option.\n\tlv_obj_t *btn_dst = lv_btn_create(mbox, NULL);\n\tnyx_create_onoff_button(th, h1, btn_dst, SYMBOL_BRIGHTNESS\" Auto Daylight Saving Time\", _action_auto_dst_toggle, true);\n\tif (n_cfg.timedst)\n\t\tlv_btn_set_state(btn_dst, LV_BTN_STATE_TGL_REL);\n\tnyx_generic_onoff_toggle(btn_dst);\n\n\t// If btn is empty, save options also because it was launched from boot.\n\tlv_mbox_add_btns(mbox, mbox_btn_map, btn ? _action_clock_edit : _action_clock_edit_save);\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\treturn LV_RES_OK;\n}\n\nvoid first_time_clock_edit(void *param)\n{\n\t_create_mbox_clock_edit(NULL);\n}\n\nstatic lv_res_t _joycon_info_dump_action(lv_obj_t * btn)\n{\n\tFIL fp;\n\tint error = 0;\n\tint cal_error = 0;\n\tbool is_l_hos = false;\n\tbool is_r_hos = false;\n\tu32 joycon_found = 0;\n\tbool nx_hoag = fuse_read_hw_type() == FUSE_NX_HW_TYPE_HOAG;\n\tjc_gamepad_rpt_t *jc_pad = jc_get_bt_pairing_info(&is_l_hos, &is_r_hos);\n\n\tchar *data = (char *)malloc(SZ_16K);\n\tchar *txt_buf = (char *)malloc(SZ_4K);\n\n\tif (!nx_hoag && !jc_pad)\n\t\terror = 255;\n\n\t// Try 2 times to get factory calibration data.\n\tfor (u32 i = 0; i < 2; i++)\n\t{\n\t\tif (!error)\n\t\t\tcal_error = hos_dump_cal0();\n\t\tif (!cal_error)\n\t\t\tbreak;\n\t}\n\n\tif (cal_error && nx_hoag)\n\t\terror = cal_error;\n\n\tif (error)\n\t\tgoto disabled_or_cal0_issue;\n\n\tif (nx_hoag)\n\t\tgoto save_data;\n\n\t// Count valid joycon.\n\tjoycon_found = jc_pad->bt_conn_l.type ? 1 : 0;\n\tif (jc_pad->bt_conn_r.type)\n\t\tjoycon_found++;\n\n\t// Reset PC based for dumping.\n\tjc_pad->bt_conn_l.type = is_l_hos ? jc_pad->bt_conn_l.type : 0;\n\tjc_pad->bt_conn_r.type = is_r_hos ? jc_pad->bt_conn_r.type : 0;\n\nsave_data:\n\terror = sd_mount() ? 5 : 0;\n\n\tif (!error)\n\t{\n\t\tnx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)cal0_buf;\n\n\t\tf_mkdir(\"switchroot\");\n\n\t\tif (!nx_hoag)\n\t\t{\n\t\t\t// Save binary dump.\n\t\t\tmemcpy(data, &jc_pad->bt_conn_l, sizeof(jc_bt_conn_t));\n\t\t\tmemcpy(data + sizeof(jc_bt_conn_t), &jc_pad->bt_conn_r, sizeof(jc_bt_conn_t));\n\n\t\t\terror = sd_save_to_file((u8 *)data, sizeof(jc_bt_conn_t) * 2, \"switchroot/joycon_mac.bin\") ? 4 : 0;\n\n\t\t\t// Save readable dump.\n\t\t\tdata[0] = 0;\n\t\t\tfor (u32 i = 0; i < 2; i++)\n\t\t\t{\n\t\t\t\tjc_bt_conn_t *bt = !i ? &jc_pad->bt_conn_l : &jc_pad->bt_conn_r;\n\t\t\t\ts_printf(data + strlen(data),\n\t\t\t\t\t\"[joycon_0%d]\\ntype=%d\\nmac=%02X:%02X:%02X:%02X:%02X:%02X\\n\"\n\t\t\t\t\t\"host=%02X:%02X:%02X:%02X:%02X:%02X\\n\"\n\t\t\t\t\t\"ltk=%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\\n\\n\",\n\t\t\t\t\ti, bt->type, bt->mac[0], bt->mac[1], bt->mac[2], bt->mac[3], bt->mac[4], bt->mac[5],\n\t\t\t\t\tbt->host_mac[0], bt->host_mac[1], bt->host_mac[2], bt->host_mac[3], bt->host_mac[4], bt->host_mac[5],\n\t\t\t\t\tbt->ltk[0], bt->ltk[1], bt->ltk[2], bt->ltk[3], bt->ltk[4], bt->ltk[5], bt->ltk[6], bt->ltk[7],\n\t\t\t\t\tbt->ltk[8], bt->ltk[9], bt->ltk[10], bt->ltk[11], bt->ltk[12], bt->ltk[13], bt->ltk[14], bt->ltk[15]);\n\t\t\t}\n\n\t\t\tif (!error)\n\t\t\t\terror = f_open(&fp, \"switchroot/joycon_mac.ini\", FA_WRITE | FA_CREATE_ALWAYS) ? 4 : 0;\n\t\t\tif (!error)\n\t\t\t{\n\t\t\t\tf_puts(data, &fp);\n\t\t\t\tf_close(&fp);\n\t\t\t}\n\n\t\t\t// Save IMU Calibration data.\n\t\t\tif (!error && !cal_error)\n\t\t\t{\n\t\t\t\ts_printf(data,\n\t\t\t\t\t\"imu_type=%d\\n\\n\"\n\t\t\t\t\t\"acc_cal_off_x=0x%X\\n\"\n\t\t\t\t\t\"acc_cal_off_y=0x%X\\n\"\n\t\t\t\t\t\"acc_cal_off_z=0x%X\\n\"\n\t\t\t\t\t\"acc_cal_scl_x=0x%X\\n\"\n\t\t\t\t\t\"acc_cal_scl_y=0x%X\\n\"\n\t\t\t\t\t\"acc_cal_scl_z=0x%X\\n\\n\"\n\n\t\t\t\t\t\"gyr_cal_off_x=0x%X\\n\"\n\t\t\t\t\t\"gyr_cal_off_y=0x%X\\n\"\n\t\t\t\t\t\"gyr_cal_off_z=0x%X\\n\"\n\t\t\t\t\t\"gyr_cal_scl_x=0x%X\\n\"\n\t\t\t\t\t\"gyr_cal_scl_y=0x%X\\n\"\n\t\t\t\t\t\"gyr_cal_scl_z=0x%X\\n\\n\"\n\n\t\t\t\t\t\"device_bt_mac=%02X:%02X:%02X:%02X:%02X:%02X\\n\",\n\t\t\t\t\tcal0->console_6axis_sensor_type,\n\t\t\t\t\tcal0->acc_offset[0],  cal0->acc_offset[1],  cal0->acc_offset[2],\n\t\t\t\t\tcal0->acc_scale[0],   cal0->acc_scale[1],   cal0->acc_scale[2],\n\t\t\t\t\tcal0->gyro_offset[0], cal0->gyro_offset[1], cal0->gyro_offset[2],\n\t\t\t\t\tcal0->gyro_scale[0],  cal0->gyro_scale[1],  cal0->gyro_scale[2],\n\t\t\t\t\tcal0->bd_mac[0], cal0->bd_mac[1], cal0->bd_mac[2], cal0->bd_mac[3], cal0->bd_mac[4], cal0->bd_mac[5]);\n\n\t\t\t\terror = f_open(&fp, \"switchroot/switch.cal\", FA_WRITE | FA_CREATE_ALWAYS) ? 4 : 0;\n\t\t\t\tif (!error)\n\t\t\t\t{\n\t\t\t\t\tf_puts(data, &fp);\n\t\t\t\t\tf_close(&fp);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tjc_calib_t *stick_cal_l = (jc_calib_t *)cal0->analog_stick_cal_l;\n\t\t\tjc_calib_t *stick_cal_r = (jc_calib_t *)cal0->analog_stick_cal_r;\n\n\t\t\t// Save Lite Gamepad and IMU Calibration data.\n\t\t\t// Actual max/min are right/left and up/down offsets.\n\t\t\t// Sticks: 0x23: H1 (Hosiden), 0x25: H5 (Hosiden), 0x41: F1 (FIT), ?add missing?\n\t\t\ts_printf(data,\n\t\t\t\t\"lite_cal_l_type=0x%X\\n\"\n\t\t\t\t\"lite_cal_lx_lof=0x%X\\n\"\n\t\t\t\t\"lite_cal_lx_cnt=0x%X\\n\"\n\t\t\t\t\"lite_cal_lx_rof=0x%X\\n\"\n\t\t\t\t\"lite_cal_ly_dof=0x%X\\n\"\n\t\t\t\t\"lite_cal_ly_cnt=0x%X\\n\"\n\t\t\t\t\"lite_cal_ly_uof=0x%X\\n\\n\"\n\n\t\t\t\t\"lite_cal_r_type=0x%X\\n\"\n\t\t\t\t\"lite_cal_rx_lof=0x%X\\n\"\n\t\t\t\t\"lite_cal_rx_cnt=0x%X\\n\"\n\t\t\t\t\"lite_cal_rx_rof=0x%X\\n\"\n\t\t\t\t\"lite_cal_ry_dof=0x%X\\n\"\n\t\t\t\t\"lite_cal_ry_cnt=0x%X\\n\"\n\t\t\t\t\"lite_cal_ry_uof=0x%X\\n\\n\"\n\n\t\t\t\t\"imu_type=%d\\n\\n\"\n\t\t\t\t\"acc_cal_off_x=0x%X\\n\"\n\t\t\t\t\"acc_cal_off_y=0x%X\\n\"\n\t\t\t\t\"acc_cal_off_z=0x%X\\n\"\n\t\t\t\t\"acc_cal_scl_x=0x%X\\n\"\n\t\t\t\t\"acc_cal_scl_y=0x%X\\n\"\n\t\t\t\t\"acc_cal_scl_z=0x%X\\n\\n\"\n\n\t\t\t\t\"gyr_cal_off_x=0x%X\\n\"\n\t\t\t\t\"gyr_cal_off_y=0x%X\\n\"\n\t\t\t\t\"gyr_cal_off_z=0x%X\\n\"\n\t\t\t\t\"gyr_cal_scl_x=0x%X\\n\"\n\t\t\t\t\"gyr_cal_scl_y=0x%X\\n\"\n\t\t\t\t\"gyr_cal_scl_z=0x%X\\n\\n\"\n\n\t\t\t\t\"device_bt_mac=%02X:%02X:%02X:%02X:%02X:%02X\\n\",\n\t\t\t\tcal0->analog_stick_type_l,\n\t\t\t\tstick_cal_l->x_min, stick_cal_l->x_center, stick_cal_l->x_max,\n\t\t\t\tstick_cal_l->y_min, stick_cal_l->y_center, stick_cal_l->y_max,\n\t\t\t\tcal0->analog_stick_type_r,\n\t\t\t\tstick_cal_r->x_min, stick_cal_r->x_center, stick_cal_r->x_max,\n\t\t\t\tstick_cal_r->y_min, stick_cal_r->y_center, stick_cal_r->y_max,\n\t\t\t\tcal0->console_6axis_sensor_type,\n\t\t\t\tcal0->acc_offset[0],  cal0->acc_offset[1],  cal0->acc_offset[2],\n\t\t\t\tcal0->acc_scale[0],   cal0->acc_scale[1],   cal0->acc_scale[2],\n\t\t\t\tcal0->gyro_offset[0], cal0->gyro_offset[1], cal0->gyro_offset[2],\n\t\t\t\tcal0->gyro_scale[0],  cal0->gyro_scale[1],  cal0->gyro_scale[2],\n\t\t\t\tcal0->bd_mac[0], cal0->bd_mac[1], cal0->bd_mac[2], cal0->bd_mac[3], cal0->bd_mac[4], cal0->bd_mac[5]);\n\t\t\tif (!error)\n\t\t\t\terror = f_open(&fp, \"switchroot/switch.cal\", FA_WRITE | FA_CREATE_ALWAYS) ? 4 : 0;\n\t\t\tif (!error)\n\t\t\t{\n\t\t\t\tf_puts(data, &fp);\n\t\t\t\tf_close(&fp);\n\t\t\t}\n\t\t}\n\n\t\tsd_unmount();\n\t}\n\ndisabled_or_cal0_issue:;\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_map[] = { \"\\251\", \"\\222OK\", \"\\251\", \"\" };\n\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);\n\n\tif (!error)\n\t{\n\t\tif (!nx_hoag)\n\t\t{\n\t\t\ts_printf(txt_buf,\n\t\t\t\t\"Dumping to SD card finished!\\n\"\n\t\t\t\t\"Saved to: #C7EA46 switchroot/joycon_mac.[bin/ini]#\\n\\n\");\n\n\t\t\tbool success = true;\n\n\t\t\t// Check if pairing info was found.\n\t\t\tif (joycon_found == 2)\n\t\t\t\tstrcat(txt_buf, \"#C7EA46 Success!#\\n#C7EA46 Found 2 out of 2 Joy-Con pairing data!#\\n\");\n\t\t\telse\n\t\t\t{\n\t\t\t\ts_printf(txt_buf + strlen(txt_buf), \"#FF8000 Failed!#\\n#FF8000 Warning:# Found #FFDD00 %d out of 2# pairing data!\\n\", joycon_found);\n\t\t\t\tsuccess = false;\n\t\t\t}\n\n\t\t\t// Check if pairing was done in HOS.\n\t\t\tif (is_l_hos && is_r_hos)\n\t\t\t\tstrcat(txt_buf, \"#C7EA46 Both pairing data are HOS based!#\");\n\t\t\telse if (!is_l_hos && is_r_hos)\n\t\t\t{\n\t\t\t\tstrcat(txt_buf, \"#FF8000 Warning:# #FFDD00 Left# pairing data is not HOS based!\");\n\t\t\t\tsuccess = false;\n\t\t\t}\n\t\t\telse if (is_l_hos && !is_r_hos)\n\t\t\t{\n\t\t\t\tstrcat(txt_buf, \"#FF8000 Warning:# #FFDD00 Right# pairing data is not HOS based!\");\n\t\t\t\tsuccess = false;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstrcat(txt_buf, \"#FF8000 Warning:# #FFDD00 No# pairing data is HOS based!\");\n\t\t\t\tsuccess = false;\n\t\t\t}\n\n\t\t\tif (!success)\n\t\t\t\tstrcat(txt_buf,\n\t\t\t\t\t\"\\n\\n#FFDD00 Make sure that both Joy-Con are connected,#\\n\"\n\t\t\t\t\t\"#FFDD00 and that you paired them in HOS!#\");\n\n\t\t\tif (cal_error)\n\t\t\t\ts_printf(txt_buf + strlen(txt_buf), \"\\n\\n#FF8000 Warning: Failed (%d) to get IMU calibration!#\", cal_error);\n\t\t}\n\t\telse\n\t\t{\n\t\t\ts_printf(txt_buf,\n\t\t\t\t\"Dumping to SD card finished!\\n\"\n\t\t\t\t\"Saved to: #C7EA46 switchroot/switch.cal#\\n\\n\");\n\t\t\tstrcat(txt_buf, \"#C7EA46 Success!#\\n#C7EA46 Found Lite Gamepad data!#\\n\");\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (!nx_hoag)\n\t\t\ts_printf(txt_buf, \"#FFDD00 Failed to dump Joy-Con pairing info!#\\n#FFDD00 Error: %d#\", error);\n\t\telse\n\t\t\ts_printf(txt_buf, \"#FFDD00 Failed to get Lite Gamepad info!#\\n#FFDD00 Error: %d#\", error);\n\t}\n\n\tlv_mbox_set_text(mbox, txt_buf);\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action); // Important. After set_text.\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\tfree(txt_buf);\n\tfree(data);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _home_screen_action(lv_obj_t *ddlist)\n{\n\tu32 new_selection = lv_ddlist_get_selected(ddlist);\n\tif (n_cfg.home_screen != new_selection)\n\t{\n\t\tn_cfg.home_screen = new_selection;\n\t\tnyx_changes_made = true;\n\t}\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _action_nyx_options_save(lv_obj_t *btns, const char * txt)\n{\n\tint btn_idx = lv_btnm_get_pressed(btns);\n\n\tnyx_mbox_action(btns, txt);\n\n\tif (!btn_idx)\n\t\t_save_nyx_options_action(NULL);\n\n\treturn LV_RES_INV;\n}\n\nstatic void _check_nyx_changes()\n{\n\tif (nyx_changes_made)\n\t{\n\t\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\t\tlv_obj_set_style(dark_bg, &mbox_darken);\n\t\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\t\tstatic const char * mbox_btn_map[] = { \"\\222Save\", \"\\222Cancel\", \"\" };\n\t\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\t\tlv_mbox_set_recolor_text(mbox, true);\n\n\t\tlv_mbox_set_text(mbox,\n\t\t\t\"#FF8000 Nyx configuration#\\n\\n\"\n\t\t\t\"You changed the configuration!\\n\\n\"\n\t\t\t\"Do you want to save it?\");\n\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map, _action_nyx_options_save);\n\t\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);\n\t\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\t\tlv_obj_set_top(mbox, true);\n\n\t\tnyx_changes_made = false;\n\t}\n}\n\nstatic lv_res_t _action_win_nyx_options_close(lv_obj_t *btn)\n{\n\t// Hide status bar options save button.\n\tlv_obj_set_opa_scale(status_bar.mid, LV_OPA_0);\n\tlv_obj_set_click(status_bar.mid, false);\n\n\tlv_res_t res = nyx_win_close_action(btn);\n\n\t_check_nyx_changes();\n\n\treturn res;\n}\n\nlv_res_t create_win_nyx_options(lv_obj_t *parrent_btn)\n{\n\tlv_theme_t *th = lv_theme_get_current();\n\n\tlv_obj_t *win = nyx_create_standard_window(SYMBOL_HOME\" Nyx Settings\", _action_win_nyx_options_close);\n\n\tstatic lv_style_t h_style;\n\tlv_style_copy(&h_style, &lv_style_transp);\n\th_style.body.padding.inner = 0;\n\th_style.body.padding.hor = LV_DPI - (LV_DPI / 4);\n\th_style.body.padding.ver = LV_DPI / 6;\n\n\t// Create containers to keep content inside.\n\tlv_obj_t * sw_h2 = lv_cont_create(win, NULL);\n\tlv_cont_set_style(sw_h2, &h_style);\n\tlv_cont_set_fit(sw_h2, false, true);\n\tlv_obj_set_width(sw_h2, (LV_HOR_RES / 9) * 4);\n\tlv_obj_set_click(sw_h2, false);\n\tlv_cont_set_layout(sw_h2, LV_LAYOUT_OFF);\n\n\tlv_obj_t * sw_h3 = lv_cont_create(win, NULL);\n\tlv_cont_set_style(sw_h3, &h_style);\n\tlv_cont_set_fit(sw_h3, false, true);\n\tlv_obj_set_width(sw_h3, (LV_HOR_RES / 9) * 4);\n\tlv_obj_set_click(sw_h3, false);\n\tlv_cont_set_layout(sw_h3, LV_LAYOUT_OFF);\n\tlv_obj_align(sw_h3, sw_h2, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 11 / 25, 0);\n\n\tlv_obj_t * l_cont = lv_cont_create(sw_h2, NULL);\n\tlv_cont_set_style(l_cont, &lv_style_transp_tight);\n\tlv_cont_set_fit(l_cont, true, true);\n\tlv_obj_set_click(l_cont, false);\n\tlv_cont_set_layout(l_cont, LV_LAYOUT_OFF);\n\tlv_obj_set_opa_scale(l_cont, LV_OPA_40);\n\n\tlv_obj_t *label_sep = lv_label_create(sw_h2, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\t// Create theme button.\n\tlv_obj_t *btn = lv_btn_create(sw_h2, NULL);\n\tlv_obj_t *label_btn = lv_label_create(btn, NULL);\n\tlv_btn_set_fit(btn, true, true);\n\tlv_label_set_static_text(label_btn, SYMBOL_COPY\" Color Theme\");\n\tlv_obj_align(btn, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI / 5 + 3);\n\tlv_btn_set_action(btn, LV_BTN_ACTION_CLICK, _create_window_nyx_colors);\n\n\tlv_obj_t *label_txt2 = lv_label_create(sw_h2, NULL);\n\tlv_label_set_recolor(label_txt2, true);\n\tlv_label_set_static_text(label_txt2, \"Customize #C7EA46 Theme# and #C7EA46 Accent# colors in Nyx.\\n\");\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, btn, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 - 8);\n\n\t// Create home screen settings list.\n\tlv_obj_t *line_sep = lv_line_create(sw_h2, NULL);\n\tstatic const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 2, 0} };\n\tlv_line_set_points(line_sep, line_pp, 2);\n\tlv_line_set_style(line_sep, th->line.decor);\n\tlv_obj_align(line_sep, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 4);\n\n\tlv_obj_t *label_txt = lv_label_create(l_cont, NULL);\n\tlv_label_set_static_text(label_txt, SYMBOL_HOME\" Home Screen\");\n\tlv_obj_set_style(label_txt, th->label.prim);\n\tlv_obj_align(label_txt, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);\n\n\tlv_obj_t *ddlist = lv_ddlist_create(l_cont, NULL);\n\tlv_obj_set_top(ddlist, true);\n\tlv_ddlist_set_draw_arrow(ddlist, true);\n\tlv_ddlist_set_options(ddlist,\n\t\t\"Main menu       \\n\"\n\t\t\"All Configs\\n\"\n\t\t\"Launch\\n\"\n\t\t\"More Configs\");\n\tlv_ddlist_set_selected(ddlist, n_cfg.home_screen);\n\tlv_ddlist_set_action(ddlist, _home_screen_action);\n\tlv_obj_align(ddlist, label_txt, LV_ALIGN_OUT_RIGHT_MID, LV_DPI * 2 / 3, 0);\n\n\tlabel_txt2 = lv_label_create(l_cont, NULL);\n\tlv_label_set_recolor(label_txt2, true);\n\tlv_label_set_static_text(label_txt2,\n\t\t\"Select what screen to show on Nyx boot.\\n\"\n\t\t\"#FF8000 All Configs:# #C7EA46 Combines More configs into Launch empty slots.#\\n\"\n\t\t\"#FF8000 Launch / More Configs:# #C7EA46 Uses the classic divided view.#\");\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 4);\n\n\tline_sep = lv_line_create(sw_h2, line_sep);\n\tlv_obj_align(line_sep, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 4);\n\n\t// Create entries per line button.\n\tlv_obj_t *btn2 = lv_btn_create(sw_h2, NULL);\n\tnyx_create_onoff_button(th, sw_h2, btn2, SYMBOL_GPS\" Extended Boot Entries\", _entries_columns_action, true);\n\tlv_obj_align(btn2, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 10);\n\tif (n_cfg.entries_5_col)\n\t\tlv_btn_set_state(btn2, LV_BTN_STATE_TGL_REL);\n\tnyx_generic_onoff_toggle(btn2);\n\n\tlabel_txt2 = lv_label_create(sw_h2, NULL);\n\tlv_label_set_recolor(label_txt2, true);\n\tlv_label_set_static_text(label_txt2,\n\t\t\"Sets the boot entries per line to 5. (Default is 4)\\n\"\n\t\t\"#C7EA46 This allows a total of 10 boot entries to be shown in Launch#\\n\"\n\t\t\"#C7EA46 and More Configs sections.#\\n\\n\\n\");\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, btn2, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 12);\n\n\t// Create the second column.\n\tlabel_sep = lv_label_create(sw_h3, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\t// Create Dump Joy-Con BT button.\n\tlv_obj_t *btn3 = lv_btn_create(sw_h3, NULL);\n\tlv_obj_t *label_btn3 = lv_label_create(btn3, NULL);\n\tlv_btn_set_fit(btn3, true, true);\n\tlv_label_set_static_text(label_btn3, SYMBOL_DOWNLOAD\" Dump Joy-Con BT\");\n\tlv_obj_align(btn3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI / 3);\n\tlv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, _joycon_info_dump_action);\n\n\tlabel_txt2 = lv_label_create(sw_h3, NULL);\n\tlv_label_set_recolor(label_txt2, true);\n\tlv_label_set_static_text(label_txt2,\n\t\t\"Allows you to save the Switch and Joy-Con MAC addresses\\n\"\n\t\t\"and the LTKs associated with them. For #C7EA46 Android# and #C7EA46 Linux#.\");\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, btn3, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 4);\n\n\tline_sep = lv_line_create(sw_h3, line_sep);\n\tlv_obj_align(line_sep, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 4);\n\n\t// Create Backup/Restore Verification list.\n\tlabel_txt = lv_label_create(sw_h3, NULL);\n\tlv_label_set_static_text(label_txt, SYMBOL_MODULES_ALT\" Data Verification\");\n\tlv_obj_set_style(label_txt, th->label.prim);\n\tlv_obj_align(label_txt, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);\n\n\tlv_obj_t *ddlist2 = lv_ddlist_create(sw_h3, NULL);\n\tlv_obj_set_top(ddlist2, true);\n\tlv_ddlist_set_draw_arrow(ddlist2, true);\n\tlv_ddlist_set_options(ddlist2,\n\t\t\"Off (Fastest)\\n\"\n\t\t\"Sparse (Fast)    \\n\"\n\t\t\"Full (Slow)\\n\"\n\t\t\"Full (Hashes)\");\n\tlv_ddlist_set_selected(ddlist2, n_cfg.verification);\n\tlv_obj_align(ddlist2, label_txt, LV_ALIGN_OUT_RIGHT_MID, LV_DPI * 3 / 8, 0);\n\tlv_ddlist_set_action(ddlist2, _data_verification_action);\n\n\tlabel_txt2 = lv_label_create(sw_h3, NULL);\n\tlv_label_set_static_text(label_txt2, \"Set the type of data verification done for backup and restore.\\n\"\n\t\t\"Can be canceled without losing the backup/restore.\\n\");\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 4);\n\n\tline_sep = lv_line_create(sw_h3, line_sep);\n\tlv_obj_align(line_sep, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 4);\n\n\t// Create clock edit button.\n\tlv_obj_t *btn5 = lv_btn_create(sw_h3, NULL);\n\tlv_obj_t *label_btn5 = lv_label_create(btn5, NULL);\n\tlv_btn_set_fit(btn5, true, true);\n\tlv_label_set_static_text(label_btn5, SYMBOL_CLOCK\" Clock (Offset)\");\n\tlv_obj_align(btn5, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);\n\tlv_btn_set_action(btn5, LV_BTN_ACTION_CLICK, _create_mbox_clock_edit);\n\n\tlabel_txt2 = lv_label_create(sw_h3, NULL);\n\tlv_label_set_recolor(label_txt2, true);\n\tlv_label_set_static_text(label_txt2,\n\t\t\"Change clock offset manually.\\n\"\n\t\t\"#C7EA46 The entered Date and Time will be converted to an offset#\\n\"\n\t\t\"#C7EA46 automatically. This will be also used for FatFS operations.#\");\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, btn5, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 4);\n\n\t// Enable save options button in status bar and set action.\n\tlv_btn_set_action(status_bar.mid, LV_BTN_ACTION_CLICK, _save_nyx_options_action);\n\tlv_obj_set_opa_scale(status_bar.mid, LV_OPA_COVER);\n\tlv_obj_set_click(status_bar.mid, true);\n\n\tlv_obj_set_top(l_cont, true); // Set the ddlist container at top.\n\tlv_obj_set_parent(ddlist, l_cont); // Reorder ddlist.\n\tlv_obj_set_top(ddlist, true);\n\tlv_obj_set_top(ddlist2, true);\n\n\treturn LV_RES_OK;\n}\n\nvoid create_tab_options(lv_theme_t *th, lv_obj_t *parent)\n{\n\tlv_page_set_scrl_layout(parent, LV_LAYOUT_PRETTY);\n\n\tstatic lv_style_t h_style;\n\tlv_style_copy(&h_style, &lv_style_transp);\n\th_style.body.padding.inner = 0;\n\th_style.body.padding.hor = LV_DPI - (LV_DPI / 4);\n\th_style.body.padding.ver = LV_DPI / 6;\n\n\t// Create containers to keep content inside.\n\tlv_obj_t * sw_h2 = lv_cont_create(parent, NULL);\n\tlv_cont_set_style(sw_h2, &h_style);\n\tlv_cont_set_fit(sw_h2, false, true);\n\tlv_obj_set_width(sw_h2, (LV_HOR_RES / 9) * 4);\n\tlv_obj_set_click(sw_h2, false);\n\tlv_cont_set_layout(sw_h2, LV_LAYOUT_OFF);\n\n\tlv_obj_t * sw_h3 = lv_cont_create(parent, NULL);\n\tlv_cont_set_style(sw_h3, &h_style);\n\tlv_cont_set_fit(sw_h3, false, true);\n\tlv_obj_set_width(sw_h3, (LV_HOR_RES / 9) * 4);\n\tlv_obj_set_click(sw_h3, false);\n\tlv_cont_set_layout(sw_h3, LV_LAYOUT_OFF);\n\n\tlv_obj_t * l_cont = lv_cont_create(sw_h2, NULL);\n\tlv_cont_set_style(l_cont, &lv_style_transp_tight);\n\tlv_cont_set_fit(l_cont, true, true);\n\tlv_obj_set_click(l_cont, false);\n\tlv_cont_set_layout(l_cont, LV_LAYOUT_OFF);\n\tlv_obj_set_opa_scale(l_cont, LV_OPA_40);\n\n\tlv_obj_t *label_sep = lv_label_create(sw_h2, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\t// Create Auto Boot button.\n\tlv_obj_t *btn = lv_btn_create(sw_h2, NULL);\n\tif (hekate_bg)\n\t{\n\t\tlv_btn_set_style(btn, LV_BTN_STYLE_REL, &btn_transp_rel);\n\t\tlv_btn_set_style(btn, LV_BTN_STYLE_PR, &btn_transp_pr);\n\t\tlv_btn_set_style(btn, LV_BTN_STYLE_TGL_REL, &btn_transp_tgl_rel);\n\t\tlv_btn_set_style(btn, LV_BTN_STYLE_TGL_PR, &btn_transp_tgl_pr);\n\t}\n\tlv_btn_set_layout(btn, LV_LAYOUT_OFF);\n\tlv_obj_t *label_btn = lv_label_create(btn, NULL);\n\tlv_label_set_recolor(label_btn, true);\n\tlv_btn_set_fit(btn, true, true);\n\tlv_btn_set_toggle(btn, true);\n\tlv_label_set_static_text(label_btn, SYMBOL_GPS\" Auto Boot #00FFC9   ON #\");\n\tlv_btn_set_action(btn, LV_BTN_ACTION_CLICK, _autoboot_hide_delay_action);\n\tlv_obj_align(btn, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI / 18 + 6);\n\tlv_btn_set_fit(btn, false, false);\n\tautoboot_btn = btn;\n\n\tlv_obj_t *label_txt2 = lv_label_create(sw_h2, NULL);\n\tlv_label_set_static_text(label_txt2, \"Choose which boot entry or payload to automatically boot\\nwhen injecting.\");\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, btn, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 - 4);\n\n\tlv_obj_t *line_sep = lv_line_create(sw_h2, NULL);\n\tstatic const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 2, 0} };\n\tlv_line_set_points(line_sep, line_pp, 2);\n\tlv_line_set_style(line_sep, th->line.decor);\n\tlv_obj_align(line_sep, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 4);\n\n\t// Create Boot time delay list.\n\tlv_obj_t *label_txt = lv_label_create(l_cont, NULL);\n\tlv_label_set_static_text(label_txt, SYMBOL_CLOCK\" Boot Time Delay  \");\n\tlv_obj_set_style(label_txt, th->label.prim);\n\tlv_obj_align(label_txt, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);\n\n\tlv_obj_t *ddlist = lv_ddlist_create(l_cont, NULL);\n\tlv_obj_set_top(ddlist, true);\n\tlv_ddlist_set_draw_arrow(ddlist, true);\n\tlv_ddlist_set_options(ddlist,\n\t\t\"No bootlogo    \\n\"\n\t\t\"1 second\\n\"\n\t\t\"2 seconds\\n\"\n\t\t\"3 seconds\\n\"\n\t\t\"4 seconds\\n\"\n\t\t\"5 seconds\\n\"\n\t\t\"6 seconds\");\n\tlv_ddlist_set_selected(ddlist, 3);\n\tlv_obj_align(ddlist, label_txt, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 4, 0);\n\tlv_ddlist_set_action(ddlist, _autoboot_delay_action);\n\tlv_ddlist_set_selected(ddlist, h_cfg.bootwait);\n\n\tif (hekate_bg)\n\t{\n\t\tlv_ddlist_set_style(ddlist, LV_DDLIST_STYLE_BG, &ddlist_transp_bg);\n\t\tlv_ddlist_set_style(ddlist, LV_DDLIST_STYLE_BGO, &ddlist_transp_bg);\n\t\tlv_ddlist_set_style(ddlist, LV_DDLIST_STYLE_PR, &ddlist_transp_sel);\n\t\tlv_ddlist_set_style(ddlist, LV_DDLIST_STYLE_SEL, &ddlist_transp_sel);\n\t}\n\n\tlabel_txt2 = lv_label_create(l_cont, NULL);\n\tlv_label_set_recolor(label_txt2, true);\n\tlv_label_set_static_text(label_txt2,\n\t\t\"Set how long to show bootlogo when autoboot is enabled.\\n\"\n\t\t\"#C7EA46 You can press# #FF8000 VOL-# #C7EA46 during that time to enter hekate's menu.#\\n\");\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 4);\n\n\tline_sep = lv_line_create(sw_h2, line_sep);\n\tlv_obj_align(line_sep, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 4);\n\n\t// Create Auto NoGC button.\n\tlv_obj_t *btn2 = lv_btn_create(sw_h2, NULL);\n\tnyx_create_onoff_button(th, sw_h2, btn2, SYMBOL_CHIP\" Auto NoGC\", auto_nogc_toggle, true);\n\tlv_obj_align(btn2, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 10);\n\n\tlabel_txt2 = lv_label_create(sw_h2, NULL);\n\tlv_label_set_recolor(label_txt2, true);\n\tlv_label_set_static_text(label_txt2,\n\t\t\"It checks fuses and applies the patch automatically\\n\"\n\t\t\"if higher firmware. It is now a global config and set\\n\"\n\t\t\"at auto by default. (ON: Auto)\\n\\n\\n\");\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, btn2, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 12);\n\n\tlabel_sep = lv_label_create(sw_h3, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\t// Create Auto HOS Power Off button.\n\tlv_obj_t *btn3 = lv_btn_create(sw_h3, NULL);\n\tnyx_create_onoff_button(th, sw_h3, btn3, SYMBOL_POWER\" Auto HOS Power Off\", auto_hos_poweroff_toggle, true);\n\tlv_obj_align(btn3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);\n\n\tlabel_txt2 = lv_label_create(sw_h3, NULL);\n\tlv_label_set_static_text(label_txt2,\n\t\t\"When Shutdown is used from HOS, the device wakes up after\\n\"\n\t\t\"15s. Enable this to automatically power off on the next\\npayload injection.\");\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, btn3, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 12);\n\n\tline_sep = lv_line_create(sw_h3, line_sep);\n\tlv_obj_align(line_sep, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 4);\n\n\t// Create Backlight slider.\n\tlabel_txt = lv_label_create(sw_h3, NULL);\n\tlv_label_set_static_text(label_txt, SYMBOL_BRIGHTNESS\" Backlight\");\n\tlv_obj_set_style(label_txt, th->label.prim);\n\tlv_obj_align(label_txt, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);\n\n\tlv_obj_t * slider = lv_slider_create(sw_h3, NULL);\n\tlv_obj_set_width(slider, LV_DPI * 80 / 34);\n\t//lv_obj_set_height(slider, LV_DPI * 4 / 10);\n\tlv_bar_set_range(slider, 30, 220);\n\tlv_bar_set_value(slider, h_cfg.backlight);\n\tlv_slider_set_action(slider, _slider_brightness_action);\n\tlv_obj_align(slider, label_txt, LV_ALIGN_OUT_RIGHT_MID, LV_DPI * 20 / 15, 0);\n\n\tlabel_txt2 = lv_label_create(sw_h3, NULL);\n\tlv_label_set_static_text(label_txt2, \"Set backlight brightness.\\n\\n\");\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 4);\n\n\tline_sep = lv_line_create(sw_h3, line_sep);\n\tlv_obj_align(line_sep, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 4);\n\n\t// Create Update r2p button.\n\tlv_obj_t *btn4 = lv_btn_create(sw_h3, NULL);\n\tnyx_create_onoff_button(th, sw_h3, btn4, SYMBOL_REFRESH\" Update Reboot 2 Payload\", _update_r2p_action, true);\n\tlv_obj_align(btn4, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 10);\n\n\tlabel_txt2 = lv_label_create(sw_h3, NULL);\n\tlv_label_set_recolor(label_txt2, true);\n\tlv_label_set_static_text(label_txt2,\n\t\t\"If #FF8000 FSS0# is used in the selected boot entry, the reboot 2 payload\\n\"\n\t\t\"binary will be checked and forced to be updated to hekate.\\n\\n\\n\\n\");\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, btn4, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 12);\n\n\t// Set default loaded states.\n\tif (h_cfg.autohosoff)\n\t\tlv_btn_set_state(btn3, LV_BTN_STATE_TGL_REL);\n\tif (h_cfg.autonogc)\n\t\tlv_btn_set_state(btn2, LV_BTN_STATE_TGL_REL);\n\tif (h_cfg.updater2p)\n\t\tlv_btn_set_state(btn4, LV_BTN_STATE_TGL_REL);\n\n\tnyx_generic_onoff_toggle(btn2);\n\tnyx_generic_onoff_toggle(btn3);\n\tnyx_generic_onoff_toggle(btn4);\n\t_autoboot_hide_delay_action(btn);\n\n\tlv_obj_set_top(l_cont, true); // Set the ddlist container at top.\n\tlv_obj_set_parent(ddlist, l_cont); // Reorder ddlist.\n\tlv_obj_set_top(ddlist, true);\n}\n"
  },
  {
    "path": "nyx/nyx_gui/frontend/gui_options.h",
    "content": "/*\n * Copyright (c) 2018-2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _GUI_OPTIONS_H_\n#define _GUI_OPTIONS_H_\n\n#include <libs/lvgl/lvgl.h>\n\nvoid nyx_options_clear_ini_changes_made();\nbool nyx_options_get_ini_changes_made();\nvoid first_time_clock_edit(void *param);\nlv_res_t create_win_nyx_options(lv_obj_t *parrent_btn);\nvoid create_tab_options(lv_theme_t *th, lv_obj_t *parent);\n\n#endif\n"
  },
  {
    "path": "nyx/nyx_gui/frontend/gui_tools.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <stdlib.h>\n\n#include <bdk.h>\n\n#include \"gui.h\"\n#include \"gui_tools.h\"\n#include \"gui_tools_partition_manager.h\"\n#include \"gui_emmc_tools.h\"\n#include \"fe_emummc_tools.h\"\n#include \"../config.h\"\n#include \"../hos/pkg1.h\"\n#include \"../hos/pkg2.h\"\n#include \"../hos/hos.h\"\n#include <libs/compr/blz.h>\n#include <libs/fatfs/ff.h>\n\nlv_obj_t *ums_mbox;\n\nextern char *emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);\n\nstatic lv_obj_t *_create_container(lv_obj_t *parent)\n{\n\tstatic lv_style_t h_style;\n\tlv_style_copy(&h_style, &lv_style_transp);\n\th_style.body.padding.inner = 0;\n\th_style.body.padding.hor = LV_DPI - (LV_DPI / 4);\n\th_style.body.padding.ver = LV_DPI / 6;\n\n\tlv_obj_t *h1 = lv_cont_create(parent, NULL);\n\tlv_cont_set_style(h1, &h_style);\n\tlv_cont_set_fit(h1, false, true);\n\tlv_obj_set_width(h1, (LV_HOR_RES / 9) * 4);\n\tlv_obj_set_click(h1, false);\n\tlv_cont_set_layout(h1, LV_LAYOUT_OFF);\n\n\treturn h1;\n}\n\nbool get_set_autorcm_status(bool toggle)\n{\n\tu32 sector;\n\tu8 corr_mod0, mod1;\n\tbool enabled = false;\n\n\tif (h_cfg.t210b01)\n\t\treturn false;\n\n\temmc_initialize(false);\n\n\tu8 *tempbuf = (u8 *)malloc(0x200);\n\temmc_set_partition(EMMC_BOOT0);\n\tsdmmc_storage_read(&emmc_storage, 0x200 / EMMC_BLOCKSIZE, 1, tempbuf);\n\n\t// Get the correct RSA modulus byte masks.\n\tnx_emmc_get_autorcm_masks(&corr_mod0, &mod1);\n\n\t// Check if 2nd byte of modulus is correct.\n\tif (tempbuf[0x11] != mod1)\n\t\tgoto out;\n\n\tif (tempbuf[0x10] != corr_mod0)\n\t\tenabled = true;\n\n\t// Toggle autorcm status if requested.\n\tif (toggle)\n\t{\n\t\t// Iterate BCTs.\n\t\tfor (u32 i = 0; i < 4; i++)\n\t\t{\n\t\t\tsector = (0x200 + (0x4000 * i)) / EMMC_BLOCKSIZE; // 0x4000 bct + 0x200 offset.\n\t\t\tsdmmc_storage_read(&emmc_storage, sector, 1, tempbuf);\n\n\t\t\tif (!enabled)\n\t\t\t\ttempbuf[0x10] = 0;\n\t\t\telse\n\t\t\t\ttempbuf[0x10] = corr_mod0;\n\t\t\tsdmmc_storage_write(&emmc_storage, sector, 1, tempbuf);\n\t\t}\n\t\tenabled = !enabled;\n\t}\n\n\t// Check if RCM is patched and protect from a possible brick.\n\tif (enabled && h_cfg.rcm_patched && hw_get_chip_id() != GP_HIDREV_MAJOR_T210B01)\n\t{\n\t\t// Iterate BCTs.\n\t\tfor (u32 i = 0; i < 4; i++)\n\t\t{\n\t\t\tsector = (0x200 + (0x4000 * i)) / EMMC_BLOCKSIZE; // 0x4000 bct + 0x200 offset.\n\t\t\tsdmmc_storage_read(&emmc_storage, sector, 1, tempbuf);\n\n\t\t\t// Check if 2nd byte of modulus is correct.\n\t\t\tif (tempbuf[0x11] != mod1)\n\t\t\t\tcontinue;\n\n\t\t\t// If AutoRCM is enabled, disable it.\n\t\t\tif (tempbuf[0x10] != corr_mod0)\n\t\t\t{\n\t\t\t\ttempbuf[0x10] = corr_mod0;\n\n\t\t\t\tsdmmc_storage_write(&emmc_storage, sector, 1, tempbuf);\n\t\t\t}\n\t\t}\n\n\t\tenabled = false;\n\t}\n\nout:\n\tfree(tempbuf);\n\temmc_end();\n\n\th_cfg.autorcm_enabled = enabled;\n\n\treturn enabled;\n}\n\nstatic lv_res_t _create_mbox_autorcm_status(lv_obj_t *btn)\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char * mbox_btn_map[] = { \"\\251\", \"\\222OK\", \"\\251\", \"\" };\n\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\n\tbool enabled = get_set_autorcm_status(true);\n\n\tif (enabled)\n\t{\n\t\tlv_mbox_set_text(mbox,\n\t\t\t\"AutoRCM is now #C7EA46 ENABLED!#\\n\\n\"\n\t\t\t\"You can now automatically enter RCM by only pressing #FF8000 POWER#.\\n\"\n\t\t\t\"Use the AutoRCM button here again if you want to remove it later on.\");\n\t}\n\telse\n\t{\n\t\tlv_mbox_set_text(mbox,\n\t\t\t\"AutoRCM is now #FF8000 DISABLED!#\\n\\n\"\n\t\t\t\"The boot process is now normal and you need the #FF8000 VOL+# + #FF8000 HOME# (jig) combo to enter RCM.\\n\");\n\t}\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\tif (enabled)\n\t\tlv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);\n\telse\n\t\tlv_btn_set_state(btn, LV_BTN_STATE_REL);\n\tnyx_generic_onoff_toggle(btn);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _create_mbox_hid(usb_ctxt_t *usbs)\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_map_dis[] = { \"\\251\", \"\\262Close\", \"\\251\", \"\" };\n\tstatic const char *mbox_btn_map[] = { \"\\251\", \"\\222Close\", \"\\251\", \"\" };\n\tlv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\n\tchar *txt_buf = malloc(SZ_4K);\n\n\ts_printf(txt_buf, \"#FF8000 HID Emulation#\\n\\n#C7EA46 Device:# \");\n\n\tif (usbs->type == USB_HID_GAMEPAD)\n\t\tstrcat(txt_buf, \"Gamepad\");\n\telse\n\t\tstrcat(txt_buf, \"Touchpad\");\n\n\tlv_mbox_set_text(mbox, txt_buf);\n\tfree(txt_buf);\n\n\tlv_obj_t *lbl_status = lv_label_create(mbox, NULL);\n\tlv_label_set_recolor(lbl_status, true);\n\tlv_label_set_text(lbl_status, \" \");\n\tusbs->label = (void *)lbl_status;\n\n\tlv_obj_t *lbl_tip = lv_label_create(mbox, NULL);\n\tlv_label_set_recolor(lbl_tip, true);\n\tlv_label_set_static_text(lbl_tip, \"Note: To end it, press #C7EA46 L3# + #C7EA46 HOME# or remove the cable.\");\n\tlv_obj_set_style(lbl_tip, &hint_small_style);\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map_dis, nyx_mbox_action);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\tusb_device_gadget_hid(usbs);\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _create_mbox_ums(usb_ctxt_t *usbs)\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_map_dis[] = { \"\\251\", \"\\262Close\", \"\\251\", \"\" };\n\tstatic const char *mbox_btn_map[] = { \"\\251\", \"\\222Close\", \"\\251\", \"\" };\n\tlv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\n\tchar *txt_buf = malloc(SZ_4K);\n\n\ts_printf(txt_buf, \"#FF8000 USB Mass Storage#\\n\\n#C7EA46 Device:# \");\n\n\tif (usbs->type == MMC_SD)\n\t{\n\t\tswitch (usbs->partition)\n\t\t{\n\t\tcase 0:\n\t\t\tstrcat(txt_buf, \"SD Card\");\n\t\t\tbreak;\n\t\tcase EMMC_GPP + 1:\n\t\t\tstrcat(txt_buf, \"emuMMC GPP\");\n\t\t\tbreak;\n\t\tcase EMMC_BOOT0 + 1:\n\t\t\tstrcat(txt_buf, \"emuMMC BOOT0\");\n\t\t\tbreak;\n\t\tcase EMMC_BOOT1 + 1:\n\t\t\tstrcat(txt_buf, \"emuMMC BOOT1\");\n\t\t\tbreak;\n\t\t}\n\t}\n\telse\n\t{\n\t\tswitch (usbs->partition)\n\t\t{\n\t\tcase EMMC_GPP + 1:\n\t\t\tstrcat(txt_buf, \"eMMC GPP\");\n\t\t\tbreak;\n\t\tcase EMMC_BOOT0 + 1:\n\t\t\tstrcat(txt_buf, \"eMMC BOOT0\");\n\t\t\tbreak;\n\t\tcase EMMC_BOOT1 + 1:\n\t\t\tstrcat(txt_buf, \"eMMC BOOT1\");\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tlv_mbox_set_text(mbox, txt_buf);\n\tfree(txt_buf);\n\n\tlv_obj_t *lbl_status = lv_label_create(mbox, NULL);\n\tlv_label_set_recolor(lbl_status, true);\n\tlv_label_set_text(lbl_status, \" \");\n\tusbs->label = (void *)lbl_status;\n\n\tlv_obj_t *lbl_tip = lv_label_create(mbox, NULL);\n\tlv_label_set_recolor(lbl_tip, true);\n\tif (!usbs->ro)\n\t{\n\t\tif (usbs->type == MMC_SD)\n\t\t{\n\t\t\tlv_label_set_static_text(lbl_tip,\n\t\t\t\t\"Note: To end it, #C7EA46 safely eject# from inside the OS.\\n\"\n\t\t\t\t\"       #FFDD00 DO NOT remove the cable!#\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlv_label_set_static_text(lbl_tip,\n\t\t\t\t\"Note: To end it, #C7EA46 safely eject# from inside the OS.\\n\"\n\t\t\t\t\"       #FFDD00 If it's not mounted, you might need to remove the cable!#\");\n\t\t}\n\t}\n\telse\n\t{\n\t\tlv_label_set_static_text(lbl_tip,\n\t\t\t\"Note: To end it, #C7EA46 safely eject# from inside the OS\\n\"\n\t\t\t\"       or by removing the cable!#\");\n\t}\n\tlv_obj_set_style(lbl_tip, &hint_small_style);\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map_dis, nyx_mbox_action);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\t// Dim backlight.\n\tdisplay_backlight_brightness(20, 1000);\n\n\tusb_device_gadget_ums(usbs);\n\n\t// Restore backlight.\n\tdisplay_backlight_brightness(h_cfg.backlight - 20, 1000);\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);\n\n\tums_mbox = dark_bg;\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _create_mbox_ums_error(int error)\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_map[] = { \"\\251\", \"\\222OK\", \"\\251\", \"\" };\n\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\n\tswitch (error)\n\t{\n\tcase 1:\n\t\tlv_mbox_set_text(mbox, \"#FF8000 USB Mass Storage#\\n\\n#FFFF00 Error mounting SD Card!#\");\n\t\tbreak;\n\tcase 2:\n\t\tlv_mbox_set_text(mbox, \"#FF8000 USB Mass Storage#\\n\\n#FFFF00 No emuMMC found active!#\");\n\t\tbreak;\n\tcase 3:\n\t\tlv_mbox_set_text(mbox, \"#FF8000 USB Mass Storage#\\n\\n#FFFF00 Active emuMMC is not partition based!#\");\n\t\tbreak;\n\t}\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\treturn LV_RES_OK;\n}\n\nstatic void usb_gadget_set_text(void *lbl, const char *text)\n{\n\tlv_label_set_text((lv_obj_t *)lbl, text);\n\tmanual_system_maintenance(true);\n}\n\nstatic lv_res_t _action_hid_jc(lv_obj_t *btn)\n{\n\t// Reduce BPMP, RAM and backlight and power off SDMMC1 to conserve power.\n\tsd_end();\n\tminerva_change_freq(FREQ_800);\n\tbpmp_clk_rate_relaxed(true);\n\tdisplay_backlight_brightness(10, 1000);\n\n\tusb_ctxt_t usbs;\n\tusbs.type = USB_HID_GAMEPAD;\n\tusbs.system_maintenance = &manual_system_maintenance;\n\tusbs.set_text = &usb_gadget_set_text;\n\n\t_create_mbox_hid(&usbs);\n\n\t// Restore BPMP, RAM and backlight.\n\tminerva_change_freq(FREQ_1600);\n\tbpmp_clk_rate_relaxed(false);\n\tdisplay_backlight_brightness(h_cfg.backlight - 20, 1000);\n\n\treturn LV_RES_OK;\n}\n\n/*\nstatic lv_res_t _action_hid_touch(lv_obj_t *btn)\n{\n\t// Reduce BPMP, RAM and backlight and power off SDMMC1 to conserve power.\n\tsd_end();\n\tminerva_change_freq(FREQ_800);\n\tbpmp_clk_rate_relaxed(true);\n\tdisplay_backlight_brightness(10, 1000);\n\n\tusb_ctxt_t usbs;\n\tusbs.type = USB_HID_TOUCHPAD;\n\tusbs.system_maintenance = &manual_system_maintenance;\n\tusbs.set_text = &usb_gadget_set_text;\n\n\t_create_mbox_hid(&usbs);\n\n\t// Restore BPMP, RAM and backlight.\n\tminerva_change_freq(FREQ_1600);\n\tbpmp_clk_rate_relaxed(false);\n\tdisplay_backlight_brightness(h_cfg.backlight - 20, 1000);\n\n\treturn LV_RES_OK;\n}\n*/\n\nstatic bool usb_msc_emmc_read_only;\nlv_res_t action_ums_sd(lv_obj_t *btn)\n{\n\tusb_ctxt_t usbs;\n\tusbs.type = MMC_SD;\n\tusbs.partition = 0;\n\tusbs.offset = 0;\n\tusbs.sectors = 0;\n\tusbs.ro = 0;\n\tusbs.system_maintenance = &manual_system_maintenance;\n\tusbs.set_text = &usb_gadget_set_text;\n\n\t_create_mbox_ums(&usbs);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _action_ums_emmc_boot0(lv_obj_t *btn)\n{\n\tif (!nyx_emmc_check_battery_enough())\n\t\treturn LV_RES_OK;\n\n\tusb_ctxt_t usbs;\n\tusbs.type = MMC_EMMC;\n\tusbs.partition = EMMC_BOOT0 + 1;\n\tusbs.offset = 0;\n\tusbs.sectors = 0;\n\tusbs.ro = usb_msc_emmc_read_only;\n\tusbs.system_maintenance = &manual_system_maintenance;\n\tusbs.set_text = &usb_gadget_set_text;\n\n\t_create_mbox_ums(&usbs);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _action_ums_emmc_boot1(lv_obj_t *btn)\n{\n\tif (!nyx_emmc_check_battery_enough())\n\t\treturn LV_RES_OK;\n\n\tusb_ctxt_t usbs;\n\tusbs.type = MMC_EMMC;\n\tusbs.partition = EMMC_BOOT1 + 1;\n\tusbs.offset = 0;\n\tusbs.sectors = 0;\n\tusbs.ro = usb_msc_emmc_read_only;\n\tusbs.system_maintenance = &manual_system_maintenance;\n\tusbs.set_text = &usb_gadget_set_text;\n\n\t_create_mbox_ums(&usbs);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _action_ums_emmc_gpp(lv_obj_t *btn)\n{\n\tif (!nyx_emmc_check_battery_enough())\n\t\treturn LV_RES_OK;\n\n\tusb_ctxt_t usbs;\n\tusbs.type = MMC_EMMC;\n\tusbs.partition = EMMC_GPP + 1;\n\tusbs.offset = 0;\n\tusbs.sectors = 0;\n\tusbs.ro = usb_msc_emmc_read_only;\n\tusbs.system_maintenance = &manual_system_maintenance;\n\tusbs.set_text = &usb_gadget_set_text;\n\n\t_create_mbox_ums(&usbs);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _action_ums_emuemmc_boot0(lv_obj_t *btn)\n{\n\tif (!nyx_emmc_check_battery_enough())\n\t\treturn LV_RES_OK;\n\n\tusb_ctxt_t usbs;\n\n\tint error = sd_mount();\n\tif (!error)\n\t{\n\t\temummc_cfg_t emu_info;\n\t\tload_emummc_cfg(&emu_info);\n\n\t\terror = 2;\n\t\tif (emu_info.enabled)\n\t\t{\n\t\t\terror = 3;\n\t\t\tif (emu_info.sector)\n\t\t\t{\n\t\t\t\terror = 0;\n\t\t\t\tusbs.offset = emu_info.sector;\n\t\t\t}\n\t\t}\n\n\t\tif (emu_info.path)\n\t\t\tfree(emu_info.path);\n\t\tif (emu_info.nintendo_path)\n\t\t\tfree(emu_info.nintendo_path);\n\t}\n\tsd_unmount();\n\n\tif (error)\n\t\t_create_mbox_ums_error(error);\n\telse\n\t{\n\t\tusbs.type = MMC_SD;\n\t\tusbs.partition = EMMC_BOOT0 + 1;\n\t\tusbs.sectors = 0x2000; // Forced 4MB.\n\t\tusbs.ro = usb_msc_emmc_read_only;\n\t\tusbs.system_maintenance = &manual_system_maintenance;\n\t\tusbs.set_text = &usb_gadget_set_text;\n\t\t_create_mbox_ums(&usbs);\n\t}\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _action_ums_emuemmc_boot1(lv_obj_t *btn)\n{\n\tif (!nyx_emmc_check_battery_enough())\n\t\treturn LV_RES_OK;\n\n\tusb_ctxt_t usbs;\n\n\tint error = sd_mount();\n\tif (!error)\n\t{\n\t\temummc_cfg_t emu_info;\n\t\tload_emummc_cfg(&emu_info);\n\n\t\terror = 2;\n\t\tif (emu_info.enabled)\n\t\t{\n\t\t\terror = 3;\n\t\t\tif (emu_info.sector)\n\t\t\t{\n\t\t\t\terror = 0;\n\t\t\t\tusbs.offset = emu_info.sector + 0x2000;\n\t\t\t}\n\t\t}\n\n\t\tif (emu_info.path)\n\t\t\tfree(emu_info.path);\n\t\tif (emu_info.nintendo_path)\n\t\t\tfree(emu_info.nintendo_path);\n\t}\n\tsd_unmount();\n\n\tif (error)\n\t\t_create_mbox_ums_error(error);\n\telse\n\t{\n\t\tusbs.type = MMC_SD;\n\t\tusbs.partition = EMMC_BOOT1 + 1;\n\t\tusbs.sectors = 0x2000; // Forced 4MB.\n\t\tusbs.ro = usb_msc_emmc_read_only;\n\t\tusbs.system_maintenance = &manual_system_maintenance;\n\t\tusbs.set_text = &usb_gadget_set_text;\n\t\t_create_mbox_ums(&usbs);\n\t}\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _action_ums_emuemmc_gpp(lv_obj_t *btn)\n{\n\tif (!nyx_emmc_check_battery_enough())\n\t\treturn LV_RES_OK;\n\n\tusb_ctxt_t usbs;\n\n\tint error = sd_mount();\n\tif (!error)\n\t{\n\t\temummc_cfg_t emu_info;\n\t\tload_emummc_cfg(&emu_info);\n\n\t\terror = 2;\n\t\tif (emu_info.enabled)\n\t\t{\n\t\t\terror = 3;\n\t\t\tif (emu_info.sector)\n\t\t\t{\n\t\t\t\terror = 1;\n\t\t\t\tusbs.offset = emu_info.sector + 0x4000;\n\n\t\t\t\tu8 *gpt = malloc(SD_BLOCKSIZE);\n\t\t\t\tif (!sdmmc_storage_read(&sd_storage, usbs.offset + 1, 1, gpt))\n\t\t\t\t{\n\t\t\t\t\tif (!memcmp(gpt, \"EFI PART\", 8))\n\t\t\t\t\t{\n\t\t\t\t\t\terror = 0;\n\t\t\t\t\t\tusbs.sectors = *(u32 *)(gpt + 0x20) + 1; // Backup LBA + 1.\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (emu_info.path)\n\t\t\tfree(emu_info.path);\n\t\tif (emu_info.nintendo_path)\n\t\t\tfree(emu_info.nintendo_path);\n\t}\n\tsd_unmount();\n\n\tif (error)\n\t\t_create_mbox_ums_error(error);\n\telse\n\t{\n\t\tusbs.type = MMC_SD;\n\t\tusbs.partition = EMMC_GPP + 1;\n\t\tusbs.ro = usb_msc_emmc_read_only;\n\t\tusbs.system_maintenance = &manual_system_maintenance;\n\t\tusbs.set_text = &usb_gadget_set_text;\n\t\t_create_mbox_ums(&usbs);\n\t}\n\n\treturn LV_RES_OK;\n}\n\nvoid nyx_run_ums(void *param)\n{\n\tu32 *cfg = (u32 *)param;\n\n\tu8 type = (*cfg) >> 24;\n\t*cfg = *cfg & (~NYX_CFG_EXTRA);\n\n\t// Disable read only flag.\n\tusb_msc_emmc_read_only = false;\n\n\tswitch (type)\n\t{\n\tcase NYX_UMS_SD_CARD:\n\t\taction_ums_sd(NULL);\n\t\tbreak;\n\tcase NYX_UMS_EMMC_BOOT0:\n\t\t_action_ums_emmc_boot0(NULL);\n\t\tbreak;\n\tcase NYX_UMS_EMMC_BOOT1:\n\t\t_action_ums_emmc_boot1(NULL);\n\t\tbreak;\n\tcase NYX_UMS_EMMC_GPP:\n\t\t_action_ums_emmc_gpp(NULL);\n\t\tbreak;\n\tcase NYX_UMS_EMUMMC_BOOT0:\n\t\t_action_ums_emuemmc_boot0(NULL);\n\t\tbreak;\n\tcase NYX_UMS_EMUMMC_BOOT1:\n\t\t_action_ums_emuemmc_boot1(NULL);\n\t\tbreak;\n\tcase NYX_UMS_EMUMMC_GPP:\n\t\t_action_ums_emuemmc_gpp(NULL);\n\t\tbreak;\n\t}\n}\n\nstatic lv_res_t _emmc_read_only_toggle(lv_obj_t *btn)\n{\n\tnyx_generic_onoff_toggle(btn);\n\n\tusb_msc_emmc_read_only = lv_btn_get_state(btn) & LV_BTN_STATE_TGL_REL ? 1 : 0;\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _create_window_usb_tools(lv_obj_t *parent)\n{\n\tlv_obj_t *win = nyx_create_standard_window(SYMBOL_USB\" USB Tools\", NULL);\n\n\tstatic lv_style_t h_style;\n\tlv_style_copy(&h_style, &lv_style_transp);\n\th_style.body.padding.inner = 0;\n\th_style.body.padding.hor = LV_DPI - (LV_DPI / 4);\n\th_style.body.padding.ver = LV_DPI / 9;\n\n\t// Create USB Mass Storage container.\n\tlv_obj_t *h1 = lv_cont_create(win, NULL);\n\tlv_cont_set_style(h1, &h_style);\n\tlv_cont_set_fit(h1, false, true);\n\tlv_obj_set_width(h1, (LV_HOR_RES / 9) * 5);\n\tlv_obj_set_click(h1, false);\n\tlv_cont_set_layout(h1, LV_LAYOUT_OFF);\n\n\tlv_obj_t *label_sep = lv_label_create(h1, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\tlv_obj_t *label_txt = lv_label_create(h1, NULL);\n\tlv_label_set_static_text(label_txt, \"USB Mass Storage\");\n\tlv_obj_set_style(label_txt, lv_theme_get_current()->label.prim);\n\tlv_obj_align(label_txt, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI * 3 / 10);\n\n\tlv_obj_t *line_sep = lv_line_create(h1, NULL);\n\tstatic const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 2, 0} };\n\tlv_line_set_points(line_sep, line_pp, 2);\n\tlv_line_set_style(line_sep, lv_theme_get_current()->line.decor);\n\tlv_obj_align(line_sep, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);\n\n\t// Create SD UMS button.\n\tlv_obj_t *btn1 = lv_btn_create(h1, NULL);\n\tlv_obj_t *label_btn = lv_label_create(btn1, NULL);\n\tlv_btn_set_fit(btn1, true, true);\n\tlv_label_set_static_text(label_btn, SYMBOL_SD\"  SD Card\");\n\n\tlv_obj_align(btn1, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);\n\tlv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, action_ums_sd);\n\n\tlv_obj_t *label_txt2 = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(label_txt2, true);\n\tlv_label_set_static_text(label_txt2,\n\t\t\"Allows you to mount the SD Card to a PC/Phone.\\n\"\n\t\t\"#C7EA46 All operating systems are supported. Access is# #FF8000 Read/Write.#\");\n\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, btn1, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\t// Create RAW GPP button.\n\tlv_obj_t *btn_gpp = lv_btn_create(h1, btn1);\n\tlabel_btn = lv_label_create(btn_gpp, NULL);\n\tlv_label_set_static_text(label_btn, SYMBOL_CHIP\"  eMMC RAW GPP\");\n\tlv_obj_align(btn_gpp, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);\n\tlv_btn_set_action(btn_gpp, LV_BTN_ACTION_CLICK, _action_ums_emmc_gpp);\n\n\t// Create BOOT0 button.\n\tlv_obj_t *btn_boot0 = lv_btn_create(h1, btn1);\n\tlabel_btn = lv_label_create(btn_boot0, NULL);\n\tlv_label_set_static_text(label_btn, \"BOOT0\");\n\tlv_obj_align(btn_boot0, btn_gpp, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 10, 0);\n\tlv_btn_set_action(btn_boot0, LV_BTN_ACTION_CLICK, _action_ums_emmc_boot0);\n\n\t// Create BOOT1 button.\n\tlv_obj_t *btn_boot1 = lv_btn_create(h1, btn1);\n\tlabel_btn = lv_label_create(btn_boot1, NULL);\n\tlv_label_set_static_text(label_btn, \"BOOT1\");\n\tlv_obj_align(btn_boot1, btn_boot0, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 10, 0);\n\tlv_btn_set_action(btn_boot1, LV_BTN_ACTION_CLICK, _action_ums_emmc_boot1);\n\n\t// Create emuMMC RAW GPP button.\n\tlv_obj_t *btn_emu_gpp = lv_btn_create(h1, btn1);\n\tlabel_btn = lv_label_create(btn_emu_gpp, NULL);\n\tlv_label_set_static_text(label_btn, SYMBOL_MODULES_ALT\"  emu RAW GPP\");\n\tlv_obj_align(btn_emu_gpp, btn_gpp, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);\n\tlv_btn_set_action(btn_emu_gpp, LV_BTN_ACTION_CLICK, _action_ums_emuemmc_gpp);\n\n\t// Create emuMMC BOOT0 button.\n\tlv_obj_t *btn_emu_boot0 = lv_btn_create(h1, btn1);\n\tlabel_btn = lv_label_create(btn_emu_boot0, NULL);\n\tlv_label_set_static_text(label_btn, \"BOOT0\");\n\tlv_obj_align(btn_emu_boot0, btn_boot0, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);\n\tlv_btn_set_action(btn_emu_boot0, LV_BTN_ACTION_CLICK, _action_ums_emuemmc_boot0);\n\n\t// Create emuMMC BOOT1 button.\n\tlv_obj_t *btn_emu_boot1 = lv_btn_create(h1, btn1);\n\tlabel_btn = lv_label_create(btn_emu_boot1, NULL);\n\tlv_label_set_static_text(label_btn, \"BOOT1\");\n\tlv_obj_align(btn_emu_boot1, btn_boot1, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);\n\tlv_btn_set_action(btn_emu_boot1, LV_BTN_ACTION_CLICK, _action_ums_emuemmc_boot1);\n\n\tlabel_txt2 = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(label_txt2, true);\n\tlv_label_set_static_text(label_txt2,\n\t\t\"Allows you to mount the eMMC/emuMMC.\\n\"\n\t\t\"#C7EA46 Default access is# #FF8000 read-only.#\");\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, btn_emu_gpp, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\tlv_obj_t *h_write = lv_cont_create(win, NULL);\n\tlv_cont_set_style(h_write, &h_style);\n\tlv_cont_set_fit(h_write, false, true);\n\tlv_obj_set_width(h_write, (LV_HOR_RES / 9) * 2);\n\tlv_obj_set_click(h_write, false);\n\tlv_cont_set_layout(h_write, LV_LAYOUT_OFF);\n\tlv_obj_align(h_write, label_txt2, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 10, 0);\n\n\t// Create read/write access button.\n\tlv_obj_t *btn_write_access = lv_btn_create(h_write, NULL);\n\tnyx_create_onoff_button(lv_theme_get_current(), h_write,\n\t\tbtn_write_access, SYMBOL_EDIT\" Read-Only\", _emmc_read_only_toggle, false);\n\tif (!n_cfg.ums_emmc_rw)\n\t\tlv_btn_set_state(btn_write_access, LV_BTN_STATE_TGL_REL);\n\t_emmc_read_only_toggle(btn_write_access);\n\n\t// Create USB Input Devices container.\n\tlv_obj_t *h2 = lv_cont_create(win, NULL);\n\tlv_cont_set_style(h2, &h_style);\n\tlv_cont_set_fit(h2, false, true);\n\tlv_obj_set_width(h2, (LV_HOR_RES / 9) * 3);\n\tlv_obj_set_click(h2, false);\n\tlv_cont_set_layout(h2, LV_LAYOUT_OFF);\n\tlv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 17 / 29, 0);\n\n\tlabel_sep = lv_label_create(h2, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\tlv_obj_t *label_txt3 = lv_label_create(h2, NULL);\n\tlv_label_set_static_text(label_txt3, \"USB Input Devices\");\n\tlv_obj_set_style(label_txt3, lv_theme_get_current()->label.prim);\n\tlv_obj_align(label_txt3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI * 4 / 21);\n\n\tline_sep = lv_line_create(h2, line_sep);\n\tlv_obj_align(line_sep, label_txt3, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);\n\n\t// Create Gamepad button.\n\tlv_obj_t *btn3 = lv_btn_create(h2, NULL);\n\tlabel_btn = lv_label_create(btn3, NULL);\n\tlv_btn_set_fit(btn3, true, true);\n\tlv_label_set_static_text(label_btn, SYMBOL_CIRCUIT\"  Gamepad\");\n\tlv_obj_align(btn3, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);\n\tlv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, _action_hid_jc);\n\n\tlv_obj_t *label_txt4 = lv_label_create(h2, NULL);\n\tlv_label_set_recolor(label_txt4, true);\n\tlv_label_set_static_text(label_txt4,\n\t\t\"Plug-in the Joy-Con and convert the device\\n\"\n\t\t\"into a gamepad for PC or Phone.\\n\"\n\t\t\"#C7EA46 Needs both Joy-Con in order to function.#\");\n\n\tlv_obj_set_style(label_txt4, &hint_small_style);\n\tlv_obj_align(label_txt4, btn3, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n/*\n\t// Create Touchpad button.\n\tlv_obj_t *btn4 = lv_btn_create(h2, btn1);\n\tlabel_btn = lv_label_create(btn4, NULL);\n\tlv_label_set_static_text(label_btn, SYMBOL_KEYBOARD\"  Touchpad\");\n\tlv_obj_align(btn4, label_txt4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);\n\tlv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, _action_hid_touch);\n\tlv_btn_set_state(btn4, LV_BTN_STATE_INA);\n\n\tlabel_txt4 = lv_label_create(h2, NULL);\n\tlv_label_set_recolor(label_txt4, true);\n\tlv_label_set_static_text(label_txt4,\n\t\t\"Control the PC via the device\\'s touchscreen.\\n\"\n\t\t\"#C7EA46 Two fingers tap acts like a# #FF8000 Right click##C7EA46 .#\\n\");\n\tlv_obj_set_style(label_txt4, &hint_small_style);\n\tlv_obj_align(label_txt4, btn4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n*/\n\treturn LV_RES_OK;\n}\n\nstatic int _fix_attributes(lv_obj_t *lb_val, char *path, u32 *total)\n{\n\tFRESULT res;\n\tDIR dir;\n\tu32 dirLength = 0;\n\tstatic FILINFO fno;\n\n\t// Open directory.\n\tres = f_opendir(&dir, path);\n\tif (res != FR_OK)\n\t\treturn res;\n\n\tdirLength = strlen(path);\n\n\t// Hard limit path to 1024 characters. Do not result to error.\n\tif (dirLength > 1024)\n\t{\n\t\ttotal[2]++;\n\t\tgoto out;\n\t}\n\n\tfor (;;)\n\t{\n\t\t// Clear file or folder path.\n\t\tpath[dirLength] = 0;\n\n\t\t// Read a directory item.\n\t\tres = f_readdir(&dir, &fno);\n\n\t\t// Break on error or end of dir.\n\t\tif (res != FR_OK || fno.fname[0] == 0)\n\t\t\tbreak;\n\n\t\t// Set new directory or file.\n\t\tmemcpy(&path[dirLength], \"/\", 1);\n\t\tstrcpy(&path[dirLength + 1], fno.fname);\n\n\t\t// Is it a directory?\n\t\tif (fno.fattrib & AM_DIR)\n\t\t{\n\t\t\t// Check if it's a HOS single file folder.\n\t\t\tstrcat(path, \"/00\");\n\t\t\tbool is_hos_special = !f_stat(path, NULL);\n\t\t\tpath[strlen(path) - 3] = 0;\n\n\t\t\t// Set archive bit to HOS single file folders.\n\t\t\tif (is_hos_special)\n\t\t\t{\n\t\t\t\tif (!(fno.fattrib & AM_ARC))\n\t\t\t\t{\n\t\t\t\t\tif (!f_chmod(path, AM_ARC, AM_ARC))\n\t\t\t\t\t\ttotal[0]++;\n\t\t\t\t\telse\n\t\t\t\t\t\ttotal[3]++;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (fno.fattrib & AM_ARC) // If not, clear the archive bit.\n\t\t\t{\n\t\t\t\tif (!f_chmod(path, 0, AM_ARC))\n\t\t\t\t\ttotal[1]++;\n\t\t\t\telse\n\t\t\t\t\ttotal[3]++;\n\t\t\t}\n\n\t\t\tlv_label_set_text(lb_val, path);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\t// Enter the directory.\n\t\t\tres = _fix_attributes(lb_val, path, total);\n\t\t\tif (res != FR_OK)\n\t\t\t\tbreak;\n\t\t}\n\t}\n\nout:\n\tf_closedir(&dir);\n\n\treturn res;\n}\n\nstatic lv_res_t _create_window_unset_abit_tool(lv_obj_t *btn)\n{\n\tlv_obj_t *win = nyx_create_standard_window(SYMBOL_COPY\" Fix Archive Bit (All folders)\", NULL);\n\n\t// Disable buttons.\n\tnyx_window_toggle_buttons(win, true);\n\n\tlv_obj_t *desc = lv_cont_create(win, NULL);\n\tlv_obj_set_size(desc, LV_HOR_RES * 10 / 11, LV_VER_RES - (LV_DPI * 11 / 7) * 4);\n\n\tlv_obj_t * lb_desc = lv_label_create(desc, NULL);\n\tlv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);\n\tlv_label_set_recolor(lb_desc, true);\n\n\tif (sd_mount())\n\t{\n\t\tlv_label_set_text(lb_desc, \"#FFDD00 Failed to init SD!#\");\n\t\tlv_obj_set_width(lb_desc, lv_obj_get_width(desc));\n\t}\n\telse\n\t{\n\t\tlv_label_set_text(lb_desc, \"#00DDFF Traversing all SD card files!#\\nThis may take some time...\");\n\t\tlv_obj_set_width(lb_desc, lv_obj_get_width(desc));\n\n\t\tlv_obj_t *val = lv_cont_create(win, NULL);\n\t\tlv_obj_set_size(val, LV_HOR_RES * 10 / 11, LV_VER_RES - (LV_DPI * 11 / 7) * 4);\n\n\t\tlv_obj_t * lb_val = lv_label_create(val, lb_desc);\n\n\t\tchar *path = malloc(0x1000);\n\t\tpath[0] = 0;\n\n\t\tlv_label_set_text(lb_val, \"\");\n\t\tlv_obj_set_width(lb_val, lv_obj_get_width(val));\n\t\tlv_obj_align(val, desc, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);\n\n\t\tu32 total[4] = { 0 };\n\t\t_fix_attributes(lb_val, path, total);\n\n\t\tsd_unmount();\n\n\t\tlv_obj_t *desc2 = lv_cont_create(win, NULL);\n\t\tlv_obj_set_size(desc2, LV_HOR_RES * 10 / 11, LV_VER_RES - (LV_DPI * 11 / 7) * 4);\n\t\tlv_obj_t * lb_desc2 = lv_label_create(desc2, lb_desc);\n\n\t\tchar *txt_buf = (char *)malloc(0x500);\n\n\t\tif (!total[0] && !total[1])\n\t\t\ts_printf(txt_buf, \"#96FF00 Done! No change was needed.#\");\n\t\telse\n\t\t\ts_printf(txt_buf, \"#96FF00 Done! Archive bits fixed:# #FF8000 %d unset and %d set!#\", total[1], total[0]);\n\n\t\t// Check errors.\n\t\tif (total[2] || total[3])\n\t\t{\n\t\t\ts_printf(txt_buf, \"\\n\\n#FFDD00 Errors: folder accesses: %d, arc bit fixes: %d!#\\n\"\n\t\t\t\t\t          \"#FFDD00 Filesystem should be checked for errors.#\",\n\t\t\t\t\t          total[2], total[3]);\n\t\t}\n\n\t\tlv_label_set_text(lb_desc2, txt_buf);\n\t\tlv_obj_set_width(lb_desc2, lv_obj_get_width(desc2));\n\t\tlv_obj_align(desc2, val, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, 0);\n\n\t\tfree(path);\n\t}\n\n\t// Enable buttons.\n\tnyx_window_toggle_buttons(win, false);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _create_mbox_fix_touchscreen(lv_obj_t *btn)\n{\n\tint res = 1;\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_map[] = { \"\\251\", \"\\222OK\", \"\\251\", \"\" };\n\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\n\tchar *txt_buf = malloc(SZ_16K);\n\tstrcpy(txt_buf, \"#FF8000 Don't touch the screen!#\\n\\nThe tuning process will start in \");\n\tu32 text_idx = strlen(txt_buf);\n\tlv_mbox_set_text(mbox, txt_buf);\n\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\tlv_mbox_set_text(mbox,\n\t\t\"#FFDD00 Warning: Only run this if you really have issues!#\\n\\n\"\n\t\t\"Press #FF8000 POWER# to Continue.\\nPress #FF8000 VOL# to abort.\");\n\tmanual_system_maintenance(true);\n\n\tif (!(btn_wait() & BTN_POWER))\n\t\tgoto out;\n\n\tmanual_system_maintenance(true);\n\tlv_mbox_set_text(mbox, txt_buf);\n\n\tu32 seconds = 5;\n\twhile (seconds)\n\t{\n\t\ts_printf(txt_buf + text_idx, \"%d seconds...\", seconds);\n\t\tlv_mbox_set_text(mbox, txt_buf);\n\t\tmanual_system_maintenance(true);\n\t\tmsleep(1000);\n\t\tseconds--;\n\t}\n\n\tu8 err[2];\n\tif (touch_panel_ito_test(err))\n\t\tgoto ito_failed;\n\n\tif (!err[0] && !err[1])\n\t{\n\t\tres = touch_execute_autotune();\n\t\tif (!res)\n\t\t\tgoto out;\n\t}\n\telse\n\t{\n\t\ttouch_sense_enable();\n\n\t\ts_printf(txt_buf, \"#FFFF00 ITO Test: \");\n\t\tswitch (err[0])\n\t\t{\n\t\tcase ITO_FORCE_OPEN:\n\t\t\tstrcat(txt_buf, \"Force Open\");\n\t\t\tbreak;\n\t\tcase ITO_SENSE_OPEN:\n\t\t\tstrcat(txt_buf, \"Sense Open\");\n\t\t\tbreak;\n\t\tcase ITO_FORCE_SHRT_GND:\n\t\t\tstrcat(txt_buf, \"Force Short to GND\");\n\t\t\tbreak;\n\t\tcase ITO_SENSE_SHRT_GND:\n\t\t\tstrcat(txt_buf, \"Sense Short to GND\");\n\t\t\tbreak;\n\t\tcase ITO_FORCE_SHRT_VCM:\n\t\t\tstrcat(txt_buf, \"Force Short to VDD\");\n\t\t\tbreak;\n\t\tcase ITO_SENSE_SHRT_VCM:\n\t\t\tstrcat(txt_buf, \"Sense Short to VDD\");\n\t\t\tbreak;\n\t\tcase ITO_FORCE_SHRT_FORCE:\n\t\t\tstrcat(txt_buf, \"Force Short to Force\");\n\t\t\tbreak;\n\t\tcase ITO_SENSE_SHRT_SENSE:\n\t\t\tstrcat(txt_buf, \"Sense Short to Sense\");\n\t\t\tbreak;\n\t\tcase ITO_F2E_SENSE:\n\t\t\tstrcat(txt_buf, \"Force Short to Sense\");\n\t\t\tbreak;\n\t\tcase ITO_FPC_FORCE_OPEN:\n\t\t\tstrcat(txt_buf, \"FPC Force Open\");\n\t\t\tbreak;\n\t\tcase ITO_FPC_SENSE_OPEN:\n\t\t\tstrcat(txt_buf, \"FPC Sense Open\");\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tstrcat(txt_buf, \"Unknown\");\n\t\t\tbreak;\n\n\t\t}\n\t\ts_printf(txt_buf + strlen(txt_buf), \" (%d), Chn: %d#\\n\\n\", err[0], err[1]);\n\t\tstrcat(txt_buf, \"#FFFF00 The touchscreen calibration failed!\");\n\t\tlv_mbox_set_text(mbox, txt_buf);\n\t\tgoto out2;\n\t}\n\nito_failed:\n\ttouch_sense_enable();\n\nout:\n\tif (!res)\n\t\tlv_mbox_set_text(mbox, \"#C7EA46 The touchscreen calibration finished!\");\n\telse\n\t\tlv_mbox_set_text(mbox, \"#FFFF00 The touchscreen calibration failed!\");\n\nout2:\n\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);\n\n\tfree(txt_buf);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn)\n{\n\tlv_obj_t *win = nyx_create_standard_window(SYMBOL_MODULES\" Dump package1/2\", NULL);\n\n\t// Disable buttons.\n\tnyx_window_toggle_buttons(win, true);\n\n\tlv_obj_t *desc = lv_cont_create(win, NULL);\n\tlv_obj_set_size(desc, LV_HOR_RES * 10 / 11, LV_VER_RES - (LV_DPI * 12 / 7));\n\n\tlv_obj_t *lb_desc = lv_label_create(desc, NULL);\n\tlv_obj_set_style(lb_desc, &monospace_text);\n\tlv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);\n\tlv_label_set_recolor(lb_desc, true);\n\tlv_obj_set_width(lb_desc, lv_obj_get_width(desc) / 2);\n\n\tlv_obj_t *lb_desc2 = lv_label_create(desc, NULL);\n\tlv_obj_set_style(lb_desc2, &monospace_text);\n\tlv_label_set_long_mode(lb_desc2, LV_LABEL_LONG_BREAK);\n\tlv_label_set_recolor(lb_desc2, true);\n\tlv_obj_set_width(lb_desc2, lv_obj_get_width(desc) / 2);\n\tlv_label_set_text(lb_desc2, \" \");\n\n\tlv_obj_align(lb_desc2, lb_desc, LV_ALIGN_OUT_RIGHT_TOP, 0, 0);\n\n\tif (sd_mount())\n\t{\n\t\tlv_label_set_text(lb_desc, \"#FFDD00 Failed to init SD!#\");\n\n\t\tgoto out_end;\n\t}\n\n\tchar path[128];\n\n\tu8 mkey = 0;\n\tu8 *pkg1 = (u8 *)zalloc(SZ_256K);\n\tu8 *warmboot = (u8 *)zalloc(SZ_256K);\n\tu8 *secmon = (u8 *)zalloc(SZ_256K);\n\tu8 *loader = (u8 *)zalloc(SZ_256K);\n\tu8 *pkg2   = (u8 *)zalloc(SZ_8M);\n\n\tchar *txt_buf  = (char *)malloc(SZ_16K);\n\n\tif (emmc_initialize(false))\n\t{\n\t\tlv_label_set_text(lb_desc, \"#FFDD00 Failed to init eMMC!#\");\n\n\t\tgoto out_free;\n\t}\n\n\tchar *bct_paths[2] = {\n\t\t\"/pkg/main\",\n\t\t\"/pkg/safe\"\n\t};\n\n\tchar *pkg1_paths[2] = {\n\t\t\"/pkg/main/pkg1\",\n\t\t\"/pkg/safe/pkg1\"\n\t};\n\n\tchar *pkg2_partitions[2] = {\n\t\t\"BCPKG2-1-Normal-Main\",\n\t\t\"BCPKG2-3-SafeMode-Main\"\n\t};\n\n\tchar *pkg2_paths[2] = {\n\t\t\"/pkg/main/pkg2\",\n\t\t\"/pkg/safe/pkg2\"\n\t};\n\n\tchar *pkg2ini_paths[2] = {\n\t\t\"/pkg/main/pkg2/ini\",\n\t\t\"/pkg/safe/pkg2/ini\"\n\t};\n\n\t// Create main directories.\n\temmcsn_path_impl(path, \"/pkg\", \"\", &emmc_storage);\n\temmcsn_path_impl(path, \"/pkg/main\", \"\", &emmc_storage);\n\temmcsn_path_impl(path, \"/pkg/safe\", \"\", &emmc_storage);\n\n\t// Parse eMMC GPT.\n\temmc_set_partition(EMMC_GPP);\n\tLIST_INIT(gpt);\n\temmc_gpt_parse(&gpt);\n\n\tlv_obj_t *lb_log = lb_desc;\n\tfor (u32 idx = 0; idx < 2; idx++)\n\t{\n\t\tif (idx)\n\t\t\tlb_log = lb_desc2;\n\n\t\t// Read package1.\n\t\tchar *build_date = malloc(32);\n\t\tu32   pk1_offset = h_cfg.t210b01 ? sizeof(bl_hdr_t210b01_t) : 0; // Skip T210B01 OEM header.\n\t\temmc_set_partition(!idx ? EMMC_BOOT0 : EMMC_BOOT1);\n\t\tsdmmc_storage_read(&emmc_storage,\n\t\t\t!idx ? PKG1_BOOTLOADER_MAIN_OFFSET : PKG1_BOOTLOADER_SAFE_OFFSET, PKG1_BOOTLOADER_SIZE / EMMC_BLOCKSIZE, pkg1);\n\n\t\tconst pkg1_id_t *pkg1_id = pkg1_identify(pkg1 + pk1_offset, build_date);\n\n\t\ts_printf(txt_buf, \"#00DDFF Found %s pkg1 ('%s')#\\n\\n\", !idx ? \"Main\" : \"Safe\", build_date);\n\t\tlv_label_set_text(lb_log, txt_buf);\n\t\tmanual_system_maintenance(true);\n\t\tfree(build_date);\n\n\t\t// Dump package1 in its encrypted state.\n\t\temmcsn_path_impl(path, pkg1_paths[idx], \"pkg1_enc.bin\", &emmc_storage);\n\t\tbool res = sd_save_to_file(pkg1, PKG1_BOOTLOADER_SIZE, path);\n\n\t\t// Exit if unknown.\n\t\tif (!pkg1_id)\n\t\t{\n\t\t\tstrcat(txt_buf, \"#FFDD00 Unknown pkg1 version!#\");\n\t\t\tlv_label_set_text(lb_log, txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tif (!res)\n\t\t\t{\n\t\t\t\tstrcat(txt_buf, \"\\nEncrypted pkg1 extracted to pkg1_enc.bin\");\n\t\t\t\tlv_label_set_text(lb_log, txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\t\t\t}\n\n\t\t\tgoto out;\n\t\t}\n\n\t\tmkey = pkg1_id->mkey;\n\n\t\ttsec_ctxt_t tsec_ctxt = {0};\n\t\ttsec_ctxt.fw = (void *)(pkg1 + pkg1_id->tsec_off);\n\t\ttsec_ctxt.pkg1 = (void *)pkg1;\n\t\ttsec_ctxt.pkg11_off = pkg1_id->pkg11_off;\n\n\t\t// Read the correct eks for older HOS versions.\n\t\tconst u32 eks_size = sizeof(pkg1_eks_t);\n\t\tpkg1_eks_t *eks = (pkg1_eks_t *)malloc(eks_size);\n\t\temmc_set_partition(EMMC_BOOT0);\n\t\tsdmmc_storage_read(&emmc_storage, PKG1_HOS_EKS_OFFSET + (mkey * eks_size) / EMMC_BLOCKSIZE,\n\t\t\t\t\t\t\t\t\t\t  eks_size / EMMC_BLOCKSIZE, eks);\n\n\t\t// Generate keys.\n\t\thos_keygen(eks, mkey, &tsec_ctxt);\n\t\tfree(eks);\n\n\t\t// Decrypt.\n\t\tif (h_cfg.t210b01 || mkey <= HOS_MKEY_VER_600)\n\t\t{\n\t\t\tif (!pkg1_decrypt(pkg1_id, pkg1))\n\t\t\t{\n\t\t\t\tstrcat(txt_buf, \"#FFDD00 Pkg1 decryption failed!#\\n\");\n\t\t\t\tif (h_cfg.t210b01)\n\t\t\t\t\tstrcat(txt_buf, \"#FFDD00 Is BEK missing?#\\n\");\n\t\t\t\tlv_label_set_text(lb_log, txt_buf);\n\t\t\t\tgoto out;\n\t\t\t}\n\t\t}\n\n\t\t// Dump the BCTs from blocks 2/3 (backup) which are normally valid.\n\t\tstatic const u32 BCT_SIZE = 0x2800;\n\t\tstatic const u32 BLK_SIZE = SZ_16K / EMMC_BLOCKSIZE;\n\t\tu8 *bct = (u8 *)zalloc(BCT_SIZE);\n\t\tsdmmc_storage_read(&emmc_storage, BLK_SIZE * 2 + BLK_SIZE * idx, BCT_SIZE / EMMC_BLOCKSIZE, bct);\n\t\temmcsn_path_impl(path, bct_paths[idx], \"bct.bin\", &emmc_storage);\n\t\tif (sd_save_to_file(bct, 0x2800, path))\n\t\t\tgoto out;\n\t\tif (h_cfg.t210b01)\n\t\t{\n\t\t\tse_aes_iv_clear(13);\n\t\t\tse_aes_crypt_cbc(13, DECRYPT, bct + 0x480, bct + 0x480, BCT_SIZE - 0x480);\n\t\t\temmcsn_path_impl(path, bct_paths[idx], \"bct_decr.bin\", &emmc_storage);\n\t\t\tif (sd_save_to_file(bct, 0x2800, path))\n\t\t\t\tgoto out;\n\t\t}\n\n\t\t// Dump package1.1 contents.\n\t\tif (h_cfg.t210b01 || mkey <= HOS_MKEY_VER_620)\n\t\t{\n\t\t\tpkg1_unpack(warmboot, secmon, loader, pkg1_id, pkg1 + pk1_offset);\n\t\t\tpk11_hdr_t *hdr_pk11 = (pk11_hdr_t *)(pkg1 + pk1_offset + pkg1_id->pkg11_off + 0x20);\n\n\t\t\t// Display info.\n\t\t\ts_printf(txt_buf + strlen(txt_buf),\n\t\t\t\t\"#C7EA46 NX Bootloader size:  #0x%05X\\n\"\n\t\t\t\t\"#C7EA46 Secure monitor size: #0x%05X\\n\"\n\t\t\t\t\"#C7EA46 Warmboot size:       #0x%05X\\n\\n\",\n\t\t\t\thdr_pk11->ldr_size, hdr_pk11->sm_size, hdr_pk11->wb_size);\n\n\t\t\tlv_label_set_text(lb_log, txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\t// Dump package1.1.\n\t\t\temmcsn_path_impl(path, pkg1_paths[idx], \"pkg1_decr.bin\", &emmc_storage);\n\t\t\tif (sd_save_to_file(pkg1, SZ_256K, path))\n\t\t\t\tgoto out;\n\t\t\tstrcat(txt_buf, \"Package1 extracted to pkg1_decr.bin\\n\");\n\t\t\tlv_label_set_text(lb_log, txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\t// Dump nxbootloader.\n\t\t\temmcsn_path_impl(path, pkg1_paths[idx], \"nxloader.bin\", &emmc_storage);\n\t\t\tif (sd_save_to_file(loader, hdr_pk11->ldr_size, path))\n\t\t\t\tgoto out;\n\t\t\tstrcat(txt_buf, \"NX Bootloader extracted to nxloader.bin\\n\");\n\t\t\tlv_label_set_text(lb_log, txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\t// Dump secmon.\n\t\t\temmcsn_path_impl(path, pkg1_paths[idx], \"secmon.bin\", &emmc_storage);\n\t\t\tif (sd_save_to_file(secmon, hdr_pk11->sm_size, path))\n\t\t\t\tgoto out;\n\t\t\tstrcat(txt_buf, \"Secure Monitor extracted to secmon.bin\\n\");\n\t\t\tlv_label_set_text(lb_log, txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\t// Dump warmboot.\n\t\t\temmcsn_path_impl(path, pkg1_paths[idx], \"warmboot.bin\", &emmc_storage);\n\t\t\tif (sd_save_to_file(warmboot, hdr_pk11->wb_size, path))\n\t\t\t\tgoto out;\n\t\t\t// If T210B01, save a copy of decrypted warmboot binary also.\n\t\t\tif (h_cfg.t210b01)\n\t\t\t{\n\n\t\t\t\tse_aes_iv_clear(13);\n\t\t\t\tse_aes_crypt_cbc(13, DECRYPT, warmboot + 0x330, warmboot + 0x330, hdr_pk11->wb_size - 0x330);\n\t\t\t\temmcsn_path_impl(path, pkg1_paths[idx], \"warmboot_dec.bin\", &emmc_storage);\n\t\t\t\tif (sd_save_to_file(warmboot, hdr_pk11->wb_size, path))\n\t\t\t\t\tgoto out;\n\t\t\t}\n\t\t\tstrcat(txt_buf, \"Warmboot extracted to warmboot.bin\\n\\n\");\n\t\t\tlv_label_set_text(lb_log, txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\t\t}\n\n\t\t// Find and dump package2 partition.\n\t\temmc_set_partition(EMMC_GPP);\n\t\temmc_part_t *pkg2_part = emmc_part_find(&gpt, pkg2_partitions[idx]);\n\t\tif (!pkg2_part)\n\t\t\tgoto out;\n\n\t\t// Read in package2 header and get package2 real size.\n\t\tstatic const u32 PKG2_OFFSET = 0x4000;\n\t\tu8 *tmp = (u8 *)malloc(EMMC_BLOCKSIZE);\n\t\temmc_part_read(pkg2_part, PKG2_OFFSET / EMMC_BLOCKSIZE, 1, tmp);\n\t\tu32 *hdr_pkg2_raw = (u32 *)(tmp + 0x100);\n\t\tu32 pkg2_size = hdr_pkg2_raw[0] ^ hdr_pkg2_raw[2] ^ hdr_pkg2_raw[3];\n\t\tfree(tmp);\n\n\t\t// Read in package2.\n\t\tu32 pkg2_size_aligned = ALIGN(pkg2_size, EMMC_BLOCKSIZE);\n\t\temmc_part_read(pkg2_part, PKG2_OFFSET / EMMC_BLOCKSIZE, pkg2_size_aligned / EMMC_BLOCKSIZE, pkg2);\n\n\t\t// Dump encrypted package2.\n\t\temmcsn_path_impl(path, pkg2_paths[idx], \"pkg2_encr.bin\", &emmc_storage);\n\t\tres = sd_save_to_file(pkg2, pkg2_size, path);\n\n\t\t// Decrypt package2 and parse KIP1 blobs in INI1 section.\n\t\tpkg2_hdr_t *pkg2_hdr = pkg2_decrypt(pkg2, mkey);\n\t\tif (!pkg2_hdr)\n\t\t{\n\t\t\tstrcat(txt_buf, \"#FFDD00 Pkg2 decryption failed!#\");\n\t\t\tlv_label_set_text(lb_log, txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tif (!res)\n\t\t\t{\n\t\t\t\tstrcat(txt_buf, \"\\npkg2 encrypted extracted to pkg2_encr.bin\\n\");\n\t\t\t\tlv_label_set_text(lb_log, txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\t\t\t}\n\n\t\t\t// Clear EKS slot, in case something went wrong with tsec keygen.\n\t\t\thos_eks_clear(mkey);\n\n\t\t\tgoto out;\n\t\t}\n\n\t\t// Display info.\n\t\ts_printf(txt_buf + strlen(txt_buf),\n\t\t\t\"#C7EA46 Kernel size:   #0x%06X\\n\"\n\t\t\t\"#C7EA46 INI1 size:     #0x%06X\\n\\n\",\n\t\t\tpkg2_hdr->sec_size[PKG2_SEC_KERNEL], pkg2_hdr->sec_size[PKG2_SEC_INI1]);\n\n\t\tlv_label_set_text(lb_log, txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\t// Dump pkg2.1.\n\t\temmcsn_path_impl(path, pkg2_paths[idx], \"pkg2_decr.bin\", &emmc_storage);\n\t\tif (sd_save_to_file(pkg2, pkg2_hdr->sec_size[PKG2_SEC_KERNEL] + pkg2_hdr->sec_size[PKG2_SEC_INI1], path))\n\t\t\tgoto out;\n\t\tstrcat(txt_buf, \"Package2 extracted to pkg2_decr.bin\\n\");\n\t\tlv_label_set_text(lb_log, txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\t// Dump kernel.\n\t\temmcsn_path_impl(path, pkg2_paths[idx], \"kernel.bin\", &emmc_storage);\n\t\tif (sd_save_to_file(pkg2_hdr->data, pkg2_hdr->sec_size[PKG2_SEC_KERNEL], path))\n\t\t\tgoto out;\n\t\tstrcat(txt_buf, \"Kernel extracted to kernel.bin\\n\");\n\t\tlv_label_set_text(lb_log, txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\t// Dump INI1.\n\t\tu32 ini1_off  = pkg2_hdr->sec_size[PKG2_SEC_KERNEL];\n\t\tu32 ini1_size = pkg2_hdr->sec_size[PKG2_SEC_INI1];\n\t\tif (!ini1_size)\n\t\t{\n\t\t\tpkg2_get_newkern_info(pkg2_hdr->data);\n\t\t\tini1_off  = pkg2_newkern_ini1_start;\n\t\t\tini1_size = pkg2_newkern_ini1_end - pkg2_newkern_ini1_start;\n\t\t}\n\n\t\tif (!ini1_off)\n\t\t{\n\t\t\tstrcat(txt_buf, \"#FFDD00 Failed to dump INI1 and kips!#\\n\");\n\t\t\tgoto out;\n\t\t}\n\n\t\tpkg2_ini1_t *ini1 = (pkg2_ini1_t *)(pkg2_hdr->data + ini1_off);\n\t\temmcsn_path_impl(path, pkg2_paths[idx], \"ini1.bin\", &emmc_storage);\n\t\tif (sd_save_to_file(ini1, ini1_size, path))\n\t\t\tgoto out;\n\n\t\tstrcat(txt_buf, \"INI1 extracted to ini1.bin\\n\");\n\t\tlv_label_set_text(lb_log, txt_buf);\n\t\tmanual_system_maintenance(true);\n\n\t\tchar filename[32];\n\t\tu8 *ptr = (u8 *)ini1;\n\t\tptr += sizeof(pkg2_ini1_t);\n\n\t\t// Dump all kips.\n\t\tfor (u32 i = 0; i < ini1->num_procs; i++)\n\t\t{\n\t\t\tpkg2_kip1_t *kip1 = (pkg2_kip1_t *)ptr;\n\t\t\tu32 kip1_size = pkg2_calc_kip1_size(kip1);\n\t\t\tchar *kip_name = kip1->name;\n\n\t\t\t// Check if FS supports exFAT.\n\t\t\tif (!strcmp(\"FS\", kip_name))\n\t\t\t{\n\t\t\t\tu8 *ro_data = malloc(SZ_4M);\n\t\t\t\tu32 offset      = (kip1->flags & BIT(KIP_TEXT)) ? kip1->sections[KIP_TEXT].size_comp :\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  kip1->sections[KIP_TEXT].size_decomp;\n\t\t\t\tu32 size_comp   = kip1->sections[KIP_RODATA].size_comp;\n\t\t\t\tu32 size_decomp = kip1->sections[KIP_RODATA].size_decomp;\n\t\t\t\tif (kip1->flags & BIT(KIP_RODATA))\n\t\t\t\t\tblz_uncompress_srcdest(&kip1->data[offset], size_comp, ro_data, size_decomp);\n\t\t\t\telse\n\t\t\t\t\tmemcpy(ro_data, &kip1->data[offset], size_decomp);\n\n\t\t\t\tfor (u32 i = 0; i < 0x100; i+= sizeof(u32))\n\t\t\t\t{\n\t\t\t\t\t// Check size and name of nss matches.\n\t\t\t\t\tif (*(u32 *)&ro_data[i] == 8 && !memcmp(\"fs.exfat\", &ro_data[i + 4], 8))\n\t\t\t\t\t{\n\t\t\t\t\t\tkip_name = \"FS_exfat\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfree(ro_data);\n\t\t\t}\n\n\t\t\ts_printf(filename, \"%s.kip1\", kip_name);\n\t\t\temmcsn_path_impl(path, pkg2ini_paths[idx], filename, &emmc_storage);\n\t\t\tif (sd_save_to_file(kip1, kip1_size, path))\n\t\t\t\tgoto out;\n\n\t\t\ts_printf(txt_buf + strlen(txt_buf), \"- Extracted %s.kip1\\n\", kip_name);\n\t\t\tlv_label_set_text(lb_log, txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tptr += kip1_size;\n\t\t}\n\t}\n\nout:\n\temmc_gpt_free(&gpt);\nout_free:\n\tfree(pkg1);\n\tfree(secmon);\n\tfree(warmboot);\n\tfree(loader);\n\tfree(pkg2);\n\tfree(txt_buf);\n\temmc_end();\n\tsd_unmount();\n\n\tif (mkey >= HOS_MKEY_VER_620)\n\t\tse_aes_key_clear(8);\nout_end:\n\t// Enable buttons.\n\tnyx_window_toggle_buttons(win, false);\n\n\treturn LV_RES_OK;\n}\n\nstatic void _create_tab_tools_emmc_sd_usb(lv_theme_t *th, lv_obj_t *parent)\n{\n\tlv_page_set_scrl_layout(parent, LV_LAYOUT_PRETTY);\n\n\t// Create Backup & Restore container.\n\tlv_obj_t *h1 = _create_container(parent);\n\n\tlv_obj_t *label_sep = lv_label_create(h1, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\tlv_obj_t *label_txt = lv_label_create(h1, NULL);\n\tlv_label_set_static_text(label_txt, \"Backup & Restore\");\n\tlv_obj_set_style(label_txt, th->label.prim);\n\tlv_obj_align(label_txt, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI * 3 / 10);\n\n\tlv_obj_t *line_sep = lv_line_create(h1, NULL);\n\tstatic const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 2, 0} };\n\tlv_line_set_points(line_sep, line_pp, 2);\n\tlv_line_set_style(line_sep, th->line.decor);\n\tlv_obj_align(line_sep, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);\n\n\t// Create Backup eMMC button.\n\tlv_obj_t *btn = lv_btn_create(h1, NULL);\n\tif (hekate_bg)\n\t{\n\t\tlv_btn_set_style(btn, LV_BTN_STYLE_REL, &btn_transp_rel);\n\t\tlv_btn_set_style(btn, LV_BTN_STYLE_PR, &btn_transp_pr);\n\t}\n\tlv_obj_t *label_btn = lv_label_create(btn, NULL);\n\tlv_btn_set_fit(btn, true, true);\n\tlv_label_set_static_text(label_btn, SYMBOL_UPLOAD\"  Backup eMMC\");\n\tlv_obj_align(btn, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);\n\tlv_btn_set_action(btn, LV_BTN_ACTION_CLICK, create_window_backup_restore_tool);\n\n\tlv_obj_t *label_txt2 = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(label_txt2, true);\n\tlv_label_set_static_text(label_txt2,\n\t\t\"Allows you to backup eMMC/emuMMC partitions individually\\n\"\n\t\t\"or as a whole raw image to the SD card.\\n\"\n\t\t\"#C7EA46 Supports SD cards from# #FF8000 4GB# #C7EA46 and up. #\"\n\t\t\"#FF8000 FAT32# #C7EA46 and ##FF8000 exFAT##C7EA46 .#\");\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, btn, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\t// Create Restore eMMC button.\n\tlv_obj_t *btn2 = lv_btn_create(h1, btn);\n\tlabel_btn = lv_label_create(btn2, NULL);\n\tlv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD\"  Restore eMMC\");\n\tlv_obj_align(btn2, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);\n\tlv_btn_set_action(btn2, LV_BTN_ACTION_CLICK, create_window_backup_restore_tool);\n\n\tlabel_txt2 = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(label_txt2, true);\n\tlv_label_set_static_text(label_txt2,\n\t\t\"Allows you to restore eMMC/emuMMC partitions individually\\n\"\n\t\t\"or as a whole raw image from the SD card.\\n\"\n\t\t\"#C7EA46 Supports SD cards from# #FF8000 4GB# #C7EA46 and up. #\"\n\t\t\"#FF8000 FAT32# #C7EA46 and ##FF8000 exFAT##C7EA46 .#\");\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, btn2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\t// Create Misc container.\n\tlv_obj_t *h2 = _create_container(parent);\n\tlv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, 0, 0);\n\n\tlabel_sep = lv_label_create(h2, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\tlv_obj_t *label_txt3 = lv_label_create(h2, NULL);\n\tlv_label_set_static_text(label_txt3, \"SD Partitions & USB\");\n\tlv_obj_set_style(label_txt3, th->label.prim);\n\tlv_obj_align(label_txt3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI * 3 / 10);\n\n\tline_sep = lv_line_create(h2, line_sep);\n\tlv_obj_align(line_sep, label_txt3, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);\n\n\t// Create Partition SD Card button.\n\tlv_obj_t *btn3 = lv_btn_create(h2, NULL);\n\tif (hekate_bg)\n\t{\n\t\tlv_btn_set_style(btn3, LV_BTN_STYLE_REL, &btn_transp_rel);\n\t\tlv_btn_set_style(btn3, LV_BTN_STYLE_PR, &btn_transp_pr);\n\t}\n\tlabel_btn = lv_label_create(btn3, NULL);\n\tlv_btn_set_fit(btn3, true, true);\n\tlv_label_set_static_text(label_btn, SYMBOL_SD\"  Partition SD Card\");\n\tlv_obj_align(btn3, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);\n\tlv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, create_window_sd_partition_manager);\n\tlv_btn_set_action(btn3, LV_BTN_ACTION_LONG_PR, create_window_emmc_partition_manager);\n\n\tlv_obj_t *label_txt4 = lv_label_create(h2, NULL);\n\tlv_label_set_recolor(label_txt4, true);\n\tlv_label_set_static_text(label_txt4,\n\t\t\"Allows you to partition the SD Card for using it with #C7EA46 emuMMC#,\\n\"\n\t\t\"#C7EA46 Android# and #C7EA46 Linux#. You can also flash Linux and Android.\\n\");\n\tlv_obj_set_style(label_txt4, &hint_small_style);\n\tlv_obj_align(label_txt4, btn3, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\t// Create USB Tools button.\n\tlv_obj_t *btn4 = lv_btn_create(h2, btn3);\n\tlabel_btn = lv_label_create(btn4, NULL);\n\tlv_label_set_static_text(label_btn, SYMBOL_USB\"  USB Tools\");\n\tlv_obj_align(btn4, label_txt4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);\n\tlv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, _create_window_usb_tools);\n\n\tlabel_txt4 = lv_label_create(h2, NULL);\n\tlv_label_set_recolor(label_txt4, true);\n\tlv_label_set_static_text(label_txt4,\n\t\t\"#C7EA46 USB mass storage#, #C7EA46 gamepad# and other USB tools.\\n\"\n\t\t\"Mass storage can mount SD, eMMC and emuMMC. The\\n\"\n\t\t\"gamepad transforms the Switch into an input device.#\");\n\tlv_obj_set_style(label_txt4, &hint_small_style);\n\tlv_obj_align(label_txt4, btn4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n}\n\nstatic void _create_tab_tools_arc_rcm_pkg12(lv_theme_t *th, lv_obj_t *parent)\n{\n\tlv_page_set_scrl_layout(parent, LV_LAYOUT_PRETTY);\n\n\t// Create Misc container.\n\tlv_obj_t *h1 = _create_container(parent);\n\n\tlv_obj_t *label_sep = lv_label_create(h1, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\tlv_obj_t *label_txt = lv_label_create(h1, NULL);\n\tlv_label_set_static_text(label_txt, \"Misc\");\n\tlv_obj_set_style(label_txt, th->label.prim);\n\tlv_obj_align(label_txt, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI * 3 / 10);\n\n\tlv_obj_t *line_sep = lv_line_create(h1, NULL);\n\tstatic const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 2, 0} };\n\tlv_line_set_points(line_sep, line_pp, 2);\n\tlv_line_set_style(line_sep, th->line.decor);\n\tlv_obj_align(line_sep, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);\n\n\t// Create fix archive bit button.\n\tlv_obj_t *btn = lv_btn_create(h1, NULL);\n\tif (hekate_bg)\n\t{\n\t\tlv_btn_set_style(btn, LV_BTN_STYLE_REL, &btn_transp_rel);\n\t\tlv_btn_set_style(btn, LV_BTN_STYLE_PR, &btn_transp_pr);\n\t}\n\tlv_obj_t *label_btn = lv_label_create(btn, NULL);\n\tlv_btn_set_fit(btn, true, true);\n\tlv_label_set_static_text(label_btn, SYMBOL_DIRECTORY\"  Fix Archive Bit\");\n\tlv_obj_align(btn, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);\n\tlv_btn_set_action(btn, LV_BTN_ACTION_CLICK, _create_window_unset_abit_tool);\n\n\tlv_obj_t *label_txt2 = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(label_txt2, true);\n\tlv_label_set_static_text(label_txt2,\n\t\t\"Allows you to fix the archive bit for all folders including the\\n\"\n\t\t\"root and emuMMC \\'Nintendo\\' folders.\\n\"\n\t\t\"#C7EA46 It sets the archive bit to folders named with ##FF8000 .[ext]#\\n\"\n\t\t\"#FF8000 Use that option when you have corruption messages.#\");\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, btn, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\t// Create Fix touch calibration button.\n\tlv_obj_t *btn2 = lv_btn_create(h1, btn);\n\tlabel_btn = lv_label_create(btn2, NULL);\n\tlv_label_set_static_text(label_btn, SYMBOL_KEYBOARD\"  Calibrate Touchscreen\");\n\tlv_obj_align(btn2, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);\n\tlv_btn_set_action(btn2, LV_BTN_ACTION_CLICK, _create_mbox_fix_touchscreen);\n\n\tlabel_txt2 = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(label_txt2, true);\n\tlv_label_set_static_text(label_txt2,\n\t\t\"Allows you to calibrate the touchscreen module.\\n\"\n\t\t\"#FF8000 This can fix any issues with touchscreen in Nyx and HOS.#\");\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, btn2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\t// Create Others container.\n\tlv_obj_t *h2 = _create_container(parent);\n\tlv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, 0, 0);\n\n\tlabel_sep = lv_label_create(h2, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\n\tlv_obj_t *label_txt3 = lv_label_create(h2, NULL);\n\tlv_label_set_static_text(label_txt3, \"Others\");\n\tlv_obj_set_style(label_txt3, th->label.prim);\n\tlv_obj_align(label_txt3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI * 3 / 10);\n\n\tline_sep = lv_line_create(h2, line_sep);\n\tlv_obj_align(line_sep, label_txt3, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);\n\n\t// Create AutoRCM On/Off button.\n\tlv_obj_t *btn3 = lv_btn_create(h2, NULL);\n\tif (hekate_bg)\n\t{\n\t\tlv_btn_set_style(btn3, LV_BTN_STYLE_REL,     &btn_transp_rel);\n\t\tlv_btn_set_style(btn3, LV_BTN_STYLE_PR,      &btn_transp_pr);\n\t\tlv_btn_set_style(btn3, LV_BTN_STYLE_TGL_REL, &btn_transp_tgl_rel);\n\t\tlv_btn_set_style(btn3, LV_BTN_STYLE_TGL_PR,  &btn_transp_tgl_pr);\n\t\tlv_btn_set_style(btn3, LV_BTN_STYLE_INA,     &btn_transp_ina);\n\t}\n\tlabel_btn = lv_label_create(btn3, NULL);\n\tlv_btn_set_fit(btn3, true, true);\n\tlv_label_set_recolor(label_btn, true);\n\tlv_label_set_text(label_btn, SYMBOL_REFRESH\"  AutoRCM #00FFC9   ON #\");\n\tlv_obj_align(btn3, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);\n\tlv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, _create_mbox_autorcm_status);\n\n\t// Set default state for AutoRCM and lock it out if patched unit.\n\tif (get_set_autorcm_status(false))\n\t\tlv_btn_set_state(btn3, LV_BTN_STATE_TGL_REL);\n\telse\n\t\tlv_btn_set_state(btn3, LV_BTN_STATE_REL);\n\tnyx_generic_onoff_toggle(btn3);\n\n\tif (h_cfg.rcm_patched)\n\t{\n\t\tlv_obj_set_click(btn3, false);\n\t\tlv_btn_set_state(btn3, LV_BTN_STATE_INA);\n\t}\n\tautorcm_btn = btn3;\n\n\tchar *txt_buf = (char *)malloc(SZ_4K);\n\n\ts_printf(txt_buf,\n\t\t\"Allows you to enter RCM without using #C7EA46 VOL+# & #C7EA46 HOME# (jig).\\n\"\n\t\t\"#FF8000 It can restore all versions of AutoRCM whenever requested.#\\n\"\n\t\t\"#FF3C28 This corrupts the BCT and you can't boot without a custom#\\n\"\n\t\t\"#FF3C28 bootloader.#\");\n\n\tif (h_cfg.rcm_patched)\n\t\tstrcat(txt_buf, \" #FF8000 This is disabled because this unit is patched!#\");\n\n\tlv_obj_t *label_txt4 = lv_label_create(h2, NULL);\n\tlv_label_set_recolor(label_txt4, true);\n\tlv_label_set_text(label_txt4, txt_buf);\n\tfree(txt_buf);\n\n\tlv_obj_set_style(label_txt4, &hint_small_style);\n\tlv_obj_align(label_txt4, btn3, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\tlabel_sep = lv_label_create(h2, NULL);\n\tlv_label_set_static_text(label_sep, \"\");\n\tlv_obj_align(label_sep, label_txt4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI * 11 / 7);\n\n\t// Create Dump Package1/2 button.\n\tlv_obj_t *btn4 = lv_btn_create(h2, btn);\n\tlabel_btn = lv_label_create(btn4, NULL);\n\tlv_label_set_static_text(label_btn, SYMBOL_MODULES\"  Dump Package1/2\");\n\tlv_obj_align(btn4, label_txt4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);\n\tlv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, _create_window_dump_pk12_tool);\n\n\tlabel_txt2 = lv_label_create(h2, NULL);\n\tlv_label_set_recolor(label_txt2, true);\n\tlv_label_set_static_text(label_txt2,\n\t\t\"Allows you to dump and decrypt pkg1 and pkg2 and further\\n\"\n\t\t\"split it up into their individual parts. It also dumps the kip1.\");\n\tlv_obj_set_style(label_txt2, &hint_small_style);\n\tlv_obj_align(label_txt2, btn4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n}\n\nvoid create_tab_tools(lv_theme_t *th, lv_obj_t *parent)\n{\n\tlv_obj_t *tv = lv_tabview_create(parent, NULL);\n\n\tlv_obj_set_size(tv, LV_HOR_RES, 572);\n\n\tstatic lv_style_t tabview_style;\n\tlv_style_copy(&tabview_style, th->tabview.btn.rel);\n\ttabview_style.body.padding.ver = LV_DPI / 8;\n\n\tlv_tabview_set_style(tv, LV_TABVIEW_STYLE_BTN_REL, &tabview_style);\n\tif (hekate_bg)\n\t{\n\t\tlv_tabview_set_style(tv, LV_TABVIEW_STYLE_BTN_PR, &tabview_btn_pr);\n\t\tlv_tabview_set_style(tv, LV_TABVIEW_STYLE_BTN_TGL_PR, &tabview_btn_tgl_pr);\n\t}\n\n\tlv_tabview_set_sliding(tv, false);\n\tlv_tabview_set_btns_pos(tv, LV_TABVIEW_BTNS_POS_BOTTOM);\n\n\tlv_obj_t *tab1= lv_tabview_add_tab(tv, \"eMMC \"SYMBOL_DOT\" SD Partitions \"SYMBOL_DOT\" USB\");\n\tlv_obj_t *tab2 = lv_tabview_add_tab(tv, \"Arch bit \"SYMBOL_DOT\" RCM \"SYMBOL_DOT\" Touch \"SYMBOL_DOT\" Pkg1/2\");\n\n\tlv_obj_t *line_sep = lv_line_create(tv, NULL);\n\tstatic const lv_point_t line_pp[] = { {0, 0}, { 0, LV_DPI / 4} };\n\tlv_line_set_points(line_sep, line_pp, 2);\n\tlv_line_set_style(line_sep, lv_theme_get_current()->line.decor);\n\tlv_obj_align(line_sep, tv, LV_ALIGN_IN_BOTTOM_MID, -1, -LV_DPI * 2 / 12);\n\n\t_create_tab_tools_emmc_sd_usb(th, tab1);\n\t_create_tab_tools_arc_rcm_pkg12(th, tab2);\n\n\tlv_tabview_set_tab_act(tv, 0, false);\n}\n"
  },
  {
    "path": "nyx/nyx_gui/frontend/gui_tools.h",
    "content": "/*\n * Copyright (c) 2018-2021 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _GUI_TOOLS_H_\n#define _GUI_TOOLS_H_\n\n#include <libs/lvgl/lvgl.h>\n\nextern lv_obj_t *ums_mbox;\n\nvoid create_tab_tools(lv_theme_t *th, lv_obj_t *parent);\nvoid nyx_run_ums(void *param);\nbool get_set_autorcm_status(bool change);\nlv_res_t action_ums_sd(lv_obj_t *btn);\n\n#endif\n"
  },
  {
    "path": "nyx/nyx_gui/frontend/gui_tools_partition_manager.c",
    "content": "/*\n * Copyright (c) 2019-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <stdlib.h>\n\n#include <bdk.h>\n\n#include \"gui.h\"\n#include \"gui_tools.h\"\n#include \"fe_emummc_tools.h\"\n#include \"gui_tools_partition_manager.h\"\n#include \"../hos/hos.h\"\n#include <libs/fatfs/diskio.h>\n#include <libs/lvgl/lvgl.h>\n\n#define SECTORS_PER_GB   0x200000\n\n#define AU_ALIGN_SECTORS 0x8000 // 16MB.\n#define AU_ALIGN_BYTES   (AU_ALIGN_SECTORS * SD_BLOCKSIZE)\n\n#define HOS_USER_SECTOR      0x53C000\n#define HOS_FAT_MIN_SIZE_MB  2048\n#define HOS_USER_MIN_SIZE_MB 1024\n\n#define EMU_SLIDER_MIN     0\n#define EMU_SLIDER_MAX     44 // 24 GB. Always an even number.\n#define EMU_SLIDER_1X_MAX  (EMU_SLIDER_MAX / 2)\n#define EMU_SLIDER_1X_FULL EMU_SLIDER_1X_MAX\n#define EMU_SLIDER_2X_MIN  (EMU_SLIDER_1X_MAX + 1)\n#define EMU_SLIDER_2X_FULL EMU_SLIDER_MAX\n#define EMU_SLIDER_OFFSET  3 // Min 4GB.\n#define EMU_RSVD_MB        (4 + 4 + 16 + 8) // BOOT0 + BOOT1 + 16MB offset + 8MB alignment.\n\n#define EMU_32GB_FULL      29856 // Actual: 29820 MB.\n#define EMU_64GB_FULL      59680 // Actual: 59640 MB.\n\n#define AND_SYS_SIZE_MB     6144 // 6 GB. Fits both Legacy (4912MB) and Dynamic (6144MB) partition schemes.\n\nextern volatile boot_cfg_t *b_cfg;\nextern volatile nyx_storage_t *nyx_str;\n\ntypedef struct _partition_ctxt_t\n{\n\tbool emmc;\n\tsdmmc_storage_t *storage;\n\n\tu32 total_sct;\n\tu32 alignment;\n\tu32 emmc_size_mb;\n\tint backup_possible;\n\n\ts32 hos_min_size;\n\n\ts32 hos_size;\n\tu32 emu_size;\n\tu32 l4t_size;\n\tu32 and_size;\n\n\tbool emu_double;\n\tbool emmc_is_64gb;\n\n\tbool and_dynamic;\n\n\tmbr_t mbr_old;\n\n\tlv_obj_t *bar_hos;\n\tlv_obj_t *bar_emu;\n\tlv_obj_t *bar_l4t;\n\tlv_obj_t *bar_and;\n\n\tlv_obj_t *sep_emu;\n\tlv_obj_t *sep_l4t;\n\tlv_obj_t *sep_and;\n\n\tlv_obj_t *slider_bar_hos;\n\n\tlv_obj_t *cont_lbl;\n\n\tlv_obj_t *lbl_hos;\n\tlv_obj_t *lbl_emu;\n\tlv_obj_t *lbl_l4t;\n\tlv_obj_t *lbl_and;\n\n\tlv_obj_t *partition_button;\n} partition_ctxt_t;\n\ntypedef struct _l4t_flasher_ctxt_t\n{\n\tu32 offset_sct;\n\tu32 image_size_sct;\n} l4t_flasher_ctxt_t;\n\npartition_ctxt_t part_info;\nl4t_flasher_ctxt_t l4t_flash_ctxt;\n\nlv_obj_t *btn_flash_l4t;\nlv_obj_t *btn_flash_android;\n\nstatic FRESULT _copy_file(const char *src, const char *dst, const char *path)\n{\n\tFIL fp_src;\n\tFIL fp_dst;\n\tFRESULT res;\n\n\t// Open file for reading.\n\tf_chdrive(src);\n\tres = f_open(&fp_src, path, FA_READ);\n\tif (res != FR_OK)\n\t\treturn res;\n\n\tu32 file_bytes_left = f_size(&fp_src);\n\n\t// Open file for writing.\n\tf_chdrive(dst);\n\tf_open(&fp_dst, path, FA_CREATE_ALWAYS | FA_WRITE);\n\tf_lseek(&fp_dst, f_size(&fp_src));\n\tf_lseek(&fp_dst, 0);\n\n\twhile (file_bytes_left)\n\t{\n\t\tu32 chunk_size = MIN(file_bytes_left, SZ_4M); // 4MB chunks.\n\t\tfile_bytes_left -= chunk_size;\n\n\t\t// Copy file to buffer.\n\t\tf_read(&fp_src, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL);\n\n\t\t// Write file to disk.\n\t\tf_write(&fp_dst, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL);\n\t}\n\n\tf_close(&fp_dst);\n\tf_chdrive(src);\n\tf_close(&fp_src);\n\n\treturn FR_OK;\n}\n\nstatic int _stat_and_copy_files(const char *src, const char *dst, char *path, u32 *total_files, u32 *total_size, lv_obj_t **labels)\n{\n\tFRESULT res;\n\tDIR dir;\n\tu32 dirLength = 0;\n\tstatic FILINFO fno;\n\n\tf_chdrive(src);\n\n\t// Open directory.\n\tres = f_opendir(&dir, path);\n\tif (res != FR_OK)\n\t\treturn res;\n\n\tif (labels)\n\t\tlv_label_set_text(labels[0], path);\n\n\tdirLength = strlen(path);\n\n\t// Hard limit path to 1024 characters. Do not result to error.\n\tif (dirLength > 1024)\n\t\tgoto out;\n\n\tfor (;;)\n\t{\n\t\t// Clear file path.\n\t\tpath[dirLength] = 0;\n\n\t\t// Read a directory item.\n\t\tres = f_readdir(&dir, &fno);\n\n\t\t// Break on error or end of dir.\n\t\tif (res != FR_OK || fno.fname[0] == 0)\n\t\t\tbreak;\n\n\t\t// Set new directory or file.\n\t\tmemcpy(&path[dirLength], \"/\", 1);\n\t\tstrcpy(&path[dirLength + 1], fno.fname);\n\n\t\tif (labels)\n\t\t{\n\t\t\tlv_label_set_text(labels[1], fno.fname);\n\t\t\tmanual_system_maintenance(true);\n\t\t}\n\n\t\t// Copy file to destination disk.\n\t\tif (!(fno.fattrib & AM_DIR))\n\t\t{\n\t\t\tu64 file_size = fno.fsize > RAMDISK_CLUSTER_SZ ? fno.fsize : RAMDISK_CLUSTER_SZ;\n\n\t\t\t// Check for FAT32 or total overflow.\n\t\t\tif ((file_size + *total_size) > 0xFFFFFFFFu)\n\t\t\t{\n\t\t\t\t// Set size to > 1GB, skip next folders and return.\n\t\t\t\t*total_size = SZ_2G;\n\t\t\t\tres = -1;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t*total_size  += file_size;\n\t\t\t*total_files += 1;\n\n\t\t\t// Create a copy to destination.\n\t\t\tif (dst)\n\t\t\t{\n\t\t\t\tFIL fp_src;\n\t\t\t\tFIL fp_dst;\n\t\t\t\tu32 file_bytes_left = fno.fsize;\n\n\t\t\t\t// Open file for writing.\n\t\t\t\tf_chdrive(dst);\n\t\t\t\tf_open(&fp_dst, path, FA_CREATE_ALWAYS | FA_WRITE);\n\t\t\t\tf_lseek(&fp_dst, fno.fsize);\n\t\t\t\tf_lseek(&fp_dst, 0);\n\n\t\t\t\t// Open file for reading.\n\t\t\t\tf_chdrive(src);\n\t\t\t\tf_open(&fp_src, path, FA_READ);\n\n\t\t\t\twhile (file_bytes_left)\n\t\t\t\t{\n\t\t\t\t\tu32 chunk_size = MIN(file_bytes_left, SZ_4M); // 4MB chunks.\n\t\t\t\t\tfile_bytes_left -= chunk_size;\n\n\t\t\t\t\t// Copy file to buffer.\n\t\t\t\t\tf_read(&fp_src, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL);\n\t\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\t\t// Write file to disk.\n\t\t\t\t\tf_write(&fp_dst, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL);\n\t\t\t\t}\n\n\t\t\t\t// Finalize copied file.\n\t\t\t\tf_close(&fp_dst);\n\t\t\t\tf_chdrive(dst);\n\t\t\t\tf_chmod(path, fno.fattrib, 0xFF);\n\n\t\t\t\tf_chdrive(src);\n\t\t\t\tf_close(&fp_src);\n\t\t\t}\n\n\t\t\t// If total is > 1.2GB exit.\n\t\t\tif (*total_size > (RAM_DISK_SZ - SZ_16M)) // Account for alignment.\n\t\t\t{\n\t\t\t\t// Skip next folders and return.\n\t\t\t\tres = -1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse // It's a directory.\n\t\t{\n\t\t\tif (!memcmp(\"System Volume Information\", fno.fname, 25))\n\t\t\t\tcontinue;\n\n\t\t\t// Create folder to destination.\n\t\t\tif (dst)\n\t\t\t{\n\t\t\t\tf_chdrive(dst);\n\t\t\t\tf_mkdir(path);\n\t\t\t\tf_chmod(path, fno.fattrib, 0xFF);\n\t\t\t}\n\n\t\t\t// Enter the directory.\n\t\t\tres = _stat_and_copy_files(src, dst, path, total_files, total_size, labels);\n\t\t\tif (res != FR_OK)\n\t\t\t\tbreak;\n\n\t\t\tif (labels)\n\t\t\t{\n\t\t\t\t// Clear folder path.\n\t\t\t\tpath[dirLength] = 0;\n\t\t\t\tlv_label_set_text(labels[0], path);\n\t\t\t}\n\t\t}\n\t}\n\nout:\n\tf_closedir(&dir);\n\n\treturn res;\n}\n\nstatic void _create_gpt_partition(gpt_t *gpt, u8 *gpt_idx, u32 *curr_part_lba, u32 size_lba, const char *name, int name_size)\n{\n\tstatic const u8 linux_part_guid[] = { 0xAF, 0x3D, 0xC6, 0x0F,  0x83, 0x84,  0x72, 0x47,  0x8E, 0x79,  0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4 };\n\n\t// Reset partition.\n\tmemset(&gpt->entries[*gpt_idx], 0, sizeof(gpt_entry_t));\n\n\t// Create GPT partition.\n\tmemcpy(gpt->entries[*gpt_idx].type_guid, linux_part_guid, 16);\n\n\t// Set randomly created GUID.\n\tu8 random_number[SE_RNG_BLOCK_SIZE];\n\tse_rng_pseudo(random_number, SE_RNG_BLOCK_SIZE);\n\tmemcpy(gpt->entries[*gpt_idx].part_guid, random_number, SE_RNG_BLOCK_SIZE);\n\n\t// Set partition start and end.\n\tgpt->entries[*gpt_idx].lba_start = *curr_part_lba;\n\tgpt->entries[*gpt_idx].lba_end = *curr_part_lba + size_lba - 1;\n\n\t// Set name.\n\tu16 name_utf16[36] = {0};\n\tu32 name_lenth = strlen(name);\n\tfor (u32 i = 0; i < name_lenth; i++)\n\t\tname_utf16[i] = name[i];\n\tmemcpy(gpt->entries[*gpt_idx].name, name_utf16, name_lenth * sizeof(u16));\n\n\t// Wipe the first 1MB to sanitize it as raw-empty partition.\n\tsdmmc_storage_write(part_info.storage, *curr_part_lba, 0x800, (void *)SDMMC_ALT_DMA_BUFFER);\n\n\t// Prepare for next.\n\t(*curr_part_lba) += size_lba;\n\t(*gpt_idx)++;\n}\n\nstatic void _sd_prepare_and_flash_mbr_gpt()\n{\n\tmbr_t mbr;\n\tu8 random_number[SE_RNG_BLOCK_SIZE];\n\n\t// Read current MBR.\n\tsdmmc_storage_read(&sd_storage, 0, 1, &mbr);\n\n\t// Copy over metadata if they exist.\n\tif (*(u32 *)&part_info.mbr_old.bootstrap[0x80])\n\t\tmemcpy(&mbr.bootstrap[0x80], &part_info.mbr_old.bootstrap[0x80], 64);\n\tif (*(u32 *)&part_info.mbr_old.bootstrap[0xE0])\n\t\tmemcpy(&mbr.bootstrap[0xE0], &part_info.mbr_old.bootstrap[0xE0], 208);\n\n\t// Clear the first 16MB.\n\tmemset((void *)SDMMC_ALT_DMA_BUFFER, 0, AU_ALIGN_BYTES);\n\tsdmmc_storage_write(&sd_storage, 0, AU_ALIGN_SECTORS, (void *)SDMMC_ALT_DMA_BUFFER);\n\n\t// Set disk signature.\n\tse_rng_pseudo(random_number, sizeof(u32));\n\tmemcpy(&mbr.signature, random_number, sizeof(u32));\n\n\t// FAT partition as first.\n\tu8 mbr_idx = 1;\n\n\t// Apply L4T Linux second to MBR if no Android.\n\tif (part_info.l4t_size && !part_info.and_size)\n\t{\n\t\tmbr.partitions[mbr_idx].type = 0x83; // Linux system partition.\n\t\tmbr.partitions[mbr_idx].start_sct = AU_ALIGN_SECTORS + ((u32)part_info.hos_size << 11);\n\t\tmbr.partitions[mbr_idx].size_sct = part_info.l4t_size << 11;\n\t\tsdmmc_storage_write(&sd_storage, mbr.partitions[mbr_idx].start_sct, 0x800, (void *)SDMMC_ALT_DMA_BUFFER); // Clear the first 1MB.\n\t\tmbr_idx++;\n\t}\n\n\t// emuMMC goes second or third. Next to L4T if no Android.\n\tif (part_info.emu_size)\n\t{\n\t\tmbr.partitions[mbr_idx].type = 0xE0; // emuMMC partition.\n\t\tmbr.partitions[mbr_idx].start_sct = AU_ALIGN_SECTORS + ((u32)part_info.hos_size << 11) + (part_info.l4t_size << 11) + (part_info.and_size << 11);\n\n\t\tif (!part_info.emu_double)\n\t\t\tmbr.partitions[mbr_idx].size_sct = (part_info.emu_size << 11) - 0x800; // Reserve 1MB.\n\t\telse\n\t\t{\n\t\t\tmbr.partitions[mbr_idx].size_sct = part_info.emu_size << 10;\n\t\t\tmbr_idx++;\n\n\t\t\t// 2nd emuMMC.\n\t\t\tmbr.partitions[mbr_idx].type = 0xE0; // emuMMC partition.\n\t\t\tmbr.partitions[mbr_idx].start_sct = mbr.partitions[mbr_idx - 1].start_sct + (part_info.emu_size << 10);\n\t\t\tmbr.partitions[mbr_idx].size_sct = (part_info.emu_size << 10) - 0x800; // Reserve 1MB.\n\t\t}\n\t\tmbr_idx++;\n\t}\n\n\tif (part_info.and_size)\n\t{\n\t\tgpt_t *gpt = zalloc(sizeof(gpt_t));\n\t\tgpt_header_t gpt_hdr_backup = { 0 };\n\n\t\t// Set GPT protective partition in MBR.\n\t\tmbr.partitions[mbr_idx].type = 0xEE;\n\t\tmbr.partitions[mbr_idx].start_sct = 1;\n\t\tmbr.partitions[mbr_idx].size_sct = sd_storage.sec_cnt - 1;\n\t\tmbr_idx++;\n\n\t\t// Set GPT header.\n\t\tmemcpy(&gpt->header.signature, \"EFI PART\", 8);\n\t\tgpt->header.revision = 0x10000;\n\t\tgpt->header.size = 92;\n\t\tgpt->header.my_lba = 1;\n\t\tgpt->header.alt_lba = sd_storage.sec_cnt - 1;\n\t\tgpt->header.first_use_lba = (sizeof(mbr_t) + sizeof(gpt_t)) >> 9;\n\t\tgpt->header.last_use_lba = sd_storage.sec_cnt - 0x800 - 1; // sd_storage.sec_cnt - 33 is start of backup gpt partition entries.\n\t\tse_rng_pseudo(random_number, SE_RNG_BLOCK_SIZE);\n\t\tmemcpy(gpt->header.disk_guid, random_number, 10);\n\t\tmemcpy(gpt->header.disk_guid + 10, \"NYXGPT\", 6);\n\t\tgpt->header.part_ent_lba = 2;\n\t\tgpt->header.part_ent_size = 128;\n\n\t\t// Set FAT GPT partition manually.\n\t\tconst u8 basic_part_guid[] = { 0xA2, 0xA0, 0xD0, 0xEB,  0xE5, 0xB9,  0x33, 0x44,  0x87, 0xC0,  0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 };\n\t\tmemcpy(gpt->entries[0].type_guid, basic_part_guid, 16);\n\t\tse_rng_pseudo(random_number, SE_RNG_BLOCK_SIZE);\n\t\tmemcpy(gpt->entries[0].part_guid, random_number, SE_RNG_BLOCK_SIZE);\n\n\t\t// Clear non-standard Windows MBR attributes. bit4: Read only, bit5: Shadow copy, bit6: Hidden, bit7: No drive letter.\n\t\tgpt->entries[0].part_guid[7] = 0;\n\n\t\tgpt->entries[0].lba_start = mbr.partitions[0].start_sct;\n\t\tgpt->entries[0].lba_end = mbr.partitions[0].start_sct + mbr.partitions[0].size_sct - 1;\n\t\tmemcpy(gpt->entries[0].name, (u16[]) { 'h', 'o', 's', '_', 'd', 'a', 't', 'a' }, 16);\n\n\t\t// Set the rest of GPT partitions.\n\t\tu8  gpt_idx = 1;\n\t\tu32 curr_part_lba = AU_ALIGN_SECTORS + ((u32)part_info.hos_size << 11);\n\n\t\t// L4T partition.\n\t\tif (part_info.l4t_size)\n\t\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, part_info.l4t_size << 11, \"l4t\", 6);\n\n\t\tif (part_info.and_dynamic)\n\t\t{\n\t\t\t// Android Linux Kernel partition. 64MB.\n\t\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba,  0x20000, \"boot\", 8);\n\n\t\t\t// Android Recovery partition. 64MB.\n\t\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba,  0x20000, \"recovery\", 16);\n\n\t\t\t// Android Device Tree Reference partition. 1MB.\n\t\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba,    0x800, \"dtb\", 6);\n\n\t\t\t// Android Misc partition. 3MB.\n\t\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba,   0x1800, \"misc\", 8);\n\n\t\t\t// Android Cache partition. 60MB.\n\t\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba,  0x1E000, \"cache\", 10);\n\n\t\t\t// Android Super dynamic partition. 5952MB.\n\t\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0xBA0000, \"super\", 10);\n\n\t\t\t// Android Userdata partition.\n\t\t\tu32 uda_size = (part_info.and_size << 11) - 0xC00000; // Subtract the other partitions (6144MB).\n\t\t\tif (!part_info.emu_size)\n\t\t\t\tuda_size -= 0x800; // Reserve 1MB.\n\t\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, uda_size, \"userdata\", 16);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Android Vendor partition. 1GB\n\t\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x200000, \"vendor\", 12);\n\n\t\t\t// Android System partition. 3GB.\n\t\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x600000, \"APP\", 6);\n\n\t\t\t// Android Linux Kernel partition. 32MB.\n\t\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba,  0x10000, \"LNX\", 6);\n\n\t\t\t// Android Recovery partition. 64MB.\n\t\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba,  0x20000, \"SOS\", 6);\n\n\t\t\t// Android Device Tree Reference partition. 1MB.\n\t\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba,    0x800, \"DTB\", 6);\n\n\t\t\t// Android Encryption partition. 16MB.\n\t\t\t// Note: 16MB size is for aligning UDA. If any other tiny partition must be added, it should split the MDA one.\n\t\t\tsdmmc_storage_write(&sd_storage, curr_part_lba, 0x8000, (void *)SDMMC_ALT_DMA_BUFFER); // Clear the whole of it.\n\t\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba,   0x8000, \"MDA\", 6);\n\n\t\t\t// Android Cache partition. 700MB.\n\t\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x15E000, \"CAC\", 6);\n\n\t\t\t// Android Misc partition. 3MB.\n\t\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba,   0x1800, \"MSC\", 6);\n\n\t\t\t// Android Userdata partition.\n\t\t\tu32 uda_size = (part_info.and_size << 11) - 0x998000; // Subtract the other partitions (4912MB).\n\t\t\tif (!part_info.emu_size)\n\t\t\t\tuda_size -= 0x800; // Reserve 1MB.\n\t\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, uda_size, \"UDA\", 6);\n\t\t}\n\n\t\t// Handle emuMMC partitions manually.\n\t\tif (part_info.emu_size)\n\t\t{\n\t\t\t// Set 1st emuMMC.\n\t\t\tu8 emu_part_guid[] = { 0x00, 0x7E, 0xCA, 0x11,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  'e', 'm', 'u', 'M', 'M', 'C' };\n\t\t\tmemcpy(gpt->entries[gpt_idx].type_guid, emu_part_guid, 16);\n\t\t\tse_rng_pseudo(random_number, SE_RNG_BLOCK_SIZE);\n\t\t\tmemcpy(gpt->entries[gpt_idx].part_guid, random_number, SE_RNG_BLOCK_SIZE);\n\t\t\tgpt->entries[gpt_idx].lba_start = curr_part_lba;\n\t\t\tif (!part_info.emu_double)\n\t\t\t\tgpt->entries[gpt_idx].lba_end = curr_part_lba + (part_info.emu_size << 11) - 0x800 - 1; // Reserve 1MB.\n\t\t\telse\n\t\t\t\tgpt->entries[gpt_idx].lba_end = curr_part_lba + (part_info.emu_size << 10) - 1;\n\t\t\tmemcpy(gpt->entries[gpt_idx].name, (u16[]) { 'e', 'm', 'u', 'm', 'm', 'c' }, 12);\n\t\t\tgpt_idx++;\n\n\t\t\t// Set 2nd emuMMC.\n\t\t\tif (part_info.emu_double)\n\t\t\t{\n\t\t\t\tcurr_part_lba += (part_info.emu_size << 10);\n\t\t\t\tmemcpy(gpt->entries[gpt_idx].type_guid, emu_part_guid, 16);\n\t\t\t\tse_rng_pseudo(random_number, SE_RNG_BLOCK_SIZE);\n\t\t\t\tmemcpy(gpt->entries[gpt_idx].part_guid, random_number, SE_RNG_BLOCK_SIZE);\n\t\t\t\tgpt->entries[gpt_idx].lba_start = curr_part_lba;\n\t\t\t\tgpt->entries[gpt_idx].lba_end = curr_part_lba + (part_info.emu_size << 10) - 0x800 - 1; // Reserve 1MB.\n\t\t\t\tmemcpy(gpt->entries[gpt_idx].name, (u16[]) { 'e', 'm', 'u', 'm', 'm', 'c', '2' }, 14);\n\t\t\t\tgpt_idx++;\n\t\t\t}\n\t\t}\n\n\t\t// Set final GPT header parameters.\n\t\tgpt->header.num_part_ents = gpt_idx;\n\t\tgpt->header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt->entries, sizeof(gpt_entry_t) * gpt->header.num_part_ents);\n\t\tgpt->header.crc32 = 0; // Set to 0 for calculation.\n\t\tgpt->header.crc32 = crc32_calc(0, (const u8 *)&gpt->header, gpt->header.size);\n\n\t\t// Set final backup GPT header parameters.\n\t\tmemcpy(&gpt_hdr_backup, &gpt->header, sizeof(gpt_header_t));\n\t\tgpt_hdr_backup.my_lba = sd_storage.sec_cnt - 1;\n\t\tgpt_hdr_backup.alt_lba = 1;\n\t\tgpt_hdr_backup.part_ent_lba = sd_storage.sec_cnt - 33;\n\t\tgpt_hdr_backup.crc32 = 0; // Set to 0 for calculation.\n\t\tgpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size);\n\n\t\t// Write main GPT.\n\t\tsdmmc_storage_write(&sd_storage, gpt->header.my_lba, sizeof(gpt_t) >> 9, gpt);\n\n\t\t// Write backup GPT partition table.\n\t\tsdmmc_storage_write(&sd_storage, gpt_hdr_backup.part_ent_lba, ((sizeof(gpt_entry_t) * 128) >> 9), gpt->entries);\n\n\t\t// Write backup GPT header.\n\t\tsdmmc_storage_write(&sd_storage, gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup);\n\n\t\tfree(gpt);\n\t}\n\n\t// Write MBR.\n\tsdmmc_storage_write(&sd_storage, 0, 1, &mbr);\n}\n\nstatic int _emmc_prepare_and_flash_mbr_gpt()\n{\n\tgpt_t *gpt = zalloc(sizeof(gpt_t));\n\tgpt_header_t gpt_hdr_backup = { 0 };\n\n\tmemset((void *)SDMMC_ALT_DMA_BUFFER, 0, AU_ALIGN_BYTES);\n\n\t// Read main GPT.\n\tsdmmc_storage_read(&emmc_storage, 1, sizeof(gpt_t) >> 9, gpt);\n\n\t// Set GPT header.\n\tgpt->header.alt_lba = emmc_storage.sec_cnt - 1;\n\tgpt->header.last_use_lba = emmc_storage.sec_cnt - 0x800 - 1; // emmc_storage.sec_cnt - 33 is start of backup gpt partition entries.\n\n\t// Calculate HOS USER partition\n\tu32 part_rsvd_size = (part_info.l4t_size << 11) + (part_info.and_size << 11);\n\tpart_rsvd_size += part_rsvd_size ? part_info.alignment : 0x800; // Only reserve 1MB if no extra partitions.\n\tu32 hos_user_size = emmc_storage.sec_cnt - HOS_USER_SECTOR - part_rsvd_size;\n\n\t// Get HOS USER partition index.\n\tLIST_INIT(gpt_emmc);\n\temmc_gpt_parse(&gpt_emmc);\n\temmc_part_t *user_part = emmc_part_find(&gpt_emmc, \"USER\");\n\tif (!user_part)\n\t{\n\t\temmc_gpt_free(&gpt_emmc);\n\t\tfree(gpt);\n\n\t\treturn 1;\n\t}\n\tu8 gpt_idx = user_part->index;\n\temmc_gpt_free(&gpt_emmc);\n\n\t// HOS USER partition.\n\tu32 curr_part_lba = gpt->entries[gpt_idx].lba_start;\n\tgpt->entries[gpt_idx].lba_end = curr_part_lba + hos_user_size - 1;\n\n\tcurr_part_lba += hos_user_size;\n\tgpt_idx++;\n\n\t// L4T partition.\n\tif (part_info.l4t_size)\n\t{\n\t\tu32 l4t_size = part_info.l4t_size << 11;\n\t\tif (!part_info.and_size)\n\t\t\tl4t_size -= 0x800; // Reserve 1MB.\n\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, l4t_size, \"l4t\", 6);\n\t}\n\n\tif (part_info.and_size && part_info.and_dynamic)\n\t{\n\t\t// Android Linux Kernel partition. 64MB.\n\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba,  0x20000, \"boot\", 8);\n\n\t\t// Android Recovery partition. 64MB.\n\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba,  0x20000, \"recovery\", 16);\n\n\t\t// Android Device Tree Reference partition. 1MB.\n\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba,    0x800, \"dtb\", 6);\n\n\t\t// Android Misc partition. 3MB.\n\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba,   0x1800, \"misc\", 8);\n\n\t\t// Android Cache partition. 60MB.\n\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba,  0x1E000, \"cache\", 10);\n\n\t\t// Android Super dynamic partition. 5952MB.\n\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0xBA0000, \"super\", 10);\n\n\t\t// Android Userdata partition.\n\t\tu32 uda_size = (part_info.and_size << 11) - 0xC00000; // Subtract the other partitions (6144MB).\n\t\tuda_size -= 0x800; // Reserve 1MB.\n\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, uda_size, \"userdata\", 16);\n\t}\n\telse if (part_info.and_size)\n\t{\n\t\t// Android Vendor partition. 1GB\n\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x200000, \"vendor\", 12);\n\n\t\t// Android System partition. 3GB.\n\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x600000, \"APP\", 6);\n\n\t\t// Android Linux Kernel partition. 32MB.\n\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba,  0x10000, \"LNX\", 6);\n\n\t\t// Android Recovery partition. 64MB.\n\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba,  0x20000, \"SOS\", 6);\n\n\t\t// Android Device Tree Reference partition. 1MB.\n\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba,    0x800, \"DTB\", 6);\n\n\t\t// Android Encryption partition. 16MB.\n\t\t// Note: 16MB size is for aligning UDA. If any other tiny partition must be added, it should split the MDA one.\n\t\tsdmmc_storage_write(&emmc_storage, curr_part_lba, 0x8000, (void *)SDMMC_ALT_DMA_BUFFER); // Clear the whole of it.\n\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba,   0x8000, \"MDA\", 6);\n\n\t\t// Android Cache partition. 700MB.\n\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x15E000, \"CAC\", 6);\n\n\t\t// Android Misc partition. 3MB.\n\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba,   0x1800, \"MSC\", 6);\n\n\t\t// Android Userdata partition.\n\t\tu32 uda_size = (part_info.and_size << 11) - 0x998000; // Subtract the other partitions (4912MB).\n\t\tuda_size -= 0x800; // Reserve 1MB.\n\t\t_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, uda_size, \"UDA\", 6);\n\t}\n\n\t// Clear the rest of GPT partition table.\n\tfor (u32 i = gpt_idx; i < 128; i++)\n\t\tmemset(&gpt->entries[i], 0, sizeof(gpt_entry_t));\n\n\t// Set final GPT header parameters.\n\tgpt->header.num_part_ents = gpt_idx;\n\tgpt->header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt->entries, sizeof(gpt_entry_t) * gpt->header.num_part_ents);\n\tgpt->header.crc32 = 0; // Set to 0 for calculation.\n\tgpt->header.crc32 = crc32_calc(0, (const u8 *)&gpt->header, gpt->header.size);\n\n\t// Set final backup GPT header parameters.\n\tmemcpy(&gpt_hdr_backup, &gpt->header, sizeof(gpt_header_t));\n\tgpt_hdr_backup.my_lba = emmc_storage.sec_cnt - 1;\n\tgpt_hdr_backup.alt_lba = 1;\n\tgpt_hdr_backup.part_ent_lba = emmc_storage.sec_cnt - 33;\n\tgpt_hdr_backup.crc32 = 0; // Set to 0 for calculation.\n\tgpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size);\n\n\t// Write main GPT.\n\tsdmmc_storage_write(&emmc_storage, gpt->header.my_lba, sizeof(gpt_t) >> 9, gpt);\n\n\t// Write backup GPT partition table.\n\tsdmmc_storage_write(&emmc_storage, gpt_hdr_backup.part_ent_lba, ((sizeof(gpt_entry_t) * 128) >> 9), gpt->entries);\n\n\t// Write backup GPT header.\n\tsdmmc_storage_write(&emmc_storage, gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup);\n\n\t// Clear nand patrol.\n\tu8 *buf = (u8 *)gpt;\n\tmemset(buf, 0, EMMC_BLOCKSIZE);\n\temmc_set_partition(EMMC_BOOT0);\n\tsdmmc_storage_write(&emmc_storage, NAND_PATROL_SECTOR, 1, buf);\n\temmc_set_partition(EMMC_GPP);\n\n\tfree(gpt);\n\n\treturn 0;\n}\n\nstatic lv_res_t _action_part_manager_ums_sd(lv_obj_t *btn)\n{\n\taction_ums_sd(NULL);\n\n\t// Close and reopen partition manager.\n\tlv_action_t close_btn_action = lv_btn_get_action(close_btn, LV_BTN_ACTION_CLICK);\n\tclose_btn_action(close_btn);\n\tlv_obj_del(ums_mbox);\n\tcreate_window_sd_partition_manager(NULL);\n\n\treturn LV_RES_INV;\n}\n\nstatic lv_res_t _action_delete_linux_installer_files(lv_obj_t * btns, const char * txt)\n{\n\n\tint btn_idx = lv_btnm_get_pressed(btns);\n\n\t// Delete parent mbox.\n\tnyx_mbox_action(btns, txt);\n\n\t// Flash Linux.\n\tif (!btn_idx)\n\t{\n\t\tchar path[128];\n\n\t\tsd_mount();\n\n\t\tstrcpy(path, \"switchroot/install/l4t.\");\n\n\t\t// Delete all l4t.xx files.\n\t\tu32 idx = 0;\n\t\twhile (true)\n\t\t{\n\t\t\tif (idx < 10)\n\t\t\t{\n\t\t\t\tpath[23] = '0';\n\t\t\t\titoa(idx, &path[23 + 1], 10);\n\t\t\t}\n\t\t\telse\n\t\t\t\titoa(idx, &path[23], 10);\n\n\t\t\tif (!f_stat(path, NULL))\n\t\t\t{\n\t\t\t\tf_unlink(path);\n\t\t\t}\n\t\t\telse\n\t\t\t\tbreak;\n\n\t\t\tidx++;\n\t\t}\n\n\t\tsd_unmount();\n\t}\n\n\treturn LV_RES_INV;\n}\n\nstatic lv_res_t _action_flash_linux_data(lv_obj_t * btns, const char * txt)\n{\n\tint btn_idx = lv_btnm_get_pressed(btns);\n\n\t// Delete parent mbox.\n\tnyx_mbox_action(btns, txt);\n\n\tbool succeeded = false;\n\n\tif (btn_idx)\n\t\treturn LV_RES_INV;\n\n\t// Flash Linux.\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_map[] = { \"\\251\", \"\\222OK\", \"\\251\", \"\" };\n\tstatic const char *mbox_btn_map2[] = { \"\\223Delete Installation Files\", \"\\221OK\", \"\" };\n\tlv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 10 * 5);\n\n\tlv_mbox_set_text(mbox, \"#FF8000 Linux Flasher#\");\n\n\tlv_obj_t *lbl_status = lv_label_create(mbox, NULL);\n\tlv_label_set_recolor(lbl_status, true);\n\tlv_label_set_text(lbl_status, \"#C7EA46 Status:# Flashing Linux...\");\n\n\t// Create container to keep content inside.\n\tlv_obj_t *h1 = lv_cont_create(mbox, NULL);\n\tlv_cont_set_fit(h1, true, true);\n\tlv_cont_set_style(h1, &lv_style_transp_tight);\n\n\tlv_obj_t *bar = lv_bar_create(h1, NULL);\n\tlv_obj_set_size(bar, LV_DPI * 30 / 10, LV_DPI / 5);\n\tlv_bar_set_range(bar, 0, 100);\n\tlv_bar_set_value(bar, 0);\n\n\tlv_obj_t *label_pct = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(label_pct, true);\n\tlv_label_set_text(label_pct, \" \"SYMBOL_DOT\" 0%\");\n\tlv_label_set_style(label_pct, lv_theme_get_current()->label.prim);\n\tlv_obj_align(label_pct, bar, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 20, 0);\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\tsd_mount();\n\tif (part_info.emmc)\n\t\temmc_initialize(false);\n\n\tint res = 0;\n\tchar *path = malloc(1024);\n\tchar *txt_buf = malloc(SZ_4K);\n\tstrcpy(path, \"switchroot/install/l4t.00\");\n\tu32 path_len = strlen(path) - 2;\n\n\tFIL fp;\n\n\tres = f_open(&fp, path, FA_READ);\n\tif (res)\n\t{\n\t\tlv_label_set_text(lbl_status, \"#FFDD00 Error:# Failed to open 1st part!\");\n\n\t\tgoto exit;\n\t}\n\n\tu64 fileSize = (u64)f_size(&fp);\n\n\tu32 num = 0;\n\tu32 pct = 0;\n\tu32 lba_curr = 0;\n\tu32 bytesWritten = 0;\n\tu32 currPartIdx = 0;\n\tu32 prevPct = 200;\n\tint retryCount = 0;\n\tu32 total_size_sct = l4t_flash_ctxt.image_size_sct;\n\n\tu8 *buf = (u8 *)MIXD_BUF_ALIGNED;\n\tDWORD *clmt = f_expand_cltbl(&fp, SZ_4M, 0);\n\n\t// Start flashing L4T.\n\twhile (total_size_sct > 0)\n\t{\n\t\t// If we have more than one part, check the size for the split parts and make sure that the bytes written is not more than that.\n\t\tif (bytesWritten >= fileSize)\n\t\t{\n\t\t\t// If we have more bytes written then close the file pointer and increase the part index we are using\n\t\t\tf_close(&fp);\n\t\t\tfree(clmt);\n\t\t\tmemset(&fp, 0, sizeof(fp));\n\t\t\tcurrPartIdx++;\n\n\t\t\tif (currPartIdx < 10)\n\t\t\t{\n\t\t\t\tpath[path_len] = '0';\n\t\t\t\titoa(currPartIdx, &path[path_len + 1], 10);\n\t\t\t}\n\t\t\telse\n\t\t\t\titoa(currPartIdx, &path[path_len], 10);\n\n\t\t\t// Try to open the next file part\n\t\t\tres = f_open(&fp, path, FA_READ);\n\t\t\tif (res)\n\t\t\t{\n\t\t\t\ts_printf(txt_buf, \"#FFDD00 Error:# Failed to open part %d#\", currPartIdx);\n\t\t\t\tlv_label_set_text(lbl_status, txt_buf);\n\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\tgoto exit;\n\t\t\t}\n\t\t\tfileSize = (u64)f_size(&fp);\n\t\t\tbytesWritten = 0;\n\t\t\tclmt = f_expand_cltbl(&fp, SZ_4M, 0);\n\t\t}\n\n\t\tretryCount = 0;\n\t\tnum = MIN(total_size_sct, 8192);\n\n\t\t// Read next data block from SD.\n\t\tres = f_read_fast(&fp, buf, num << 9);\n\t\tmanual_system_maintenance(false);\n\n\t\tif (res)\n\t\t{\n\t\t\tlv_label_set_text(lbl_status, \"#FFDD00 Error:# Reading from SD!\");\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tf_close(&fp);\n\t\t\tfree(clmt);\n\t\t\tgoto exit;\n\t\t}\n\n\t\t// Write data block to L4T partition.\n\t\tres = sdmmc_storage_write(part_info.storage, lba_curr + l4t_flash_ctxt.offset_sct, num, buf);\n\n\t\tmanual_system_maintenance(false);\n\n\t\t// If failed, retry 3 more times.\n\t\twhile (res)\n\t\t{\n\t\t\tmsleep(150);\n\t\t\tmanual_system_maintenance(true);\n\n\t\t\tif (retryCount >= 3)\n\t\t\t{\n\t\t\t\tlv_label_set_text(lbl_status, \"#FFDD00 Error:# Writing to SD!\");\n\t\t\t\tmanual_system_maintenance(true);\n\n\t\t\t\tf_close(&fp);\n\t\t\t\tfree(clmt);\n\t\t\t\tgoto exit;\n\t\t\t}\n\n\t\t\tres = sdmmc_storage_write(part_info.storage, lba_curr + l4t_flash_ctxt.offset_sct, num, buf);\n\t\t\tmanual_system_maintenance(false);\n\t\t}\n\n\t\t// Update completion percentage.\n\t\tpct = (u64)((u64)lba_curr * 100u) / (u64)l4t_flash_ctxt.image_size_sct;\n\t\tif (pct != prevPct)\n\t\t{\n\t\t\tlv_bar_set_value(bar, pct);\n\t\t\ts_printf(txt_buf, \" #DDDDDD \"SYMBOL_DOT\"# %d%%\", pct);\n\t\t\tlv_label_set_text(label_pct, txt_buf);\n\t\t\tmanual_system_maintenance(true);\n\t\t\tprevPct = pct;\n\t\t}\n\n\t\tlba_curr += num;\n\t\ttotal_size_sct -= num;\n\t\tbytesWritten += num * EMMC_BLOCKSIZE;\n\t}\n\tlv_bar_set_value(bar, 100);\n\tlv_label_set_text(label_pct, \" \"SYMBOL_DOT\" 100%\");\n\tmanual_system_maintenance(true);\n\n\t// Restore operation ended successfully.\n\tf_close(&fp);\n\tfree(clmt);\n\n\tsucceeded = true;\n\nexit:\n\tfree(path);\n\tfree(txt_buf);\n\n\tif (!succeeded)\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);\n\telse\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map2, _action_delete_linux_installer_files);\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\n\tsd_unmount();\n\tif (part_info.emmc)\n\t\temmc_end();\n\n\treturn LV_RES_INV;\n}\n\nstatic u32 _get_available_l4t_partition()\n{\n\tmbr_t mbr = { 0 };\n\tgpt_t *gpt = zalloc(sizeof(gpt_t));\n\n\tmemset(&l4t_flash_ctxt, 0, sizeof(l4t_flasher_ctxt_t));\n\n\t// Read MBR.\n\tsdmmc_storage_read(part_info.storage, 0, 1, &mbr);\n\n\t// Read main GPT.\n\tsdmmc_storage_read(part_info.storage, 1, sizeof(gpt_t) >> 9, gpt);\n\n\t// Search for a suitable partition.\n\tu32 size_sct = 0;\n\tif (!memcmp(&gpt->header.signature, \"EFI PART\", 8) || gpt->header.num_part_ents > 128)\n\t{\n\t\tfor (u32 i = 0; i < gpt->header.num_part_ents; i++)\n\t\t{\n\t\t\tif (!memcmp(gpt->entries[i].name, (u16[]) { 'l', '4', 't' }, 6))\n\t\t\t{\n\t\t\t\tl4t_flash_ctxt.offset_sct = gpt->entries[i].lba_start;\n\t\t\t\tsize_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (u32 i = 1; i < 4; i++)\n\t\t{\n\t\t\tif (mbr.partitions[i].type == 0x83)\n\t\t\t{\n\t\t\t\tl4t_flash_ctxt.offset_sct = mbr.partitions[i].start_sct;\n\t\t\t\tsize_sct = mbr.partitions[i].size_sct;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tfree(gpt);\n\n\treturn size_sct;\n}\n\nstatic int _get_available_android_partition()\n{\n\tgpt_t *gpt = zalloc(sizeof(gpt_t));\n\n\t// Read main GPT.\n\tsdmmc_storage_read(part_info.storage, 1, sizeof(gpt_t) >> 9, gpt);\n\n\t// Check if GPT.\n\tif (memcmp(&gpt->header.signature, \"EFI PART\", 8) || gpt->header.num_part_ents > 128)\n\t\tgoto out;\n\n\t// Find kernel partition.\n\tfor (u32 i = 0; i < gpt->header.num_part_ents; i++)\n\t{\n\t\tif (gpt->entries[i].lba_start)\n\t\t{\n\t\t\tint found  = !memcmp(gpt->entries[i].name, (u16[]) { 'b', 'o', 'o', 't' }, 8) ? 2 : 0;\n\t\t\t\tfound |= !memcmp(gpt->entries[i].name, (u16[]) { 'L', 'N', 'X' },      6) ? 1 : 0;\n\n\t\t\tif (found)\n\t\t\t{\n\t\t\t\tfree(gpt);\n\n\t\t\t\treturn found;\n\t\t\t}\n\t\t}\n\t}\n\nout:\n\tfree(gpt);\n\n\treturn false;\n}\n\nstatic lv_res_t _action_check_flash_linux(lv_obj_t *btn)\n{\n\tFILINFO fno;\n\tchar path[128];\n\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_map[] = { \"\\251\", \"\\222OK\", \"\\251\", \"\" };\n\tstatic const char *mbox_btn_map2[] = { \"\\222Continue\", \"\\222Cancel\", \"\" };\n\tlv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);\n\n\tlv_mbox_set_text(mbox, \"#FF8000 Linux Flasher#\");\n\n\tlv_obj_t *lbl_status = lv_label_create(mbox, NULL);\n\tlv_label_set_recolor(lbl_status, true);\n\tlv_label_set_text(lbl_status, \"#C7EA46 Status:# Searching for files and partitions...\");\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\tmanual_system_maintenance(true);\n\n\tsd_mount();\n\tif (part_info.emmc)\n\t\temmc_initialize(false);\n\n\t// Check if L4T image exists.\n\tstrcpy(path, \"switchroot/install/l4t.00\");\n\tif (f_stat(path, NULL))\n\t{\n\t\tlv_label_set_text(lbl_status, \"#FFDD00 Error:# Installation files not found!\");\n\t\tgoto error;\n\t}\n\n\t// Find an applicable partition for L4T.\n\tu32 size_sct = _get_available_l4t_partition();\n\tif (!l4t_flash_ctxt.offset_sct || size_sct < 0x800000)\n\t{\n\t\tlv_label_set_text(lbl_status, \"#FFDD00 Error:# No partition found!\");\n\t\tgoto error;\n\t}\n\n\tu32 idx = 0;\n\tpath[23] = 0;\n\n\t// Validate L4T images and consolidate their info.\n\twhile (true)\n\t{\n\t\tif (idx < 10)\n\t\t{\n\t\t\tpath[23] = '0';\n\t\t\titoa(idx, &path[23 + 1], 10);\n\t\t}\n\t\telse\n\t\t\titoa(idx, &path[23], 10);\n\n\t\t// Check for alignment.\n\t\tif (f_stat(path, &fno))\n\t\t\tbreak;\n\n\t\t// Check if current part is unaligned.\n\t\tif ((u64)fno.fsize % SZ_4M)\n\t\t{\n\t\t\t// Get next part filename.\n\t\t\tidx++;\n\t\t\tif (idx < 10)\n\t\t\t{\n\t\t\t\tpath[23] = '0';\n\t\t\t\titoa(idx, &path[23 + 1], 10);\n\t\t\t}\n\t\t\telse\n\t\t\t\titoa(idx, &path[23], 10);\n\n\t\t\t// If it exists, unaligned size for current part is not permitted.\n\t\t\tif (!f_stat(path, NULL)) // NULL: Don't override current part fs info.\n\t\t\t{\n\t\t\t\tlv_label_set_text(lbl_status, \"#FFDD00 Error:# The image is not aligned to 4 MiB!\");\n\t\t\t\tgoto error;\n\t\t\t}\n\n\t\t\t// Last part. Align size to LBA (SD_BLOCKSIZE).\n\t\t\tfno.fsize = ALIGN((u64)fno.fsize, SD_BLOCKSIZE);\n\t\t\tidx--;\n\t\t}\n\t\tl4t_flash_ctxt.image_size_sct += (u64)fno.fsize >> 9;\n\n\t\tidx++;\n\t}\n\n\t// Check if image size is bigger than the partition available.\n\tif (l4t_flash_ctxt.image_size_sct > size_sct)\n\t{\n\t\tlv_label_set_text(lbl_status, \"#FFDD00 Error:# The image is bigger than the partition!\");\n\t\tgoto error;\n\t}\n\n\tchar *txt_buf = malloc(SZ_4K);\n\ts_printf(txt_buf,\n\t\t\"#C7EA46 Status:# Found installation files and partition.\\n\"\n\t\t\"#00DDFF Offset:# %08x, #00DDFF Size:# %X, #00DDFF Image size:# %d MiB\\n\"\n\t\t\"\\nDo you want to continue?\", l4t_flash_ctxt.offset_sct, size_sct, l4t_flash_ctxt.image_size_sct >> 11);\n\tlv_label_set_text(lbl_status, txt_buf);\n\tfree(txt_buf);\n\tlv_mbox_add_btns(mbox, mbox_btn_map2, _action_flash_linux_data);\n\tgoto exit;\n\nerror:\n\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);\n\nexit:\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\n\tsd_unmount();\n\tif (part_info.emmc)\n\t\temmc_end();\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _action_reboot_recovery(lv_obj_t * btns, const char * txt)\n{\n\tint btn_idx = lv_btnm_get_pressed(btns);\n\n\t// Delete parent mbox.\n\tnyx_mbox_action(btns, txt);\n\n\tif (!btn_idx)\n\t{\n\t\t// Set custom reboot type to Android Recovery.\n\t\tPMC(APBDEV_PMC_SCRATCH0) |= PMC_SCRATCH0_MODE_RECOVERY;\n\n\t\t// Enable hekate boot configuration.\n\t\tb_cfg->boot_cfg = BOOT_CFG_FROM_ID | BOOT_CFG_AUTOBOOT_EN;\n\n\t\t// Set id to Android.\n\t\tstrcpy((char *)b_cfg->id, \"SWANDR\");\n\n\t\tvoid (*main_ptr)() = (void *)nyx_str->hekate;\n\n\t\t// Deinit hardware.\n\t\tsd_end();\n\t\thw_deinit(false);\n\n\t\t// Chainload to hekate main.\n\t\t(*main_ptr)();\n\t}\n\n\treturn LV_RES_INV;\n}\n\nstatic lv_res_t _action_flash_android_data(lv_obj_t * btns, const char * txt)\n{\n\tint btn_idx = lv_btnm_get_pressed(btns);\n\tbool boot_recovery = false;\n\n\t// Delete parent mbox.\n\tnyx_mbox_action(btns, txt);\n\n\tif (btn_idx)\n\t\treturn LV_RES_INV;\n\n\t// Flash Android components.\n\tchar path[128];\n\tgpt_t *gpt = zalloc(sizeof(gpt_t));\n\tchar *txt_buf = malloc(SZ_4K);\n\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_map[] = { \"\\251\", \"\\222OK\", \"\\251\", \"\" };\n\tstatic const char *mbox_btn_map2[] = { \"\\222Continue\", \"\\222No\", \"\" };\n\tlv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);\n\n\tlv_mbox_set_text(mbox, \"#FF8000 Android Flasher#\");\n\n\tlv_obj_t *lbl_status = lv_label_create(mbox, NULL);\n\tlv_label_set_recolor(lbl_status, true);\n\tlv_label_set_text(lbl_status, \"#C7EA46 Status:# Searching for files and partitions...\");\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\tmanual_system_maintenance(true);\n\n\tsd_mount();\n\tif (part_info.emmc)\n\t\temmc_initialize(false);\n\n\t// Read main GPT.\n\tsdmmc_storage_read(part_info.storage, 1, sizeof(gpt_t) >> 9, gpt);\n\n\t// Validate GPT header.\n\tif (memcmp(&gpt->header.signature, \"EFI PART\", 8) || gpt->header.num_part_ents > 128)\n\t{\n\t\tlv_label_set_text(lbl_status, \"#FFDD00 Error:# No Android GPT was found!\");\n\t\tgoto error;\n\t}\n\n\tu32 offset_sct = 0;\n\tu32 size_sct = 0;\n\n\t// Check if Kernel image should be flashed.\n\tstrcpy(path, \"switchroot/install/boot.img\");\n\tif (f_stat(path, NULL))\n\t{\n\t\ts_printf(txt_buf, \"#FF8000 Warning:# Kernel image not found!\\n\");\n\t\tgoto boot_img_not_found;\n\t}\n\n\t// Find Kernel partition.\n\tfor (u32 i = 0; i < gpt->header.num_part_ents; i++)\n\t{\n\t\tif (!memcmp(gpt->entries[i].name, (u16[]) { 'L', 'N', 'X' },      6) ||\n\t\t\t!memcmp(gpt->entries[i].name, (u16[]) { 'b', 'o', 'o', 't' }, 8))\n\t\t{\n\t\t\toffset_sct = gpt->entries[i].lba_start;\n\t\t\tsize_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Flash Kernel.\n\tif (offset_sct && size_sct)\n\t{\n\t\tu32 file_size = 0;\n\t\tu8 *buf = sd_file_read(path, &file_size);\n\n\t\tif (file_size % 0x200)\n\t\t{\n\t\t\tfile_size = ALIGN(file_size, 0x200);\n\t\t\tu8 *buf_tmp = zalloc(file_size);\n\t\t\tmemcpy(buf_tmp, buf, file_size);\n\t\t\tfree(buf);\n\t\t\tbuf = buf_tmp;\n\t\t}\n\n\t\tif ((file_size >> 9) > size_sct)\n\t\t\ts_printf(txt_buf, \"#FF8000 Warning:# Kernel image too big!\\n\");\n\t\telse\n\t\t{\n\t\t\tsdmmc_storage_write(part_info.storage, offset_sct, file_size >> 9, buf);\n\n\t\t\ts_printf(txt_buf, \"#C7EA46 Success:# Kernel image flashed!\\n\");\n\t\t\tf_unlink(path);\n\t\t}\n\n\t\tfree(buf);\n\t}\n\telse\n\t\ts_printf(txt_buf, \"#FF8000 Warning:# Kernel partition not found!\\n\");\n\nboot_img_not_found:\n\tlv_label_set_text(lbl_status, txt_buf);\n\tmanual_system_maintenance(true);\n\n\t// Check if Recovery should be flashed.\n\tstrcpy(path, \"switchroot/install/recovery.img\");\n\tif (f_stat(path, NULL))\n\t{\n\t\t// Not found, try twrp.img instead.\n\t\tstrcpy(path, \"switchroot/install/twrp.img\");\n\t\tif (f_stat(path, NULL))\n\t\t{\n\t\t\tstrcat(txt_buf, \"#FF8000 Warning:# Recovery image not found!\\n\");\n\t\t\tgoto recovery_not_found;\n\t\t}\n\t}\n\n\toffset_sct = 0;\n\tsize_sct = 0;\n\n\t// Find Recovery partition.\n\tfor (u32 i = 0; i < gpt->header.num_part_ents; i++)\n\t{\n\t\tif (!memcmp(gpt->entries[i].name, (u16[]) { 'S', 'O', 'S' },                           6) ||\n\t\t\t!memcmp(gpt->entries[i].name, (u16[]) { 'r', 'e', 'c', 'o', 'v', 'e', 'r', 'y' }, 16))\n\t\t{\n\t\t\toffset_sct = gpt->entries[i].lba_start;\n\t\t\tsize_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Flash Recovery.\n\tif (offset_sct && size_sct)\n\t{\n\t\tu32 file_size = 0;\n\t\tu8 *buf = sd_file_read(path, &file_size);\n\n\t\tif (file_size % 0x200)\n\t\t{\n\t\t\tfile_size = ALIGN(file_size, 0x200);\n\t\t\tu8 *buf_tmp = zalloc(file_size);\n\t\t\tmemcpy(buf_tmp, buf, file_size);\n\t\t\tfree(buf);\n\t\t\tbuf = buf_tmp;\n\t\t}\n\n\t\tif ((file_size >> 9) > size_sct)\n\t\t\tstrcat(txt_buf, \"#FF8000 Warning:# Recovery image too big!\\n\");\n\t\telse\n\t\t{\n\t\t\tsdmmc_storage_write(part_info.storage, offset_sct, file_size >> 9, buf);\n\t\t\tstrcat(txt_buf, \"#C7EA46 Success:# Recovery image flashed!\\n\");\n\t\t\tf_unlink(path);\n\t\t}\n\n\t\tfree(buf);\n\t}\n\telse\n\t\tstrcat(txt_buf, \"#FF8000 Warning:# Recovery partition not found!\\n\");\n\nrecovery_not_found:\n\tlv_label_set_text(lbl_status, txt_buf);\n\tmanual_system_maintenance(true);\n\n\t// Check if Device Tree should be flashed.\n\tstrcpy(path, \"switchroot/install/nx-plat.dtimg\");\n\tif (f_stat(path, NULL))\n\t{\n\t\tstrcpy(path, \"switchroot/install/tegra210-icosa.dtb\");\n\t\tif (f_stat(path, NULL))\n\t\t{\n\t\t\tstrcat(txt_buf, \"#FF8000 Warning:# DTB image not found!\");\n\t\t\tgoto dtb_not_found;\n\t\t}\n\t}\n\n\toffset_sct = 0;\n\tsize_sct = 0;\n\n\t// Find Device Tree partition.\n\tfor (u32 i = 0; i < gpt->header.num_part_ents; i++)\n\t{\n\t\tif (!memcmp(gpt->entries[i].name, (u16[]) { 'D', 'T', 'B' }, 6) ||\n\t\t\t!memcmp(gpt->entries[i].name, (u16[]) { 'd', 't', 'b' }, 6))\n\t\t{\n\t\t\toffset_sct = gpt->entries[i].lba_start;\n\t\t\tsize_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Flash Device Tree.\n\tif (offset_sct && size_sct)\n\t{\n\t\tu32 file_size = 0;\n\t\tu8 *buf = sd_file_read(path, &file_size);\n\n\t\tif (file_size % 0x200)\n\t\t{\n\t\t\tfile_size = ALIGN(file_size, 0x200);\n\t\t\tu8 *buf_tmp = zalloc(file_size);\n\t\t\tmemcpy(buf_tmp, buf, file_size);\n\t\t\tfree(buf);\n\t\t\tbuf = buf_tmp;\n\t\t}\n\n\t\tif ((file_size >> 9) > size_sct)\n\t\t\tstrcat(txt_buf, \"#FF8000 Warning:# DTB image too big!\");\n\t\telse\n\t\t{\n\t\t\tsdmmc_storage_write(part_info.storage, offset_sct, file_size >> 9, buf);\n\t\t\tstrcat(txt_buf, \"#C7EA46 Success:# DTB image flashed!\");\n\t\t\tf_unlink(path);\n\t\t}\n\n\t\tfree(buf);\n\t}\n\telse\n\t\tstrcat(txt_buf, \"#FF8000 Warning:# DTB partition not found!\");\n\ndtb_not_found:\n\tlv_label_set_text(lbl_status, txt_buf);\n\n\t// Check if Recovery is flashed unconditionally.\n\tu8 *rec = malloc(SD_BLOCKSIZE);\n\tfor (u32 i = 0; i < gpt->header.num_part_ents; i++)\n\t{\n\t\tif (!memcmp(gpt->entries[i].name, (u16[]) { 'S', 'O', 'S' },                           6) ||\n\t\t\t!memcmp(gpt->entries[i].name, (u16[]) { 'r', 'e', 'c', 'o', 'v', 'e', 'r', 'y' }, 16))\n\t\t{\n\t\t\tsdmmc_storage_read(part_info.storage, gpt->entries[i].lba_start, 1, rec);\n\t\t\tif (!memcmp(rec, \"ANDROID\", 7))\n\t\t\t\tboot_recovery = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\tfree(rec);\n\nerror:\n\tif (boot_recovery)\n\t{\n\t\t// If a Recovery partition was found, ask user if rebooting into it is wanted.\n\t\tstrcat(txt_buf,\"\\n\\nDo you want to reboot into Recovery\\nto finish Android installation?\");\n\t\tlv_label_set_text(lbl_status, txt_buf);\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map2, _action_reboot_recovery);\n\t}\n\telse\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\n\tfree(txt_buf);\n\tfree(gpt);\n\n\tsd_unmount();\n\tif (part_info.emmc)\n\t\temmc_end();\n\n\treturn LV_RES_INV;\n}\n\nstatic lv_res_t _action_flash_android(lv_obj_t *btn)\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_map[] = { \"\\222Continue\", \"\\222Cancel\", \"\" };\n\tlv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);\n\n\tlv_mbox_set_text(mbox, \"#FF8000 Android Flasher#\");\n\n\tlv_obj_t *lbl_status = lv_label_create(mbox, NULL);\n\tlv_label_set_recolor(lbl_status, true);\n\tlv_label_set_text(lbl_status,\n\t\t\"This will flash #C7EA46 Kernel#, #C7EA46 DTB# and #C7EA46 Recovery# if found.\\n\"\n\t\t\"These will be deleted after a successful flash.\\n\"\n\t\t\"Do you want to continue?\");\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map, _action_flash_android_data);\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _action_part_manager_flash_options0(lv_obj_t *btns, const char *txt)\n{\n\tint btn_idx = lv_btnm_get_pressed(btns);\n\tif (part_info.emmc)\n\t\tbtn_idx++;\n\n\tswitch (btn_idx)\n\t{\n\tcase 0:\n\t\taction_ums_sd(NULL);\n\t\tlv_obj_del(ums_mbox);\n\t\tbreak;\n\tcase 1:\n\t\t_action_check_flash_linux(NULL);\n\t\tbreak;\n\tcase 2:\n\t\t_action_flash_android(NULL);\n\t\tbreak;\n\tcase 3:\n\t\tnyx_mbox_action(btns, txt);\n\t\treturn LV_RES_INV;\n\t}\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _action_part_manager_flash_options1(lv_obj_t *btns, const char *txt)\n{\n\tint btn_idx = lv_btnm_get_pressed(btns);\n\tif (part_info.emmc)\n\t\tbtn_idx++;\n\n\tswitch (btn_idx)\n\t{\n\tcase 0:\n\t\taction_ums_sd(NULL);\n\t\tlv_obj_del(ums_mbox);\n\t\tbreak;\n\tcase 1:\n\t\tnyx_mbox_action(btns, txt);\n\t\t_action_check_flash_linux(NULL);\n\t\treturn LV_RES_INV;\n\tcase 2:\n\t\tnyx_mbox_action(btns, txt);\n\t\treturn LV_RES_INV;\n\t}\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _action_part_manager_flash_options2(lv_obj_t *btns, const char *txt)\n{\n\tint btn_idx = lv_btnm_get_pressed(btns);\n\tif (part_info.emmc)\n\t\tbtn_idx++;\n\n\tswitch (btn_idx)\n\t{\n\tcase 0:\n\t\taction_ums_sd(NULL);\n\t\tlv_obj_del(ums_mbox);\n\t\tbreak;\n\tcase 1:\n\t\tnyx_mbox_action(btns, txt);\n\t\t_action_flash_android(NULL);\n\t\treturn LV_RES_INV;\n\tcase 2:\n\t\tnyx_mbox_action(btns, txt);\n\t\treturn LV_RES_INV;\n\t}\n\n\treturn LV_RES_OK;\n}\n\nstatic int _backup_and_restore_files(bool backup, lv_obj_t **labels)\n{\n\tconst char *src_drv = backup ? \"sd:\"  : \"ram:\";\n\tconst char *dst_drv = backup ? \"ram:\" : \"sd:\";\n\n\tint res = 0;\n\tu32 total_size = 0;\n\tu32 total_files = 0;\n\tchar *path = malloc(0x1000);\n\tpath[0] = 0; // Set default as root folder.\n\n\t// Check if Mariko Warmboot Storage exists in source drive.\n\tf_chdrive(src_drv);\n\tbool backup_pld = !part_info.backup_possible && !f_stat(\"payload.bin\", NULL);\n\n\tif (!part_info.backup_possible)\n\t{\n\t\t// Change path to hekate/Nyx.\n\t\tstrcpy(path, \"bootloader\");\n\n\t\t// Create hekate/Nyx/MWS folders in destination drive.\n\t\tf_chdrive(dst_drv);\n\t\tf_mkdir(\"bootloader\");\n\t}\n\n\t// Copy all or hekate/Nyx files.\n\tres = _stat_and_copy_files(src_drv, dst_drv, path, &total_files, &total_size, labels);\n\n\t// If incomplete backup mode, copy MWS and payload.bin also.\n\tif (!res)\n\t{\n\t\tif (!res && backup_pld)\n\t\t{\n\t\t\tstrcpy(path, \"payload.bin\");\n\t\t\tres = _copy_file(src_drv, dst_drv, path);\n\t\t}\n\t}\n\n\tfree(path);\n\n\treturn res;\n}\n\nstatic lv_res_t _sd_create_mbox_start_partitioning()\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_map[] =  { \"\\251\", \"\\222OK\", \"\\251\", \"\" };\n\tstatic const char *mbox_btn_map1[] = { \"\\222SD UMS\", \"\\222Flash Linux\", \"\\222Flash Android\", \"\\221OK\", \"\" };\n\tstatic const char *mbox_btn_map2[] = { \"\\222SD UMS\", \"\\222Flash Linux\", \"\\221OK\", \"\" };\n\tstatic const char *mbox_btn_map3[] = { \"\\222SD UMS\", \"\\222Flash Android\", \"\\221OK\", \"\" };\n\tlv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);\n\n\tlv_mbox_set_text(mbox, \"#FF8000 SD Partition Manager#\");\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\tbool buttons_set = false;\n\n\t// Use safety wait if backup is not possible.\n\tchar *txt_buf = malloc(SZ_4K);\n\tstrcpy(txt_buf, \"#FF8000 SD Partition Manager#\\n\\nSafety wait ends in \");\n\tlv_mbox_set_text(mbox, txt_buf);\n\n\tu32 seconds = 5;\n\tu32 text_idx = strlen(txt_buf);\n\twhile (seconds)\n\t{\n\t\ts_printf(txt_buf + text_idx, \"%d seconds...\", seconds);\n\t\tlv_mbox_set_text(mbox, txt_buf);\n\t\tmanual_system_maintenance(true);\n\t\tmsleep(1000);\n\t\tseconds--;\n\t}\n\n\tlv_mbox_set_text(mbox,\n\t\t\"#FF8000 SD Partition Manager#\\n\\n\"\n\t\t\"#FFDD00 Warning: Do you really want to continue?!#\\n\\n\"\n\t\t\"Press #FF8000 POWER# to Continue.\\nPress #FF8000 VOL# to abort.\");\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tmanual_system_maintenance(true);\n\n\tfree(txt_buf);\n\n\tif (!(btn_wait() & BTN_POWER))\n\t\tgoto exit;\n\n\t// Start partitioning.\n\tlv_mbox_set_text(mbox, \"#FF8000 SD Partition Manager#\");\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tmanual_system_maintenance(true);\n\n\tlv_obj_t *lbl_status = lv_label_create(mbox, NULL);\n\tlv_label_set_recolor(lbl_status, true);\n\n\tlv_obj_t *lbl_paths[2];\n\n\t// Create backup/restore paths labels.\n\tlbl_paths[0] = lv_label_create(mbox, NULL);\n\tlv_label_set_text(lbl_paths[0], \"/\");\n\tlv_label_set_long_mode(lbl_paths[0], LV_LABEL_LONG_DOT);\n\tlv_cont_set_fit(lbl_paths[0], false, true);\n\tlv_obj_set_width(lbl_paths[0], (LV_HOR_RES / 9 * 6) - LV_DPI / 2);\n\tlv_label_set_align(lbl_paths[0], LV_LABEL_ALIGN_CENTER);\n\tlbl_paths[1] = lv_label_create(mbox, NULL);\n\tlv_label_set_text(lbl_paths[1], \" \");\n\tlv_label_set_long_mode(lbl_paths[1], LV_LABEL_LONG_DOT);\n\tlv_cont_set_fit(lbl_paths[1], false, true);\n\tlv_obj_set_width(lbl_paths[1], (LV_HOR_RES / 9 * 6) - LV_DPI / 2);\n\tlv_label_set_align(lbl_paths[1], LV_LABEL_ALIGN_CENTER);\n\n\tsd_mount();\n\n\tFATFS ram_fs;\n\n\t// Read current MBR.\n\tsdmmc_storage_read(part_info.storage, 0, 1, &part_info.mbr_old);\n\n\tlv_label_set_text(lbl_status, \"#00DDFF Status:# Initializing Ramdisk...\");\n\tlv_label_set_text(lbl_paths[0], \"Please wait...\");\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tmanual_system_maintenance(true);\n\n\t// Initialize RAM disk.\n\tif (ram_disk_init(&ram_fs, RAM_DISK_SZ))\n\t{\n\t\tlv_label_set_text(lbl_status, \"#FFDD00 Error:# Failed to initialize Ramdisk!\");\n\t\tgoto error;\n\t}\n\n\tlv_label_set_text(lbl_status, \"#00DDFF Status:# Backing up files...\");\n\tmanual_system_maintenance(true);\n\n\t// Do full or hekate/Nyx backup.\n\tif (_backup_and_restore_files(true, lbl_paths))\n\t{\n\t\tif (part_info.backup_possible)\n\t\t\tlv_label_set_text(lbl_status, \"#FFDD00 Error:# Failed to back up files!\");\n\t\telse\n\t\t\tlv_label_set_text(lbl_status, \"#FFDD00 Error:# Failed to back up files!\\nBootloader folder exceeds 1.2GB or corrupt!\");\n\n\t\tgoto error;\n\t}\n\n\tf_unmount(\"sd:\"); // Unmount SD card.\n\n\tlv_label_set_text(lbl_status, \"#00DDFF Status:# Formatting FAT32 partition...\");\n\tlv_label_set_text(lbl_paths[0], \"Please wait...\");\n\tlv_label_set_text(lbl_paths[1], \" \");\n\tmanual_system_maintenance(true);\n\n\t// Set reserved size.\n\tu32 part_rsvd_size = (part_info.emu_size << 11) + (part_info.l4t_size << 11) + (part_info.and_size << 11);\n\tpart_rsvd_size += part_rsvd_size ? part_info.alignment : 0; // Do not reserve alignment space if no extra partitions.\n\tdisk_set_info(DRIVE_SD, SET_SECTOR_COUNT, &part_rsvd_size);\n\tu8 *buf = malloc(SZ_4M);\n\n\t// Set cluster size to 64KB and try to format.\n\tu32 cluster_size = 65536;\n\tu32 mkfs_error = f_mkfs(\"sd:\", FM_FAT32, cluster_size, buf, SZ_4M);\n\n\tif (!mkfs_error)\n\t\tgoto mkfs_no_error;\n\n\t// Retry formatting by halving cluster size, until one succeeds.\n\twhile (cluster_size > 4096)\n\t{\n\t\tcluster_size /= 2;\n\t\tmkfs_error = f_mkfs(\"sd:\", FM_FAT32, cluster_size, buf, SZ_4M);\n\n\t\tif (!mkfs_error)\n\t\t\tbreak;\n\t}\n\n\tif (mkfs_error)\n\t{\n\t\t// Failed to format.\n\t\ts_printf((char *)buf, \"#FFDD00 Error:# Failed to format disk (%d)!\\n\\n\"\n\t\t\t\"Remove the SD card and check that is OK.\\nIf not, format it, reinsert it and\\npress #FF8000 POWER#!\", mkfs_error);\n\n\t\tlv_label_set_text(lbl_status, (char *)buf);\n\t\tlv_label_set_text(lbl_paths[0], \" \");\n\t\tmanual_system_maintenance(true);\n\n\t\tsd_end();\n\n\t\twhile (!(btn_wait() & BTN_POWER));\n\n\t\tsd_mount();\n\n\t\tlv_label_set_text(lbl_status, \"#00DDFF Status:# Restoring files...\");\n\t\tmanual_system_maintenance(true);\n\n\t\t// Restore backed up files back to SD.\n\t\tif (_backup_and_restore_files(false, lbl_paths))\n\t\t{\n\t\t\t// Failed to restore files. Try again once more.\n\t\t\tif (_backup_and_restore_files(false, lbl_paths))\n\t\t\t{\n\t\t\t\tlv_label_set_text(lbl_status, \"#FFDD00 Error:# Failed to restore files!\");\n\t\t\t\tfree(buf);\n\t\t\t\tgoto error;\n\t\t\t}\n\t\t}\n\n\t\tlv_label_set_text(lbl_status, \"#00DDFF Status:# Restored files but the operation failed!\");\n\t\tf_unmount(\"ram:\");\n\t\tfree(buf);\n\t\tgoto error;\n\t}\n\nmkfs_no_error:\n\tfree(buf);\n\n\t// Remount sd card as it was unmounted from formatting it.\n\tf_mount(&sd_fs, \"sd:\", 1); // Mount SD card.\n\n\tlv_label_set_text(lbl_status, \"#00DDFF Status:# Restoring files...\");\n\tmanual_system_maintenance(true);\n\n\t// Restore backed up files back to SD.\n\tif (_backup_and_restore_files(false, lbl_paths))\n\t{\n\t\t// Failed to restore files. Try again once more.\n\t\tif (_backup_and_restore_files(false, lbl_paths))\n\t\t{\n\t\t\tlv_label_set_text(lbl_status, \"#FFDD00 Error:# Failed to restore files!\");\n\t\t\tgoto error;\n\t\t}\n\t}\n\n\t // Unmount ramdisk.\n\tf_unmount(\"ram:\");\n\tf_chdrive(\"sd:\");\n\n\t// Set Volume label.\n\tf_setlabel(\"0:SWITCH SD\");\n\n\tlv_label_set_text(lbl_status, \"#00DDFF Status:# Flashing partition table...\");\n\tlv_label_set_text(lbl_paths[0], \"Please wait...\");\n\tlv_label_set_text(lbl_paths[1], \" \");\n\tmanual_system_maintenance(true);\n\n\t// Prepare MBR and GPT header and partition entries and flash them.\n\t_sd_prepare_and_flash_mbr_gpt();\n\n\t// Enable/Disable buttons depending on partition layout.\n\tif (part_info.l4t_size)\n\t{\n\t\tlv_obj_set_click(btn_flash_l4t, true);\n\t\tlv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_REL);\n\t}\n\telse\n\t{\n\t\tlv_obj_set_click(btn_flash_l4t, false);\n\t\tlv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_INA);\n\t}\n\n\t// Enable/Disable buttons depending on partition layout.\n\tif (part_info.and_size)\n\t{\n\t\tlv_obj_set_click(btn_flash_android, true);\n\t\tlv_btn_set_state(btn_flash_android, LV_BTN_STATE_REL);\n\t}\n\telse\n\t{\n\t\tlv_obj_set_click(btn_flash_android, false);\n\t\tlv_btn_set_state(btn_flash_android, LV_BTN_STATE_INA);\n\t}\n\n\tsd_unmount();\n\tlv_label_set_text(lbl_status, \"#00DDFF Status:# Done!\");\n\tmanual_system_maintenance(true);\n\n\t// Set buttons depending on what user chose to create.\n\tif (part_info.l4t_size && part_info.and_size)\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map1, _action_part_manager_flash_options0);\n\telse if (part_info.l4t_size)\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map2, _action_part_manager_flash_options1);\n\telse if (part_info.and_size)\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map3, _action_part_manager_flash_options2);\n\n\tif (part_info.l4t_size || part_info.and_size)\n\t\tbuttons_set = true;\n\n\tgoto out;\n\nerror:\n\tf_chdrive(\"sd:\");\n\nout:\n\tlv_obj_del(lbl_paths[0]);\n\tlv_obj_del(lbl_paths[1]);\nexit:\n\tif (!buttons_set)\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\t// Disable partitioning button.\n\tif (part_info.partition_button)\n\t\tlv_btn_set_state(part_info.partition_button, LV_BTN_STATE_INA);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _emmc_create_mbox_start_partitioning()\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_map[] =  { \"\\251\", \"\\222OK\", \"\\251\", \"\" };\n\tstatic const char *mbox_btn_map1[] = { \"\\222Flash Linux\", \"\\222Flash Android\", \"\\221OK\", \"\" };\n\tstatic const char *mbox_btn_map2[] = { \"\\222Flash Linux\", \"\\221OK\", \"\" };\n\tstatic const char *mbox_btn_map3[] = { \"\\222Flash Android\", \"\\221OK\", \"\" };\n\tlv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);\n\n\tlv_mbox_set_text(mbox, \"#FF8000 eMMC Partition Manager#\");\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\tbool buttons_set = false;\n\n\t// Use safety wait if backup is not possible.\n\tchar *txt_buf = malloc(SZ_4K);\n\tstrcpy(txt_buf, \"#FF8000 eMMC Partition Manager#\\n\\nSafety wait ends in \");\n\tlv_mbox_set_text(mbox, txt_buf);\n\n\tu32 seconds = 5;\n\tu32 text_idx = strlen(txt_buf);\n\twhile (seconds)\n\t{\n\t\ts_printf(txt_buf + text_idx, \"%d seconds...\", seconds);\n\t\tlv_mbox_set_text(mbox, txt_buf);\n\t\tmanual_system_maintenance(true);\n\t\tmsleep(1000);\n\t\tseconds--;\n\t}\n\n\tlv_mbox_set_text(mbox,\n\t\t\"#FF8000 eMMC Partition Manager#\\n\\n\"\n\t\t\"#FFDD00 Warning: Do you really want to continue?!#\\n\\n\"\n\t\t\"Press #FF8000 POWER# to Continue.\\nPress #FF8000 VOL# to abort.\");\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tmanual_system_maintenance(true);\n\n\tif (!(btn_wait() & BTN_POWER))\n\t\tgoto exit;\n\n\t// Start partitioning.\n\tlv_mbox_set_text(mbox, \"#FF8000 eMMC Partition Manager#\");\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tmanual_system_maintenance(true);\n\n\tlv_obj_t *lbl_status = lv_label_create(mbox, NULL);\n\tlv_label_set_recolor(lbl_status, true);\n\n\tlv_obj_t *lbl_extra = lv_label_create(mbox, NULL);\n\tlv_label_set_long_mode(lbl_extra, LV_LABEL_LONG_DOT);\n\tlv_cont_set_fit(lbl_extra, false, true);\n\tlv_obj_set_width(lbl_extra, (LV_HOR_RES / 9 * 6) - LV_DPI / 2);\n\tlv_label_set_align(lbl_extra, LV_LABEL_ALIGN_CENTER);\n\n\tlv_label_set_text(lbl_status, \"#00DDFF Status:# Initializing...\");\n\tlv_label_set_text(lbl_extra, \"Please wait...\");\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tmanual_system_maintenance(true);\n\n\tif (emmc_initialize(false))\n\t{\n\t\tlv_label_set_text(lbl_extra, \"#FFDD00 Failed to init eMMC!#\");\n\t\tgoto exit;\n\t}\n\n\temmc_set_partition(EMMC_GPP);\n\n\tif (!emummc_raw_derive_bis_keys())\n\t{\n\t\tlv_label_set_text(lbl_extra, \"#FFDD00 For formatting USER partition,#\\n#FFDD00 BIS keys are needed!#\");\n\t\temmc_end();\n\t\tgoto exit;\n\t}\n\n\tlv_label_set_text(lbl_status, \"#00DDFF Status:# Flashing partition table...\");\n\tlv_label_set_text(lbl_extra, \"Please wait...\");\n\tmanual_system_maintenance(true);\n\n\t// Prepare MBR and GPT header and partition entries and flash them.\n\tif (_emmc_prepare_and_flash_mbr_gpt())\n\t\tgoto no_hos_user_part;\n\n\tlv_label_set_text(lbl_status, \"#00DDFF Status:# Formatting USER partition...\");\n\tlv_label_set_text(lbl_extra, \"Please wait...\");\n\tmanual_system_maintenance(true);\n\n\t// Get USER partition and configure BIS and FatFS.\n\tLIST_INIT(gpt);\n\temmc_gpt_parse(&gpt);\n\temmc_part_t *user_part = emmc_part_find(&gpt, \"USER\");\n\n\tif (!user_part)\n\t{\nno_hos_user_part:\n\t\ts_printf(txt_buf, \"#FF0000 HOS USER partition doesn't exist!#\\nRestore HOS backup first...\");\n\t\tlv_label_set_text(lbl_extra, txt_buf);\n\n\t\temmc_gpt_free(&gpt);\n\t\temmc_end();\n\n\t\tgoto exit;\n\t}\n\n\t// Initialize BIS for eMMC. BIS keys should be already in place.\n\tnx_emmc_bis_init(user_part, true, 0);\n\n\t// Set BIS size for FatFS.\n\tu32 user_sectors = user_part->lba_end - user_part->lba_start + 1;\n\tdisk_set_info(DRIVE_BIS, SET_SECTOR_COUNT,  &user_sectors);\n\n\t// Enable writing.\n\tbool allow_writes = true;\n\tdisk_set_info(DRIVE_BIS, SET_WRITE_PROTECT, &allow_writes);\n\n\t// Format USER partition as FAT32 with 16KB cluster and PRF2SAFE.\n\tu8 *buff = malloc(SZ_4M);\n\tint mkfs_error = f_mkfs(\"bis:\", FM_FAT32 | FM_SFD | FM_PRF2, 16384, buff, SZ_4M);\n\n\tif (mkfs_error)\n\t{\n\t\ts_printf(txt_buf, \"#FF0000 Failed (%d)!#\\nPlease try again...\\n\", mkfs_error);\n\t\tlv_label_set_text(lbl_extra, txt_buf);\n\n\t\tfree(buff);\n\t\temmc_end();\n\n\t\tgoto exit;\n\t}\n\n\t// Disable writes to BIS.\n\tallow_writes = false;\n\tdisk_set_info(DRIVE_BIS, SET_WRITE_PROTECT, &allow_writes);\n\n\t// Flush BIS cache, deinit, clear BIS keys slots and reinstate SBK.\n\tnx_emmc_bis_end();\n\thos_bis_keys_clear();\n\temmc_gpt_free(&gpt);\n\temmc_end();\n\n\t// Enable/Disable buttons depending on partition layout.\n\tif (part_info.l4t_size)\n\t{\n\t\tlv_obj_set_click(btn_flash_l4t, true);\n\t\tlv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_REL);\n\t}\n\telse\n\t{\n\t\tlv_obj_set_click(btn_flash_l4t, false);\n\t\tlv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_INA);\n\t}\n\n\t// Enable/Disable buttons depending on partition layout.\n\tif (part_info.and_size)\n\t{\n\t\tlv_obj_set_click(btn_flash_android, true);\n\t\tlv_btn_set_state(btn_flash_android, LV_BTN_STATE_REL);\n\t}\n\telse\n\t{\n\t\tlv_obj_set_click(btn_flash_android, false);\n\t\tlv_btn_set_state(btn_flash_android, LV_BTN_STATE_INA);\n\t}\n\n\tlv_label_set_text(lbl_status, \"#00DDFF Status:# Done!\");\n\tmanual_system_maintenance(true);\n\n\t// Set buttons depending on what user chose to create.\n\tif (part_info.l4t_size && part_info.and_size)\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map1, _action_part_manager_flash_options0);\n\telse if (part_info.l4t_size)\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map2, _action_part_manager_flash_options1);\n\telse if (part_info.and_size)\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map3, _action_part_manager_flash_options2);\n\n\tif (part_info.l4t_size || part_info.and_size)\n\t\tbuttons_set = true;\n\n\tlv_obj_del(lbl_extra);\n\nexit:\n\tfree(txt_buf);\n\n\tif (!buttons_set)\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\t// Disable partitioning button.\n\tif (part_info.partition_button)\n\t\tlv_btn_set_state(part_info.partition_button, LV_BTN_STATE_INA);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _create_mbox_partitioning_option0(lv_obj_t *btns, const char *txt)\n{\n\tint btn_idx = lv_btnm_get_pressed(btns);\n\n\tswitch (btn_idx)\n\t{\n\tcase 0:\n\t\taction_ums_sd(NULL);\n\t\treturn LV_RES_OK;\n\tcase 1:\n\t\tnyx_mbox_action(btns, txt);\n\t\t_sd_create_mbox_start_partitioning();\n\t\tbreak;\n\tcase 2:\n\t\tnyx_mbox_action(btns, txt);\n\t\tbreak;\n\t}\n\n\treturn LV_RES_INV;\n}\n\nstatic lv_res_t _create_mbox_partitioning_option1(lv_obj_t *btns, const char *txt)\n{\n\tint btn_idx = lv_btnm_get_pressed(btns);\n\n\tnyx_mbox_action(btns, txt);\n\n\tif (!btn_idx)\n\t{\n\t\tif (!part_info.emmc)\n\t\t\t_sd_create_mbox_start_partitioning();\n\t\telse\n\t\t\t_emmc_create_mbox_start_partitioning();\n\t\treturn LV_RES_INV;\n\t}\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _create_mbox_partitioning_warn()\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_map[] = { \"\\222SD UMS\", \"\\222Start\", \"\\222Cancel\", \"\" };\n\tstatic const char *mbox_btn_map1[] = { \"\\222Start\", \"\\222Cancel\", \"\" };\n\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\n\tchar *txt_buf = malloc(SZ_4K);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);\n\tlv_mbox_set_text(mbox, \"#FF8000 Partition Manager#\");\n\n\tlv_obj_t *lbl_status = lv_label_create(mbox, NULL);\n\tlv_label_set_recolor(lbl_status, true);\n\n\tif (!part_info.emmc)\n\t{\n\t\ts_printf(txt_buf, \"#FFDD00 Warning: This will partition the SD Card!#\\n\\n\");\n\n\t\tif (part_info.backup_possible)\n\t\t{\n\t\t\tstrcat(txt_buf, \"#C7EA46 Your files will be backed up and restored!#\\n\"\n\t\t\t\t\"#FFDD00 Any other partition will be wiped!#\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstrcat(txt_buf, \"#FFDD00 Your files will be wiped!#\\n\"\n\t\t\t\t\"#FFDD00 Any other partition will be also wiped!#\\n\"\n\t\t\t\t\"#FFDD00 Use USB UMS to copy them over!#\");\n\t\t}\n\n\t\tlv_label_set_text(lbl_status, txt_buf);\n\n\t\tif (part_info.backup_possible)\n\t\t\tlv_mbox_add_btns(mbox, mbox_btn_map1, _create_mbox_partitioning_option1);\n\t\telse\n\t\t\tlv_mbox_add_btns(mbox, mbox_btn_map, _create_mbox_partitioning_option0);\n\t}\n\telse\n\t{\n\t\ts_printf(txt_buf, \"#FFDD00 Warning: This will partition the eMMC!#\\n\\n\"\n\t\t\t\t\t\t  \"#FFDD00 The USER partition will also be formatted!#\");\n\t\tlv_label_set_text(lbl_status, txt_buf);\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map1, _create_mbox_partitioning_option1);\n\t}\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\tfree(txt_buf);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _create_mbox_partitioning_android(lv_obj_t *btns, const char *txt)\n{\n\tpart_info.and_dynamic = lv_btnm_get_pressed(btns);\n\n\tnyx_mbox_action(btns, txt);\n\n\t_create_mbox_partitioning_warn();\n\n\treturn LV_RES_INV;\n}\n\nstatic lv_res_t _create_mbox_partitioning_andr_part()\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_map[] = { \"\\222Legacy\", \"\\222Dynamic\", \"\" };\n\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\n\tlv_obj_set_width(mbox, LV_HOR_RES / 10 * 5);\n\tlv_mbox_set_text(mbox, \"#FF8000 Android Partitioning#\");\n\n\tlv_obj_t *lbl_status = lv_label_create(mbox, NULL);\n\tlv_label_set_recolor(lbl_status, true);\n\n\tlv_label_set_text(lbl_status,\n\t\t\"Please select a partition scheme:\\n\\n\"\n\t\t\"#C7EA46 Dynamic:# Android 13+ (Preferred)\\n\"\n\t\t\"#C7EA46 Legacy:# Android 11\\n\");\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map, _create_mbox_partitioning_android);\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _create_mbox_partitioning_next(lv_obj_t *btn) {\n\tif (part_info.and_size)\n\t\treturn _create_mbox_partitioning_andr_part();\n\telse\n\t\treturn _create_mbox_partitioning_warn();\n}\n\nstatic void _update_partition_bar()\n{\n\tlv_obj_t *h1 = lv_obj_get_parent(part_info.bar_hos);\n\n\t// Set widths based on max bar width.\n\tu32 total_size = (part_info.total_sct - AU_ALIGN_SECTORS) / SECTORS_PER_GB;\n\tu32 bar_hos_size = lv_obj_get_width(h1) * (part_info.hos_size >> 10) / total_size;\n\tu32 bar_emu_size = lv_obj_get_width(h1) * (part_info.emu_size >> 10) / total_size;\n\tu32 bar_l4t_size = lv_obj_get_width(h1) * (part_info.l4t_size >> 10) / total_size;\n\tu32 bar_and_size = lv_obj_get_width(h1) * (part_info.and_size >> 10) / total_size;\n\n\t// Update bar widths.\n\tlv_obj_set_width(part_info.bar_hos, bar_hos_size);\n\tlv_obj_set_width(part_info.bar_emu, bar_emu_size);\n\tlv_obj_set_width(part_info.bar_l4t, bar_l4t_size);\n\tlv_obj_set_width(part_info.bar_and, bar_and_size);\n\n\t// Re-align bars.\n\tlv_obj_realign(part_info.bar_emu);\n\tlv_obj_realign(part_info.bar_l4t);\n\tlv_obj_realign(part_info.bar_and);\n\n\t// Set emuMMC blending separator sizes and realign.\n\tlv_obj_set_width(part_info.sep_emu, bar_emu_size ? 8 : 0);\n\tlv_obj_realign(part_info.sep_emu);\n\n\t// Set L4T blending separator sizes and realign.\n\tlv_obj_set_width(part_info.sep_l4t, bar_l4t_size ? 8 : 0);\n\tlv_obj_realign(part_info.sep_l4t);\n\n\t// Set Android blending separator sizes and realign.\n\tlv_obj_set_width(part_info.sep_and, bar_and_size ? 8 : 0);\n\tlv_obj_realign(part_info.sep_and);\n\n\t// Re-align size labels.\n\tlv_obj_realign(part_info.lbl_hos);\n\tlv_obj_realign(part_info.lbl_emu);\n\tlv_obj_realign(part_info.lbl_l4t);\n\tlv_obj_realign(part_info.lbl_and);\n\tlv_obj_align(part_info.cont_lbl, part_info.bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI * 11 - LV_DPI / 2, LV_DPI * 9 / 23);\n}\n\nstatic lv_res_t _action_slider_emu(lv_obj_t *slider)\n{\n\tu32 size;\n\tchar lbl_text[64];\n\tbool prev_emu_double = part_info.emu_double;\n\tint slide_val = lv_slider_get_value(slider);\n\tu32 max_emmc_size = !part_info.emmc_is_64gb ? EMU_32GB_FULL : EMU_64GB_FULL;\n\n\tpart_info.emu_double = false;\n\n\t// Check that eMMC exists.\n\tif (!part_info.emmc_size_mb)\n\t{\n\t\tlv_slider_set_value(slider, 0);\n\t\treturn LV_RES_OK;\n\t}\n\n\t// In case of upgraded eMMC, do not allow FULL sizes. Max size is always bigger than official eMMCs.\n\tif (max_emmc_size < part_info.emmc_size_mb)\n\t{\n\t\tif (slide_val == EMU_SLIDER_1X_FULL)\n\t\t{\n\t\t\tif (prev_emu_double)\n\t\t\t\tslide_val--;\n\t\t\telse\n\t\t\t\tslide_val++;\n\t\t\tlv_slider_set_value(slider, slide_val);\n\t\t}\n\t\telse if (slide_val == EMU_SLIDER_2X_FULL)\n\t\t{\n\t\t\tslide_val--;\n\t\t\tlv_slider_set_value(slider, slide_val);\n\t\t}\n\t}\n\n\tsize  = (slide_val > EMU_SLIDER_1X_MAX ? (slide_val - EMU_SLIDER_1X_MAX) : slide_val) + EMU_SLIDER_OFFSET;\n\tsize *= 1024;        // Convert to GB.\n\tsize += EMU_RSVD_MB; // Add reserved size.\n\n\tif (slide_val == EMU_SLIDER_MIN)\n\t\tsize = 0; // Reset if 0.\n\telse if (slide_val >= EMU_SLIDER_2X_MIN)\n\t{\n\t\tsize *= 2;\n\t\tpart_info.emu_double = true;\n\t}\n\n\t// Handle special cases. 2nd value is for 64GB Aula. Values already include reserved space.\n\tif (slide_val == EMU_SLIDER_1X_FULL)\n\t\tsize = max_emmc_size;\n\telse if (slide_val == EMU_SLIDER_2X_FULL)\n\t\tsize = 2 * max_emmc_size;\n\n\t// Sanitize sizes based on new HOS size.\n\ts32 hos_size = (part_info.total_sct >> 11) - 16 - size - part_info.l4t_size - part_info.and_size;\n\tif (hos_size > part_info.hos_min_size)\n\t{\n\t\tpart_info.emu_size = size;\n\t\tpart_info.hos_size = hos_size;\n\n\t\ts_printf(lbl_text, \"#96FF00 %4d GiB#\", hos_size >> 10);\n\t\tlv_label_set_text(part_info.lbl_hos, lbl_text);\n\t\tlv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10);\n\n\t\tif (!part_info.emu_double)\n\t\t{\n\t\t\tif (slide_val != EMU_SLIDER_1X_FULL)\n\t\t\t\ts_printf(lbl_text, \"#FF3C28 %4d GiB#\", size >> 10);\n\t\t\telse\n\t\t\t\ts_printf(lbl_text, \"#FF3C28 %d FULL#\", size >> 10);\n\t\t}\n\t\telse\n\t\t\ts_printf(lbl_text, \"#FFDD00 2x##FF3C28 %d GiB#\", size >> 11);\n\t\tlv_label_set_text(part_info.lbl_emu, lbl_text);\n\t}\n\telse\n\t{\n\t\tu32 emu_size = part_info.emu_size;\n\n\t\tif (emu_size == max_emmc_size)\n\t\t\temu_size = EMU_SLIDER_1X_FULL;\n\t\telse if (emu_size == 2 * max_emmc_size)\n\t\t\temu_size = EMU_SLIDER_2X_FULL;\n\t\telse if (emu_size)\n\t\t{\n\t\t\tif (prev_emu_double)\n\t\t\t\temu_size /= 2;\n\t\t\temu_size -= EMU_RSVD_MB;\n\t\t\temu_size /= 1024;\n\t\t\temu_size -= EMU_SLIDER_OFFSET;\n\n\t\t\tif (prev_emu_double)\n\t\t\t\temu_size += EMU_SLIDER_2X_MIN;\n\t\t}\n\n\t\tint new_slider_val = emu_size;\n\t\tpart_info.emu_double = prev_emu_double ? true : false;\n\n\t\tlv_slider_set_value(slider, new_slider_val);\n\t}\n\n\t_update_partition_bar();\n\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _action_slider_l4t(lv_obj_t *slider)\n{\n\tchar lbl_text[64];\n\n\tu32 size = (u32)lv_slider_get_value(slider) << 10;\n\tif (size < 4096)\n\t\tsize = 0;\n\telse if (size < 8192)\n\t\tsize = 8192;\n\n\ts32 hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - size - part_info.and_size;\n\n\t// Sanitize sizes based on new HOS size.\n\tif (hos_size > part_info.hos_min_size)\n\t{\n\t\tif (size <= 8192)\n\t\t\tlv_slider_set_value(slider, size >> 10);\n\t}\n\telse\n\t{\n\t\tsize = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.and_size - 2048;\n\t\thos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.and_size - size;\n\t\tif (hos_size < part_info.hos_min_size || size < 8192)\n\t\t{\n\t\t\tlv_slider_set_value(slider, part_info.l4t_size >> 10);\n\t\t\tgoto out;\n\t\t}\n\t\tlv_slider_set_value(slider, size >> 10);\n\t}\n\n\tpart_info.l4t_size = size;\n\tpart_info.hos_size = hos_size;\n\n\ts_printf(lbl_text, \"#96FF00 %4d GiB#\", hos_size >> 10);\n\tlv_label_set_text(part_info.lbl_hos, lbl_text);\n\tlv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10);\n\ts_printf(lbl_text, \"#00DDFF %4d GiB#\", size >> 10);\n\tlv_label_set_text(part_info.lbl_l4t, lbl_text);\n\n\t_update_partition_bar();\n\nout:\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _action_slider_and(lv_obj_t *slider)\n{\n\tchar lbl_text[64];\n\n\tu32 user_size = (u32)lv_slider_get_value(slider) << 10;\n\tif (user_size < 2048)\n\t\tuser_size = 0;\n\telse if (user_size < 4096)\n\t\tuser_size = 4096;\n\n\tu32 and_size = user_size ? (user_size + AND_SYS_SIZE_MB) : 0;\n\ts32 hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - and_size;\n\n\t// Sanitize sizes based on new HOS size.\n\tif (hos_size > part_info.hos_min_size)\n\t{\n\t\tif (user_size <= 4096)\n\t\t\tlv_slider_set_value(slider, user_size >> 10);\n\t}\n\telse\n\t{\n\t\tand_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - 2048;\n\t\thos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - and_size;\n\t\tif (hos_size < part_info.hos_min_size || and_size < 8192)\n\t\t{\n\t\t\tlv_slider_set_value(slider, part_info.and_size >> 10);\n\t\t\tgoto out;\n\t\t}\n\t\tuser_size = and_size - AND_SYS_SIZE_MB;\n\t\tlv_slider_set_value(slider, user_size >> 10);\n\t}\n\n\tpart_info.and_size = and_size;\n\tpart_info.hos_size = hos_size;\n\n\ts_printf(lbl_text, \"#96FF00 %4d GiB#\", hos_size >> 10);\n\tlv_label_set_text(part_info.lbl_hos, lbl_text);\n\tlv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10);\n\ts_printf(lbl_text, \"#FF8000 %4d GiB#\", user_size >> 10);\n\tlv_label_set_text(part_info.lbl_and, lbl_text);\n\n\t_update_partition_bar();\n\nout:\n\treturn LV_RES_OK;\n}\n\nstatic lv_res_t _mbox_check_files_total_size_option(lv_obj_t *btns, const char *txt)\n{\n\t// If \"don't backup\" button was pressed, disable backup/restore of files.\n\tif (!lv_btnm_get_pressed(btns))\n\t\tpart_info.backup_possible = false;\n\n\tnyx_mbox_action(btns, txt);\n\n\treturn LV_RES_INV;\n}\n\nstatic void _create_mbox_check_files_total_size()\n{\n\tstatic lv_style_t bar_hos_ind, bar_emu_ind, bar_l4t_ind, bar_and_ind;\n\tstatic lv_style_t sep_emu_bg, sep_l4t_bg, sep_and_bg;\n\n\t// Set HOS bar style.\n\tlv_style_copy(&bar_hos_ind, lv_theme_get_current()->bar.indic);\n\tbar_hos_ind.body.main_color = LV_COLOR_HEX(0x96FF00);\n\tbar_hos_ind.body.grad_color = bar_hos_ind.body.main_color;\n\n\t// Set emuMMC bar style.\n\tlv_style_copy(&bar_emu_ind, lv_theme_get_current()->bar.indic);\n\tbar_emu_ind.body.main_color = LV_COLOR_HEX(0xFF3C28);\n\tbar_emu_ind.body.grad_color = bar_emu_ind.body.main_color;\n\n\t// Set L4T bar style.\n\tlv_style_copy(&bar_l4t_ind, lv_theme_get_current()->bar.indic);\n\tbar_l4t_ind.body.main_color = LV_COLOR_HEX(0x00DDFF);\n\tbar_l4t_ind.body.grad_color = bar_l4t_ind.body.main_color;\n\n\t// Set GPT bar style.\n\tlv_style_copy(&bar_and_ind, lv_theme_get_current()->bar.indic);\n\tbar_and_ind.body.main_color = LV_COLOR_HEX(0xC000FF);\n\tbar_and_ind.body.grad_color = bar_and_ind.body.main_color;\n\n\t// Set separator styles.\n\tlv_style_copy(&sep_emu_bg, lv_theme_get_current()->cont);\n\tsep_emu_bg.body.main_color = LV_COLOR_HEX(0xFF3C28);\n\tsep_emu_bg.body.grad_color = sep_emu_bg.body.main_color;\n\tsep_emu_bg.body.radius = 0;\n\tlv_style_copy(&sep_l4t_bg, &sep_emu_bg);\n\tsep_l4t_bg.body.main_color = LV_COLOR_HEX(0x00DDFF);\n\tsep_l4t_bg.body.grad_color = sep_l4t_bg.body.main_color;\n\tlv_style_copy(&sep_and_bg, &sep_emu_bg);\n\tsep_and_bg.body.main_color = LV_COLOR_HEX(0xC000FF);\n\tsep_and_bg.body.grad_color = sep_and_bg.body.main_color;\n\n\tchar *txt_buf = malloc(SZ_8K);\n\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_map[] = { \"\\251\", \"\\222OK\", \"\\251\", \"\" };\n\tstatic const char *mbox_btn_map2[] = { \"\\222Don't Backup\", \"\\222OK\", \"\" };\n\tlv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);\n\n\tlv_mbox_set_text(mbox, \"Analyzing SD card usage. This might take a while...\");\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\tmanual_system_maintenance(true);\n\n\tchar *path = malloc(0x1000);\n\tu32 total_files = 0;\n\tu32 total_size = 0;\n\tpath[0] = 0;\n\n\t// Check total size of files.\n\tint res = _stat_and_copy_files(\"sd:\", NULL, path, &total_files, &total_size, NULL);\n\n\t// Not more than 1.2GB.\n\tpart_info.backup_possible = !res && !(total_size > (RAM_DISK_SZ - SZ_16M)); // Account for alignment.\n\n\tif (part_info.backup_possible)\n\t{\n\t\ts_printf(txt_buf,\n\t\t\t\"#96FF00 The SD Card files will be backed up automatically!#\\n\"\n\t\t\t\"#FFDD00 Any other partition will be wiped!#\\n\"\n\t\t\t\"#00DDFF Total files:# %d, #00DDFF Total size:# %d MiB\", total_files, total_size >> 20);\n\t\tlv_mbox_set_text(mbox, txt_buf);\n\t}\n\telse\n\t{\n\t\tlv_mbox_set_text(mbox,\n\t\t\t\"#FFDD00 The SD Card cannot be backed up automatically!#\\n\"\n\t\t\t\"#FFDD00 Any other partition will be also wiped!#\\n\\n\"\n\t\t\t\"You will be asked to back up your files later via UMS.\");\n\t}\n\n\t// Create container to keep content inside.\n\tlv_obj_t *h1 = lv_cont_create(mbox, NULL);\n\tlv_cont_set_fit(h1, false, true);\n\tlv_cont_set_style(h1, &lv_style_transp_tight);\n\tlv_obj_set_width(h1, lv_obj_get_width(mbox) - LV_DPI * 3);\n\n\tlv_obj_t *lbl_part = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(lbl_part, true);\n\tlv_label_set_text(lbl_part, \"#00DDFF Current MBR partition layout:#\");\n\n\t// Read current MBR.\n\tmbr_t mbr = { 0 };\n\tsdmmc_storage_read(&sd_storage, 0, 1, &mbr);\n\n\t// Calculate MBR partitions size.\n\ttotal_size = (sd_storage.sec_cnt - AU_ALIGN_SECTORS) / SECTORS_PER_GB;\n\tu32 bar_hos_size = lv_obj_get_width(h1) * (mbr.partitions[0].size_sct / SECTORS_PER_GB) / total_size;\n\tu32 bar_emu_size = 0;\n\tfor (u32 i = 1; i < 4; i++)\n\t\tif (mbr.partitions[i].type == 0xE0)\n\t\t\tbar_emu_size += mbr.partitions[i].size_sct;\n\tbar_emu_size = lv_obj_get_width(h1) * (bar_emu_size / SECTORS_PER_GB) / total_size;\n\n\tu32 bar_l4t_size = 0;\n\tfor (u32 i = 1; i < 4; i++)\n\t\tif (mbr.partitions[i].type == 0x83)\n\t\t\tbar_l4t_size += mbr.partitions[i].size_sct;\n\tbar_l4t_size = lv_obj_get_width(h1) * (bar_l4t_size / SECTORS_PER_GB) / total_size;\n\n\tu32 bar_and_size = lv_obj_get_width(h1) - bar_hos_size - bar_emu_size - bar_l4t_size;\n\n\t// Create HOS bar.\n\tlv_obj_t *bar_mbr_hos = lv_bar_create(h1, NULL);\n\tlv_obj_set_size(bar_mbr_hos, bar_hos_size, LV_DPI / 3);\n\tlv_bar_set_range(bar_mbr_hos, 0, 1);\n\tlv_bar_set_value(bar_mbr_hos, 1);\n\tlv_bar_set_style(bar_mbr_hos, LV_BAR_STYLE_INDIC, &bar_hos_ind);\n\tlv_obj_align(bar_mbr_hos, lbl_part, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6);\n\n\t// Create emuMMC bar.\n\tlv_obj_t *bar_mbr_emu = lv_bar_create(h1, bar_mbr_hos);\n\tlv_obj_set_size(bar_mbr_emu, bar_emu_size, LV_DPI / 3);\n\tlv_bar_set_style(bar_mbr_emu, LV_BAR_STYLE_INDIC, &bar_emu_ind);\n\tlv_obj_align(bar_mbr_emu, bar_mbr_hos, LV_ALIGN_OUT_RIGHT_MID, 0, 0);\n\n\t// Create L4T bar.\n\tlv_obj_t *bar_mbr_l4t = lv_bar_create(h1, bar_mbr_hos);\n\tlv_obj_set_size(bar_mbr_l4t, bar_l4t_size, LV_DPI / 3);\n\tlv_bar_set_style(bar_mbr_l4t, LV_BAR_STYLE_INDIC, &bar_l4t_ind);\n\tlv_obj_align(bar_mbr_l4t, bar_mbr_emu, LV_ALIGN_OUT_RIGHT_MID, 0, 0);\n\n\t// Create GPT bar.\n\tlv_obj_t *bar_mbr_gpt = lv_bar_create(h1, bar_mbr_hos);\n\tlv_obj_set_size(bar_mbr_gpt, bar_and_size > 1 ? bar_and_size : 0, LV_DPI / 3);\n\tlv_bar_set_style(bar_mbr_gpt, LV_BAR_STYLE_INDIC, &bar_and_ind);\n\tlv_obj_align(bar_mbr_gpt, bar_mbr_l4t, LV_ALIGN_OUT_RIGHT_MID, 0, 0);\n\n\t// Create emuMMC separator.\n\tlv_obj_t *sep_mbr_emu = lv_cont_create(h1, NULL);\n\tlv_obj_set_size(sep_mbr_emu, bar_emu_size ? 8 : 0, LV_DPI / 3);\n\tlv_obj_set_style(sep_mbr_emu, &sep_emu_bg);\n\tlv_obj_align(sep_mbr_emu, bar_mbr_hos, LV_ALIGN_OUT_RIGHT_MID, -4, 0);\n\n\t// Create L4T separator.\n\tlv_obj_t *sep_mbr_l4t = lv_cont_create(h1, sep_mbr_emu);\n\tlv_obj_set_size(sep_mbr_l4t, bar_l4t_size ? 8 : 0, LV_DPI / 3);\n\tlv_obj_set_style(sep_mbr_l4t, &sep_l4t_bg);\n\tlv_obj_align(sep_mbr_l4t, bar_mbr_emu, LV_ALIGN_OUT_RIGHT_MID, -4, 0);\n\n\t// Create GPT separator.\n\tlv_obj_t *sep_mbr_gpt = lv_cont_create(h1, sep_mbr_emu);\n\tlv_obj_set_size(sep_mbr_gpt, bar_and_size ? (bar_and_size > 1 ? 8 : 0) : 0, LV_DPI / 3);\n\tlv_obj_set_style(sep_mbr_gpt, &sep_and_bg);\n\tlv_obj_align(sep_mbr_gpt, bar_mbr_l4t, LV_ALIGN_OUT_RIGHT_MID, -4, 0);\n\n\t// Print partition table info.\n\ts_printf(txt_buf,\n\t\t\"Partition 0 - Type: %02x, Start: %08x, Size: %08x\\n\"\n\t\t\"Partition 1 - Type: %02x, Start: %08x, Size: %08x\\n\"\n\t\t\"Partition 2 - Type: %02x, Start: %08x, Size: %08x\\n\"\n\t\t\"Partition 3 - Type: %02x, Start: %08x, Size: %08x\",\n\t\tmbr.partitions[0].type, mbr.partitions[0].start_sct, mbr.partitions[0].size_sct,\n\t\tmbr.partitions[1].type, mbr.partitions[1].start_sct, mbr.partitions[1].size_sct,\n\t\tmbr.partitions[2].type, mbr.partitions[2].start_sct, mbr.partitions[2].size_sct,\n\t\tmbr.partitions[3].type, mbr.partitions[3].start_sct, mbr.partitions[3].size_sct);\n\n\tlv_obj_t *lbl_table = lv_label_create(h1, NULL);\n\tlv_label_set_style(lbl_table, &monospace_text);\n\tlv_label_set_text(lbl_table, txt_buf);\n\tlv_obj_align(lbl_table, h1, LV_ALIGN_IN_TOP_MID, 0, LV_DPI);\n\n\tif (!part_info.backup_possible)\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);\n\telse\n\t\tlv_mbox_add_btns(mbox, mbox_btn_map2, _mbox_check_files_total_size_option);\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\n\tfree(txt_buf);\n\tfree(path);\n}\n\nstatic lv_res_t _action_fix_mbr_gpt(lv_obj_t *btn)\n{\n\tlv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);\n\tlv_obj_set_style(dark_bg, &mbox_darken);\n\tlv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);\n\n\tstatic const char *mbox_btn_map[] = { \"\\251\", \"\\222OK\", \"\\251\", \"\" };\n\tlv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);\n\tlv_mbox_set_recolor_text(mbox, true);\n\n\tlv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);\n\tlv_mbox_set_text(mbox, \"#FF8000 Fix Hybrid MBR#\");\n\n\tlv_obj_t *lbl_status = lv_label_create(mbox, NULL);\n\tlv_label_set_recolor(lbl_status, true);\n\n\tmbr_t mbr[2] = { 0 };\n\tgpt_t *gpt = zalloc(sizeof(gpt_t));\n\tgpt_header_t gpt_hdr_backup = { 0 };\n\n\tbool has_mbr_attributes   = false;\n\tbool hybrid_mbr_changed   = false;\n\tbool gpt_partition_exists = false;\n\tint  gpt_oob_empty_part_no = 0;\n\tint  gpt_emummc_migrate_no = 0;\n\n\t// Try to init sd card. No need for valid MBR.\n\tif (sd_mount() && !sd_get_card_initialized())\n\t{\n\t\tlv_label_set_text(lbl_status, \"#FFDD00 Failed to init SD!#\");\n\t\tgoto out;\n\t}\n\n\tsdmmc_storage_read(&sd_storage, 0, 1, &mbr[0]);\n\tsdmmc_storage_read(&sd_storage, 1, sizeof(gpt_t) >> 9, gpt);\n\n\tmemcpy(&mbr[1], &mbr[0], sizeof(mbr_t));\n\n\tsd_unmount();\n\n\t// Check for secret MBR attributes.\n\tif (gpt->entries[0].part_guid[7])\n\t\thas_mbr_attributes = true;\n\n\t// Check if there's a GPT Protective partition.\n\tfor (u32 i = 0; i < 4; i++)\n\t{\n\t\tif (mbr[0].partitions[i].type == 0xEE)\n\t\t\tgpt_partition_exists = true;\n\t}\n\n\t// Check if GPT is valid.\n\tif (!gpt_partition_exists || memcmp(&gpt->header.signature, \"EFI PART\", 8) || gpt->header.num_part_ents > 128)\n\t{\n\t\tlv_label_set_text(lbl_status, \"#FFDD00 Warning:# No valid GPT was found!\");\n\n\t\tgpt_partition_exists = false;\n\n\t\tif (has_mbr_attributes)\n\t\t\tgoto check_changes;\n\t\telse\n\t\t\tgoto out;\n\t}\n\n\tsdmmc_storage_read(&sd_storage, gpt->header.alt_lba, 1, &gpt_hdr_backup);\n\n\t// Parse GPT.\n\tLIST_INIT(gpt_parsed);\n\tfor (u32 i = 0; i < gpt->header.num_part_ents; i++)\n\t{\n\t\t// Check if partition is out of bounds or empty.\n\t\tif ( gpt->entries[i].lba_start <   gpt->header.first_use_lba ||\n\t\t\t gpt->entries[i].lba_start >=  gpt->entries[i].lba_end   ||\n\t\t\t!gpt->entries[i].lba_end)\n\t\t{\n\t\t\tgpt_oob_empty_part_no++;\n\t\t\tcontinue;\n\t\t}\n\n\t\temmc_part_t *part = (emmc_part_t *)zalloc(sizeof(emmc_part_t));\n\n\t\tpart->index = i;\n\t\tpart->lba_start = gpt->entries[i].lba_start;\n\t\tpart->lba_end = gpt->entries[i].lba_end;\n\n\t\t// ASCII conversion. Copy only the LSByte of the UTF-16LE name.\n\t\tfor (u32 j = 0; j < 36; j++)\n\t\t\tpart->name[j] = gpt->entries[i].name[j];\n\t\tpart->name[35] = 0;\n\n\t\tlist_append(&gpt_parsed, &part->link);\n\t}\n\n\t// Set FAT and emuMMC partitions.\n\tu32 mbr_idx = 1;\n\tbool found_hos_data = false;\n\tu32 emummc_mbr_part_idx[2] = {0};\n\tLIST_FOREACH_ENTRY(emmc_part_t, part, &gpt_parsed, link)\n\t{\n\t\t// FatFS simple GPT found a fat partition, set it.\n\t\tif (sd_fs.part_type && !part->index)\n\t\t{\n\t\t\tmbr[1].partitions[0].type = sd_fs.fs_type == FS_EXFAT ? 0x7 : 0xC;\n\t\t\tmbr[1].partitions[0].start_sct = part->lba_start;\n\t\t\tmbr[1].partitions[0].size_sct  = part->lba_end - part->lba_start + 1;\n\t\t}\n\n\t\t// FatFS simple GPT didn't find a fat partition as the first one.\n\t\tif (!sd_fs.part_type && !found_hos_data && !strcmp(part->name, \"hos_data\"))\n\t\t{\n\t\t\tmbr[1].partitions[0].type = 0xC;\n\t\t\tmbr[1].partitions[0].start_sct = part->lba_start;\n\t\t\tmbr[1].partitions[0].size_sct  = part->lba_end - part->lba_start + 1;\n\t\t\tfound_hos_data = true;\n\t\t}\n\n\t\t// Set up to max 2 emuMMC partitions.\n\t\tif (!strcmp(part->name, \"emummc\") || !strcmp(part->name, \"emummc2\"))\n\t\t{\n\t\t\tmbr[1].partitions[mbr_idx].type = 0xE0;\n\t\t\tmbr[1].partitions[mbr_idx].start_sct = part->lba_start;\n\t\t\tmbr[1].partitions[mbr_idx].size_sct  = part->lba_end - part->lba_start + 1;\n\t\t\tif (!strcmp(part->name, \"emummc\"))\n\t\t\t\temummc_mbr_part_idx[0] = mbr_idx;\n\t\t\telse\n\t\t\t\temummc_mbr_part_idx[1] = mbr_idx;\n\t\t\tmbr_idx++;\n\t\t}\n\n\t\t// Total reached last slot.\n\t\tif (mbr_idx >= 3)\n\t\t\tbreak;\n\t}\n\n\temmc_gpt_free(&gpt_parsed);\n\n\t// Set GPT protective partition.\n\tmbr[1].partitions[mbr_idx].type = 0xEE;\n\tmbr[1].partitions[mbr_idx].start_sct = 1;\n\tmbr[1].partitions[mbr_idx].size_sct = sd_storage.sec_cnt - 1;\n\n\t// Check for differences.\n\tfor (u32 i = 1; i < 4; i++)\n\t{\n\t\tif ((mbr[0].partitions[i].type      != mbr[1].partitions[i].type)      ||\n\t\t\t(mbr[0].partitions[i].start_sct != mbr[1].partitions[i].start_sct) ||\n\t\t\t(mbr[0].partitions[i].size_sct  != mbr[1].partitions[i].size_sct))\n\t\t{\n\t\t\t// Check if original MBR already has an emuMMC and use it as source of truth.\n\t\t\tif (mbr[0].partitions[i].type == 0xE0)\n\t\t\t{\n\t\t\t\tmemcpy(&mbr[1].partitions[i], &mbr[0].partitions[i], sizeof(mbr_part_t));\n\t\t\t\tgpt_emummc_migrate_no++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse\n\t\t\t\thybrid_mbr_changed = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\ncheck_changes:\n\tif (!hybrid_mbr_changed && !has_mbr_attributes && !gpt_emummc_migrate_no)\n\t{\n\t\tlv_label_set_text(lbl_status, \"#96FF00 Warning:# The Hybrid MBR needs no change!#\");\n\t\tgoto out;\n\t}\n\n\tchar *txt_buf = malloc(SZ_16K);\n\n\tif (hybrid_mbr_changed)\n\t{\n\t\t// Current MBR info.\n\t\ts_printf(txt_buf, \"#00DDFF Current MBR Layout:#\\n\");\n\t\ts_printf(txt_buf + strlen(txt_buf),\n\t\t\t\"Partition 0 - Type: %02x, Start: %08x, Size: %08x\\n\"\n\t\t\t\"Partition 1 - Type: %02x, Start: %08x, Size: %08x\\n\"\n\t\t\t\"Partition 2 - Type: %02x, Start: %08x, Size: %08x\\n\"\n\t\t\t\"Partition 3 - Type: %02x, Start: %08x, Size: %08x\\n\\n\",\n\t\t\tmbr[0].partitions[0].type, mbr[0].partitions[0].start_sct, mbr[0].partitions[0].size_sct,\n\t\t\tmbr[0].partitions[1].type, mbr[0].partitions[1].start_sct, mbr[0].partitions[1].size_sct,\n\t\t\tmbr[0].partitions[2].type, mbr[0].partitions[2].start_sct, mbr[0].partitions[2].size_sct,\n\t\t\tmbr[0].partitions[3].type, mbr[0].partitions[3].start_sct, mbr[0].partitions[3].size_sct);\n\n\t\t// New MBR info.\n\t\ts_printf(txt_buf + strlen(txt_buf), \"#00DDFF New MBR Layout:#\\n\");\n\t\ts_printf(txt_buf + strlen(txt_buf),\n\t\t\t\"Partition 0 - Type: %02x, Start: %08x, Size: %08x\\n\"\n\t\t\t\"Partition 1 - Type: %02x, Start: %08x, Size: %08x\\n\"\n\t\t\t\"Partition 2 - Type: %02x, Start: %08x, Size: %08x\\n\"\n\t\t\t\"Partition 3 - Type: %02x, Start: %08x, Size: %08x\",\n\t\t\tmbr[1].partitions[0].type, mbr[1].partitions[0].start_sct, mbr[1].partitions[0].size_sct,\n\t\t\tmbr[1].partitions[1].type, mbr[1].partitions[1].start_sct, mbr[1].partitions[1].size_sct,\n\t\t\tmbr[1].partitions[2].type, mbr[1].partitions[2].start_sct, mbr[1].partitions[2].size_sct,\n\t\t\tmbr[1].partitions[3].type, mbr[1].partitions[3].start_sct, mbr[1].partitions[3].size_sct);\n\t}\n\telse if (has_mbr_attributes || gpt_emummc_migrate_no || gpt_oob_empty_part_no)\n\t{\n\t\ts_printf(txt_buf, \"#00DDFF The following need to be corrected:#\\n\");\n\t\tif (has_mbr_attributes)\n\t\t\ts_printf(txt_buf + strlen(txt_buf), \"- MBR attributes\\n\");\n\t\tif (gpt_emummc_migrate_no)\n\t\t\ts_printf(txt_buf + strlen(txt_buf), \"- emuMMC GPT Partition address and size\\n\");\n\t\tif (gpt_oob_empty_part_no)\n\t\t\ts_printf(txt_buf + strlen(txt_buf), \"- GPT OOB/Empty Partitions (removal)\\n\");\n\t}\n\n\tlv_label_set_text(lbl_status, txt_buf);\n\tlv_label_set_style(lbl_status, &monospace_text);\n\n\tfree(txt_buf);\n\n\tlbl_status = lv_label_create(mbox, NULL);\n\tlv_label_set_recolor(lbl_status, true);\n\tlv_label_set_align(lbl_status, LV_LABEL_ALIGN_CENTER);\n\n\tlv_label_set_text(lbl_status,\n\t\t\"#FF8000 Warning: Do you really want to continue?!#\\n\\n\"\n\t\t\"Press #FF8000 POWER# to Continue.\\nPress #FF8000 VOL# to abort.\");\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\tmanual_system_maintenance(true);\n\n\tif (btn_wait() & BTN_POWER)\n\t{\n\t\tbool has_gpt_changes = false;\n\n\t\tsd_mount();\n\n\t\t// Write MBR.\n\t\tif (hybrid_mbr_changed)\n\t\t\tsdmmc_storage_write(&sd_storage, 0, 1, &mbr[1]);\n\n\t\t// Fix MBR secret attributes.\n\t\tif (has_mbr_attributes)\n\t\t{\n\t\t\t// Clear secret attributes.\n\t\t\tgpt->entries[0].part_guid[7] = 0;\n\t\t\thas_gpt_changes = gpt_partition_exists;\n\n\t\t\tif (!has_gpt_changes)\n\t\t\t{\n\t\t\t\t// Only write the relevant sector if the only change is MBR attributes.\n\t\t\t\tsdmmc_storage_write(&sd_storage, 2, 1, &gpt->entries[0]);\n\t\t\t}\n\t\t}\n\n\t\tif (gpt_emummc_migrate_no)\n\t\t{\n\t\t\tu32 emu_idx = 0;\n\t\t\tfor (u32 i = 0; i < gpt->header.num_part_ents; i++)\n\t\t\t{\n\t\t\t\tif (!memcmp(gpt->entries[i].name, (u16[]) { 'e', 'm', 'u', 'm', 'm', 'c' }, 12))\n\t\t\t\t{\n\t\t\t\t\tu32 idx = emummc_mbr_part_idx[emu_idx];\n\t\t\t\t\tgpt->entries[i].lba_start = mbr[0].partitions[idx].start_sct;\n\t\t\t\t\tgpt->entries[i].lba_end   = mbr[0].partitions[idx].start_sct + mbr[0].partitions[idx].size_sct - 1;\n\t\t\t\t\tgpt_emummc_migrate_no--;\n\t\t\t\t\temu_idx++;\n\n\t\t\t\t\thas_gpt_changes = true;\n\t\t\t\t}\n\n\t\t\t\tif (i > 126 || !gpt_emummc_migrate_no)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (gpt_oob_empty_part_no)\n\t\t{\n\t\t\tu32 part_idx = 0;\n\t\t\tfor (u32 i = 0; i < gpt->header.num_part_ents; i++)\n\t\t\t{\n\t\t\t\tif ( gpt->entries[i].lba_start <   gpt->header.first_use_lba ||\n\t\t\t\t\t gpt->entries[i].lba_start >=  gpt->entries[i].lba_end   ||\n\t\t\t\t\t!gpt->entries[i].lba_end)\n\t\t\t\t{\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (part_idx != i)\n\t\t\t\t\tmemcpy(&gpt->entries[part_idx], &gpt->entries[i], sizeof(gpt_entry_t));\n\t\t\t\tpart_idx++;\n\t\t\t}\n\t\t\tgpt->header.num_part_ents -= gpt_oob_empty_part_no;\n\t\t\thas_gpt_changes = true;\n\t\t}\n\n\t\tif (has_gpt_changes)\n\t\t{\n\t\t\t// Fix GPT CRC32s.\n\t\t\tu32 entries_size = sizeof(gpt_entry_t) * gpt->header.num_part_ents;\n\t\t\tgpt->header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt->entries, entries_size);\n\t\t\tgpt->header.crc32 = 0; // Set to 0 for calculation.\n\t\t\tgpt->header.crc32 = crc32_calc(0, (const u8 *)&gpt->header, gpt->header.size);\n\n\t\t\tgpt_hdr_backup.part_ents_crc32 = gpt->header.part_ents_crc32;\n\t\t\tgpt_hdr_backup.crc32 = 0; // Set to 0 for calculation.\n\t\t\tgpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size);\n\n\t\t\t// Write main GPT.\n\t\t\tu32 aligned_entries_size = ALIGN(entries_size, SD_BLOCKSIZE);\n\t\t\tsdmmc_storage_write(&sd_storage, gpt->header.my_lba, (sizeof(gpt_header_t) + aligned_entries_size) >> 9, gpt);\n\n\t\t\t// Write backup GPT partition table.\n\t\t\tsdmmc_storage_write(&sd_storage, gpt_hdr_backup.part_ent_lba, aligned_entries_size >> 9, gpt->entries);\n\n\t\t\t// Write backup GPT header.\n\t\t\tsdmmc_storage_write(&sd_storage, gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup);\n\t\t}\n\n\t\tsd_unmount();\n\n\t\tlv_label_set_text(lbl_status, \"#96FF00 The new Hybrid MBR was written successfully!#\");\n\t}\n\telse\n\t\tlv_label_set_text(lbl_status, \"#FFDD00 Warning: The Hybrid MBR Fix was canceled!#\");\n\nout:\n\tfree(gpt);\n\n\tlv_mbox_add_btns(mbox, mbox_btn_map, nyx_mbox_action);\n\n\tlv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);\n\tlv_obj_set_top(mbox, true);\n\n\treturn LV_RES_OK;\n}\n\nlv_res_t create_window_partition_manager(bool emmc)\n{\n\tlv_obj_t *win;\n\n\tif (!emmc)\n\t{\n\t\twin = nyx_create_standard_window(SYMBOL_SD\" SD Partition Manager\", NULL);\n\t\tlv_win_add_btn(win, NULL, SYMBOL_MODULES_ALT\" Fix Hybrid MBR/GPT\", _action_fix_mbr_gpt);\n\t}\n\telse\n\t\twin = nyx_create_standard_window(SYMBOL_CHIP\" eMMC Partition Manager\", NULL);\n\n\tstatic lv_style_t bar_hos_bg, bar_emu_bg, bar_l4t_bg, bar_and_bg;\n\tstatic lv_style_t bar_hos_ind, bar_emu_ind, bar_l4t_ind, bar_and_ind;\n\tstatic lv_style_t bar_emu_btn, bar_l4t_btn, bar_and_btn;\n\tstatic lv_style_t sep_emu_bg, sep_l4t_bg, sep_and_bg;\n\n\t// Set HOS bar styles.\n\tlv_style_copy(&bar_hos_bg, lv_theme_get_current()->bar.bg);\n\tbar_hos_bg.body.main_color = LV_COLOR_HEX(0x4A8000);\n\tbar_hos_bg.body.grad_color = bar_hos_bg.body.main_color;\n\tlv_style_copy(&bar_hos_ind, lv_theme_get_current()->bar.indic);\n\tbar_hos_ind.body.main_color = LV_COLOR_HEX(0x96FF00);\n\tbar_hos_ind.body.grad_color = bar_hos_ind.body.main_color;\n\n\t// Set eMUMMC bar styles.\n\tlv_style_copy(&bar_emu_bg, lv_theme_get_current()->bar.bg);\n\tbar_emu_bg.body.main_color = LV_COLOR_HEX(0x940F00);\n\tbar_emu_bg.body.grad_color = bar_emu_bg.body.main_color;\n\tlv_style_copy(&bar_emu_ind, lv_theme_get_current()->bar.indic);\n\tbar_emu_ind.body.main_color = LV_COLOR_HEX(0xFF3C28);\n\tbar_emu_ind.body.grad_color = bar_emu_ind.body.main_color;\n\tlv_style_copy(&bar_emu_btn, lv_theme_get_current()->slider.knob);\n\tbar_emu_btn.body.main_color = LV_COLOR_HEX(0xB31200);\n\tbar_emu_btn.body.grad_color = bar_emu_btn.body.main_color;\n\tlv_style_copy(&sep_emu_bg, lv_theme_get_current()->cont);\n\tsep_emu_bg.body.main_color = LV_COLOR_HEX(0xFF3C28);\n\tsep_emu_bg.body.grad_color = sep_emu_bg.body.main_color;\n\tsep_emu_bg.body.radius = 0;\n\n\t// Set L4T bar styles.\n\tlv_style_copy(&bar_l4t_bg, lv_theme_get_current()->bar.bg);\n\tbar_l4t_bg.body.main_color = LV_COLOR_HEX(0x006E80);\n\tbar_l4t_bg.body.grad_color = bar_l4t_bg.body.main_color;\n\tlv_style_copy(&bar_l4t_ind, lv_theme_get_current()->bar.indic);\n\tbar_l4t_ind.body.main_color = LV_COLOR_HEX(0x00DDFF);\n\tbar_l4t_ind.body.grad_color = bar_l4t_ind.body.main_color;\n\tlv_style_copy(&bar_l4t_btn, lv_theme_get_current()->slider.knob);\n\tbar_l4t_btn.body.main_color = LV_COLOR_HEX(0x00B1CC);\n\tbar_l4t_btn.body.grad_color = bar_l4t_btn.body.main_color;\n\tlv_style_copy(&sep_l4t_bg, &sep_emu_bg);\n\tsep_l4t_bg.body.main_color = LV_COLOR_HEX(0x00DDFF);\n\tsep_l4t_bg.body.grad_color = sep_l4t_bg.body.main_color;\n\n\t// Set Android bar styles.\n\tlv_style_copy(&bar_and_bg, lv_theme_get_current()->bar.bg);\n\tbar_and_bg.body.main_color = LV_COLOR_HEX(0x804000);\n\tbar_and_bg.body.grad_color = bar_and_bg.body.main_color;\n\tlv_style_copy(&bar_and_ind, lv_theme_get_current()->bar.indic);\n\tbar_and_ind.body.main_color = LV_COLOR_HEX(0xFF8000);\n\tbar_and_ind.body.grad_color = bar_and_ind.body.main_color;\n\tlv_style_copy(&bar_and_btn, lv_theme_get_current()->slider.knob);\n\tbar_and_btn.body.main_color = LV_COLOR_HEX(0xCC6600);\n\tbar_and_btn.body.grad_color = bar_and_btn.body.main_color;\n\tlv_style_copy(&sep_and_bg, &sep_emu_bg);\n\tsep_and_bg.body.main_color = LV_COLOR_HEX(0xFF8000);\n\tsep_and_bg.body.grad_color = sep_and_bg.body.main_color;\n\n\tlv_obj_t *sep = lv_label_create(win, NULL);\n\tlv_label_set_static_text(sep, \"\");\n\tlv_obj_align(sep, NULL, LV_ALIGN_IN_TOP_MID, 0, 0);\n\n\t// Create container to keep content inside.\n\tlv_obj_t *h1 = lv_cont_create(win, NULL);\n\tlv_obj_set_size(h1, LV_HOR_RES - (LV_DPI * 8 / 10), LV_VER_RES - LV_DPI);\n\n\tu32 emmc_size = 0;\n\tif (!emmc)\n\t{\n\t\tif (sd_mount())\n\t\t{\n\t\t\tlv_obj_t *lbl = lv_label_create(h1, NULL);\n\t\t\tlv_label_set_recolor(lbl, true);\n\t\t\tlv_label_set_text(lbl, \"#FFDD00 Failed to init SD!#\");\n\t\t\treturn LV_RES_OK;\n\t\t}\n\n\t\tif (!emmc_initialize(false))\n\t\t{\n\t\t\temmc_set_partition(EMMC_GPP);\n\t\t\temmc_size = emmc_storage.sec_cnt >> 11;\n\t\t\temmc_end();\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (emmc_initialize(false))\n\t\t{\n\t\t\tlv_obj_t *lbl = lv_label_create(h1, NULL);\n\t\t\tlv_label_set_recolor(lbl, true);\n\t\t\tlv_label_set_text(lbl, \"#FFDD00 Failed to init eMMC!#\");\n\t\t\treturn LV_RES_OK;\n\t\t}\n\t\temmc_set_partition(EMMC_GPP);\n\t}\n\n\tmemset(&part_info, 0, sizeof(partition_ctxt_t));\n\tif (!emmc)\n\t\t_create_mbox_check_files_total_size();\n\n\tchar *txt_buf = malloc(SZ_8K);\n\n\tpart_info.emmc      = emmc;\n\tpart_info.storage   = !emmc ? &sd_storage : &emmc_storage;\n\tpart_info.total_sct = part_info.storage->sec_cnt;\n\tif (emmc)\n\t\tpart_info.total_sct -= HOS_USER_SECTOR; // Reserved HOS partitions.\n\n\t// Align down total size to ensure alignment of all partitions after HOS one.\n\tpart_info.alignment  = part_info.total_sct - ALIGN_DOWN(part_info.total_sct, AU_ALIGN_SECTORS);\n\tpart_info.total_sct -= part_info.alignment;\n\n\tu32 extra_sct = AU_ALIGN_SECTORS + 0x400000; // Reserved 16MB alignment for FAT partition + 2GB.\n\n\t// Set initial HOS partition size, so the correct cluster size can be selected.\n\tpart_info.hos_size = (part_info.total_sct >> 11) - 16; // Important if there's no slider change.\n\n\t// Check if eMMC should be 64GB (Aula).\n\tpart_info.emmc_is_64gb = fuse_read_hw_type() == FUSE_NX_HW_TYPE_AULA;\n\n\t// Set actual eMMC size.\n\tpart_info.emmc_size_mb = emmc_size;\n\n\t// Set HOS FAT or USER minimum size.\n\tpart_info.hos_min_size = !emmc? HOS_FAT_MIN_SIZE_MB : HOS_USER_MIN_SIZE_MB;\n\n\t// Read current MBR.\n\tmbr_t mbr = { 0 };\n\tsdmmc_storage_read(part_info.storage, 0, 1, &mbr);\n\n\tu32 bar_hos_size = lv_obj_get_width(h1);\n\tu32 bar_emu_size = 0;\n\tu32 bar_l4t_size = 0;\n\tu32 bar_and_size = 0;\n\n\tlv_obj_t *lbl = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(lbl, true);\n\tlv_label_set_text(lbl, \"Choose #FFDD00 new# partition layout:\");\n\n\t// Create disk layout blocks.\n\t// HOS partition block.\n\tlv_obj_t *bar_hos = lv_bar_create(h1, NULL);\n\tlv_obj_set_size(bar_hos, bar_hos_size, LV_DPI / 2);\n\tlv_bar_set_range(bar_hos, 0, 1);\n\tlv_bar_set_value(bar_hos, 1);\n\tlv_bar_set_style(bar_hos, LV_BAR_STYLE_INDIC, &bar_hos_ind);\n\tlv_obj_align(bar_hos, lbl, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6);\n\tpart_info.bar_hos = bar_hos;\n\n\t// emuMMC partition block.\n\tlv_obj_t *bar_emu = lv_bar_create(h1, bar_hos);\n\tlv_obj_set_size(bar_emu, bar_emu_size, LV_DPI / 2);\n\tlv_bar_set_style(bar_emu, LV_BAR_STYLE_INDIC, &bar_emu_ind);\n\tlv_obj_align(bar_emu, bar_hos, LV_ALIGN_OUT_RIGHT_MID, 0, 0);\n\tpart_info.bar_emu = bar_emu;\n\n\t// L4T partition block.\n\tlv_obj_t *bar_l4t = lv_bar_create(h1, bar_hos);\n\tlv_obj_set_size(bar_l4t, bar_l4t_size, LV_DPI / 2);\n\tlv_bar_set_style(bar_l4t, LV_BAR_STYLE_INDIC, &bar_l4t_ind);\n\tlv_obj_align(bar_l4t, bar_emu, LV_ALIGN_OUT_RIGHT_MID, 0, 0);\n\tpart_info.bar_l4t = bar_l4t;\n\n\t// Android partition block.\n\tlv_obj_t *bar_and = lv_bar_create(h1, bar_hos);\n\tlv_obj_set_size(bar_and, bar_and_size, LV_DPI / 2);\n\tlv_bar_set_style(bar_and, LV_BAR_STYLE_INDIC, &bar_and_ind);\n\tlv_obj_align(bar_and, bar_l4t, LV_ALIGN_OUT_RIGHT_MID, 0, 0);\n\tpart_info.bar_and = bar_and;\n\n\t// HOS partition block.\n\tlv_obj_t *sep_emu = lv_cont_create(h1, NULL);\n\tlv_cont_set_fit(sep_emu, false, false);\n\tlv_obj_set_size(sep_emu, 0, LV_DPI / 2); // 8.\n\tlv_obj_set_style(sep_emu, &sep_emu_bg);\n\tlv_obj_align(sep_emu, bar_hos, LV_ALIGN_OUT_RIGHT_MID, -4, 0);\n\tpart_info.sep_emu = sep_emu;\n\n\t// Create disk layout blending separators.\n\tlv_obj_t *sep_l4t = lv_cont_create(h1, sep_emu);\n\tlv_obj_set_style(sep_l4t, &sep_l4t_bg);\n\tlv_obj_align(sep_l4t, bar_emu, LV_ALIGN_OUT_RIGHT_MID, -4, 0);\n\tpart_info.sep_l4t = sep_l4t;\n\n\tlv_obj_t *sep_and = lv_cont_create(h1, sep_emu);\n\tlv_obj_set_style(sep_and, &sep_and_bg);\n\tlv_obj_align(sep_and, bar_l4t, LV_ALIGN_OUT_RIGHT_MID, -4, 0);\n\tpart_info.sep_and = sep_and;\n\n\t// Create slider type labels.\n\tlv_obj_t *cont_lbl_hos = lv_cont_create(h1, NULL);\n\tlv_cont_set_fit(cont_lbl_hos, false, true);\n\tlv_obj_set_width(cont_lbl_hos, LV_DPI * 17 / 7);\n\tlv_obj_t *lbl_hos = lv_label_create(cont_lbl_hos, NULL);\n\tlv_label_set_recolor(lbl_hos, true);\n\tlv_label_set_static_text(lbl_hos, !emmc ? \"#96FF00 \"SYMBOL_DOT\" HOS (FAT32):#\" :\n\t\t\t\t\t\t\t\t\t\t\t  \"#96FF00 \"SYMBOL_DOT\" eMMC (USER):#\");\n\tlv_obj_align(lbl_hos, bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);\n\n\tlv_obj_t *lbl_emu = lbl_hos;\n\tif (!emmc)\n\t{\n\t\tlbl_emu = lv_label_create(h1, lbl_hos);\n\t\tlv_label_set_static_text(lbl_emu, \"#FF3C28 \"SYMBOL_DOT\" emuMMC (RAW):#\");\n\t\tlv_obj_align(lbl_emu, lbl_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\t}\n\n\tlv_obj_t *lbl_l4t = lv_label_create(h1, lbl_hos);\n\tlv_label_set_static_text(lbl_l4t, \"#00DDFF \"SYMBOL_DOT\" Linux (EXT4):#\");\n\tlv_obj_align(lbl_l4t, lbl_emu, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\tlv_obj_t *lbl_and = lv_label_create(h1, lbl_hos);\n\tlv_label_set_static_text(lbl_and, \"#FF8000 \"SYMBOL_DOT\" Android (USER):#\");\n\tlv_obj_align(lbl_and, lbl_l4t, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);\n\n\t// Create HOS size slider. Non-interactive.\n\tlv_obj_t *slider_bar_hos = lv_bar_create(h1, NULL);\n\tlv_obj_set_size(slider_bar_hos, LV_DPI * 7, LV_DPI * 3 / 17);\n\tlv_bar_set_range(slider_bar_hos, 0, (part_info.total_sct - AU_ALIGN_SECTORS) / SECTORS_PER_GB);\n\tlv_bar_set_value(slider_bar_hos, (part_info.total_sct - AU_ALIGN_SECTORS) / SECTORS_PER_GB);\n\tlv_bar_set_style(slider_bar_hos, LV_SLIDER_STYLE_BG, &bar_hos_bg);\n\tlv_bar_set_style(slider_bar_hos, LV_SLIDER_STYLE_INDIC, &bar_hos_ind);\n\tlv_obj_align(slider_bar_hos, cont_lbl_hos, LV_ALIGN_OUT_RIGHT_MID, LV_DPI, 0);\n\tpart_info.slider_bar_hos = slider_bar_hos;\n\n\tlv_obj_t *slider_emu = slider_bar_hos;\n\tif (!emmc)\n\t{\n\t\t// Create emuMMC size slider.\n\t\tslider_emu = lv_slider_create(h1, NULL);\n\t\tlv_obj_set_size(slider_emu, LV_DPI * 7, LV_DPI / 3);\n\t\tlv_slider_set_range(slider_emu, EMU_SLIDER_MIN, EMU_SLIDER_MAX);\n\t\tlv_slider_set_value(slider_emu, EMU_SLIDER_MIN);\n\t\tlv_slider_set_style(slider_emu, LV_SLIDER_STYLE_BG, &bar_emu_bg);\n\t\tlv_slider_set_style(slider_emu, LV_SLIDER_STYLE_INDIC, &bar_emu_ind);\n\t\tlv_slider_set_style(slider_emu, LV_SLIDER_STYLE_KNOB, &bar_emu_btn);\n\t\tlv_obj_align(slider_emu, slider_bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 + 5);\n\t\tlv_slider_set_action(slider_emu, _action_slider_emu);\n\t}\n\n\t// Create L4T size slider.\n\tlv_obj_t *slider_l4t = lv_slider_create(h1, NULL);\n\tlv_obj_set_size(slider_l4t, LV_DPI * 7, LV_DPI / 3);\n\tlv_slider_set_range(slider_l4t, 0, (part_info.total_sct - extra_sct) / SECTORS_PER_GB);\n\tlv_slider_set_value(slider_l4t, 0);\n\tlv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_BG, &bar_l4t_bg);\n\tlv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_INDIC, &bar_l4t_ind);\n\tlv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_KNOB, &bar_l4t_btn);\n\tlv_obj_align(slider_l4t, slider_emu, LV_ALIGN_OUT_BOTTOM_LEFT, 0, !emmc ? (LV_DPI / 3 - 3) : (LV_DPI / 3 + 5));\n\tlv_slider_set_action(slider_l4t, _action_slider_l4t);\n\n\t// Create Android size slider.\n\tlv_obj_t *slider_and = lv_slider_create(h1, NULL);\n\tlv_obj_set_size(slider_and, LV_DPI * 7, LV_DPI / 3);\n\tlv_slider_set_range(slider_and, 0, (part_info.total_sct - extra_sct) / SECTORS_PER_GB - (AND_SYS_SIZE_MB / 1024)); // Subtract android reserved size.\n\tlv_slider_set_value(slider_and, 0);\n\tlv_slider_set_style(slider_and, LV_SLIDER_STYLE_BG, &bar_and_bg);\n\tlv_slider_set_style(slider_and, LV_SLIDER_STYLE_INDIC, &bar_and_ind);\n\tlv_slider_set_style(slider_and, LV_SLIDER_STYLE_KNOB, &bar_and_btn);\n\tlv_obj_align(slider_and, slider_l4t, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 - 3);\n\tlv_slider_set_action(slider_and, _action_slider_and);\n\n\t// Create container for the labels.\n\tlv_obj_t *cont_lbl = lv_cont_create(h1, NULL);\n\tlv_cont_set_fit(cont_lbl, false, true);\n\tlv_obj_set_width(cont_lbl, LV_DPI * 3 / 2);\n\tpart_info.cont_lbl = cont_lbl;\n\n\t// Create HOS size label.\n\tlv_obj_t *lbl_sl_hos = lv_label_create(cont_lbl, NULL);\n\tlv_label_set_recolor(lbl_sl_hos, true);\n\tlv_label_set_align(lbl_sl_hos, LV_LABEL_ALIGN_RIGHT);\n\ts_printf(txt_buf, \"#96FF00 %4d GiB#\", (part_info.total_sct - AU_ALIGN_SECTORS) >> 11 >> 10);\n\tlv_label_set_text(lbl_sl_hos, txt_buf);\n\tlv_obj_align(lbl_sl_hos, cont_lbl, LV_ALIGN_IN_TOP_RIGHT, 0, 0);\n\tpart_info.lbl_hos = lbl_sl_hos;\n\n\t// Create emuMMC size label.\n\tpart_info.lbl_emu = lbl_sl_hos;\n\tif (!emmc)\n\t{\n\t\tlv_obj_t *lbl_sl_emu = lv_label_create(cont_lbl, lbl_sl_hos);\n\t\tlv_label_set_text(lbl_sl_emu, \"#FF3C28    0 GiB#\");\n\t\tlv_obj_align(lbl_sl_emu, lbl_sl_hos, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, LV_DPI / 3);\n\t\tpart_info.lbl_emu = lbl_sl_emu;\n\t}\n\n\t// Create L4T size label.\n\tlv_obj_t *lbl_sl_l4t = lv_label_create(cont_lbl, lbl_sl_hos);\n\tlv_label_set_text(lbl_sl_l4t, \"#00DDFF    0 GiB#\");\n\tlv_obj_align(lbl_sl_l4t, part_info.lbl_emu, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, LV_DPI / 3);\n\tpart_info.lbl_l4t = lbl_sl_l4t;\n\n\t// Create Android size label.\n\tlv_obj_t *lbl_sl_and = lv_label_create(cont_lbl, lbl_sl_hos);\n\tlv_label_set_text(lbl_sl_and, \"#FF8000    0 GiB#\");\n\tlv_obj_align(lbl_sl_and, lbl_sl_l4t, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, LV_DPI / 3);\n\tpart_info.lbl_and = lbl_sl_and;\n\n\tlv_obj_align(cont_lbl, bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI * 11 - LV_DPI / 2, LV_DPI * 9 / 23);\n\n\t// Set partition manager notes.\n\tlv_obj_t *lbl_notes = lv_label_create(h1, NULL);\n\tlv_label_set_recolor(lbl_notes, true);\n\tlv_label_set_style(lbl_notes, &hint_small_style);\n\tif (!emmc)\n\t{\n\t\tlv_label_set_static_text(lbl_notes,\n\t\t\t\"Note 1: Only up to #C7EA46 1.2GB# can be backed up. If more, you will be asked to back them manually at the next step.\\n\"\n\t\t\t\"Note 2: Resized emuMMC formats the USER partition. A save data manager can be used to move them over.\\n\"\n\t\t\t\"Note 3: The #C7EA46 Flash Linux# and #C7EA46 Flash Android# will flash files if suitable partitions and installer files are found.\\n\");\n\t\tlv_obj_align(lbl_notes, lbl_and, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6 * 2);\n\t}\n\telse\n\t{\n\t\tlv_label_set_static_text(lbl_notes,\n\t\t\t\"Note 1: Any partition existing after the selected ones gets removed from the table.\\n\"\n\t\t\t\"Note 2: The HOS USER partition gets formatted. A save data manager can be used to move them over.\\n\"\n\t\t\t\"Note 3: The #C7EA46 Flash Linux# and #C7EA46 Flash Android# will flash files if suitable partitions and installer files are found.\\n\");\n\t\tlv_obj_align(lbl_notes, lbl_and, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6 * 4);\n\t}\n\n\tlv_obj_t *btn1 = NULL;\n\tlv_obj_t *label_btn = NULL;\n\tif (!emmc)\n\t{\n\t\t// Create UMS button.\n\t\tbtn1 = lv_btn_create(h1, NULL);\n\t\tlv_obj_t *label_btn = lv_label_create(btn1, NULL);\n\t\tlv_btn_set_fit(btn1, true, true);\n\t\tlv_label_set_static_text(label_btn, SYMBOL_USB\"  SD UMS\");\n\t\tlv_obj_align(btn1, h1, LV_ALIGN_IN_TOP_LEFT, 0, LV_DPI * 5);\n\t\tlv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, _action_part_manager_ums_sd);\n\t}\n\n\t// Create Flash Linux button.\n\tbtn_flash_l4t = lv_btn_create(h1, NULL);\n\tlabel_btn = lv_label_create(btn_flash_l4t, NULL);\n\tlv_btn_set_fit(btn_flash_l4t, true, true);\n\tlv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD\"  Flash Linux\");\n\tif (!emmc)\n\t\tlv_obj_align(btn_flash_l4t, btn1, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 3, 0);\n\telse\n\t\tlv_obj_align(btn_flash_l4t, h1, LV_ALIGN_IN_TOP_LEFT, 0, LV_DPI * 5);\n\tlv_btn_set_action(btn_flash_l4t, LV_BTN_ACTION_CLICK, _action_check_flash_linux);\n\n\t// Disable Flash Linux button if partition not found.\n\tu32 size_sct = _get_available_l4t_partition();\n\tif (!l4t_flash_ctxt.offset_sct || size_sct < 0x800000)\n\t{\n\t\tlv_obj_set_click(btn_flash_l4t, false);\n\t\tlv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_INA);\n\t}\n\n\tint part_type_and = _get_available_android_partition();\n\n\t// Create Flash Android button.\n\tbtn_flash_android = lv_btn_create(h1, NULL);\n\tlabel_btn = lv_label_create(btn_flash_android, NULL);\n\tlv_btn_set_fit(btn_flash_android, true, true);\n\tswitch (part_type_and)\n\t{\n\tcase 0: // Disable Flash Android button if partition not found.\n\t\tlv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD\"  Flash Android\");\n\t\tlv_obj_set_click(btn_flash_android, false);\n\t\tlv_btn_set_state(btn_flash_android, LV_BTN_STATE_INA);\n\t\tbreak;\n\tcase 1: // Android 11.\n\t\tlv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD\"  Flash Android 11\");\n\t\tbreak;\n\tcase 2: // Android 13+\n\t\tlv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD\"  Flash Android 13+\");\n\t\tbreak;\n\t}\n\tlv_obj_align(btn_flash_android, btn_flash_l4t, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 3, 0);\n\tlv_btn_set_action(btn_flash_android, LV_BTN_ACTION_CLICK, _action_flash_android);\n\n\t// Create next step button.\n\tbtn1 = lv_btn_create(h1, NULL);\n\tlabel_btn = lv_label_create(btn1, NULL);\n\tlv_btn_set_fit(btn1, true, true);\n\tlv_label_set_static_text(label_btn, SYMBOL_SD\"  Next Step\");\n\tlv_obj_align(btn1, h1, LV_ALIGN_IN_TOP_RIGHT, 0, LV_DPI * 5);\n\tlv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, _create_mbox_partitioning_next);\n\tpart_info.partition_button = btn1;\n\n\tfree(txt_buf);\n\n\tif (!emmc)\n\t\tsd_unmount();\n\telse\n\t\temmc_end();\n\n\treturn LV_RES_OK;\n}\n\nlv_res_t create_window_sd_partition_manager(lv_obj_t *btn)   { return create_window_partition_manager(false); }\nlv_res_t create_window_emmc_partition_manager(lv_obj_t *btn) { return create_window_partition_manager(true);  }\n"
  },
  {
    "path": "nyx/nyx_gui/frontend/gui_tools_partition_manager.h",
    "content": "/*\n * Copyright (c) 2019-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _GUI_TOOLS_PART_MANAGER_H_\n#define _GUI_TOOLS_PART_MANAGER_H_\n\nlv_res_t create_window_sd_partition_manager(lv_obj_t *btn);\nlv_res_t create_window_emmc_partition_manager(lv_obj_t *btn);\n\n#endif\n"
  },
  {
    "path": "nyx/nyx_gui/gfx/gfx.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2022 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <stdarg.h>\n#include <string.h>\n#include \"gfx.h\"\n\n#define COLUMN2_X 640\n\n// Global gfx console and context.\ngfx_ctxt_t gfx_ctxt;\ngfx_con_t gfx_con;\n\nstatic bool gfx_con_init_done = false;\n\nstatic const u8 _gfx_font[] = {\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( )\n\t0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, // Char 033 (!)\n\t0x00, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, // Char 034 (\")\n\t0x00, 0x66, 0x66, 0xFF, 0x66, 0xFF, 0x66, 0x66, // Char 035 (#)\n\t0x00, 0x18, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x18, // Char 036 ($)\n\t0x00, 0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, // Char 037 (%)\n\t0x00, 0x3C, 0x66, 0x3C, 0x1C, 0xE6, 0x66, 0xFC, // Char 038 (&)\n\t0x00, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, // Char 039 (')\n\t0x00, 0x30, 0x18, 0x0C, 0x0C, 0x18, 0x30, 0x00, // Char 040 (()\n\t0x00, 0x0C, 0x18, 0x30, 0x30, 0x18, 0x0C, 0x00, // Char 041 ())\n\t0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, // Char 042 (*)\n\t0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, // Char 043 (+)\n\t0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0C, 0x00, // Char 044 (,)\n\t0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, // Char 045 (-)\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, // Char 046 (.)\n\t0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, // Char 047 (/)\n\t0x00, 0x3C, 0x66, 0x76, 0x6E, 0x66, 0x3C, 0x00, // Char 048 (0)\n\t0x00, 0x18, 0x1C, 0x18, 0x18, 0x18, 0x7E, 0x00, // Char 049 (1)\n\t0x00, 0x3C, 0x62, 0x30, 0x0C, 0x06, 0x7E, 0x00, // Char 050 (2)\n\t0x00, 0x3C, 0x62, 0x38, 0x60, 0x66, 0x3C, 0x00, // Char 051 (3)\n\t0x00, 0x6C, 0x6C, 0x66, 0xFE, 0x60, 0x60, 0x00, // Char 052 (4)\n\t0x00, 0x7E, 0x06, 0x7E, 0x60, 0x66, 0x3C, 0x00, // Char 053 (5)\n\t0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x3C, 0x00, // Char 054 (6)\n\t0x00, 0x7E, 0x30, 0x30, 0x18, 0x18, 0x18, 0x00, // Char 055 (7)\n\t0x00, 0x3C, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, // Char 056 (8)\n\t0x00, 0x3C, 0x66, 0x7C, 0x60, 0x66, 0x3C, 0x00, // Char 057 (9)\n\t0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, // Char 058 (:)\n\t0x00, 0x00, 0x18, 0x00, 0x18, 0x18, 0x0C, 0x00, // Char 059 (;)\n\t0x00, 0x70, 0x1C, 0x06, 0x06, 0x1C, 0x70, 0x00, // Char 060 (<)\n\t0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, // Char 061 (=)\n\t0x00, 0x0E, 0x38, 0x60, 0x60, 0x38, 0x0E, 0x00, // Char 062 (>)\n\t0x00, 0x3C, 0x66, 0x30, 0x18, 0x00, 0x18, 0x00, // Char 063 (?)\n\t0x00, 0x3C, 0x66, 0x76, 0x76, 0x06, 0x46, 0x3C, // Char 064 (@)\n\t0x00, 0x3C, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // Char 065 (A)\n\t0x00, 0x3E, 0x66, 0x3E, 0x66, 0x66, 0x3E, 0x00, // Char 066 (B)\n\t0x00, 0x3C, 0x66, 0x06, 0x06, 0x66, 0x3C, 0x00, // Char 067 (C)\n\t0x00, 0x1E, 0x36, 0x66, 0x66, 0x36, 0x1E, 0x00, // Char 068 (D)\n\t0x00, 0x7E, 0x06, 0x1E, 0x06, 0x06, 0x7E, 0x00, // Char 069 (E)\n\t0x00, 0x3E, 0x06, 0x1E, 0x06, 0x06, 0x06, 0x00, // Char 070 (F)\n\t0x00, 0x3C, 0x66, 0x06, 0x76, 0x66, 0x3C, 0x00, // Char 071 (G)\n\t0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // Char 072 (H)\n\t0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // Char 073 (I)\n\t0x00, 0x78, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, // Char 074 (J)\n\t0x00, 0x66, 0x36, 0x1E, 0x1E, 0x36, 0x66, 0x00, // Char 075 (K)\n\t0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7E, 0x00, // Char 076 (L)\n\t0x00, 0x46, 0x6E, 0x7E, 0x56, 0x46, 0x46, 0x00, // Char 077 (M)\n\t0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00, // Char 078 (N)\n\t0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 079 (O)\n\t0x00, 0x3E, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00, // Char 080 (P)\n\t0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x70, 0x00, // Char 081 (Q)\n\t0x00, 0x3E, 0x66, 0x3E, 0x1E, 0x36, 0x66, 0x00, // Char 082 (R)\n\t0x00, 0x3C, 0x66, 0x0C, 0x30, 0x66, 0x3C, 0x00, // Char 083 (S)\n\t0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // Char 084 (T)\n\t0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 085 (U)\n\t0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // Char 086 (V)\n\t0x00, 0x46, 0x46, 0x56, 0x7E, 0x6E, 0x46, 0x00, // Char 087 (W)\n\t0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, // Char 088 (X)\n\t0x00, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, // Char 089 (Y)\n\t0x00, 0x7E, 0x30, 0x18, 0x0C, 0x06, 0x7E, 0x00, // Char 090 (Z)\n\t0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, // Char 091 ([)\n\t0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00, // Char 092 (\\)\n\t0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, // Char 093 (])\n\t0x00, 0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, // Char 094 (^)\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // Char 095 (_)\n\t0x00, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, // Char 096 (`)\n\t0x00, 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x7C, 0x00, // Char 097 (a)\n\t0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x00, // Char 098 (b)\n\t0x00, 0x00, 0x3C, 0x06, 0x06, 0x06, 0x3C, 0x00, // Char 099 (c)\n\t0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, // Char 100 (d)\n\t0x00, 0x00, 0x3C, 0x66, 0x7E, 0x06, 0x3C, 0x00, // Char 101 (e)\n\t0x00, 0x38, 0x0C, 0x3E, 0x0C, 0x0C, 0x0C, 0x00, // Char 102 (f)\n\t0x00, 0x00, 0x7C, 0x66, 0x7C, 0x40, 0x3C, 0x00, // Char 103 (g)\n\t0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x00, // Char 104 (h)\n\t0x00, 0x18, 0x00, 0x1C, 0x18, 0x18, 0x3C, 0x00, // Char 105 (i)\n\t0x00, 0x30, 0x00, 0x30, 0x30, 0x30, 0x1E, 0x00, // Char 106 (j)\n\t0x00, 0x06, 0x06, 0x36, 0x1E, 0x36, 0x66, 0x00, // Char 107 (k)\n\t0x00, 0x1C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // Char 108 (l)\n\t0x00, 0x00, 0x66, 0xFE, 0xFE, 0xD6, 0xC6, 0x00, // Char 109 (m)\n\t0x00, 0x00, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x00, // Char 110 (n)\n\t0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, // Char 111 (o)\n\t0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x00, // Char 112 (p)\n\t0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00, // Char 113 (q)\n\t0x00, 0x00, 0x3E, 0x66, 0x06, 0x06, 0x06, 0x00, // Char 114 (r)\n\t0x00, 0x00, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x00, // Char 115 (s)\n\t0x00, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x70, 0x00, // Char 116 (t)\n\t0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, // Char 117 (u)\n\t0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // Char 118 (v)\n\t0x00, 0x00, 0xC6, 0xD6, 0xFE, 0x7C, 0x6C, 0x00, // Char 119 (w)\n\t0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, // Char 120 (x)\n\t0x00, 0x00, 0x66, 0x66, 0x7C, 0x60, 0x3C, 0x00, // Char 121 (y)\n\t0x00, 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x7E, 0x00, // Char 122 (z)\n\t0x00, 0x18, 0x08, 0x08, 0x04, 0x08, 0x08, 0x18, // Char 123 ({)\n\t0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, // Char 124 (|)\n\t0x00, 0x0C, 0x08, 0x08, 0x10, 0x08, 0x08, 0x0C, // Char 125 (})\n\t0x00, 0x00, 0x00, 0x4C, 0x32, 0x00, 0x00, 0x00  // Char 126 (~)\n};\n\nvoid gfx_clear_grey(u8 color)\n{\n\tmemset(gfx_ctxt.fb, color, gfx_ctxt.width * gfx_ctxt.height * 4);\n}\n\nvoid gfx_clear_color(u32 color)\n{\n\tfor (u32 i = 0; i < gfx_ctxt.width * gfx_ctxt.height; i++)\n\t\tgfx_ctxt.fb[i] = color;\n}\n\nvoid gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride)\n{\n\tgfx_ctxt.fb = fb;\n\tgfx_ctxt.width = width;\n\tgfx_ctxt.height = height;\n\tgfx_ctxt.stride = stride;\n\n\tgfx_clear_grey(0);\n}\n\nvoid gfx_con_init()\n{\n\tgfx_con.gfx_ctxt = &gfx_ctxt;\n\tgfx_con.fntsz = 16;\n\tgfx_con.x = 0;\n\tgfx_con.y = 0;\n\tgfx_con.col = 0;\n\tgfx_con.savedx = 0;\n\tgfx_con.savedy = 0;\n\tgfx_con.fgcol = TXT_CLR_DEFAULT;\n\tgfx_con.fillbg = 1;\n\tgfx_con.bgcol = TXT_CLR_BG;\n\tgfx_con.mute = 0;\n\n\tgfx_con_init_done = true;\n}\n\nvoid gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol)\n{\n\tgfx_con.fgcol = fgcol;\n\tgfx_con.fillbg = fillbg;\n\tgfx_con.bgcol = bgcol;\n}\n\nvoid gfx_con_getpos(u32 *x, u32 *y, u32 *c)\n{\n\t*x = gfx_con.x;\n\t*y = gfx_con.y;\n\t*c = gfx_con.col;\n}\n\nvoid gfx_con_setpos(u32 x, u32 y, u32 c)\n{\n\tgfx_con.x = x;\n\tgfx_con.y = y;\n\n\tswitch (c)\n\t{\n\tcase GFX_COL_KEEP:\n\t\tbreak;\n\tcase GFX_COL_AUTO:\n\t\tif (x < COLUMN2_X)\n\t\t\tgfx_con.col = 0;\n\t\telse\n\t\t\tgfx_con.col = COLUMN2_X;\n\t\tbreak;\n\tdefault:\n\t\tgfx_con.col = c;\n\t\tbreak;\n\t}\n}\n\nvoid gfx_putc(char c)\n{\n\t// Duplicate code for performance reasons.\n\tswitch (gfx_con.fntsz)\n\t{\n\tcase 16:\n\t\tif (c >= 32 && c <= 126)\n\t\t{\n\t\t\tu8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];\n\t\t\tfor (u32 i = 0; i < 16; i += 2)\n\t\t\t{\n\t\t\t\tu8 v = *cbuf;\n\t\t\t\tfor (u32 k = 0; k < 2; k++)\n\t\t\t\t{\n\t\t\t\t\tu32 fb_off = gfx_con.y + i + k + (gfx_ctxt.width - gfx_con.x) * gfx_ctxt.stride;\n\t\t\t\t\tfor (u32 j = 0; j < 16; j += 2)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (u32 l = 0; l < 2; l++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (v & 1)\n\t\t\t\t\t\t\t\tgfx_ctxt.fb[fb_off - (j + l) * gfx_ctxt.stride] = gfx_con.fgcol;\n\t\t\t\t\t\t\telse if (gfx_con.fillbg)\n\t\t\t\t\t\t\t\tgfx_ctxt.fb[fb_off - (j + l) * gfx_ctxt.stride] = gfx_con.bgcol;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tv >>= 1;\n\t\t\t\t\t}\n\t\t\t\t\tv = *cbuf;\n\t\t\t\t}\n\t\t\t\tcbuf++;\n\t\t\t}\n\t\t\tgfx_con.x += 16;\n\t\t\tif (gfx_con.x > gfx_ctxt.width - 16)\n\t\t\t{\n\t\t\t\tgfx_con.x = gfx_con.col;\n\t\t\t\tgfx_con.y += 16;\n\t\t\t\tif (gfx_con.y > gfx_ctxt.height - 33)\n\t\t\t\t{\n\t\t\t\t\tgfx_con.y = 0;\n\n\t\t\t\t\tif (!gfx_con.col)\n\t\t\t\t\t\tgfx_con.col = COLUMN2_X;\n\t\t\t\t\telse\n\t\t\t\t\t\tgfx_con.col = 0;\n\t\t\t\t\tgfx_con.x = gfx_con.col;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (c == '\\n')\n\t\t{\n\t\t\tgfx_con.x = gfx_con.col;\n\t\t\tgfx_con.y += 16;\n\t\t\tif (gfx_con.y > gfx_ctxt.height - 33)\n\t\t\t{\n\t\t\t\tgfx_con.y = 0;\n\n\t\t\t\tif (!gfx_con.col)\n\t\t\t\t\tgfx_con.col = COLUMN2_X;\n\t\t\t\telse\n\t\t\t\t\tgfx_con.col = 0;\n\t\t\t\tgfx_con.x = gfx_con.col;\n\t\t\t}\n\t\t}\n\t\tbreak;\n\tcase 8:\n\tdefault:\n\t\tif (c >= 32 && c <= 126)\n\t\t{\n\t\t\tu8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];\n\t\t\tfor (u32 i = 0; i < 8; i++)\n\t\t\t{\n\t\t\t\tu8 v = *cbuf++;\n\t\t\t\tu32 fb_off = gfx_con.y + i + (gfx_ctxt.width - gfx_con.x) * gfx_ctxt.stride;\n\t\t\t\tfor (u32 j = 0; j < 8; j++)\n\t\t\t\t{\n\t\t\t\t\tif (v & 1)\n\t\t\t\t\t\tgfx_ctxt.fb[fb_off - (j * gfx_ctxt.stride)] = gfx_con.fgcol;\n\t\t\t\t\telse if (gfx_con.fillbg)\n\t\t\t\t\t\tgfx_ctxt.fb[fb_off - (j * gfx_ctxt.stride)] = gfx_con.bgcol;\n\t\t\t\t\tv >>= 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tgfx_con.x += 8;\n\t\t\tif (gfx_con.x > gfx_ctxt.width / 2 + gfx_con.col - 8)\n\t\t\t{\n\t\t\t\tgfx_con.x = gfx_con.col;\n\t\t\t\tgfx_con.y += 8;\n\t\t\t\tif (gfx_con.y > gfx_ctxt.height - 33)\n\t\t\t\t{\n\t\t\t\t\tgfx_con.y = 0;\n\n\t\t\t\t\tif (!gfx_con.col)\n\t\t\t\t\t\tgfx_con.col = COLUMN2_X;\n\t\t\t\t\telse\n\t\t\t\t\t\tgfx_con.col = 0;\n\t\t\t\t\tgfx_con.x = gfx_con.col;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (c == '\\n')\n\t\t{\n\t\t\tgfx_con.x = gfx_con.col;\n\t\t\tgfx_con.y += 8;\n\t\t\tif (gfx_con.y > gfx_ctxt.height - 33)\n\t\t\t{\n\t\t\t\tgfx_con.y = 0;\n\n\t\t\t\tif (!gfx_con.col)\n\t\t\t\t\tgfx_con.col = COLUMN2_X;\n\t\t\t\telse\n\t\t\t\t\tgfx_con.col = 0;\n\t\t\t\tgfx_con.x = gfx_con.col;\n\t\t\t}\n\t\t}\n\t\tbreak;\n\t}\n}\n\nvoid gfx_puts(const char *s)\n{\n\tif (!s || !gfx_con_init_done || gfx_con.mute)\n\t\treturn;\n\n\tfor (; *s; s++)\n\t\tgfx_putc(*s);\n}\n\nstatic void _gfx_putn(u32 v, int base, char fill, int fcnt)\n{\n\tstatic const char digits[] = \"0123456789ABCDEF\";\n\n\tchar *p;\n\tchar buf[65];\n\tint c = fcnt;\n\tbool negative = false;\n\n\tif (base != 10 && base != 16)\n\t\treturn;\n\n\t// Account for negative numbers.\n\tif (base == 10 && v & 0x80000000)\n\t{\n\t\tnegative = true;\n\t\tv = (int)v * -1;\n\t\tc--;\n\t}\n\n\tp = buf + 64;\n\t*p = 0;\n\tdo\n\t{\n\t\tc--;\n\t\t*--p = digits[v % base];\n\t\tv /= base;\n\t} while (v);\n\n\tif (negative)\n\t\t*--p = '-';\n\n\tif (fill != 0)\n\t{\n\t\twhile (c > 0 && p > buf)\n\t\t{\n\t\t\t*--p = fill;\n\t\t\tc--;\n\t\t}\n\t}\n\n\tgfx_puts(p);\n}\n\nvoid gfx_printf(const char *fmt, ...)\n{\n\tif (!gfx_con_init_done || gfx_con.mute)\n\t\treturn;\n\n\tva_list ap;\n\tint fill, fcnt;\n\n\tva_start(ap, fmt);\n\twhile (*fmt)\n\t{\n\t\tif (*fmt == '%')\n\t\t{\n\t\t\tfmt++;\n\t\t\tfill = 0;\n\t\t\tfcnt = 0;\n\t\t\tif ((*fmt >= '0' && *fmt <= '9') || *fmt == ' ')\n\t\t\t{\n\t\t\t\tfcnt = *fmt;\n\t\t\t\tfmt++;\n\t\t\t\tif (*fmt >= '0' && *fmt <= '9')\n\t\t\t\t{\n\t\t\t\t\tfill = fcnt;\n\t\t\t\t\tfcnt = *fmt - '0';\n\t\t\t\t\tfmt++;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfill = ' ';\n\t\t\t\t\tfcnt -= '0';\n\t\t\t\t}\n\t\t\t}\n\t\t\tswitch(*fmt)\n\t\t\t{\n\t\t\tcase 'c':\n\t\t\t\tgfx_putc(va_arg(ap, u32));\n\t\t\t\tbreak;\n\t\t\tcase 's':\n\t\t\t\tgfx_puts(va_arg(ap, char *));\n\t\t\t\tbreak;\n\t\t\tcase 'd':\n\t\t\t\t_gfx_putn(va_arg(ap, u32), 10, fill, fcnt);\n\t\t\t\tbreak;\n\t\t\tcase 'p':\n\t\t\tcase 'P':\n\t\t\tcase 'x':\n\t\t\tcase 'X':\n\t\t\t\t_gfx_putn(va_arg(ap, u32), 16, fill, fcnt);\n\t\t\t\tbreak;\n\t\t\tcase 'k':\n\t\t\t\tgfx_con.fgcol = va_arg(ap, u32);\n\t\t\t\tbreak;\n\t\t\tcase 'K':\n\t\t\t\tgfx_con.bgcol = va_arg(ap, u32);\n\t\t\t\tgfx_con.fillbg = 1;\n\t\t\t\tbreak;\n\t\t\tcase '%':\n\t\t\t\tgfx_putc('%');\n\t\t\t\tbreak;\n\t\t\tcase '\\0':\n\t\t\t\tgoto out;\n\t\t\tdefault:\n\t\t\t\tgfx_putc('%');\n\t\t\t\tgfx_putc(*fmt);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tgfx_putc(*fmt);\n\t\tfmt++;\n\t}\n\n\tout:\n\tva_end(ap);\n}\n\nstatic void _gfx_cputs(u32 color, const char *s)\n{\n\tgfx_con.fgcol = color;\n\tgfx_puts(s);\n\tgfx_putc('\\n');\n\tgfx_con.fgcol = TXT_CLR_DEFAULT;\n}\n\nvoid gfx_wputs(const char *s) { _gfx_cputs(TXT_CLR_WARNING, s); }\nvoid gfx_eputs(const char *s) { _gfx_cputs(TXT_CLR_ERROR,   s); }\n\nvoid gfx_hexdump(u32 base, const void *buf, u32 len)\n{\n\tif (!gfx_con_init_done || gfx_con.mute)\n\t\treturn;\n\n\tu8 *buff = (u8 *)buf;\n\n\tu8 prevFontSize = gfx_con.fntsz;\n\tgfx_con.fntsz = 8;\n\tfor (u32 i = 0; i < len; i++)\n\t{\n\t\tif (i % 0x10 == 0)\n\t\t{\n\t\t\tif (i != 0)\n\t\t\t{\n\t\t\t\tgfx_puts(\"| \");\n\t\t\t\tfor (u32 j = 0; j < 0x10; j++)\n\t\t\t\t{\n\t\t\t\t\tu8 c = buff[i - 0x10 + j];\n\t\t\t\t\tif (c >= 32 && c <= 126)\n\t\t\t\t\t\tgfx_putc(c);\n\t\t\t\t\telse\n\t\t\t\t\t\tgfx_putc('.');\n\t\t\t\t}\n\t\t\t\tgfx_putc('\\n');\n\t\t\t}\n\t\t\tgfx_printf(\"%08x: \", base + i);\n\t\t}\n\t\tgfx_printf(\"%02x \", buff[i]);\n\t\tif (i == len - 1)\n\t\t{\n\t\t\tint ln = len % 0x10 != 0;\n\t\t\tu32 k = 0x10 - 1;\n\t\t\tif (ln)\n\t\t\t{\n\t\t\t\tk = (len & 0xF) - 1;\n\t\t\t\tfor (u32 j = 0; j < 0x10 - k; j++)\n\t\t\t\t\tgfx_puts(\"   \");\n\t\t\t}\n\t\t\tgfx_puts(\"| \");\n\t\t\tfor (u32 j = 0; j < (ln ? k : k + 1); j++)\n\t\t\t{\n\t\t\t\tu8 c = buff[i - k + j];\n\t\t\t\tif (c >= 32 && c <= 126)\n\t\t\t\t\tgfx_putc(c);\n\t\t\t\telse\n\t\t\t\t\tgfx_putc('.');\n\t\t\t}\n\t\t\tgfx_putc('\\n');\n\t\t}\n\t}\n\tgfx_putc('\\n');\n\tgfx_con.fntsz = prevFontSize;\n}\n\nvoid gfx_set_pixel(u32 x, u32 y, u32 color)\n{\n\tgfx_ctxt.fb[y + (gfx_ctxt.width - x) * gfx_ctxt.stride] = color;\n}\n\nvoid gfx_set_rect_pitch(u32 *fb, const u32 *buf, u32 stride, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2)\n{\n\tu32 *ptr = (u32 *)buf;\n\tu32 line_size = pos_x2 - pos_x + 1;\n\t//ptr = gfx_debug_rect(buf, pos_x, pos_y, pos_x2, pos_y2);\n\tfor (u32 y = pos_y; y <= pos_y2; y++)\n\t{\n\t\tmemcpy(&fb[pos_x + y * stride], ptr, line_size * sizeof(u32));\n\t\tptr += line_size;\n\t}\n}\n\nvoid gfx_set_rect_land_pitch(u32 *fb, const u32 *buf, u32 stride, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2)\n{\n\tu32 *ptr = (u32 *)buf;\n\n\tu32 pixels_w = pos_x2 - pos_x + 1;\n\n\tif (!(pixels_w % 8))\n\t{\n\t\tfor (u32 y = pos_y; y <= pos_y2; y++)\n\t\t\tfor (u32 x = pos_x; x <= pos_x2; x += 8)\n\t\t\t{\n\t\t\t\tu32 *fbx = &fb[x * stride + y];\n\n\t\t\t\tfbx[0]          = *ptr++;\n\t\t\t\tfbx[stride]     = *ptr++;\n\t\t\t\tfbx[stride * 2] = *ptr++;\n\t\t\t\tfbx[stride * 3] = *ptr++;\n\t\t\t\tfbx[stride * 4] = *ptr++;\n\t\t\t\tfbx[stride * 5] = *ptr++;\n\t\t\t\tfbx[stride * 6] = *ptr++;\n\t\t\t\tfbx[stride * 7] = *ptr++;\n\t\t\t}\n\t}\n\telse\n\t{\n\t\tfor (u32 y = pos_y; y < (pos_y2 + 1); y++)\n\t\t\tfor (u32 x = pos_x; x < (pos_x2 + 1); x++)\n\t\t\t\tfb[x * stride + y] = *ptr++;\n\t}\n}\n\nvoid gfx_set_rect_land_block(u32 *fb, const u32 *buf, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2)\n{\n\tu32 *ptr = (u32 *)buf;\n\tu32 GOB_address = 0;\n\tu32 addr = 0;\n\tu32 x2 = 0;\n\n\t// Optimized\n\tu32 image_width_in_gobs = 655360; //1280\n\tfor (u32 y = pos_y; y <= pos_y2; y++)\n\t{\n\t\tfor (u32 x = pos_x; x <= pos_x2; x++)\n\t\t{\n\t\t\tGOB_address = (y >> 7) * image_width_in_gobs + ((x >> 4) << 13) + (((y % 128) >> 3) << 9);\n\n\t\t\tx2 = x << 2;\n\t\t\taddr = GOB_address\n\t\t\t\t+ (((x2 % 64) >> 5) << 8)\n\t\t\t\t+ (((y % 8) >> 1) << 6)\n\t\t\t\t+ (((x2 % 32) >> 4) << 5)\n\t\t\t\t+ ((y % 2) << 4) + (x2 % 16);\n\n\t\t\t*(u32 *)(fb + (addr >> 2)) = *ptr++;\n\t\t}\n\t}\n\n\t// Proper\n\t// u32 block_height = 16;\n\t// u32 image_width_in_gobs = (512 * block_height * 1280 * 4) / 64;\n\t// for (u32 y = pos_y; y <= pos_y2; y++)\n\t// {\n\t// \tfor (int x = pos_x; x <= pos_x2; x++)\n\t// \t{\n\t// \t\tGOB_address = (y / (8 * block_height)) * image_width_in_gobs + ((x * 4 / 64) * 512 * block_height) + ((y % (8 * block_height) / 8) * 512);\n\n\t// \t\tx2 = x << 2;\n\t// \t\taddr = GOB_address\n\t// \t\t\t+ (((x2 % 64) >> 5) << 8)\n\t// \t\t\t+ (((y % 8) >> 1) << 6)\n\t// \t\t\t+ (((x2 % 32) >> 4) << 5)\n\t// \t\t\t+ ((y % 2) << 4) + (x2 % 16);\n\n\t// \t\t*(u32 *)(gfx_ctxt.fb + (addr >> 2)) = *ptr++;\n\t// \t}\n\t// }\n}\n"
  },
  {
    "path": "nyx/nyx_gui/gfx/gfx.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2021 CTCaer\n * Copyright (c) 2018 M4xw\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _GFX_H_\n#define _GFX_H_\n\n#include <bdk.h>\n\n#define GFX_COL_KEEP 0xFFFE\n#define GFX_COL_AUTO 0xFFFF\n\n#define TXT_CLR_BG        0xFF000000 // Black.\n#define TXT_CLR_DEFAULT   0xFFFFFFFF // White.\n#define TXT_CLR_WARNING   0xFFFFDD00 // Yellow.\n#define TXT_CLR_ERROR     0xFFFF0000 // Red.\n#define TXT_CLR_CYAN_L    0xFF00CCFF // Light Cyan.  0xFF0099EE 0xFF00DDFF FF0AB9E6\n#define TXT_CLR_TURQUOISE 0xFF00FFCC // Turquoise.\n#define TXT_CLR_ORANGE    0xFFFFBA00 // Orange.\n#define TXT_CLR_GREENISH  0xFF96FF00 // Toxic Green. 0xFFAEFD14 0xFFC7EA46\n#define TXT_CLR_GREEN_D   0xFF008800 // Dark Green.\n#define TXT_CLR_RED_D     0xFF880000 // Dark Red.    0xFF800000\n#define TXT_CLR_GREY_D    0xFF303030 // Darkest Grey.\n#define TXT_CLR_GREY_DM   0xFF444444 // Darker Grey.\n#define TXT_CLR_GREY_M    0xFF555555 // Dark Grey.\n#define TXT_CLR_GREY      0xFF888888 // Grey.\n\n#define EPRINTF(text) gfx_eputs(text)\n#define EPRINTFARGS(text, args...) gfx_printf(\"%k\"text\"%k\\n\", TXT_CLR_ERROR,   args, TXT_CLR_DEFAULT)\n#define WPRINTF(text) gfx_wputs(text)\n#define WPRINTFARGS(text, args...) gfx_printf(\"%k\"text\"%k\\n\", TXT_CLR_WARNING, args, TXT_CLR_DEFAULT)\n\ntypedef struct _gfx_ctxt_t\n{\n\tu32 *fb;\n\tu32 width;\n\tu32 height;\n\tu32 stride;\n} gfx_ctxt_t;\n\ntypedef struct _gfx_con_t\n{\n\tgfx_ctxt_t *gfx_ctxt;\n\tu32 fntsz;\n\tu32 x;\n\tu32 y;\n\tu32 col;\n\tu32 savedx;\n\tu32 savedy;\n\tu32 savedcol;\n\tu32 fgcol;\n\tint fillbg;\n\tu32 bgcol;\n\tbool mute;\n} gfx_con_t;\n\n// Global gfx console and context.\nextern gfx_ctxt_t gfx_ctxt;\nextern gfx_con_t gfx_con;\n\nvoid gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride);\nvoid gfx_clear_grey(u8 color);\nvoid gfx_clear_color(u32 color);\nvoid gfx_con_init();\nvoid gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol);\nvoid gfx_con_getpos(u32 *x, u32 *y, u32 *c);\nvoid gfx_con_setpos(u32 x, u32 y, u32 c);\nvoid gfx_putc(char c);\nvoid gfx_puts(const char *s);\nvoid gfx_wputs(const char *s);\nvoid gfx_eputs(const char *s);\nvoid gfx_printf(const char *fmt, ...) /* __attribute__((format(printf, 1, 2))) */;\nvoid gfx_hexdump(u32 base, const void *buf, u32 len);\n\nvoid gfx_set_pixel(u32 x, u32 y, u32 color);\n\nvoid gfx_set_rect_pitch(u32 *fb, const u32 *buf, u32 stride, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2);\nvoid gfx_set_rect_land_pitch(u32 *fb, const u32 *buf, u32 stride, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2);\nvoid gfx_set_rect_land_block(u32 *fb, const u32 *buf, u32 pos_x, u32 pos_y, u32 pos_x2, u32 pos_y2);\n\n#endif\n"
  },
  {
    "path": "nyx/nyx_gui/gfx/logos-gui.h",
    "content": "/*\n * Copyright (c) 2018-2024 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _LOGOS_GUI_H_\n#define _LOGOS_GUI_H_\n\n#include <bdk.h>\n\n#include <libs/lv_conf.h>\n#include <libs/lvgl/lv_draw/lv_draw_img.h>\n\n#define HEKATE_LOGO\n\nconst u8 touch_cursor_map[] = {\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04,\n\t0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07,\n\t0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,\n\t0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0c,\n\t0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18,\n\t0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1b,\n\t0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x17,\n\t0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1f,\n\t0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x30,\n\t0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x33,\n\t0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2c,\n\t0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x14,\n\t0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,\n\t0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x17,\n\t0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x38,\n\t0x07, 0x07, 0x07, 0x44, 0x0d, 0x0d, 0x0d, 0x4c, 0x16, 0x16, 0x16, 0x53,\n\t0x1e, 0x1e, 0x1e, 0x54, 0x21, 0x21, 0x21, 0x57, 0x21, 0x21, 0x21, 0x57,\n\t0x18, 0x18, 0x18, 0x54, 0x10, 0x10, 0x10, 0x50, 0x07, 0x07, 0x07, 0x4c,\n\t0x04, 0x04, 0x04, 0x44, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x2b,\n\t0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x2b,\n\t0x00, 0x00, 0x00, 0x38, 0x0a, 0x0a, 0x0a, 0x4b, 0x1d, 0x1d, 0x1d, 0x58,\n\t0x38, 0x38, 0x38, 0x64, 0x59, 0x59, 0x59, 0x6c, 0x73, 0x73, 0x73, 0x70,\n\t0x84, 0x84, 0x84, 0x74, 0x8b, 0x8b, 0x8b, 0x74, 0x86, 0x86, 0x86, 0x74,\n\t0x76, 0x76, 0x76, 0x73, 0x5c, 0x5c, 0x5c, 0x6f, 0x3a, 0x3a, 0x3a, 0x6b,\n\t0x1d, 0x1d, 0x1d, 0x60, 0x09, 0x09, 0x09, 0x53, 0x04, 0x04, 0x04, 0x44,\n\t0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x13,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10,\n\t0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x30, 0x04, 0x04, 0x04, 0x44,\n\t0x15, 0x15, 0x15, 0x54, 0x41, 0x41, 0x41, 0x67, 0x7b, 0x7b, 0x7b, 0x74,\n\t0xb2, 0xb2, 0xb2, 0x7b, 0xe1, 0xe1, 0xe1, 0x7f, 0xf7, 0xf7, 0xf7, 0x7f,\n\t0xfd, 0xfd, 0xfd, 0x80, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,\n\t0xf9, 0xf9, 0xf9, 0x7f, 0xe5, 0xe5, 0xe5, 0x7f, 0xb9, 0xb9, 0xb9, 0x7c,\n\t0x80, 0x80, 0x80, 0x78, 0x46, 0x46, 0x46, 0x6f, 0x1b, 0x1b, 0x1b, 0x5f,\n\t0x03, 0x03, 0x03, 0x48, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x20,\n\t0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c,\n\t0x00, 0x00, 0x00, 0x30, 0x04, 0x04, 0x04, 0x47, 0x21, 0x21, 0x21, 0x5f,\n\t0x63, 0x63, 0x63, 0x70, 0xb9, 0xb9, 0xb9, 0x7b, 0xf5, 0xf5, 0xf5, 0x7f,\n\t0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xf9, 0xf9, 0xf9, 0x80, 0xc2, 0xc2, 0xc2, 0x7c, 0x6d, 0x6d, 0x6d, 0x74,\n\t0x27, 0x27, 0x27, 0x63, 0x07, 0x07, 0x07, 0x4b, 0x00, 0x00, 0x00, 0x34,\n\t0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x07,\n\t0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2b,\n\t0x04, 0x04, 0x04, 0x43, 0x23, 0x23, 0x23, 0x5f, 0x7a, 0x7a, 0x7a, 0x74,\n\t0xdb, 0xdb, 0xdb, 0x7f, 0xfd, 0xfd, 0xfd, 0x7f, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xe3, 0xe3, 0xe3, 0x7f,\n\t0x87, 0x87, 0x87, 0x77, 0x2e, 0x2e, 0x2e, 0x63, 0x07, 0x07, 0x07, 0x4b,\n\t0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c,\n\t0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,\n\t0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x38,\n\t0x1d, 0x1d, 0x1d, 0x57, 0x79, 0x79, 0x79, 0x73, 0xe5, 0xe5, 0xe5, 0x7f,\n\t0xfd, 0xfd, 0xfd, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xef, 0xef, 0xef, 0x7f, 0x86, 0x86, 0x86, 0x77, 0x26, 0x26, 0x26, 0x5f,\n\t0x04, 0x04, 0x04, 0x44, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x17,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2f, 0x0e, 0x0e, 0x0e, 0x4b,\n\t0x5d, 0x5d, 0x5d, 0x6b, 0xda, 0xda, 0xda, 0x7c, 0xfd, 0xfd, 0xfd, 0x7f,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xe5, 0xe5, 0xe5, 0x7f, 0x69, 0x69, 0x69, 0x70,\n\t0x15, 0x15, 0x15, 0x57, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x20,\n\t0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0f,\n\t0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x3b, 0x30, 0x30, 0x30, 0x5b,\n\t0xb5, 0xb5, 0xb5, 0x78, 0xf9, 0xf9, 0xf9, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xc1, 0xc1, 0xc1, 0x7c,\n\t0x3c, 0x3c, 0x3c, 0x67, 0x07, 0x07, 0x07, 0x48, 0x00, 0x00, 0x00, 0x2c,\n\t0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03,\n\t0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17,\n\t0x00, 0x00, 0x00, 0x2c, 0x0a, 0x0a, 0x0a, 0x48, 0x6a, 0x6a, 0x6a, 0x6c,\n\t0xef, 0xef, 0xef, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xf9, 0xf9, 0xf9, 0x80,\n\t0x77, 0x77, 0x77, 0x74, 0x15, 0x15, 0x15, 0x57, 0x00, 0x00, 0x00, 0x38,\n\t0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x03,\n\t0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1f,\n\t0x00, 0x00, 0x00, 0x38, 0x1d, 0x1d, 0x1d, 0x58, 0xa7, 0xa7, 0xa7, 0x77,\n\t0xf9, 0xf9, 0xf9, 0x7f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xb4, 0xb4, 0xb4, 0x7b, 0x2a, 0x2a, 0x2a, 0x60, 0x04, 0x04, 0x04, 0x44,\n\t0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x04,\n\t0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x27,\n\t0x04, 0x04, 0x04, 0x44, 0x36, 0x36, 0x36, 0x64, 0xd6, 0xd6, 0xd6, 0x7c,\n\t0xfd, 0xfd, 0xfd, 0x7f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xe5, 0xe5, 0xe5, 0x7f, 0x46, 0x46, 0x46, 0x6b, 0x07, 0x07, 0x07, 0x4c,\n\t0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x07,\n\t0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x2c,\n\t0x03, 0x03, 0x03, 0x4b, 0x4e, 0x4e, 0x4e, 0x6c, 0xeb, 0xeb, 0xeb, 0x7f,\n\t0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xf9, 0xf9, 0xf9, 0x7f, 0x60, 0x60, 0x60, 0x6f, 0x0a, 0x0a, 0x0a, 0x50,\n\t0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2f,\n\t0x06, 0x06, 0x06, 0x4f, 0x5e, 0x5e, 0x5e, 0x6f, 0xf1, 0xf1, 0xf1, 0x80,\n\t0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0x71, 0x71, 0x71, 0x70, 0x0f, 0x0f, 0x0f, 0x53,\n\t0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2f,\n\t0x06, 0x06, 0x06, 0x4f, 0x63, 0x63, 0x63, 0x6f, 0xf3, 0xf3, 0xf3, 0x7f,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x7f, 0x74, 0x74, 0x74, 0x73, 0x0f, 0x0f, 0x0f, 0x53,\n\t0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2c,\n\t0x03, 0x03, 0x03, 0x4b, 0x5a, 0x5a, 0x5a, 0x6c, 0xf1, 0xf1, 0xf1, 0x7f,\n\t0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xfd, 0xfd, 0xfd, 0x7f, 0x6b, 0x6b, 0x6b, 0x70, 0x10, 0x10, 0x10, 0x50,\n\t0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x28,\n\t0x04, 0x04, 0x04, 0x47, 0x45, 0x45, 0x45, 0x67, 0xe5, 0xe5, 0xe5, 0x7f,\n\t0xfd, 0xfd, 0xfd, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xf3, 0xf3, 0xf3, 0x7f, 0x57, 0x57, 0x57, 0x6c, 0x0a, 0x0a, 0x0a, 0x4c,\n\t0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x07,\n\t0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x20,\n\t0x00, 0x00, 0x00, 0x3c, 0x2e, 0x2e, 0x2e, 0x5f, 0xc7, 0xc7, 0xc7, 0x7b,\n\t0xfb, 0xfb, 0xfb, 0x7f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xd4, 0xd4, 0xd4, 0x7c, 0x3d, 0x3d, 0x3d, 0x64, 0x04, 0x04, 0x04, 0x44,\n\t0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07,\n\t0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x1b,\n\t0x00, 0x00, 0x00, 0x33, 0x16, 0x16, 0x16, 0x53, 0x8f, 0x8f, 0x8f, 0x74,\n\t0xf5, 0xf5, 0xf5, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xfd, 0xfd, 0xfd, 0x80,\n\t0x9f, 0x9f, 0x9f, 0x77, 0x23, 0x23, 0x23, 0x58, 0x00, 0x00, 0x00, 0x38,\n\t0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14,\n\t0x00, 0x00, 0x00, 0x28, 0x07, 0x07, 0x07, 0x47, 0x4e, 0x4e, 0x4e, 0x68,\n\t0xdf, 0xdf, 0xdf, 0x7f, 0xfd, 0xfd, 0xfd, 0x7f, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xeb, 0xeb, 0xeb, 0x7f,\n\t0x5f, 0x5f, 0x5f, 0x6b, 0x0e, 0x0e, 0x0e, 0x4b, 0x00, 0x00, 0x00, 0x2f,\n\t0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c,\n\t0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x38, 0x1e, 0x1e, 0x1e, 0x57,\n\t0x93, 0x93, 0x93, 0x74, 0xf1, 0xf1, 0xf1, 0x7f, 0xff, 0xff, 0xff, 0x7f,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xf7, 0xf7, 0xf7, 0x80, 0xa4, 0xa4, 0xa4, 0x77,\n\t0x2b, 0x2b, 0x2b, 0x58, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x20,\n\t0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2b, 0x04, 0x04, 0x04, 0x44,\n\t0x3c, 0x3c, 0x3c, 0x63, 0xbc, 0xbc, 0xbc, 0x7b, 0xf5, 0xf5, 0xf5, 0x80,\n\t0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xfb, 0xfb, 0xfb, 0x7f, 0xc9, 0xc9, 0xc9, 0x7b, 0x4d, 0x4d, 0x4d, 0x64,\n\t0x0f, 0x0f, 0x0f, 0x47, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x17,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,\n\t0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x33,\n\t0x0e, 0x0e, 0x0e, 0x4b, 0x54, 0x54, 0x54, 0x67, 0xc5, 0xc5, 0xc5, 0x7c,\n\t0xf3, 0xf3, 0xf3, 0x80, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xf7, 0xf7, 0xf7, 0x80,\n\t0xd2, 0xd2, 0xd2, 0x7c, 0x63, 0x63, 0x63, 0x6b, 0x14, 0x14, 0x14, 0x4c,\n\t0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0f,\n\t0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,\n\t0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20,\n\t0x00, 0x00, 0x00, 0x34, 0x11, 0x11, 0x11, 0x4c, 0x54, 0x54, 0x54, 0x67,\n\t0xb8, 0xb8, 0xb8, 0x7b, 0xe9, 0xe9, 0xe9, 0x7f, 0xfd, 0xfd, 0xfd, 0x7f,\n\t0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80,\n\t0xfd, 0xfd, 0xfd, 0x80, 0xef, 0xef, 0xef, 0x7f, 0xc3, 0xc3, 0xc3, 0x7b,\n\t0x61, 0x61, 0x61, 0x68, 0x17, 0x17, 0x17, 0x4f, 0x00, 0x00, 0x00, 0x34,\n\t0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x07,\n\t0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x13,\n\t0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x34, 0x0e, 0x0e, 0x0e, 0x4b,\n\t0x3c, 0x3c, 0x3c, 0x63, 0x90, 0x90, 0x90, 0x74, 0xd2, 0xd2, 0xd2, 0x7c,\n\t0xe9, 0xe9, 0xe9, 0x7f, 0xf7, 0xf7, 0xf7, 0x7f, 0xfd, 0xfd, 0xfd, 0x7f,\n\t0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,\n\t0xfd, 0xfd, 0xfd, 0x80, 0xf7, 0xf7, 0xf7, 0x80, 0xeb, 0xeb, 0xeb, 0x7f,\n\t0xd9, 0xd9, 0xd9, 0x7f, 0x9b, 0x9b, 0x9b, 0x74, 0x46, 0x46, 0x46, 0x63,\n\t0x11, 0x11, 0x11, 0x4b, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x23,\n\t0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x33,\n\t0x04, 0x04, 0x04, 0x44, 0x1b, 0x1b, 0x1b, 0x54, 0x4a, 0x4a, 0x4a, 0x67,\n\t0x87, 0x87, 0x87, 0x73, 0xb8, 0xb8, 0xb8, 0x7b, 0xd2, 0xd2, 0xd2, 0x7c,\n\t0xdd, 0xdd, 0xdd, 0x7f, 0xdf, 0xdf, 0xdf, 0x7f, 0xdd, 0xdd, 0xdd, 0x7f,\n\t0xd5, 0xd5, 0xd5, 0x7f, 0xbf, 0xbf, 0xbf, 0x7b, 0x90, 0x90, 0x90, 0x73,\n\t0x53, 0x53, 0x53, 0x68, 0x23, 0x23, 0x23, 0x58, 0x07, 0x07, 0x07, 0x44,\n\t0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x13,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1c,\n\t0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x38, 0x07, 0x07, 0x07, 0x47,\n\t0x16, 0x16, 0x16, 0x53, 0x29, 0x29, 0x29, 0x5c, 0x3f, 0x3f, 0x3f, 0x67,\n\t0x4f, 0x4f, 0x4f, 0x6b, 0x57, 0x57, 0x57, 0x6c, 0x53, 0x53, 0x53, 0x6c,\n\t0x43, 0x43, 0x43, 0x67, 0x2e, 0x2e, 0x2e, 0x5f, 0x16, 0x16, 0x16, 0x53,\n\t0x07, 0x07, 0x07, 0x47, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x2b,\n\t0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0c,\n\t0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x28,\n\t0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3c, 0x04, 0x04, 0x04, 0x47,\n\t0x03, 0x03, 0x03, 0x4b, 0x07, 0x07, 0x07, 0x4f, 0x07, 0x07, 0x07, 0x4c,\n\t0x04, 0x04, 0x04, 0x44, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x33,\n\t0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x17,\n\t0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04,\n\t0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x14,\n\t0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x28,\n\t0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x2c,\n\t0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1b,\n\t0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x08,\n\t0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07,\n\t0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x13,\n\t0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x17,\n\t0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0b,\n\t0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07,\n\t0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07,\n\t0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n};\n\nconst lv_img_dsc_t touch_cursor = {\n\t.header.always_zero = 0,\n\t.header.w = 33,\n\t.header.h = 33,\n\t.data_size = 1089 * LV_IMG_PX_SIZE_ALPHA_BYTE,\n\t.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA,\n\t.data = touch_cursor_map,\n};\n\n#ifdef HEKATE_LOGO\n\nconst lv_img_dsc_t hekate_logo = {\n\t.header.always_zero = 0,\n\t.header.w = 193,\n\t.header.h = 76,\n\t.data_size = 14668 * LV_IMG_PX_SIZE_ALPHA_BYTE,\n\t.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA,\n\t.data = (const uint8_t *)(NYX_RES_ADDR + 0x1D900),\n};\n\nconst lv_img_dsc_t ctcaer_logo = {\n\t.header.always_zero = 0,\n\t.header.w = 147,\n\t.header.h = 76,\n\t.data_size = 11172 * LV_IMG_PX_SIZE_ALPHA_BYTE,\n\t.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA,\n\t.data = (const uint8_t *)(NYX_RES_ADDR + 0x2BF00),\n};\n\n#endif\n\n#endif\n"
  },
  {
    "path": "nyx/nyx_gui/hos/hos.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018 st4rk\n * Copyright (c) 2018 Ced2911\n * Copyright (c) 2018-2025 CTCaer\n * Copyright (c) 2018 balika011\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <bdk.h>\n\n#include \"hos.h\"\n#include \"../config.h\"\n\nu8 *cal0_buf = NULL;\n\nstatic const u8 eks_keyseeds[HOS_MKEY_VER_600 - HOS_MKEY_VER_100 + 1][SE_KEY_128_SIZE] = {\n\t{ 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3 }, // 1.0.0.\n\t{ 0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC }, // 3.0.0.\n\t{ 0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B }, // 3.0.1.\n\t{ 0x2D, 0x1F, 0x48, 0x80, 0xED, 0xEC, 0xED, 0x3E, 0x3C, 0xF2, 0x48, 0xB5, 0x65, 0x7D, 0xF7, 0xBE }, // 4.0.0.\n\t{ 0xBB, 0x5A, 0x01, 0xF9, 0x88, 0xAF, 0xF5, 0xFC, 0x6C, 0xFF, 0x07, 0x9E, 0x13, 0x3C, 0x39, 0x80 }, // 5.0.0.\n\t{ 0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0 }  // 6.0.0.\n};\n\nstatic const u8 cmac_keyseed[SE_KEY_128_SIZE] =\n\t{ 0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5 };\n\nstatic const u8 master_keyseed_retail[SE_KEY_128_SIZE] =\n\t{ 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C };\n\n// Unused in this context.\n//static const u8 master_keyseed_4xx[SE_KEY_128_SIZE] =\n//\t{ 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 };\n\nstatic const u8 master_kekseed_620[SE_KEY_128_SIZE] =\n\t{ 0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A };\n\n//!TODO: Update on mkey changes.\nstatic const u8 master_kekseed_t210_max[SE_KEY_128_SIZE] =\n\t{ 0x15, 0xAC, 0x96, 0x34, 0xF5, 0x32, 0x56, 0x68, 0xFE, 0x5B, 0x9D, 0xD7, 0xED, 0x19, 0xB7, 0x8E }; // 22.0.0.\n\n//!TODO: Update on mkey changes.\nstatic const u8 master_kekseed_t210b01[HOS_MKEY_VER_MAX - HOS_MKEY_VER_600 + 1][SE_KEY_128_SIZE] = {\n\t{ 0x77, 0x60, 0x5A, 0xD2, 0xEE, 0x6E, 0xF8, 0x3C, 0x3F, 0x72, 0xE2, 0x59, 0x9D, 0xAC, 0x5E, 0x56 }, // 6.0.0.\n\t{ 0x1E, 0x80, 0xB8, 0x17, 0x3E, 0xC0, 0x60, 0xAA, 0x11, 0xBE, 0x1A, 0x4A, 0xA6, 0x6F, 0xE4, 0xAE }, // 6.2.0.\n\t{ 0x94, 0x08, 0x67, 0xBD, 0x0A, 0x00, 0x38, 0x84, 0x11, 0xD3, 0x1A, 0xDB, 0xDD, 0x8D, 0xF1, 0x8A }, // 7.0.0.\n\t{ 0x5C, 0x24, 0xE3, 0xB8, 0xB4, 0xF7, 0x00, 0xC2, 0x3C, 0xFD, 0x0A, 0xCE, 0x13, 0xC3, 0xDC, 0x23 }, // 8.1.0.\n\t{ 0x86, 0x69, 0xF0, 0x09, 0x87, 0xC8, 0x05, 0xAE, 0xB5, 0x7B, 0x48, 0x74, 0xDE, 0x62, 0xA6, 0x13 }, // 9.0.0.\n\t{ 0x0E, 0x44, 0x0C, 0xED, 0xB4, 0x36, 0xC0, 0x3F, 0xAA, 0x1D, 0xAE, 0xBF, 0x62, 0xB1, 0x09, 0x82 }, // 9.1.0.\n\t{ 0xE5, 0x41, 0xAC, 0xEC, 0xD1, 0xA7, 0xD1, 0xAB, 0xED, 0x03, 0x77, 0xF1, 0x27, 0xCA, 0xF8, 0xF1 }, // 12.1.0.\n\t{ 0x52, 0x71, 0x9B, 0xDF, 0xA7, 0x8B, 0x61, 0xD8, 0xD5, 0x85, 0x11, 0xE4, 0x8E, 0x4F, 0x74, 0xC6 }, // 13.0.0.\n\t{ 0xD2, 0x68, 0xC6, 0x53, 0x9D, 0x94, 0xF9, 0xA8, 0xA5, 0xA8, 0xA7, 0xC8, 0x8F, 0x53, 0x4B, 0x7A }, // 14.0.0.\n\t{ 0xEC, 0x61, 0xBC, 0x82, 0x1E, 0x0F, 0x5A, 0xC3, 0x2B, 0x64, 0x3F, 0x9D, 0xD6, 0x19, 0x22, 0x2D }, // 15.0.0.\n\t{ 0xA5, 0xEC, 0x16, 0x39, 0x1A, 0x30, 0x16, 0x08, 0x2E, 0xCF, 0x09, 0x6F, 0x5E, 0x7C, 0xEE, 0xA9 }, // 16.0.0.\n\t{ 0x8D, 0xEE, 0x9E, 0x11, 0x36, 0x3A, 0x9B, 0x0A, 0x6A, 0xC7, 0xBB, 0xE9, 0xD1, 0x03, 0xF7, 0x80 }, // 17.0.0.\n\t{ 0x4F, 0x41, 0x3C, 0x3B, 0xFB, 0x6A, 0x01, 0x2A, 0x68, 0x9F, 0x83, 0xE9, 0x53, 0xBD, 0x16, 0xD2 }, // 18.0.0.\n\t{ 0x31, 0xBE, 0x25, 0xFB, 0xDB, 0xB4, 0xEE, 0x49, 0x5C, 0x77, 0x05, 0xC2, 0x36, 0x9F, 0x34, 0x80 }, // 19.0.0.\n\t{ 0x1A, 0x31, 0x62, 0x87, 0xA8, 0x09, 0xCA, 0xF8, 0x69, 0x15, 0x45, 0xC2, 0x6B, 0xAA, 0x5A, 0x8A }, // 20.0.0.\n\t{ 0xEB, 0xF3, 0x5B, 0x2D, 0x4A, 0x2D, 0xCE, 0x45, 0x3A, 0x6F, 0x61, 0x38, 0x0B, 0x00, 0x3B, 0x46 }, // 21.0.0.\n\t{ 0x82, 0xE2, 0x0A, 0x59, 0x67, 0xDF, 0xBF, 0x51, 0x47, 0x62, 0x11, 0xF2, 0x41, 0xD3, 0xEE, 0x13 }, // 22.0.0.\n};\n\nstatic const u8 console_keyseed[SE_KEY_128_SIZE] =\n\t{ 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 };\n\nstatic const u8 console_keyseed_4xx[SE_KEY_128_SIZE] =\n\t{ 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 };\n\nconst u8 package2_keyseed[SE_KEY_128_SIZE] =\n\t{ 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 };\n\n//!TODO: Update on mkey changes.\nstatic const u8 mkey_vectors[HOS_MKEY_VER_MAX + 1][SE_KEY_128_SIZE] = {\n\t{ 0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D }, // Zeroes  encrypted with mkey 00.\n\t{ 0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD }, // Mkey 00 encrypted with mkey 01.\n\t{ 0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72 }, // Mkey 01 encrypted with mkey 02.\n\t{ 0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07 }, // Mkey 02 encrypted with mkey 03.\n\t{ 0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9 }, // Mkey 03 encrypted with mkey 04.\n\t{ 0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE }, // Mkey 04 encrypted with mkey 05.\n\t{ 0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57 }, // Mkey 05 encrypted with mkey 06.\n\t{ 0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F }, // Mkey 06 encrypted with mkey 07.\n\t{ 0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29 }, // Mkey 07 encrypted with mkey 08.\n\t{ 0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80 }, // Mkey 08 encrypted with mkey 09.\n\t{ 0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A }, // Mkey 09 encrypted with mkey 10.\n\t{ 0xC1, 0x8D, 0x16, 0xBB, 0x2A, 0xE4, 0x1D, 0xD4, 0xC2, 0xC1, 0xB6, 0x40, 0x94, 0x35, 0x63, 0x98 }, // Mkey 10 encrypted with mkey 11.\n\t{ 0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06 }, // Mkey 11 encrypted with mkey 12.\n\t{ 0x83, 0x67, 0xAF, 0x01, 0xCF, 0x93, 0xA1, 0xAB, 0x80, 0x45, 0xF7, 0x3F, 0x72, 0xFD, 0x3B, 0x38 }, // Mkey 12 encrypted with mkey 13.\n\t{ 0xB1, 0x81, 0xA6, 0x0D, 0x72, 0xC7, 0xEE, 0x15, 0x21, 0xF3, 0xC0, 0xB5, 0x6B, 0x61, 0x6D, 0xE7 }, // Mkey 13 encrypted with mkey 14.\n\t{ 0xAF, 0x11, 0x4C, 0x67, 0x17, 0x7A, 0x52, 0x43, 0xF7, 0x70, 0x2F, 0xC7, 0xEF, 0x81, 0x72, 0x16 }, // Mkey 14 encrypted with mkey 15.\n\t{ 0x25, 0x12, 0x8B, 0xCB, 0xB5, 0x46, 0xA1, 0xF8, 0xE0, 0x52, 0x15, 0xB7, 0x0B, 0x57, 0x00, 0xBD }, // Mkey 15 encrypted with mkey 16.\n\t{ 0x58, 0x15, 0xD2, 0xF6, 0x8A, 0xE8, 0x19, 0xAB, 0xFB, 0x2D, 0x52, 0x9D, 0xE7, 0x55, 0xF3, 0x93 }, // Mkey 16 encrypted with mkey 17.\n\t{ 0x4A, 0x01, 0x3B, 0xC7, 0x44, 0x6E, 0x45, 0xBD, 0xE6, 0x5E, 0x2B, 0xEC, 0x07, 0x37, 0x52, 0x86 }, // Mkey 17 encrypted with mkey 18.\n\t{ 0x97, 0xE4, 0x11, 0xAB, 0x22, 0x72, 0x1A, 0x1F, 0x70, 0x5C, 0x00, 0xB3, 0x96, 0x30, 0x05, 0x28 }, // Mkey 18 encrypted with mkey 19.\n\t{ 0xF7, 0x92, 0xC0, 0xEC, 0xF3, 0xA4, 0x8C, 0xB7, 0x0D, 0xB3, 0xF3, 0xAB, 0x10, 0x9B, 0x18, 0xBA }, // Mkey 19 encrypted with mkey 20.\n\t{ 0x14, 0xCB, 0x60, 0x29, 0x3D, 0xE0, 0xFB, 0xF2, 0x5B, 0x60, 0xB6, 0xC5, 0x2E, 0x77, 0x8F, 0x98 }, // Mkey 20 encrypted with mkey 21.\n};\n\n//!TODO: Update on mkey changes.\nstatic const u8 new_console_keyseed[HOS_MKEY_VER_MAX - HOS_MKEY_VER_400 + 1][SE_KEY_128_SIZE] = {\n\t{ 0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D }, // 4.x    New Device Key Source.\n\t{ 0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C }, // 5.x    New Device Key Source.\n\t{ 0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4 }, // 6.x    New Device Key Source.\n\t{ 0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17 }, // 6.2.0  New Device Key Source.\n\t{ 0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D }, // 7.0.0  New Device Key Source.\n\t{ 0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE }, // 8.1.0  New Device Key Source.\n\t{ 0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49 }, // 9.0.0  New Device Key Source.\n\t{ 0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94 }, // 9.1.0  New Device Key Source.\n\t{ 0xAA, 0xFD, 0xBC, 0xBB, 0x25, 0xC3, 0xA4, 0xEF, 0xE3, 0xEE, 0x58, 0x53, 0xB7, 0xF8, 0xDD, 0xD6 }, // 12.1.0 New Device Key Source.\n\t{ 0xE4, 0xF3, 0x45, 0x6F, 0x18, 0xA1, 0x89, 0xF8, 0xDA, 0x4C, 0x64, 0x75, 0x68, 0xE6, 0xBD, 0x4F }, // 13.0.0 New Device Key Source.\n\t{ 0x5B, 0x94, 0x63, 0xF7, 0xAD, 0x96, 0x1B, 0xA6, 0x23, 0x30, 0x06, 0x4D, 0x01, 0xE4, 0xCE, 0x1D }, // 14.0.0 New Device Key Source.\n\t{ 0x5E, 0xC9, 0xC5, 0x0A, 0xD0, 0x5F, 0x8B, 0x7B, 0xA7, 0x39, 0xEA, 0xBC, 0x60, 0x0F, 0x74, 0xE6 }, // 15.0.0 New Device Key Source.\n\t{ 0xEA, 0x90, 0x6E, 0xA8, 0xAE, 0x92, 0x99, 0x64, 0x36, 0xC1, 0xF3, 0x1C, 0xC6, 0x32, 0x83, 0x8C }, // 16.0.0 New Device Key Source.\n\t{ 0xDA, 0xB9, 0xD6, 0x77, 0x52, 0x2D, 0x1F, 0x78, 0x73, 0xC9, 0x98, 0x5B, 0x06, 0xFE, 0xA0, 0x52 }, // 17.0.0 New Device Key Source.\n\t{ 0x14, 0xF5, 0xA5, 0xD0, 0x73, 0x6D, 0x44, 0x80, 0x5F, 0x31, 0x5A, 0x8F, 0x1E, 0xD4, 0x0D, 0x63 }, // 18.0.0 New Device Key Source.\n\t{ 0x07, 0x38, 0x9A, 0xEC, 0x9C, 0xBD, 0x50, 0x4A, 0x4C, 0x1F, 0x04, 0xDA, 0x40, 0x68, 0x29, 0xE3 }, // 19.0.0 New Device Key Source.\n\t{ 0xA3, 0x6B, 0x0A, 0xB5, 0x6F, 0x57, 0x4C, 0x5E, 0x00, 0xFD, 0x56, 0x21, 0xF5, 0x06, 0x6B, 0xD1 }, // 20.0.0 New Device Key Source.\n\t{ 0xF9, 0x62, 0x05, 0x99, 0xE0, 0xB9, 0xA6, 0x9B, 0x9D, 0xAA, 0xB4, 0x12, 0x0B, 0x0F, 0xF5, 0x8F }, // 21.0.0 New Device Key Source.\n\t{ 0xF8, 0xF4, 0x22, 0xA4, 0x34, 0xAE, 0x0E, 0x0C, 0x4D, 0x5C, 0x5B, 0xA1, 0x1B, 0x46, 0x1C, 0x78 }, // 22.0.0 New Device Key Source.\n};\n\n//!TODO: Update on mkey changes.\nstatic const u8 new_console_kekseed[HOS_MKEY_VER_MAX - HOS_MKEY_VER_400 + 1][SE_KEY_128_SIZE] = {\n\t{ 0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D }, // 4.x    New Device Keygen Source.\n\t{ 0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E }, // 5.x    New Device Keygen Source.\n\t{ 0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF }, // 6.x    New Device Keygen Source.\n\t{ 0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB }, // 6.2.0  New Device Keygen Source.\n\t{ 0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E }, // 7.0.0  New Device Keygen Source.\n\t{ 0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D }, // 8.1.0  New Device Keygen Source.\n\t{ 0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED }, // 9.0.0  New Device Keygen Source.\n\t{ 0xCE, 0xFE, 0x41, 0x0F, 0x46, 0x9A, 0x30, 0xD6, 0xF2, 0xE9, 0x0C, 0x6B, 0xB7, 0x15, 0x91, 0x36 }, // 9.1.0  New Device Keygen Source.\n\t{ 0xC2, 0x65, 0x34, 0x6E, 0xC7, 0xC6, 0x5D, 0x97, 0x3E, 0x34, 0x5C, 0x6B, 0xB3, 0x7E, 0xC6, 0xE3 }, // 12.1.0 New Device Keygen Source.\n\t{ 0x77, 0x52, 0x92, 0xF0, 0xAA, 0xE3, 0xFB, 0xE0, 0x60, 0x16, 0xB3, 0x78, 0x68, 0x53, 0xF7, 0xA8 }, // 13.0.0 New Device Keygen Source.\n\t{ 0x67, 0xD5, 0xD6, 0x0C, 0x08, 0xF5, 0xA3, 0x11, 0xBD, 0x6D, 0x5A, 0xEB, 0x96, 0x24, 0xB0, 0xD2 }, // 14.0.0 New Device Keygen Source.\n\t{ 0x7C, 0x30, 0xED, 0x8B, 0x39, 0x25, 0x2C, 0x08, 0x8F, 0x48, 0xDC, 0x28, 0xE6, 0x1A, 0x6B, 0x49 }, // 15.0.0 New Device Keygen Source.\n\t{ 0xF0, 0xF3, 0xFF, 0x52, 0x75, 0x2F, 0xBA, 0x4D, 0x09, 0x72, 0x30, 0x89, 0xA9, 0xDF, 0xFE, 0x1F }, // 16.0.0 New Device Keygen Source.\n\t{ 0x21, 0xD6, 0x35, 0xF1, 0x0F, 0x7A, 0xF0, 0x5D, 0xDF, 0x79, 0x1C, 0x7A, 0xE4, 0x32, 0x82, 0x9E }, // 17.0.0 New Device Keygen Source.\n\t{ 0xE7, 0x85, 0x8C, 0xA2, 0xF4, 0x49, 0xCB, 0x07, 0xD1, 0x8E, 0x48, 0x1B, 0xE8, 0x1E, 0x28, 0x3B }, // 18.0.0 New Device Keygen Source.\n\t{ 0x9B, 0xA5, 0xFD, 0x74, 0x7F, 0xCD, 0x23, 0xD1, 0xD9, 0xBD, 0x6C, 0x51, 0x72, 0x5F, 0x3D, 0x1F }, // 19.0.0 New Device Keygen Source.\n\t{ 0xDA, 0xFB, 0x61, 0x39, 0x48, 0x2D, 0xC2, 0x7E, 0x0D, 0x8E, 0x8F, 0x98, 0x57, 0x20, 0xB8, 0x15 }, // 20.0.0 New Device Keygen Source.\n\t{ 0x92, 0xBF, 0x37, 0x80, 0x0E, 0x79, 0x56, 0x8C, 0x57, 0x75, 0x72, 0x0A, 0x48, 0xD8, 0x15, 0x39 }, // 21.0.0 New Device Keygen Source.\n\t{ 0xC4, 0x6F, 0x0E, 0x72, 0x43, 0xCE, 0x87, 0xFC, 0x38, 0x95, 0x9B, 0xC9, 0x31, 0x44, 0x97, 0x63 }, // 22.0.0 New Device Keygen Source.\n};\n\nstatic const u8 gen_keyseed[SE_KEY_128_SIZE] =\n\t{ 0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8 };\n\nstatic const u8 gen_kekseed[SE_KEY_128_SIZE] =\n\t{ 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9 };\n\nstatic const u8 gen_keyseed_retail[SE_KEY_128_SIZE] =\n\t{ 0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95 };\n\nstatic const u8 bis_kekseed[SE_KEY_128_SIZE] =\n\t{ 0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F };\n\nstatic const u8 bis_keyseed[][SE_KEY_128_SIZE] = {\n\t{ 0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48 }, // BIS 0 Crypt seed.\n\t{ 0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06 }, // BIS 0 Tweak seed.\n\t{ 0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F }, // BIS 1 Crypt seed.\n\t{ 0x44, 0x42, 0x4E, 0xDA, 0xB4, 0x9D, 0xFC, 0xD9, 0x87, 0x77, 0x24, 0x9A, 0xDC, 0x9F, 0x7C, 0xA4 }, // BIS 1 Tweak seed.\n\t{ 0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C }, // BIS 2/3 Crypt seed.\n\t{ 0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4 }  // BIS 2/3 Tweak seed.\n};\n\nstatic int _hos_eks_rw_try(u8 *buf, bool write)\n{\n\tfor (u32 i = 0; i < 3; i++)\n\t{\n\t\tif (!write)\n\t\t{\n\t\t\tif (!sdmmc_storage_read(&sd_storage, 0, 1, buf))\n\t\t\t\treturn 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (!sdmmc_storage_write(&sd_storage, 0, 1, buf))\n\t\t\t\treturn 0;\n\t\t}\n\t}\n\n\treturn 1;\n}\n\nstatic void _hos_eks_get()\n{\n\t// Check if Erista based unit.\n\tif (h_cfg.t210b01)\n\t\treturn;\n\n\t// Check if EKS already found and parsed.\n\tif (!h_cfg.eks)\n\t{\n\t\t// Read EKS blob.\n\t\tu8 *mbr = malloc(SD_BLOCKSIZE);\n\t\tif (_hos_eks_rw_try(mbr, false))\n\t\t\tgoto out;\n\n\t\t// Decrypt EKS blob.\n\t\thos_eks_mbr_t *eks = (hos_eks_mbr_t *)(mbr + 0x80);\n\t\tse_aes_crypt_ecb(14, DECRYPT, eks, eks, sizeof(hos_eks_mbr_t));\n\n\t\t// Check if valid and for this unit.\n\t\tif (eks->magic == HOS_EKS_MAGIC && eks->lot0 == FUSE(FUSE_OPT_LOT_CODE_0))\n\t\t{\n\t\t\th_cfg.eks = eks;\n\t\t\treturn;\n\t\t}\n\nout:\n\t\tfree(mbr);\n\t}\n}\n\nstatic void _hos_eks_save()\n{\n\t// Check if Erista based unit.\n\tif (h_cfg.t210b01)\n\t\treturn;\n\n\t// EKS save. Only for 7.0.0 and up.\n\tbool new_eks = false;\n\tif (!h_cfg.eks)\n\t{\n\t\th_cfg.eks = zalloc(sizeof(hos_eks_mbr_t));\n\t\tnew_eks = true;\n\t}\n\n\t// If matching blob doesn't exist, create it.\n\tif (h_cfg.eks->enabled != HOS_EKS_TSEC_VER)\n\t{\n\t\t// Read EKS blob.\n\t\tu8 *mbr = malloc(SD_BLOCKSIZE);\n\t\tif (_hos_eks_rw_try(mbr, false))\n\t\t{\n\t\t\tif (new_eks)\n\t\t\t{\n\t\t\t\tfree(h_cfg.eks);\n\t\t\t\th_cfg.eks = NULL;\n\t\t\t}\n\n\t\t\tgoto out;\n\t\t}\n\n\t\t// Get keys.\n\t\tu8 *keys = (u8 *)zalloc(SZ_8K);\n\t\tse_aes_ctx_get_keys(keys + SZ_4K, keys, SE_KEY_128_SIZE);\n\n\t\t// Set magic and personalized info.\n\t\th_cfg.eks->magic   = HOS_EKS_MAGIC;\n\t\th_cfg.eks->enabled = HOS_EKS_TSEC_VER;\n\t\th_cfg.eks->lot0    = FUSE(FUSE_OPT_LOT_CODE_0);\n\n\t\t// Copy new keys.\n\t\tmemcpy(h_cfg.eks->tsec,      keys + 12 * SE_KEY_128_SIZE, SE_KEY_128_SIZE);\n\t\tmemcpy(h_cfg.eks->troot,     keys + 13 * SE_KEY_128_SIZE, SE_KEY_128_SIZE);\n\t\tmemcpy(h_cfg.eks->troot_dev, keys + 11 * SE_KEY_128_SIZE, SE_KEY_128_SIZE);\n\n\t\t// Encrypt EKS blob.\n\t\tu8 *eks = malloc(sizeof(hos_eks_mbr_t));\n\t\tmemcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t));\n\t\tse_aes_crypt_ecb(14, ENCRYPT, eks, eks, sizeof(hos_eks_mbr_t));\n\n\t\t// Write EKS blob to SD.\n\t\tmemcpy(mbr + 0x80, eks, sizeof(hos_eks_mbr_t));\n\t\t_hos_eks_rw_try(mbr, true);\n\n\t\tfree(eks);\n\t\tfree(keys);\nout:\n\t\tfree(mbr);\n\t}\n}\n\nvoid hos_eks_clear(u32 mkey)\n{\n\t// Check if Erista based unit.\n\tif (h_cfg.t210b01)\n\t\treturn;\n\n\tif (h_cfg.eks && mkey >= HOS_MKEY_VER_700)\n\t{\n\t\t// Check if current Master key is enabled.\n\t\tif (h_cfg.eks->enabled)\n\t\t{\n\t\t\t// Read EKS blob.\n\t\t\tu8 *mbr = malloc(SD_BLOCKSIZE);\n\t\t\tif (_hos_eks_rw_try(mbr, false))\n\t\t\t\tgoto out;\n\n\t\t\t// Disable current Master key version.\n\t\t\th_cfg.eks->enabled = 0;\n\n\t\t\t// Encrypt EKS blob.\n\t\t\tu8 *eks = malloc(sizeof(hos_eks_mbr_t));\n\t\t\tmemcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t));\n\t\t\tse_aes_crypt_ecb(14, ENCRYPT, eks, eks, sizeof(hos_eks_mbr_t));\n\n\t\t\t// Write EKS blob to SD.\n\t\t\tmemcpy(mbr + 0x80, eks, sizeof(hos_eks_mbr_t));\n\t\t\t_hos_eks_rw_try(mbr, true);\n\n\t\t\tfree(eks);\nout:\n\t\t\tfree(mbr);\n\t\t}\n\t}\n}\n\ntypedef struct _tsec_keys_t\n{\n\tu8 tsec[SE_KEY_128_SIZE];\n\tu8 tsec_root[SE_KEY_128_SIZE];\n\tu8 tmp[SE_KEY_128_SIZE];\n} tsec_keys_t;\n\nint hos_keygen(pkg1_eks_t *eks, u32 mkey, tsec_ctxt_t *tsec_ctxt)\n{\n\tu32 retries = 0;\n\tbool use_tsec = false;\n\ttsec_keys_t tsec_keys;\n\n\tif (mkey > HOS_MKEY_VER_MAX)\n\t\treturn 1;\n\n\t// Do Mariko keygen.\n\tif (h_cfg.t210b01)\n\t{\n\t\t// Use SBK as Device key 4x unsealer and KEK for mkey in T210B01 units.\n\t\tse_aes_unwrap_key(10, 14, console_keyseed_4xx);\n\n\t\t// Derive master key.\n\t\tse_aes_unwrap_key(7, 12, master_kekseed_t210b01[mkey - HOS_MKEY_VER_600]);\n\t\tse_aes_unwrap_key(7, 7,  master_keyseed_retail);\n\n\t\t// Derive latest pkg2 key.\n\t\tse_aes_unwrap_key(8, 7, package2_keyseed);\n\n\t\treturn 0;\n\t}\n\n\t// Do Erista keygen.\n\n\t// Use HOS EKS if it exists.\n\t_hos_eks_get();\n\n\t// Use tsec keygen for old firmware or if EKS keys does not exist for newer.\n\tif (mkey <= HOS_MKEY_VER_620 || !h_cfg.eks || (h_cfg.eks->enabled != HOS_EKS_TSEC_VER))\n\t\tuse_tsec = true;\n\n\tif (mkey <= HOS_MKEY_VER_600)\n\t{\n\t\ttsec_ctxt->size = 0xF00;\n\t\ttsec_ctxt->type = TSEC_FW_TYPE_OLD;\n\t}\n\telse if (mkey == HOS_MKEY_VER_620)\n\t{\n\t\ttsec_ctxt->size = 0x2900;\n\t\ttsec_ctxt->type = TSEC_FW_TYPE_EMU;\n\n\t\t// Prepare smmu tsec page for 6.2.0.\n\t\tu8 *tsec_paged = (u8 *)smmu_page_zalloc(3);\n\t\tmemcpy(tsec_paged, (void *)tsec_ctxt->fw, tsec_ctxt->size);\n\t\ttsec_ctxt->fw = tsec_paged;\n\t}\n\telse if (use_tsec) // 7.0.0+\n\t{\n\t\t/*\n\t\t * 7.0.0/8.1.0 tsec fw are 0x3000/0x3300.\n\t\t * Unused here because of THK.\n\t\t */\n\n\t\t// Use custom TSEC Hovi Keygen firmware.\n\t\ttsec_ctxt->fw = sd_file_read(\"bootloader/sys/thk.bin\", NULL);\n\t\tif (!tsec_ctxt->fw)\n\t\t{\n\t\t\tEPRINTF(\"\\nFailed to load thk.bin\");\n\t\t\treturn 1;\n\t\t}\n\n\t\ttsec_ctxt->size = 0x1F00;\n\t\ttsec_ctxt->type = TSEC_FW_TYPE_NEW;\n\t}\n\telse if (h_cfg.eks)\n\t{\n\t\t// EKS found. Set TSEC keys.\n\t\tse_aes_key_set(12, h_cfg.eks->tsec, SE_KEY_128_SIZE);\n\t\tse_aes_key_set(13, h_cfg.eks->troot, SE_KEY_128_SIZE);\n\t\tse_aes_key_set(11, h_cfg.eks->troot_dev, SE_KEY_128_SIZE);\n\t}\n\n\t// Get TSEC key.\n\twhile (use_tsec && tsec_query(&tsec_keys, tsec_ctxt) < 0)\n\t{\n\t\tmemset(&tsec_keys, 0x00, 0x20);\n\t\tretries++;\n\n\t\t// We rely on racing conditions, make sure we cover even the unluckiest cases.\n\t\tif (retries > 15)\n\t\t{\n\t\t\tEPRINTF(\"\\nFailed to get TSEC keys. Please try again.\");\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\tif (mkey >= HOS_MKEY_VER_700)\n\t{\n\t\t// For 7.0.0 and up, save EKS slot if it doesn't exist.\n\t\tif (use_tsec)\n\t\t{\n\t\t\t_hos_eks_save();\n\t\t\tfree(tsec_ctxt->fw);\n\t\t}\n\n\t\t// Decrypt eks and set keyslots.\n\t\tse_aes_crypt_ecb(12, DECRYPT, tsec_keys.tmp, eks_keyseeds[0], SE_KEY_128_SIZE);\n\t\tse_aes_unwrap_key(15, 14, tsec_keys.tmp);\n\n\t\t// Derive device keys.\n\t\tse_aes_unwrap_key(10, 15, console_keyseed_4xx);\n\t\tse_aes_unwrap_key(15, 15, console_keyseed);\n\n\t\t// Derive master kek.\n\t\tse_aes_unwrap_key(7, 13, master_kekseed_t210_max);\n\n\t\t// Derive master key.\n\t\tse_aes_unwrap_key(7, 7, master_keyseed_retail);\n\n\t\t// Package2 key.\n\t\tse_aes_unwrap_key(8, 7, package2_keyseed);\n\t}\n\telse if (mkey == HOS_MKEY_VER_620)\n\t{\n\t\t// Set TSEC key.\n\t\tse_aes_key_set(12, tsec_keys.tsec, SE_KEY_128_SIZE);\n\t\t// Set TSEC root key.\n\t\tse_aes_key_set(13, tsec_keys.tsec_root, SE_KEY_128_SIZE);\n\n\t\t// Decrypt eks and set keyslots.\n\t\tse_aes_crypt_ecb(12, DECRYPT, tsec_keys.tmp, eks_keyseeds[0], SE_KEY_128_SIZE);\n\t\tse_aes_unwrap_key(15, 14, tsec_keys.tmp);\n\n\t\t// Derive device keys.\n\t\tse_aes_unwrap_key(10, 15, console_keyseed_4xx);\n\t\tse_aes_unwrap_key(15, 15, console_keyseed);\n\n\t\t// Derive master kek.\n\t\tse_aes_unwrap_key(7, 13, master_kekseed_620);\n\n\t\t// Derive master key.\n\t\tse_aes_unwrap_key(7, 7, master_keyseed_retail);\n\n\t\t// Package2 key.\n\t\tse_aes_unwrap_key(8, 7, package2_keyseed);\n\t}\n\telse\n\t{\n\t\t// Set TSEC key.\n\t\tse_aes_key_set(13, tsec_keys.tsec, SE_KEY_128_SIZE);\n\n\t\t// Derive eks keys from TSEC+SBK.\n\t\tse_aes_crypt_ecb(13, DECRYPT, tsec_keys.tsec, eks_keyseeds[0], SE_KEY_128_SIZE);\n\t\tse_aes_unwrap_key(15, 14, tsec_keys.tsec);\n\t\tse_aes_crypt_ecb(13, DECRYPT, tsec_keys.tsec, eks_keyseeds[mkey], SE_KEY_128_SIZE);\n\t\tse_aes_unwrap_key(13, 14, tsec_keys.tsec);\n\n/*\n\t\t// Verify eks CMAC.\n\t\tu8 cmac[SE_KEY_128_SIZE];\n\t\tse_aes_unwrap_key(11, 13, cmac_keyseed);\n\t\tse_aes_hash_cmac(cmac, SE_KEY_128_SIZE, 11, (void *)eks->ctr, sizeof(eks->ctr) + sizeof(eks->keys));\n\t\tif (!memcmp(eks->cmac, cmac, SE_KEY_128_SIZE))\n\t\t\treturn 1;\n*/\n\n\t\tse_aes_crypt_ecb(13, DECRYPT, tsec_keys.tsec, cmac_keyseed, SE_KEY_128_SIZE);\n\t\tse_aes_unwrap_key(11, 13, cmac_keyseed);\n\n\t\t// Decrypt eks and set keyslots.\n\t\tse_aes_crypt_ctr(13, &eks->keys, &eks->keys, sizeof(eks_keys_t), eks->ctr);\n\t\tse_aes_key_set(11, eks->keys.package1_key,   SE_KEY_128_SIZE);\n\t\tse_aes_key_set(12, eks->keys.master_kekseed, SE_KEY_128_SIZE);\n\t\tse_aes_key_set(13, eks->keys.master_kekseed, SE_KEY_128_SIZE);\n\n\t\tse_aes_crypt_ecb(12, DECRYPT, tsec_keys.tsec, master_keyseed_retail, SE_KEY_128_SIZE);\n\n\t\tswitch (mkey)\n\t\t{\n\t\tcase HOS_MKEY_VER_100:\n\t\tcase HOS_MKEY_VER_300:\n\t\tcase HOS_MKEY_VER_301:\n\t\t\tse_aes_unwrap_key(13, 15, console_keyseed);\n\t\t\tse_aes_unwrap_key(12, 12, master_keyseed_retail);\n\t\t\tbreak;\n\t\tcase HOS_MKEY_VER_400:\n\t\t\tse_aes_unwrap_key(13, 15, console_keyseed_4xx);\n\t\t\tse_aes_unwrap_key(15, 15, console_keyseed);\n\t\t\t//se_aes_unwrap_key(14, 12, master_keyseed_4xx); // In this context it's useless. So don't kill SBK.\n\t\t\tse_aes_unwrap_key(12, 12, master_keyseed_retail);\n\t\t\tbreak;\n\t\tcase HOS_MKEY_VER_500:\n\t\tcase HOS_MKEY_VER_600:\n\t\t\tse_aes_unwrap_key(10, 15, console_keyseed_4xx);\n\t\t\tse_aes_unwrap_key(15, 15, console_keyseed);\n\t\t\t//se_aes_unwrap_key(14, 12, master_keyseed_4xx); // In this context it's useless. So don't kill SBK.\n\t\t\tse_aes_unwrap_key(12, 12, master_keyseed_retail);\n\t\t\tbreak;\n\t\t}\n\n\t\t// Package2 key.\n\t\tse_aes_unwrap_key(8, 12, package2_keyseed);\n\t}\n\n\treturn 0;\n}\n\nstatic void _hos_validate_mkey()\n{\n\tu8 tmp_mkey[SE_KEY_128_SIZE];\n\tu32 mkey_idx = sizeof(mkey_vectors) / SE_KEY_128_SIZE;\n\tdo\n\t{\n\t\tmkey_idx--;\n\t\tse_aes_crypt_ecb(7, DECRYPT, tmp_mkey, mkey_vectors[mkey_idx], SE_KEY_128_SIZE);\n\t\tfor (u32 idx = 0; idx < mkey_idx; idx++)\n\t\t{\n\t\t\tse_aes_key_set(2, tmp_mkey, SE_KEY_128_SIZE);\n\t\t\tse_aes_crypt_ecb(2, DECRYPT, tmp_mkey, mkey_vectors[mkey_idx - 1 - idx], SE_KEY_128_SIZE);\n\t\t}\n\n\t\tif (!memcmp(tmp_mkey, \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\", 8))\n\t\t{\n\t\t\tse_aes_key_clear(2);\n\t\t\treturn;\n\t\t}\n\t} while (mkey_idx - 1);\n\n\tse_aes_key_clear(2);\n\thos_eks_clear(HOS_MKEY_VER_MAX);\n}\n\nstatic void _hos_bis_print_key(u32 idx, u8 *key)\n{\n\tgfx_printf(\"BIS %d Crypt: \", idx);\n\tfor (int i = 0; i < SE_KEY_128_SIZE; i++)\n\t\tgfx_printf(\"%02X\", key[((idx * 2 + 0) * SE_KEY_128_SIZE) + i]);\n\tgfx_puts(\"\\n\");\n\n\tgfx_printf(\"BIS %d Tweak: \", idx);\n\tfor (int i = 0; i < SE_KEY_128_SIZE; i++)\n\t\tgfx_printf(\"%02X\", key[((idx * 2 + 1) * SE_KEY_128_SIZE) + i]);\n\tgfx_puts(\"\\n\");\n}\n\nint hos_bis_keygen()\n{\n\tu32 keygen_rev = 0;\n\tu32 console_key_slot = 15; // HOS_MKEY_VER_MAX. Only for Erista.\n\ttsec_ctxt_t tsec_ctxt = {0};\n\n\t// Run initial keygen.\n\tif (hos_keygen(NULL, HOS_MKEY_VER_MAX, &tsec_ctxt))\n\t\treturn 1;\n\n\t// All Mariko use new device keygen. New keygen was introduced in 4.0.0.\n\t// We check unconditionally in order to support downgrades.\n\tkeygen_rev = fuse_read_odm_keygen_rev();\n\n\tgfx_printf(\"Keygen rev: %d\\n\", keygen_rev);\n\n\tif (keygen_rev)\n\t{\n\t\tu8 tmp_mkey[SE_KEY_128_SIZE];\n\t\tu32 mkey_idx = sizeof(mkey_vectors) / SE_KEY_128_SIZE;\n\n\t\t// Keygen revision uses bootloader version, which starts from 1.\n\t\tkeygen_rev -= (HOS_MKEY_VER_400 + 1);\n\n\t\t// Derive mkey 0.\n\t\tdo\n\t\t{\n\t\t\tmkey_idx--;\n\t\t\tse_aes_crypt_ecb(7, DECRYPT, tmp_mkey, mkey_vectors[mkey_idx], SE_KEY_128_SIZE);\n\t\t\tfor (u32 idx = 0; idx < mkey_idx; idx++)\n\t\t\t{\n\t\t\t\tse_aes_key_set(2, tmp_mkey, SE_KEY_128_SIZE);\n\t\t\t\tse_aes_crypt_ecb(2, DECRYPT, tmp_mkey, mkey_vectors[mkey_idx - 1 - idx], SE_KEY_128_SIZE);\n\t\t\t}\n\t\t} while (memcmp(tmp_mkey, \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\", 8) != 0 && (mkey_idx - 1));\n\n\t\t// Derive new device key.\n\t\tse_aes_unwrap_key(1, 10, new_console_keyseed[keygen_rev]); // Uses Device key 4x.\n\t\tse_aes_crypt_ecb(10, DECRYPT, tmp_mkey, new_console_keyseed[keygen_rev], SE_KEY_128_SIZE); // Uses Device key 4x.\n\t\tse_aes_unwrap_key(1, 2, new_console_kekseed[keygen_rev]); // Uses Master Key 0.\n\t\tse_aes_unwrap_key(1, 1, tmp_mkey);\n\n\t\tconsole_key_slot = 1;\n\t}\n\n\t// Generate generic key.\n\tse_aes_unwrap_key(2, console_key_slot, gen_keyseed_retail);\n\n\t// Clear bis keys storage.\n\tu8 *bis_keys = malloc(SE_KEY_128_SIZE * 6);\n\tmemset(bis_keys, 0, SE_KEY_128_SIZE * 6);\n\n\t// Generate BIS 0 Keys.\n\tse_aes_crypt_ecb(2, DECRYPT, bis_keys + (0 * SE_KEY_128_SIZE), bis_keyseed[0], SE_KEY_128_SIZE);\n\tse_aes_crypt_ecb(2, DECRYPT, bis_keys + (1 * SE_KEY_128_SIZE), bis_keyseed[1], SE_KEY_128_SIZE);\n\n\t// Generate generic kek.\n\tse_aes_unwrap_key(2, console_key_slot, gen_kekseed);\n\tse_aes_unwrap_key(2, 2, bis_kekseed);\n\tse_aes_unwrap_key(2, 2, gen_keyseed);\n\n\t// Generate BIS 1 Keys.\n\tse_aes_crypt_ecb(2, DECRYPT, bis_keys + (2 * SE_KEY_128_SIZE), bis_keyseed[2], SE_KEY_128_SIZE);\n\tse_aes_crypt_ecb(2, DECRYPT, bis_keys + (3 * SE_KEY_128_SIZE), bis_keyseed[3], SE_KEY_128_SIZE);\n\n\t// Generate BIS 2/3 Keys.\n\tse_aes_crypt_ecb(2, DECRYPT, bis_keys + (4 * SE_KEY_128_SIZE), bis_keyseed[4], SE_KEY_128_SIZE);\n\tse_aes_crypt_ecb(2, DECRYPT, bis_keys + (5 * SE_KEY_128_SIZE), bis_keyseed[5], SE_KEY_128_SIZE);\n\n\t// Validate key because HOS_MKEY_VER_MAX.\n\tif (!h_cfg.t210b01)\n\t\t_hos_validate_mkey();\n\n\t// Print keys to console.\n\t_hos_bis_print_key(0, bis_keys);\n\t_hos_bis_print_key(1, bis_keys);\n\t_hos_bis_print_key(2, bis_keys);\n\n\t// Clear all AES tmp and bis keyslots.\n\tfor (u32 i = 0; i < 6; i++)\n\t\tse_aes_key_clear(i);\n\n\t// Set BIS keys.\n\tse_aes_key_set(0, bis_keys + (0 * SE_KEY_128_SIZE), SE_KEY_128_SIZE);\n\tse_aes_key_set(1, bis_keys + (1 * SE_KEY_128_SIZE), SE_KEY_128_SIZE);\n\n\tse_aes_key_set(2, bis_keys + (2 * SE_KEY_128_SIZE), SE_KEY_128_SIZE);\n\tse_aes_key_set(3, bis_keys + (3 * SE_KEY_128_SIZE), SE_KEY_128_SIZE);\n\n\tse_aes_key_set(4, bis_keys + (4 * SE_KEY_128_SIZE), SE_KEY_128_SIZE);\n\tse_aes_key_set(5, bis_keys + (5 * SE_KEY_128_SIZE), SE_KEY_128_SIZE);\n\n\treturn 0;\n}\n\nvoid hos_bis_keys_clear()\n{\n\t// Clear all aes bis keyslots.\n\tfor (u32 i = 0; i < 6; i++)\n\t\tse_aes_key_clear(i);\n}\n\nint hos_dump_cal0()\n{\n\t// Init eMMC.\n\tif (emmc_initialize(false))\n\t\treturn 1;\n\n\t// Generate BIS keys\n\tif (hos_bis_keygen())\n\t\treturn 2;\n\n\tif (!cal0_buf)\n\t\tcal0_buf = malloc(SZ_64K);\n\n\t// Read and decrypt CAL0.\n\temmc_set_partition(EMMC_GPP);\n\tLIST_INIT(gpt);\n\temmc_gpt_parse(&gpt);\n\temmc_part_t *cal0_part = emmc_part_find(&gpt, \"PRODINFO\"); // check if null\n\tnx_emmc_bis_init(cal0_part, false, 0);\n\tnx_emmc_bis_read(0, 0x40, cal0_buf);\n\tnx_emmc_bis_end();\n\temmc_gpt_free(&gpt);\n\n\temmc_end();\n\n\t// Clear BIS keys slots.\n\thos_bis_keys_clear();\n\n\tnx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)cal0_buf;\n\n\t// Check keys validity.\n\tif (memcmp(&cal0->magic, \"CAL0\", 4))\n\t{\n\t\tfree(cal0_buf);\n\t\tcal0_buf = NULL;\n\n\t\t// Clear EKS keys.\n\t\thos_eks_clear(HOS_MKEY_VER_MAX);\n\n\t\treturn 2;\n\t}\n\n\tu32 hash[8];\n\tse_sha_hash_256_oneshot(hash, (u8 *)&cal0->cfg_id1, cal0->body_size);\n\tif (memcmp(hash, cal0->body_sha256, 0x20))\n\t\treturn 3;\n\n\treturn 0;\n}\n"
  },
  {
    "path": "nyx/nyx_gui/hos/hos.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _HOS_H_\n#define _HOS_H_\n\n#include <bdk.h>\n\n#include \"pkg1.h\"\n#include \"pkg2.h\"\n\n#include <assert.h>\n\n//!TODO: Update on mkey changes.\nenum {\n\tHOS_MKEY_VER_100  = 0,\n\tHOS_MKEY_VER_300  = 1,\n\tHOS_MKEY_VER_301  = 2,\n\tHOS_MKEY_VER_400  = 3,\n\tHOS_MKEY_VER_500  = 4,\n\tHOS_MKEY_VER_600  = 5,\n\tHOS_MKEY_VER_620  = 6,\n\tHOS_MKEY_VER_700  = 7,\n\tHOS_MKEY_VER_810  = 8,\n\tHOS_MKEY_VER_900  = 9,\n\tHOS_MKEY_VER_910  = 10,\n\tHOS_MKEY_VER_1210 = 11,\n\tHOS_MKEY_VER_1300 = 12,\n\tHOS_MKEY_VER_1400 = 13,\n\tHOS_MKEY_VER_1500 = 14,\n\tHOS_MKEY_VER_1600 = 15,\n\tHOS_MKEY_VER_1700 = 16,\n\tHOS_MKEY_VER_1800 = 17,\n\tHOS_MKEY_VER_1900 = 18,\n\tHOS_MKEY_VER_2000 = 19,\n\tHOS_MKEY_VER_2100 = 20,\n\tHOS_MKEY_VER_2200 = 21,\n\tHOS_MKEY_VER_MAX  = HOS_MKEY_VER_2200\n};\n\n#define HOS_TSEC_VERSION 4 //! TODO: Update on TSEC Root Key changes.\n\n#define HOS_PKG11_MAGIC  0x31314B50\n#define HOS_EKS_MAGIC    0x31534B45 // EKS1.\n#define HOS_EKS_TSEC_VER (HOS_MKEY_VER_700 + HOS_TSEC_VERSION)\n\ntypedef struct _hos_eks_mbr_t\n{\n\tu32 magic;\n\tu32 enabled;\n\tu32 lot0;\n\tu32 rsvd;\n\tu8  tsec[SE_KEY_128_SIZE];\n\tu8  troot[SE_KEY_128_SIZE];\n\tu8  troot_dev[SE_KEY_128_SIZE];\n} hos_eks_mbr_t;\n\nstatic_assert(sizeof(hos_eks_mbr_t) == 64, \"HOS EKS size is wrong!\");\n\ntypedef struct _launch_ctxt_t\n{\n\tvoid *pkg1;\n\tconst pkg1_id_t *pkg1_id;\n\n\tvoid *warmboot;\n\tu32   warmboot_size;\n\tvoid *secmon;\n\tu32   secmon_size;\n\n\tvoid *pkg2;\n\tu32   pkg2_size;\n\tbool  new_pkg2;\n\n\tvoid *kernel;\n\tu32   kernel_size;\n\n\tlink_t kip1_list;\n\tchar  *kip1_patches;\n\n\tini_sec_t *cfg;\n} launch_ctxt_t;\n\nextern u8 *cal0_buf;\n\nvoid hos_eks_clear(u32 mkey);\nint  hos_keygen(pkg1_eks_t *eks, u32 mkey, tsec_ctxt_t *tsec_ctxt);\nint  hos_bis_keygen();\nvoid hos_bis_keys_clear();\nint  hos_dump_cal0();\n\n#endif\n"
  },
  {
    "path": "nyx/nyx_gui/hos/pkg1.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018 st4rk\n * Copyright (c) 2018-2025 CTCaer\n * Copyright (c) 2018 balika011\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <bdk.h>\n\n#include \"hos.h\"\n#include \"pkg1.h\"\n#include \"../config.h\"\n\n/*\n * package1.1 header: <wb, ldr, sm>\n * package1.1 layout:\n * 1.0:  {sm, ldr, wb} { 2, 1, 0 }\n * 2.0+: {wb, ldr, sm} { 0, 1, 2 }\n * 4.0+: {ldr, sm, wb} { 1, 2, 0 }\n */\n\nstatic const u8 sec_map_100[3] = { PK11_SECTION_SM, PK11_SECTION_LD, PK11_SECTION_WB };\nstatic const u8 sec_map_2xx[3] = { PK11_SECTION_WB, PK11_SECTION_LD, PK11_SECTION_SM };\nstatic const u8 sec_map_4xx[3] = { PK11_SECTION_LD, PK11_SECTION_SM, PK11_SECTION_WB };\n\n\t// Timestamp  MK   TSEC    PK11     SECMON     Warmboot\nstatic const pkg1_id_t _pkg1_ids[] = {\n\t{ \"20161121\",  0, 0x1900, 0x3FE0, 0x40014020, 0x8000D000 }, //  1.0.0.\n\t{ \"20170210\",  0, 0x1900, 0x3FE0, 0x4002D000, 0x8000D000 }, //  2.0.0 - 2.3.0.\n\t{ \"20170519\",  1, 0x1A00, 0x3FE0, 0x4002D000, 0x8000D000 }, //  3.0.0.\n\t{ \"20170710\",  2, 0x1A00, 0x3FE0, 0x4002D000, 0x8000D000 }, //  3.0.1 - 3.0.2.\n\t{ \"20170921\",  3, 0x1800, 0x3FE0, 0x4002B000, 0x4003B000 }, //  4.0.0 - 4.1.0.\n\t{ \"20180220\",  4, 0x1900, 0x3FE0, 0x4002B000, 0x4003B000 }, //  5.0.0 - 5.1.0.\n\t{ \"20180802\",  5, 0x1900, 0x3FE0, 0x4002B000, 0x4003D800 }, //  6.0.0 - 6.1.0.\n\t{ \"20181107\",  6, 0x0E00, 0x6FE0, 0x4002B000, 0x4003D800 }, //  6.2.0.\n\t{ \"20181218\",  7, 0x0F00, 0x6FE0, 0x40030000, 0x4003E000 }, //  7.0.0.\n\t{ \"20190208\",  7, 0x0F00, 0x6FE0, 0x40030000, 0x4003E000 }, //  7.0.1.\n\t{ \"20190314\",  7, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, //  8.0.0 - 8.0.1.\n\t{ \"20190531\",  8, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, //  8.1.0 - 8.1.1.\n\t{ \"20190809\",  9, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, //  9.0.0 - 9.0.1.\n\t{ \"20191021\", 10, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, //  9.1.0 - 9.2.0.\n\t{ \"20200303\", 10, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 10.0.0 - 10.2.0.\n\t{ \"20201030\", 10, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 11.0.0 - 11.0.1.\n\t{ \"20210129\", 10, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 12.0.0 - 12.0.1.\n\t{ \"20210422\", 10, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 12.0.2 - 12.0.3.\n\t{ \"20210607\", 11, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 12.1.0.\n\t{ \"20210805\", 12, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 13.0.0 - 13.2.0\n\t{ \"20220105\", 12, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 13.2.1.\n\t{ \"20220209\", 13, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 14.0.0 - 14.1.2.\n\t{ \"20220801\", 14, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 15.0.0 - 15.0.1.\n\t{ \"20230111\", 15, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 16.0.0 - 16.1.0.\n\t{ \"20230906\", 16, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 17.0.0 - 17.0.1.\n\t{ \"20240207\", 17, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 18.0.0 - 18.1.0.\n\t{ \"20240808\", 18, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 19.0.0 - 19.0.1.\n\t{ \"20250206\", 19, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 20.0.0 - 20.5.0.\n\t{ \"20251009\", 20, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 21.0.0 - 21.2.0.\n\t{ \"20260123\", 21, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 22.0.0+\n};\n\nconst pkg1_id_t *pkg1_identify(u8 *pkg1, char *build_date)\n{\n\tpk1_hdr_t *hdr = (pk1_hdr_t *)pkg1;\n\tif (build_date)\n\t{\n\t\tmemcpy(build_date, hdr->timestamp, 14);\n\t\tbuild_date[14] = 0;\n\t}\n\n\tfor (u32 i = 0; i < ARRAY_SIZE(_pkg1_ids); i++)\n\t\tif (!memcmp(hdr->timestamp, _pkg1_ids[i].id, 8))\n\t\t\treturn &_pkg1_ids[i];\n\n\treturn NULL;\n}\n\nbool pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1)\n{\n\tpk11_hdr_t *hdr;\n\n\t// Decrypt package1.\n\tif (!h_cfg.t210b01)\n\t{\n\t\tu8 *pkg11 = pkg1 + id->pkg11_off;\n\t\tu32 pkg11_size = *(u32 *)pkg11;\n\t\thdr = (pk11_hdr_t *)(pkg11 + 0x20);\n\t\tse_aes_crypt_ctr(11, hdr, hdr, pkg11_size, pkg11 + 0x10);\n\t}\n\telse\n\t{\n\t\tbl_hdr_t210b01_t *oem_hdr = (bl_hdr_t210b01_t *)pkg1;\n\t\tpkg1 += sizeof(bl_hdr_t210b01_t);\n\t\thdr = (pk11_hdr_t *)(pkg1 + id->pkg11_off + 0x20);\n\n\t\t// Use BEK for T210B01.\n\t\t// Additionally, skip 0x20 bytes from decryption to maintain the header.\n\t\tse_aes_iv_clear(13);\n\t\tse_aes_crypt_cbc(13, DECRYPT, pkg1 + 0x20, pkg1 + 0x20, oem_hdr->size - 0x20);\n\t}\n\n\t// Return if header is valid.\n\treturn (hdr->magic == PKG1_MAGIC);\n}\n\nconst u8 *pkg1_unpack(void *wm_dst, void *sm_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1)\n{\n\tconst u8 *sec_map;\n\tconst pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + id->pkg11_off + 0x20);\n\n\tu32 sec_size[3] = { hdr->wb_size, hdr->ldr_size, hdr->sm_size };\n\n\t// Get correct header mapping.\n\tif (id->mkey == HOS_MKEY_VER_100 && !memcmp(id->id, \"20161121\", 8))\n\t\tsec_map = sec_map_100;\n\telse if (id->mkey <= HOS_MKEY_VER_301)\n\t\tsec_map = sec_map_2xx;\n\telse\n\t\tsec_map = sec_map_4xx;\n\n\t// Copy secmon, warmboot and nx bootloader payloads.\n\tu8 *pdata = (u8 *)hdr + sizeof(pk11_hdr_t);\n\tfor (u32 i = 0; i < 3; i++)\n\t{\n\t\tu32 ssize = sec_size[sec_map[i]];\n\t\tswitch (sec_map[i])\n\t\t{\n\t\tcase PK11_SECTION_WB:\n\t\t\tif (wm_dst)\n\t\t\t\tmemcpy(wm_dst,  pdata, ssize);\n\t\t\tbreak;\n\t\tcase PK11_SECTION_LD:\n\t\t\tif (ldr_dst)\n\t\t\t\tmemcpy(ldr_dst, pdata, ssize);\n\t\t\tbreak;\n\t\tcase PK11_SECTION_SM:\n\t\t\tif (sm_dst)\n\t\t\t\tmemcpy(sm_dst,  pdata, ssize);\n\t\t\tbreak;\n\t\t}\n\t\tpdata += ssize;\n\t}\n\n\treturn sec_map;\n}\n"
  },
  {
    "path": "nyx/nyx_gui/hos/pkg1.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2022-2025 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _PKG1_H_\n#define _PKG1_H_\n\n#include <bdk.h>\n\n#define PKG1_MAGIC 0x31314B50\n\n#define PK11_SECTION_WB 0\n#define PK11_SECTION_LD 1\n#define PK11_SECTION_SM 2\n\n#define PKG1_BOOTLOADER_SIZE          SZ_256K\n#define PKG1_BOOTLOADER_MAIN_OFFSET   (0x100000 / EMMC_BLOCKSIZE)\n#define PKG1_BOOTLOADER_BACKUP_OFFSET (0x140000 / EMMC_BLOCKSIZE)\n#define PKG1_BOOTLOADER_SAFE_OFFSET   (0x000000 / EMMC_BLOCKSIZE)\n#define PKG1_HOS_EKS_OFFSET           (0x180000 / EMMC_BLOCKSIZE)\n\ntypedef struct _bl_hdr_t210b01_t\n{\n/* 0x000 */\tu8  aes_mac[0x10];\n/* 0x010 */\tu8  rsa_sig[0x100];\n/* 0x110 */\tu8  salt[0x20];\n/* 0x130 */\tu8  sha256[0x20];\n/* 0x150 */\tu32 version;\n/* 0x154 */\tu32 size;\n/* 0x158 */\tu32 load_addr;\n/* 0x15C */\tu32 entrypoint;\n/* 0x160 */\tu8  rsvd[0x10];\n} bl_hdr_t210b01_t;\n\ntypedef struct _eks_keys_t\n{\n\tu8 master_kekseed[SE_KEY_128_SIZE];\n\tu8 random_data[0x70];\n\tu8 package1_key[SE_KEY_128_SIZE];\n} eks_keys_t;\n\ntypedef struct _pkg1_eks_t\n{\n\tu8 cmac[SE_KEY_128_SIZE];\n\tu8 ctr[SE_AES_IV_SIZE];\n\teks_keys_t keys;\n\tu8 padding[0x150];\n} pkg1_eks_t;\n\ntypedef struct _pk1_hdr_t\n{\n/* 0x00 */\tu32 si_sha256; // Secure Init.\n/* 0x04 */\tu32 sm_sha256; // Secure Monitor.\n/* 0x08 */\tu32 sl_sha256; // Secure Loader.\n/* 0x0C */\tu32 unk;       // what's this? It's not warmboot.\n/* 0x10 */\tchar timestamp[14];\n/* 0x1E */\tu8 keygen;\n/* 0x1F */\tu8 version;\n} pk1_hdr_t;\n\ntypedef struct _pkg1_id_t\n{\n\tconst char *id;\n\tu16 mkey;\n\tu16 tsec_off;\n\tu32 pkg11_off;\n\tu32 secmon_base;\n\tu32 warmboot_base;\n} pkg1_id_t;\n\ntypedef struct _pk11_hdr_t\n{\n/* 0x00 */\tu32 magic;\n/* 0x04 */\tu32 wb_size;\n/* 0x08 */\tu32 wb_off;\n/* 0x0C */\tu32 pad;\n/* 0x10 */\tu32 ldr_size;\n/* 0x14 */\tu32 ldr_off;\n/* 0x18 */\tu32 sm_size;\n/* 0x1C */\tu32 sm_off;\n} pk11_hdr_t;\n\nconst pkg1_id_t *pkg1_identify(u8 *pkg1, char *build_date);\nbool  pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1);\nconst u8 *pkg1_unpack(void *wm_dst, void *sm_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1);\n\n#endif\n"
  },
  {
    "path": "nyx/nyx_gui/hos/pkg2.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n\n#include <bdk.h>\n\n#include \"pkg2.h\"\n#include \"hos.h\"\n\n#include \"../config.h\"\n#include <libs/fatfs/ff.h>\n#include <libs/compr/blz.h>\n\nextern const u8 package2_keyseed[];\n\nu32 pkg2_newkern_ini1_start;\nu32 pkg2_newkern_ini1_end;\n\n/*#define DPRINTF(...) gfx_printf(__VA_ARGS__)\n#define DEBUG_PRINTING*/\n#define DPRINTF(...)\n\nu32 pkg2_calc_kip1_size(pkg2_kip1_t *kip1)\n{\n\tu32 size = sizeof(pkg2_kip1_t);\n\tfor (u32 j = 0; j < KIP1_NUM_SECTIONS; j++)\n\t\tsize += kip1->sections[j].size_comp;\n\treturn size;\n}\n\nvoid pkg2_get_newkern_info(u8 *kern_data)\n{\n\tu32 crt_start = 0;\n\tu32 pkg2_newkern_ini1_info = 0;\n\tpkg2_newkern_ini1_start    = 0;\n\n\tu32 first_op = *(u32 *)kern_data;\n\tif ((first_op & 0xFE000000) == 0x14000000)\n\t\tcrt_start = (first_op & 0x1FFFFFF) << 2;\n\n\t// Find static OP offset that is close to INI1 offset.\n\tu32 counter_ops = 0x100;\n\twhile (counter_ops)\n\t{\n\t\tif (*(u32 *)(kern_data + crt_start + 0x100 - counter_ops) == PKG2_NEWKERN_GET_INI1_HEURISTIC)\n\t\t{\n\t\t\t// OP found. Add 12 for the INI1 info offset.\n\t\t\tpkg2_newkern_ini1_info = crt_start + 0x100 - counter_ops + 12;\n\n\t\t\t// On v2 kernel with dynamic crt there's a NOP after heuristic. Offset one op.\n\t\t\tif (crt_start)\n\t\t\t\tpkg2_newkern_ini1_info += 4;\n\t\t\tbreak;\n\t\t}\n\n\t\tcounter_ops -= 4;\n\t}\n\n\t// Offset not found?\n\tif (!counter_ops)\n\t\treturn;\n\n\tu32 info_op = *(u32 *)(kern_data + pkg2_newkern_ini1_info);\n\tpkg2_newkern_ini1_info += ((info_op & 0xFFFF) >> 3); // Parse ADR and PC.\n\n\tpkg2_newkern_ini1_start = *(u32 *)(kern_data + pkg2_newkern_ini1_info);\n\tpkg2_newkern_ini1_end   = *(u32 *)(kern_data + pkg2_newkern_ini1_info + 0x8);\n\n\t// On v2 kernel with dynamic crt, values are relative to value address.\n\tif (crt_start)\n\t{\n\t\tpkg2_newkern_ini1_start += pkg2_newkern_ini1_info;\n\t\tpkg2_newkern_ini1_end   += pkg2_newkern_ini1_info + 0x8;\n\t}\n}\n\n//!TODO: Update on mkey changes.\nstatic const u8 mkey_vector_7xx[HOS_MKEY_VER_MAX - HOS_MKEY_VER_810 + 1][SE_KEY_128_SIZE] =\n{\n\t// Master key 7  encrypted with 8.  (7.0.0 with 8.1.0)\n\t{ 0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29 },\n\t// Master key 8  encrypted with 9.  (8.1.0 with 9.0.0)\n\t{ 0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80 },\n\t// Master key 9  encrypted with 10. (9.0.0 with 9.1.0)\n\t{ 0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A },\n\t// Master key 10 encrypted with 11. (9.1.0 with 12.1.0)\n\t{ 0xC1, 0x8D, 0x16, 0xBB, 0x2A, 0xE4, 0x1D, 0xD4, 0xC2, 0xC1, 0xB6, 0x40, 0x94, 0x35, 0x63, 0x98 },\n\t// Master key 11 encrypted with 12. (12.1.0 with 13.0.0)\n\t{ 0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06 },\n\t// Master key 12 encrypted with 13. (13.0.0 with 14.0.0)\n\t{ 0x83, 0x67, 0xAF, 0x01, 0xCF, 0x93, 0xA1, 0xAB, 0x80, 0x45, 0xF7, 0x3F, 0x72, 0xFD, 0x3B, 0x38 },\n\t// Master key 13 encrypted with 14. (14.0.0 with 15.0.0)\n\t{ 0xB1, 0x81, 0xA6, 0x0D, 0x72, 0xC7, 0xEE, 0x15, 0x21, 0xF3, 0xC0, 0xB5, 0x6B, 0x61, 0x6D, 0xE7 },\n\t// Master key 14 encrypted with 15. (15.0.0 with 16.0.0)\n\t{ 0xAF, 0x11, 0x4C, 0x67, 0x17, 0x7A, 0x52, 0x43, 0xF7, 0x70, 0x2F, 0xC7, 0xEF, 0x81, 0x72, 0x16 },\n\t// Master key 15 encrypted with 16. (16.0.0 with 17.0.0)\n\t{ 0x25, 0x12, 0x8B, 0xCB, 0xB5, 0x46, 0xA1, 0xF8, 0xE0, 0x52, 0x15, 0xB7, 0x0B, 0x57, 0x00, 0xBD },\n\t// Master key 16 encrypted with 17. (17.0.0 with 18.0.0)\n\t{ 0x58, 0x15, 0xD2, 0xF6, 0x8A, 0xE8, 0x19, 0xAB, 0xFB, 0x2D, 0x52, 0x9D, 0xE7, 0x55, 0xF3, 0x93 },\n\t// Master key 17 encrypted with 18. (18.0.0 with 19.0.0)\n\t{ 0x4A, 0x01, 0x3B, 0xC7, 0x44, 0x6E, 0x45, 0xBD, 0xE6, 0x5E, 0x2B, 0xEC, 0x07, 0x37, 0x52, 0x86 },\n\t// Master key 18 encrypted with 19. (19.0.0 with 20.0.0)\n\t{ 0x97, 0xE4, 0x11, 0xAB, 0x22, 0x72, 0x1A, 0x1F, 0x70, 0x5C, 0x00, 0xB3, 0x96, 0x30, 0x05, 0x28 },\n\t// Master key 19 encrypted with 20. (20.0.0 with 21.0.0)\n\t{ 0xF7, 0x92, 0xC0, 0xEC, 0xF3, 0xA4, 0x8C, 0xB7, 0x0D, 0xB3, 0xF3, 0xAB, 0x10, 0x9B, 0x18, 0xBA },\n\t// Master key 20 encrypted with 21. (21.0.0 with 22.0.0)\n\t{ 0x14, 0xCB, 0x60, 0x29, 0x3D, 0xE0, 0xFB, 0xF2, 0x5B, 0x60, 0xB6, 0xC5, 0x2E, 0x77, 0x8F, 0x98 },\n};\n\nstatic bool _pkg2_key_unwrap_validate(pkg2_hdr_t *tmp_test, pkg2_hdr_t *hdr, u8 src_slot, u8 *mkey, const u8 *key_seed)\n{\n\t// Decrypt older encrypted mkey.\n\tse_aes_crypt_ecb(src_slot, DECRYPT, mkey, key_seed, SE_KEY_128_SIZE);\n\t// Set and unwrap pkg2 key.\n\tse_aes_key_set(9, mkey, SE_KEY_128_SIZE);\n\tse_aes_unwrap_key(9, 9, package2_keyseed);\n\n\t// Decrypt header.\n\tse_aes_crypt_ctr(9, tmp_test, hdr, sizeof(pkg2_hdr_t), hdr);\n\n\t// Return if header is valid.\n\treturn (tmp_test->magic == PKG2_MAGIC);\n}\n\npkg2_hdr_t *pkg2_decrypt(void *data, u8 mkey)\n{\n\tpkg2_hdr_t mkey_test;\n\tu8 *pdata = (u8 *)data;\n\tu8 pkg2_keyslot = 8;\n\n\t// Skip signature.\n\tpdata += 0x100;\n\n\tpkg2_hdr_t *hdr = (pkg2_hdr_t *)pdata;\n\n\t// Skip header.\n\tpdata += sizeof(pkg2_hdr_t);\n\n\t// Check if we need to decrypt with newer mkeys. Valid for THK for 7.0.0 and up.\n\tse_aes_crypt_ctr(8, &mkey_test, hdr, sizeof(pkg2_hdr_t), hdr);\n\n\tif (mkey_test.magic == PKG2_MAGIC)\n\t\tgoto key_found;\n\n\t// Decrypt older pkg2 via new mkeys.\n\tif ((mkey >= HOS_MKEY_VER_700) && (mkey < HOS_MKEY_VER_MAX))\n\t{\n\t\tu8 tmp_mkey[SE_KEY_128_SIZE];\n\t\tu8 decr_slot = 7; // THK mkey or T210B01 mkey.\n\t\tu8 mkey_seeds_cnt = sizeof(mkey_vector_7xx) / SE_KEY_128_SIZE;\n\t\tu8 mkey_seeds_idx = mkey_seeds_cnt; // Real index + 1.\n\t\tu8 mkey_seeds_min_idx = mkey_seeds_cnt - (HOS_MKEY_VER_MAX - mkey);\n\n\t\twhile (mkey_seeds_cnt)\n\t\t{\n\t\t\t// Decrypt and validate mkey.\n\t\t\tint res = _pkg2_key_unwrap_validate(&mkey_test, hdr, decr_slot,\n\t\t\t\ttmp_mkey, mkey_vector_7xx[mkey_seeds_idx - 1]);\n\n\t\t\tif (res)\n\t\t\t{\n\t\t\t\tpkg2_keyslot = 9;\n\t\t\t\tgoto key_found;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Set current mkey in order to decrypt a lower mkey.\n\t\t\t\tmkey_seeds_idx--;\n\t\t\t\tse_aes_key_set(9, tmp_mkey, SE_KEY_128_SIZE);\n\n\t\t\t\tdecr_slot = 9; // Temp key.\n\n\t\t\t\t// Check if we tried last key for that pkg2 version.\n\t\t\t\t// And start with a lower mkey in case mkey is older.\n\t\t\t\tif (mkey_seeds_idx == mkey_seeds_min_idx)\n\t\t\t\t{\n\t\t\t\t\tmkey_seeds_cnt--;\n\t\t\t\t\tmkey_seeds_idx = mkey_seeds_cnt;\n\t\t\t\t\tdecr_slot = 7; // THK mkey or T210B01 mkey.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\nkey_found:\n\t// Decrypt header.\n\tse_aes_crypt_ctr(pkg2_keyslot, hdr, hdr, sizeof(pkg2_hdr_t), hdr);\n\n\tif (hdr->magic != PKG2_MAGIC)\n\t\treturn NULL;\n\n\t// Decrypt sections.\n\tfor (u32 i = 0; i < 4; i++)\n\t{\nDPRINTF(\"sec %d has size %08X\\n\", i, hdr->sec_size[i]);\n\t\tif (!hdr->sec_size[i])\n\t\t\tcontinue;\n\n\t\tse_aes_crypt_ctr(pkg2_keyslot, pdata, pdata, hdr->sec_size[i], hdr->sec_ctr[i]);\n\n\t\tpdata += hdr->sec_size[i];\n\t}\n\n\treturn hdr;\n}\n"
  },
  {
    "path": "nyx/nyx_gui/hos/pkg2.h",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _PKG2_H_\n#define _PKG2_H_\n\n#include <bdk.h>\n\n#define PKG2_MAGIC      0x31324B50\n#define PKG2_SEC_BASE   0x80000000\n#define PKG2_SEC_KERNEL 0\n#define PKG2_SEC_INI1   1\n#define PKG2_SEC_UNUSED 2\n\n#define INI1_MAGIC 0x31494E49\n\n//! TODO: Update on kernel change if needed.\n// Offset of OP + 12 is the INI1 offset. On v2 with dynamic crt0 it's + 16.\n#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // MOV X21, #0.\n#define PKG2_NEWKERN_START 0x800\n\nextern u32 pkg2_newkern_ini1_start;\nextern u32 pkg2_newkern_ini1_end;\n\ntypedef struct _pkg2_hdr_t\n{\n/* 0x000 */\tu8  ctr[0x10];\n/* 0x010 */\tu8  sec_ctr[4][SE_AES_IV_SIZE];\n/* 0x050 */\tu32 magic;\n/* 0x054 */\tu32 base;\n/* 0x058 */\tu32 pad0;\n/* 0x05C */\tu8  pkg2_ver;\n/* 0x05D */\tu8  bl_ver;\n/* 0x05E */\tu16 pad1;\n/* 0x060 */\tu32 sec_size[4];\n/* 0x070 */\tu32 sec_off[4];\n/* 0x080 */\tu8  sec_sha256[4][SE_SHA_256_SIZE];\n/* 0x100 */\tu8  data[];\n} pkg2_hdr_t;\n\ntypedef struct _pkg2_ini1_t\n{\n\tu32 magic;\n\tu32 size;\n\tu32 num_procs;\n\tu32 pad;\n} pkg2_ini1_t;\n\nenum kip_offset_section\n{\n\tKIP_TEXT    = 0,\n\tKIP_RODATA  = 1,\n\tKIP_DATA    = 2,\n\tKIP_BSS     = 3,\n\tKIP_UNKSEC1 = 4,\n\tKIP_UNKSEC2 = 5\n};\n\n#define KIP1_NUM_SECTIONS 6\n\ntypedef struct _pkg2_kip1_sec_t\n{\n\tu32 offset;\n\tu32 size_decomp;\n\tu32 size_comp;\n\tu32 attrib;\n} pkg2_kip1_sec_t;\n\ntypedef struct _pkg2_kip1_t\n{\n/* 0x000 */\tu32 magic;\n/* 0x004 */\tchar name[12];\n/* 0x010 */\tu64 tid;\n/* 0x018 */\tu32 proc_cat;\n/* 0x01C */\tu8 main_thrd_prio;\n/* 0x01D */\tu8 def_cpu_core;\n/* 0x01E */\tu8 res;\n/* 0x01F */\tu8 flags;\n/* 0x020 */\tpkg2_kip1_sec_t sections[KIP1_NUM_SECTIONS];\n/* 0x080 */\tu32 caps[0x20];\n/* 0x100 */\tu8 data[];\n} pkg2_kip1_t;\n\ntypedef struct _pkg2_kip1_info_t\n{\n\tpkg2_kip1_t *kip1;\n\tu32 size;\n\tlink_t link;\n} pkg2_kip1_info_t;\n\nvoid pkg2_get_newkern_info(u8 *kern_data);\nu32  pkg2_calc_kip1_size(pkg2_kip1_t *kip1);\n\npkg2_hdr_t *pkg2_decrypt(void *data, u8 mkey);\n\n#endif\n"
  },
  {
    "path": "nyx/nyx_gui/libs/fatfs/diskio.c",
    "content": "/*-----------------------------------------------------------------------*/\n/* Low level disk I/O module skeleton for FatFs                          */\n/* (C) ChaN, 2016                                                        */\n/* (C) CTCaer, 2018-2025                                                 */\n/*-----------------------------------------------------------------------*/\n/* If a working storage control module is available, it should be        */\n/* attached to the FatFs via a glue function rather than modifying it.   */\n/* This is an example of glue functions to attach various exsisting      */\n/* storage control modules to the FatFs module with a defined API.       */\n/*-----------------------------------------------------------------------*/\n\n#include <string.h>\n\n#include <bdk.h>\n\n#include <libs/fatfs/diskio.h>\t/* FatFs lower layer API */\n\nstatic u32 sd_rsvd_sectors = 0;\nstatic u32 ramdisk_sectors = 0;\nstatic u32 bis_sectors     = 0;\nstatic u32 emummc_sectors  = 0;\n\nstatic bool bis_write_allowed = false;\n\n/*-----------------------------------------------------------------------*/\n/* Get Drive Status                                                      */\n/*-----------------------------------------------------------------------*/\nDSTATUS disk_status (\n\tBYTE pdrv\t\t/* Physical drive nmuber to identify the drive */\n)\n{\n\treturn 0;\n}\n\n/*-----------------------------------------------------------------------*/\n/* Inidialize a Drive                                                    */\n/*-----------------------------------------------------------------------*/\nDSTATUS disk_initialize (\n\tBYTE pdrv\t\t\t\t/* Physical drive nmuber to identify the drive */\n)\n{\n\treturn 0;\n}\n\n/*-----------------------------------------------------------------------*/\n/* Read Sector(s)                                                        */\n/*-----------------------------------------------------------------------*/\nDRESULT disk_read (\n\tBYTE pdrv,\t\t/* Physical drive nmuber to identify the drive */\n\tBYTE *buff,\t\t/* Data buffer to store read data */\n\tDWORD sector,\t/* Start sector in LBA */\n\tUINT count\t\t/* Number of sectors to read */\n)\n{\n\tswitch (pdrv)\n\t{\n\tcase DRIVE_SD:\n\t\treturn sdmmc_storage_read(&sd_storage, sector, count, (void *)buff);\n\tcase DRIVE_RAM:\n\t\treturn ram_disk_read(sector, count, (void *)buff);\n\tcase DRIVE_EMMC:\n\t\treturn sdmmc_storage_read(&emmc_storage, sector, count, (void *)buff);\n\tcase DRIVE_BIS:\n\tcase DRIVE_EMU:\n\t\treturn nx_emmc_bis_read(sector, count, (void *)buff);\n\t}\n\n\treturn RES_ERROR;\n}\n\n/*-----------------------------------------------------------------------*/\n/* Write Sector(s)                                                       */\n/*-----------------------------------------------------------------------*/\nDRESULT disk_write (\n\tBYTE pdrv,\t\t\t/* Physical drive nmuber to identify the drive */\n\tconst BYTE *buff,\t/* Data to be written */\n\tDWORD sector,\t\t/* Start sector in LBA */\n\tUINT count\t\t\t/* Number of sectors to write */\n)\n{\n\tswitch (pdrv)\n\t{\n\tcase DRIVE_SD:\n\t\treturn sdmmc_storage_write(&sd_storage, sector, count, (void *)buff);\n\tcase DRIVE_RAM:\n\t\treturn ram_disk_write(sector, count, (void *)buff);\n\tcase DRIVE_EMMC:\n\t\treturn RES_WRPRT;\n\tcase DRIVE_BIS:\n\tcase DRIVE_EMU:\n\t\tif (pdrv == DRIVE_BIS && !bis_write_allowed)\n\t\t\treturn RES_WRPRT;\n\t\treturn nx_emmc_bis_write(sector, count, (void *)buff);\n\t}\n\n\treturn RES_ERROR;\n}\n\n/*-----------------------------------------------------------------------*/\n/* Miscellaneous Functions                                               */\n/*-----------------------------------------------------------------------*/\nDRESULT disk_ioctl (\n\tBYTE pdrv,\t\t/* Physical drive nmuber (0..) */\n\tBYTE cmd,\t\t/* Control code */\n\tvoid *buff\t\t/* Buffer to send/receive control data */\n)\n{\n\tDWORD *buf = (DWORD *)buff;\n\n\tswitch (pdrv)\n\t{\n\tcase DRIVE_SD:\n\t\tswitch (cmd)\n\t\t{\n\t\tcase GET_SECTOR_COUNT:\n\t\t\t*buf = sd_storage.sec_cnt - sd_rsvd_sectors;\n\t\t\tbreak;\n\t\tcase GET_BLOCK_SIZE:\n\t\t\t*buf = 32768; // Align to 16MB.\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\n\tcase DRIVE_RAM:\n\t\tswitch (cmd)\n\t\t{\n\t\tcase GET_SECTOR_COUNT:\n\t\t\t*buf = ramdisk_sectors;\n\t\t\tbreak;\n\t\tcase GET_BLOCK_SIZE:\n\t\t\t*buf = 2048; // Align to 1MB.\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\n\tcase DRIVE_BIS:\n\t\tswitch (cmd)\n\t\t{\n\t\tcase GET_SECTOR_COUNT:\n\t\t\t*buf = bis_sectors;\n\t\t\tbreak;\n\t\tcase GET_BLOCK_SIZE:\n\t\t\t*buf = 32768; // Align to 16MB.\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\n\tcase DRIVE_EMU:\n\t\tswitch (cmd)\n\t\t{\n\t\tcase GET_SECTOR_COUNT:\n\t\t\t*buf = emummc_sectors;\n\t\t\tbreak;\n\t\tcase GET_BLOCK_SIZE:\n\t\t\t*buf = 16384; // Align to 8MB (With BOOT0/1 data will be at 16MB BU).\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\n\tdefault: // Catch all for unknown devices.\n\t\tswitch (cmd)\n\t\t{\n\t\tcase CTRL_SYNC:\n\t\t\tbreak;\n\t\tcase GET_SECTOR_COUNT:\n\t\tcase GET_BLOCK_SIZE:\n\t\t\t*buf = 0; // Zero value to force default or abort.\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\t}\n\n\treturn RES_OK;\n}\n\nDRESULT disk_set_info (\n\tBYTE pdrv,\t\t/* Physical drive nmuber (0..) */\n\tBYTE cmd,\t\t/* Control code */\n\tvoid *buff\t\t/* Buffer to send/receive control data */\n)\n{\n\tDWORD *buf = (DWORD *)buff;\n\n\tif (cmd == SET_SECTOR_COUNT)\n\t{\n\t\tswitch (pdrv)\n\t\t{\n\t\tcase DRIVE_SD:\n\t\t\tsd_rsvd_sectors = *buf;\n\t\t\tbreak;\n\n\t\tcase DRIVE_RAM:\n\t\t\tramdisk_sectors = *buf;\n\t\t\tbreak;\n\n\t\tcase DRIVE_BIS:\n\t\t\tbis_sectors = *buf;\n\t\t\tbreak;\n\n\t\tcase DRIVE_EMU:\n\t\t\temummc_sectors = *buf;\n\t\t\tbreak;\n\t\t}\n\t}\n\telse if (cmd == SET_WRITE_PROTECT && pdrv == DRIVE_BIS)\n\t\tbis_write_allowed = *(bool *)buff;\n\n\treturn RES_OK;\n}\n"
  },
  {
    "path": "nyx/nyx_gui/libs/fatfs/ffconf.h",
    "content": "/*---------------------------------------------------------------------------/\n/  FatFs Functional Configurations\n/---------------------------------------------------------------------------*/\n\n#define FFCONF_DEF\t86604\t/* Revision ID */\n\n/*---------------------------------------------------------------------------/\n/ Function Configurations\n/---------------------------------------------------------------------------*/\n\n#define FF_FS_READONLY\t0\n/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)\n/  Read-only configuration removes writing API functions, f_write(), f_sync(),\n/  f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()\n/  and optional writing functions as well. */\n\n\n#define FF_FS_MINIMIZE\t0\n/* This option defines minimization level to remove some basic API functions.\n/\n/   0: Basic functions are fully enabled.\n/   1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()\n/      are removed.\n/   2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.\n/   3: f_lseek() function is removed in addition to 2. */\n\n\n#define FF_USE_STRFUNC\t2\n/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().\n/\n/  0: Disable string functions.\n/  1: Enable without LF-CRLF conversion.\n/  2: Enable with LF-CRLF conversion. */\n\n\n#define FF_USE_FIND\t\t1\n/* This option switches filtered directory read functions, f_findfirst() and\n/  f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */\n\n\n#define FF_USE_MKFS\t\t1\n/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */\n\n\n#if FF_USE_MKFS\n#define FF_MKFS_LABEL \"SWITCH SD  \"\n#endif\n/* This sets FAT/FAT32 label. Exactly 11 characters, all caps. */\n\n\n#define FF_USE_FASTSEEK\t0\n/* This option switches fast seek function. (0:Disable or 1:Enable) */\n\n\n#define FF_FASTFS 1\n#if FF_FASTFS\n#undef FF_USE_FASTSEEK\n#define FF_USE_FASTSEEK\t1\n#endif\n/* This option switches fast access to chained clusters. (0:Disable or 1:Enable) */\n\n\n#define FF_SIMPLE_GPT 1\n/* This option switches support for the first GPT partition. (0:Disable or 1:Enable) */\n\n\n#define FF_USE_EXPAND\t0\n/* This option switches f_expand function. (0:Disable or 1:Enable) */\n\n\n#define FF_USE_CHMOD\t1\n/* This option switches attribute manipulation functions, f_chmod() and f_utime().\n/  (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */\n\n\n#define FF_USE_LABEL\t1\n/* This option switches volume label functions, f_getlabel() and f_setlabel().\n/  (0:Disable or 1:Enable) */\n\n\n#define FF_USE_FORWARD\t0\n/* This option switches f_forward() function. (0:Disable or 1:Enable) */\n\n\n/*---------------------------------------------------------------------------/\n/ Locale and Namespace Configurations\n/---------------------------------------------------------------------------*/\n\n#define FF_CODE_PAGE\t850\n/* This option specifies the OEM code page to be used on the target system.\n/  Incorrect code page setting can cause a file open failure.\n/\n/   437 - U.S.\n/   720 - Arabic\n/   737 - Greek\n/   771 - KBL\n/   775 - Baltic\n/   850 - Latin 1\n/   852 - Latin 2\n/   855 - Cyrillic\n/   857 - Turkish\n/   860 - Portuguese\n/   861 - Icelandic\n/   862 - Hebrew\n/   863 - Canadian French\n/   864 - Arabic\n/   865 - Nordic\n/   866 - Russian\n/   869 - Greek 2\n/   932 - Japanese (DBCS)\n/   936 - Simplified Chinese (DBCS)\n/   949 - Korean (DBCS)\n/   950 - Traditional Chinese (DBCS)\n/     0 - Include all code pages above and configured by f_setcp()\n*/\n\n\n#define FF_USE_LFN\t\t3\n#define FF_MAX_LFN\t\t255\n/* The FF_USE_LFN switches the support for LFN (long file name).\n/\n/   0: Disable LFN. FF_MAX_LFN has no effect.\n/   1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.\n/   2: Enable LFN with dynamic working buffer on the STACK.\n/   3: Enable LFN with dynamic working buffer on the HEAP.\n/\n/  To enable the LFN, ffunicode.c needs to be added to the project. The LFN function\n/  requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and\n/  additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.\n/  The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can\n/  be in range of 12 to 255. It is recommended to be set 255 to fully support LFN\n/  specification.\n/  When use stack for the working buffer, take care on stack overflow. When use heap\n/  memory for the working buffer, memory management functions, ff_memalloc() and\n/  ff_memfree() in ffsystem.c, need to be added to the project. */\n\n\n#define FF_LFN_UNICODE\t0\n/* This option switches the character encoding on the API when LFN is enabled.\n/\n/   0: ANSI/OEM in current CP (TCHAR = char)\n/   1: Unicode in UTF-16 (TCHAR = WCHAR)\n/   2: Unicode in UTF-8 (TCHAR = char)\n/   3: Unicode in UTF-32 (TCHAR = DWORD)\n/\n/  Also behavior of string I/O functions will be affected by this option.\n/  When LFN is not enabled, this option has no effect. */\n\n\n#define FF_LFN_BUF\t\t255\n#define FF_SFN_BUF\t\t12\n/* This set of options defines size of file name members in the FILINFO structure\n/  which is used to read out directory items. These values should be suffcient for\n/  the file names to read. The maximum possible length of the read file name depends\n/  on character encoding. When LFN is not enabled, these options have no effect. */\n\n\n#define FF_STRF_ENCODE\t0\n/* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(),\n/  f_putc(), f_puts and f_printf() convert the character encoding in it.\n/  This option selects assumption of character encoding ON THE FILE to be\n/  read/written via those functions.\n/\n/   0: ANSI/OEM in current CP\n/   1: Unicode in UTF-16LE\n/   2: Unicode in UTF-16BE\n/   3: Unicode in UTF-8\n*/\n\n\n#define FF_FS_RPATH\t\t1\n/* This option configures support for relative path.\n/\n/   0: Disable relative path and remove related functions.\n/   1: Enable relative path. f_chdir() and f_chdrive() are available.\n/   2: f_getcwd() function is available in addition to 1.\n*/\n\n\n/*---------------------------------------------------------------------------/\n/ Drive/Volume Configurations\n/---------------------------------------------------------------------------*/\n\n#define FF_VOLUMES\t\t5\n/* Number of volumes (logical drives) to be used. (1-10) */\n\n\n#define FF_STR_VOLUME_ID\t1\n#define FF_VOLUME_STRS\t\t\"sd\",\"ram\",\"emmc\",\"bis\",\"emu\"\n/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings.\n/  When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive\n/  number in the path name. FF_VOLUME_STRS defines the volume ID strings for each\n/  logical drives. Number of items must not be less than FF_VOLUMES. Valid\n/  characters for the volume ID strings are A-Z, a-z and 0-9, however, they are\n/  compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is\n/  not defined, a user defined volume string table needs to be defined as:\n/\n/  const char* VolumeStr[FF_VOLUMES] = {\"ram\",\"flash\",\"sd\",\"usb\",...\n/  Order is important! Any change to order, must also be reflected to diskio drive enum.\n*/\n\n\n#define FF_MULTI_PARTITION\t0\n/* This option switches support for multiple volumes on the physical drive.\n/  By default (0), each logical drive number is bound to the same physical drive\n/  number and only an FAT volume found on the physical drive will be mounted.\n/  When this function is enabled (1), each logical drive number can be bound to\n/  arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()\n/  funciton will be available. */\n\n\n#define FF_MIN_SS\t\t512\n#define FF_MAX_SS\t\t512\n/* This set of options configures the range of sector size to be supported. (512,\n/  1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and\n/  harddisk. But a larger value may be required for on-board flash memory and some\n/  type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured\n/  for variable sector size mode and disk_ioctl() function needs to implement\n/  GET_SECTOR_SIZE command. */\n\n\n#define FF_USE_TRIM\t\t0\n/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable)\n/  To enable Trim function, also CTRL_TRIM command should be implemented to the\n/  disk_ioctl() function. */\n\n\n#define FF_FS_NOFSINFO\t1\n/* If you need to know correct free space on the FAT32 volume, set bit 0 of this\n/  option, and f_getfree() function at first time after volume mount will force\n/  a full FAT scan. Bit 1 controls the use of last allocated cluster number.\n/\n/  bit0=0: Use free cluster count in the FSINFO if available.\n/  bit0=1: Do not trust free cluster count in the FSINFO.\n/  bit1=0: Use last allocated cluster number in the FSINFO if available.\n/  bit1=1: Do not trust last allocated cluster number in the FSINFO.\n*/\n\n\n\n/*---------------------------------------------------------------------------/\n/ System Configurations\n/---------------------------------------------------------------------------*/\n\n#define FF_FS_TINY\t\t0\n/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)\n/  At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes.\n/  Instead of private sector buffer eliminated from the file object, common sector\n/  buffer in the filesystem object (FATFS) is used for the file data transfer. */\n\n\n#define FF_FS_EXFAT\t\t1\n/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)\n/  To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)\n/  Note that enabling exFAT discards ANSI C (C89) compatibility. */\n\n\n#define FF_FS_NORTC\t\t0\n#define FF_NORTC_MON\t1\n#define FF_NORTC_MDAY\t1\n#define FF_NORTC_YEAR\t2026\n/* The option FF_FS_NORTC switches timestamp function. If the system does not have\n/  any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable\n/  the timestamp function. Every object modified by FatFs will have a fixed timestamp\n/  defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.\n/  To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be\n/  added to the project to read current time form real-time clock. FF_NORTC_MON,\n/  FF_NORTC_MDAY and FF_NORTC_YEAR have no effect.\n/  These options have no effect at read-only configuration (FF_FS_READONLY = 1). */\n\n\n#define FF_FS_LOCK\t\t0\n/* The option FF_FS_LOCK switches file lock function to control duplicated file open\n/  and illegal operation to open objects. This option must be 0 when FF_FS_READONLY\n/  is 1.\n/\n/  0:  Disable file lock function. To avoid volume corruption, application program\n/      should avoid illegal open, remove and rename to the open objects.\n/  >0: Enable file lock function. The value defines how many files/sub-directories\n/      can be opened simultaneously under file lock control. Note that the file\n/      lock control is independent of re-entrancy. */\n\n\n/* #include <somertos.h>\t// O/S definitions */\n#define FF_FS_REENTRANT\t0\n#define FF_FS_TIMEOUT\t1000\n#define FF_SYNC_t\t\tHANDLE\n/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs\n/  module itself. Note that regardless of this option, file access to different\n/  volume is always re-entrant and volume control functions, f_mount(), f_mkfs()\n/  and f_fdisk() function, are always not re-entrant. Only file/directory access\n/  to the same volume is under control of this function.\n/\n/   0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect.\n/   1: Enable re-entrancy. Also user provided synchronization handlers,\n/      ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()\n/      function, must be added to the project. Samples are available in\n/      option/syscall.c.\n/\n/  The FF_FS_TIMEOUT defines timeout period in unit of time tick.\n/  The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,\n/  SemaphoreHandle_t and etc. A header file for O/S definitions needs to be\n/  included somewhere in the scope of ff.h. */\n\n\n\n/*--- End of configuration options ---*/\n"
  },
  {
    "path": "nyx/nyx_gui/link.ld",
    "content": "ENTRY(_start)\n\nSECTIONS {\n\tPROVIDE(__ipl_start = NYX_LOAD_ADDR);\n\t. = __ipl_start;\n\t.text : {\n\t\t*(.text._start);\n\t\tKEEP(*(._ipl_version));\n\t\t*(.text._irq_setup);\n\t\t*(.text*);\n\t}\n\t.data : {\n\t\t*(.data*);\n\t\t*(.rodata*);\n\t}\n\t. = ALIGN(0x10);\n\t__ipl_end = .;\n\t.bss : {\n\t\t__bss_start = .;\n\t\t*(COMMON)\n\t\t*(.bss*)\n\t\t__bss_end = .;\n\t}\n}\n"
  },
  {
    "path": "nyx/nyx_gui/nyx.c",
    "content": "/*\n * Copyright (c) 2018 naehrwert\n *\n * Copyright (c) 2018-2026 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n#include <stdlib.h>\n\n#include <bdk.h>\n\n#include \"config.h\"\n#include \"hos/hos.h\"\n#include <ianos/ianos.h>\n#include <libs/compr/blz.h>\n#include <libs/fatfs/ff.h>\n\n#include \"frontend/fe_emmc_tools.h\"\n#include \"frontend/gui.h\"\n\nnyx_config n_cfg;\nhekate_config h_cfg;\n\nconst volatile ipl_ver_meta_t __attribute__((section (\"._ipl_version\"))) ipl_ver = {\n\t.magic = NYX_MAGIC,\n\t.version = (NYX_VER_MJ + '0') | ((NYX_VER_MN + '0') << 8) | ((NYX_VER_HF + '0') << 16) | ((NYX_VER_RL) << 24),\n};\n\nvolatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR;\nvolatile boot_cfg_t *b_cfg;\n\nchar *emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage)\n{\n\tstatic char emmc_sn[9] = {0};\n\n\t// Check if eMMC S/N storage has valid data and skip parsing in that case.\n\tif (emmc_sn[0] && strcmp(emmc_sn, \"00000000\"))\n\t\tgoto create_dir;\n\n\t// Get actual eMMC S/N.\n\tif (!storage)\n\t{\n\t\tif (emmc_initialize(false))\n\t\t\tstrcpy(emmc_sn, \"00000000\");\n\t\telse\n\t\t{\n\t\t\titoa(emmc_storage.cid.serial, emmc_sn, 16);\n\t\t\temmc_end();\n\t\t}\n\t}\n\telse\n\t\titoa(storage->cid.serial, emmc_sn, 16);\n\ncreate_dir:\n\t// Check if only eMMC S/N was requested.\n\tif (!path)\n\t\treturn emmc_sn;\n\n\t// Create main folder.\n\tstrcpy(path, \"backup\");\n\tf_mkdir(path);\n\n\t// Create eMMC S/N folder.\n\tstrcat(path, \"/\");\n\tstrcat(path, emmc_sn);\n\tf_mkdir(path);\n\n\t// Create sub folder if defined. Dir slash must be included.\n\tstrcat(path, sub_dir);  // Can be a null-terminator.\n\tif (strlen(sub_dir))\n\t\tf_mkdir(path);\n\n\t// Add filename.\n\tstrcat(path, \"/\");\n\tstrcat(path, filename); // Can be a null-terminator.\n\n\treturn emmc_sn;\n}\n\n// This is a safe and unused DRAM region for our payloads.\n#define RELOC_META_OFF      0x7C\n#define PATCHED_RELOC_SZ    0x94\n#define PATCHED_RELOC_STACK 0x40007000\n#define PATCHED_RELOC_ENTRY 0x40010000\n#define EXT_PAYLOAD_ADDR    0xC0000000\n#define RCM_PAYLOAD_ADDR    (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))\n\nstatic void _reloc_append(u32 payload_dst, u32 payload_src, u32 payload_size)\n{\n\tmemcpy((u8 *)payload_src, (u8 *)nyx_str->hekate, PATCHED_RELOC_SZ);\n\n\tvolatile reloc_meta_t *relocator = (reloc_meta_t *)(payload_src + RELOC_META_OFF);\n\n\trelocator->start = payload_dst - ALIGN(PATCHED_RELOC_SZ, 0x10);\n\trelocator->stack = PATCHED_RELOC_STACK;\n\trelocator->end   = payload_dst + payload_size;\n\trelocator->ep    = payload_dst;\n}\n\nlv_res_t launch_payload(lv_obj_t *list)\n{\n\tconst char *filename = lv_list_get_btn_text(list);\n\n\tif (!filename || !filename[0])\n\t\tgoto out;\n\n\tchar path[128];\n\n\tstrcpy(path,\"bootloader/payloads/\");\n\tstrcat(path, filename);\n\n\tif (sd_mount())\n\t\tgoto out;\n\n\t// Read payload.\n\tu32 size = 0;\n\tvoid *buf = sd_file_read(path, &size);\n\tif (!buf)\n\t{\n\t\tEPRINTFARGS(\"Payload file is missing!\\n(%s)\", path);\n\n\t\tgoto out;\n\t}\n\n\t// Check if it safely fits IRAM.\n\tif (size > 0x30000)\n\t{\n\t\tEPRINTF(\"Payload is too big!\");\n\n\t\tgoto out;\n\t}\n\n\tsd_end();\n\n\t// Copy the payload to our chosen address.\n\tmemcpy((void *)RCM_PAYLOAD_ADDR, buf, size);\n\n\t// Append relocator.\n\t_reloc_append(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10));\n\n\thw_deinit(false);\n\n\t// Launch our payload.\n\tvoid (*payload_ptr)() = (void *)EXT_PAYLOAD_ADDR;\n\t(*payload_ptr)();\n\nout:\n\tsd_unmount();\n\n\treturn LV_RES_OK;\n}\n\nstatic void _load_saved_configuration()\n{\n\tLIST_INIT(ini_sections);\n\tLIST_INIT(ini_nyx_sections);\n\n\tif (ini_parse(&ini_sections, \"bootloader/hekate_ipl.ini\", false))\n\t{\n\t\tcreate_config_entry();\n\t\tgoto skip_main_cfg_parse;\n\t}\n\n\t// Load hekate configuration.\n\tLIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)\n\t{\n\t\t// Only parse config section.\n\t\tif (ini_sec->type == INI_CHOICE && !strcmp(ini_sec->name, \"config\"))\n\t\t{\n\t\t\tLIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)\n\t\t\t{\n\t\t\t\tif      (!strcmp(\"autoboot\",      kv->key))\n\t\t\t\t\th_cfg.autoboot      = atoi(kv->val);\n\t\t\t\telse if (!strcmp(\"autoboot_list\", kv->key))\n\t\t\t\t\th_cfg.autoboot_list = atoi(kv->val);\n\t\t\t\telse if (!strcmp(\"bootwait\",      kv->key))\n\t\t\t\t\th_cfg.bootwait      = atoi(kv->val);\n\t\t\t\telse if (!strcmp(\"backlight\",     kv->key))\n\t\t\t\t{\n\t\t\t\t\th_cfg.backlight = atoi(kv->val);\n\t\t\t\t\tif (h_cfg.backlight <= 20)\n\t\t\t\t\t\th_cfg.backlight = 30;\n\t\t\t\t}\n\t\t\t\telse if (!strcmp(\"noticker\",    kv->key))\n\t\t\t\t\th_cfg.noticker    = atoi(kv->val);\n\t\t\t\telse if (!strcmp(\"autohosoff\",  kv->key))\n\t\t\t\t\th_cfg.autohosoff  = atoi(kv->val);\n\t\t\t\telse if (!strcmp(\"autonogc\",    kv->key))\n\t\t\t\t\th_cfg.autonogc    = atoi(kv->val);\n\t\t\t\telse if (!strcmp(\"updater2p\",   kv->key))\n\t\t\t\t\th_cfg.updater2p   = atoi(kv->val);\n\t\t\t\telse if (!strcmp(\"bootprotect\", kv->key))\n\t\t\t\t\th_cfg.bootprotect = atoi(kv->val);\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tini_free(&ini_sections);\n\nskip_main_cfg_parse:\n\tif (ini_parse(&ini_nyx_sections, \"bootloader/nyx.ini\", false))\n\t\treturn;\n\n\t// Load Nyx configuration.\n\tLIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_nyx_sections, link)\n\t{\n\t\t// Only parse config section.\n\t\tif (ini_sec->type == INI_CHOICE && !strcmp(ini_sec->name, \"config\"))\n\t\t{\n\t\t\tbool time_old_raw = false;\n\t\t\tLIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)\n\t\t\t{\n\t\t\t\tif      (!strcmp(\"themebg\",      kv->key))\n\t\t\t\t\tn_cfg.theme_bg       = strtol(kv->val, NULL, 16);\n\t\t\t\telse if (!strcmp(\"themecolor\",   kv->key))\n\t\t\t\t\tn_cfg.theme_color    = atoi(kv->val);\n\t\t\t\telse if (!strcmp(\"entries5col\",  kv->key))\n\t\t\t\t\tn_cfg.entries_5_col  = atoi(kv->val) == 1;\n\t\t\t\telse if (!strcmp(\"timeoffset\",   kv->key))\n\t\t\t\t{\n\t\t\t\t\tn_cfg.timeoffset = strtol(kv->val, NULL, 16);\n\t\t\t\t\tif (n_cfg.timeoffset != 1)\n\t\t\t\t\t\tmax77620_rtc_set_epoch_offset((int)n_cfg.timeoffset);\n\t\t\t\t}\n\t\t\t\telse if (!strcmp(\"timeoff\",      kv->key))\n\t\t\t\t{\n\t\t\t\t\tif (strtol(kv->val, NULL, 16) == 1)\n\t\t\t\t\t\ttime_old_raw = true;\n\t\t\t\t}\n\t\t\t\telse if (!strcmp(\"timedst\",      kv->key))\n\t\t\t\t\tn_cfg.timedst        = atoi(kv->val);\n\t\t\t\telse if (!strcmp(\"homescreen\",   kv->key))\n\t\t\t\t\tn_cfg.home_screen    = atoi(kv->val);\n\t\t\t\telse if (!strcmp(\"verification\", kv->key))\n\t\t\t\t\tn_cfg.verification   = atoi(kv->val);\n\t\t\t\telse if (!strcmp(\"umsemmcrw\",    kv->key))\n\t\t\t\t\tn_cfg.ums_emmc_rw    = atoi(kv->val) == 1;\n\t\t\t\telse if (!strcmp(\"jcdisable\",    kv->key))\n\t\t\t\t\tn_cfg.jc_disable     = atoi(kv->val) == 1;\n\t\t\t\telse if (!strcmp(\"jcforceright\", kv->key))\n\t\t\t\t\tn_cfg.jc_force_right = atoi(kv->val) == 1;\n\t\t\t\telse if (!strcmp(\"bpmpclock\",    kv->key))\n\t\t\t\t\tn_cfg.bpmp_clock     = atoi(kv->val);\n\t\t\t}\n\n\t\t\t// Check if user canceled time setting before.\n\t\t\tif (time_old_raw && !n_cfg.timeoffset)\n\t\t\t\tn_cfg.timeoffset = 1;\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Set auto DST here in case it's missing.\n\tmax77620_rtc_set_auto_dst(n_cfg.timedst);\n\n\tini_free(&ini_nyx_sections);\n}\n\nstatic int nyx_load_resources()\n{\n\tFIL fp;\n\tint res;\n\n\tres = f_open(&fp, \"bootloader/sys/res.pak\", FA_READ);\n\tif (res)\n\t\treturn res;\n\n\tres = f_read(&fp, (void *)NYX_RES_ADDR, f_size(&fp), NULL);\n\tf_close(&fp);\n\n\treturn res;\n}\n\nstatic void nyx_load_bg_icons()\n{\n\t// If no custom switch icon exists, load normal.\n\tif (!f_stat(\"bootloader/res/icon_switch_custom.bmp\", NULL))\n\t\ticon_switch = bmp_to_lvimg_obj(\"bootloader/res/icon_switch_custom.bmp\");\n\telse\n\t\ticon_switch = bmp_to_lvimg_obj(\"bootloader/res/icon_switch.bmp\");\n\n\t// If no custom payload icon exists, load normal.\n\tif (!f_stat(\"bootloader/res/icon_payload_custom.bmp\", NULL))\n\t\ticon_payload = bmp_to_lvimg_obj(\"bootloader/res/icon_payload_custom.bmp\");\n\telse\n\t\ticon_payload = bmp_to_lvimg_obj(\"bootloader/res/icon_payload.bmp\");\n\n\t// Load background resource if any.\n\thekate_bg = bmp_to_lvimg_obj(\"bootloader/res/background.bmp\");\n}\n\n#define EXCP_EN_ADDR   0x4003FF1C\n#define  EXCP_MAGIC 0x30505645      // EVP0\n#define EXCP_TYPE_ADDR 0x4003FF18\n#define  EXCP_TYPE_RESET 0x545352   // RST\n#define  EXCP_TYPE_UNDEF 0x464455   // UDF\n#define  EXCP_TYPE_PABRT 0x54424150 // PABT\n#define  EXCP_TYPE_DABRT 0x54424144 // DABT\n#define EXCP_LR_ADDR   0x4003FF14\n\nenum {\n\tSD_NO_ERROR    = 0,\n\tSD_MOUNT_ERROR = 1,\n\tSD_FILE_ERROR  = 2\n};\n\nstatic void _show_errors(int sd_error)\n{\n\tu32 *excp_enabled = (u32 *)EXCP_EN_ADDR;\n\tu32 *excp_type = (u32 *)EXCP_TYPE_ADDR;\n\tu32 *excp_lr = (u32 *)EXCP_LR_ADDR;\n\n\tif (*excp_enabled == EXCP_MAGIC || sd_error)\n\t{\n\t\tgfx_clear_grey(0);\n\t\tgfx_con_setpos(0, 0, 0);\n\t\tdisplay_backlight_brightness(150, 1000);\n\t\tdisplay_init_window_d_console();\n\t\tdisplay_window_d_console_enable();\n\t}\n\n\tswitch (sd_error)\n\t{\n\tcase SD_MOUNT_ERROR:\n\t\tWPRINTF(\"Failed to init or mount SD!\\n\");\n\t\tgoto error_occured;\n\tcase SD_FILE_ERROR:\n\t\tWPRINTF(\"Failed to load GUI resources!\\nres.pak not found or corrupted.\\n\");\n\t\tgoto error_occured;\n\tcase SD_NO_ERROR:\n\tdefault:\n\t\tbreak;\n\t}\n\n\tif (*excp_enabled == EXCP_MAGIC)\n\t{\n\t\tWPRINTFARGS(\"Nyx exception occurred (LR %08X):\\n\", *excp_lr);\n\t\tswitch (*excp_type)\n\t\t{\n\t\tcase EXCP_TYPE_RESET:\n\t\t\tWPRINTF(\"RESET\");\n\t\t\tbreak;\n\t\tcase EXCP_TYPE_UNDEF:\n\t\t\tWPRINTF(\"UNDEF\");\n\t\t\tbreak;\n\t\tcase EXCP_TYPE_PABRT:\n\t\t\tWPRINTF(\"PABRT\");\n\t\t\tbreak;\n\t\tcase EXCP_TYPE_DABRT:\n\t\t\tWPRINTF(\"DABRT\");\n\t\t\tbreak;\n\t\t}\n\t\tgfx_puts(\"\\n\");\n\n\t\t// Clear the exception.\n\t\t*excp_lr = 0;\n\t\t*excp_type = 0;\n\t\t*excp_enabled = 0;\n\nerror_occured:\n\t\tWPRINTF(\"Press any key to reload Nyx...\");\n\n\t\tmsleep(1000);\n\t\tbtn_wait();\n\n\t\treload_nyx(NULL, true);\n\t}\n}\n\nvoid nyx_init_load_res()\n{\n\tbpmp_mmu_enable();\n\tbpmp_clk_rate_get();\n\n\t// Set a modest clock for init. It will be restored later if possible.\n\tbpmp_clk_rate_set(BPMP_CLK_LOWEST_BOOST);\n\n\t// Set bootloader's default configuration.\n\tset_default_configuration();\n\tset_nyx_default_configuration();\n\n\t// Reset new info if magic not correct.\n\tif (nyx_str->info.magic != NYX_NEW_INFO)\n\t{\n\t\tnyx_str->info.sd_init = 0;\n\t\tfor (u32 i = 0; i < 3; i++)\n\t\t\tnyx_str->info.sd_errors[i] = 0;\n\t}\n\n\t// Reset new extended info if magic not correct.\n\tif (nyx_str->info_ex.magic != NYX_NEW_INFO)\n\t\tnyx_str->info_ex.rsvd_flags = 0;\n\n\t// Clear info magic.\n\tnyx_str->info.magic    = 0;\n\tnyx_str->info_ex.magic = 0;\n\n\t// Override DRAM ID if needed.\n\tif (nyx_str->info_ex.rsvd_flags & RSVD_FLAG_DRAM_8GB)\n\t\tfuse_force_8gb_dramid();\n\n\t// Set display id from previous initialization.\n\tdisplay_set_decoded_panel_id(nyx_str->info.panel_id);\n\n\t// Initialize gfx console.\n\tgfx_init_ctxt((u32 *)LOG_FB_ADDRESS, 1280, 656, 656);\n\tgfx_con_init();\n\n\t// Show exception errors if any.\n\t_show_errors(SD_NO_ERROR);\n\n\t// Try 2 times to mount SD card.\n\tif (sd_mount())\n\t{\n\t\t// Restore speed to SDR104.\n\t\tsd_end();\n\n\t\t// Retry.\n\t\tif (sd_mount())\n\t\t\t_show_errors(SD_MOUNT_ERROR); // Fatal.\n\t}\n\n\t// Train DRAM and switch to max frequency.\n\tminerva_init((minerva_str_t *)&nyx_str->minerva);\n\tminerva_change_freq(FREQ_1600);\n\n\t// Load hekate/Nyx configuration.\n\t_load_saved_configuration();\n\n\t// Load Nyx resources.\n\tif (nyx_load_resources())\n\t{\n\t\t// Try again.\n\t\tif (nyx_load_resources())\n\t\t\t_show_errors(SD_FILE_ERROR); // Fatal since resources are mandatory.\n\t}\n\n\t// Initialize nyx cfg to lower clock on first boot.\n\t// In case of lower binned SoC, this can help with hangs.\n\tif (!n_cfg.bpmp_clock)\n\t{\n\t\t// Set lower clock and save it.\n\t\tn_cfg.bpmp_clock = 2;\n\t\tcreate_nyx_config_entry(false);\n\n\t\t// Start at max clock and test it.\n\t\tn_cfg.bpmp_clock = 0;\n\t}\n\n\t// Set selected clock.\n\tswitch (n_cfg.bpmp_clock)\n\t{\n\tcase 0:\n\tcase 1:\n\t\tbpmp_clk_rate_set(BPMP_CLK_BIN0_BOOST);\n\t\tbreak;\n\tcase 2:\n\t\tbpmp_clk_rate_set(BPMP_CLK_BIN1_BOOST);\n\t\tbreak;\n\tcase 3:\n\t\tbpmp_clk_rate_set(BPMP_CLK_BIN2_BOOST);\n\t\tbreak;\n\tcase 4:\n\t\tbpmp_clk_rate_set(BPMP_CLK_BIN3_BOOST);\n\t\tbreak;\n\tcase 5:\n\tdefault:\n\t\tbpmp_clk_rate_set(BPMP_CLK_NORMAL);\n\t\tbreak;\n\t}\n\n\t// Load default launch icons and background if it exists.\n\tnyx_load_bg_icons();\n\n\t// Unmount FAT partition.\n\tsd_unmount();\n}\n\nvoid ipl_main()\n{\n\t// Set heap address.\n\theap_init((void *)IPL_HEAP_START);\n\n\tb_cfg = (boot_cfg_t *)(nyx_str->hekate + 0x94);\n\n#ifdef DEBUG_UART_PORT\n\t// Enable the selected uart debug port.\n\t#if   (DEBUG_UART_PORT == UART_B)\n\t\tgpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);\n\t#elif (DEBUG_UART_PORT == UART_C)\n\t\tgpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);\n\t#endif\n\tpinmux_config_uart(DEBUG_UART_PORT);\n\tclock_enable_uart(DEBUG_UART_PORT);\n\tuart_init(DEBUG_UART_PORT, DEBUG_UART_BAUDRATE, UART_AO_TX_AO_RX);\n\tuart_invert(DEBUG_UART_PORT, DEBUG_UART_INVERT, UART_INVERT_TXD);\n\n\tuart_send(DEBUG_UART_PORT, (u8 *)\"hekate-NYX: Hello!\\r\\n\", 20);\n\tuart_wait_xfer(DEBUG_UART_PORT, UART_TX_IDLE);\n#endif\n\n\t// Initialize the rest of hw and load Nyx resources.\n\tnyx_init_load_res();\n\n\t// Initialize Nyx GUI and show it.\n\tnyx_load_and_run();\n\n\t// Halt BPMP if we managed to get out of execution.\n\twhile (true)\n\t\tbpmp_halt();\n}\n"
  },
  {
    "path": "nyx/nyx_gui/start.S",
    "content": "/*\n* Copyright (c) 2018 naehrwert\n*\n* This program is free software; you can redistribute it and/or modify it\n* under the terms and conditions of the GNU General Public License,\n* version 2, as published by the Free Software Foundation.\n*\n* This program is distributed in the hope it will be useful, but WITHOUT\n* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n* more details.\n*\n* You should have received a copy of the GNU General Public License\n* along with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n.section .text._start\n.arm\n\n.extern _reloc_ipl\n.type _reloc_ipl, %function\n\n.extern memset\n.type memset, %function\n\n.extern _irq_setup\n.type _irq_setup, %function\n\n.globl _start\n.type _start, %function\n_start:\n\tADR R0, _start\n\tLDR R1, =__ipl_start\n\tCMP R0, R1\n\tBEQ _real_start\n\n\t/* If we are not in the right location already, copy a relocator to upper IRAM. */\n\tADR R2, _reloc_ipl\n\tLDR R3, =0x4003FF00\n\tMOV R4, #(_real_start - _reloc_ipl)\n_copy_loop:\n\tLDMIA R2!, {R5}\n\tSTMIA R3!, {R5}\n\tSUBS R4, #4\n\tBNE _copy_loop\n\n\t/* Use the relocator to copy ourselves into the right place. */\n\tLDR R2, =__ipl_end\n\tSUB R2, R2, R1\n\tLDR R3, =_real_start\n\tLDR R4, =0x4003FF00\n\tBX R4\n\n_reloc_ipl:\n\tLDMIA R0!, {R4-R7}\n\tSTMIA R1!, {R4-R7}\n\tSUBS R2, #0x10\n\tBNE _reloc_ipl\n\t/* Jump to the relocated entry. */\n\tBX R3\n\n_real_start:\n\t/* We place our stack in SDRAM. */\n\tLDR SP, =0x4003F000\n\tLDR R0, =__bss_start\n\tEOR R1, R1, R1\n\tLDR R2, =__bss_end\n\tSUB R2, R2, R0\n\tBL memset\n\tBL _irq_setup\n\tB .\n\n.globl pivot_stack\n.type pivot_stack, %function\npivot_stack:\n\tMOV SP, R0\n\tBX LR\n"
  },
  {
    "path": "res/hekate_ipl_template.ini",
    "content": "[config]\nautoboot=0\nautoboot_list=0\nbootwait=3\nnoticker=0\nbacklight=100\nautohosoff=1\nautonogc=1\nupdater2p=1\nbootprotect=0\n\n# Only include above what you want to change from defaults.\n# config.c in bootloader and Nyx have all the defaults.\n\n\n{-------- Stock -------}\n[Stock]\npkg3=atmosphere/package3\nstock=1\nemummc_force_disable=1\n\n# This disables kernel patching and CFW kips.\n# Includes exosphere and warmboot, ONLY when >= 7.0.0 and Erista.\n# Includes exosphere on Mariko.\n# Exosphere/warmboot are not identifiable as it is now.\n# This is the closest to OFW, especially when AutoRCM is needed.\n\n\n\n{-- Custom Firmwares --}\n[Atmo Vanilla]\npkg3=atmosphere/package3\nkip1=atmosphere/kips/*\n\n# Note:\n# The above adheres to emummc.ini. It will launch emuMMC if enabled, otherwise sysMMC.\n# The kip1 line can be omitted if wanted. It's in example in order to mimic fusee behavior.\n\n\n\n[Atmo EMU]\npkg3=atmosphere/package3\nemummcforce=1\n\n[Atmo SYS]\npkg3=atmosphere/package3\nemummc_force_disable=1\n\n# Note:\n# You can have 2 entries of everything where one can boot with emuMMC and one without,\n#  via the emummc_force_disable=1 and emummcforce=1 keys. Like the examples above.\n# These 2 entries allow user to easily boot enforceable SYS or EMU CFW\n# emummcforce=1 makes sure that emuMMC is enabled otherwise it will error out\n#  in order to protect user from booting SYS without knowing.\n# emummc_force_disable=1 disables emuMMC and allows user to boot SYS CFW\n#  even if emuMMC is enabled.\n\n\n\n[Atmo EMU2]\npkg3=atmosphere/package3\nemupath=emuMMC/SD02\nemummcforce=1\n\n# Note:\n# The above allows you to swap emuMMC on the fly while booting.\n# The path defined is the main path of emuMMC folder, for example\n#  emuMMC/RAW1, emuMMC/RAW2, emuMMC/SD00, emuMMC/TEST, etc.\n# Only works with emuMMC created/migrated via hekate.\n\n\n\n[Atmo with extra kips]\npkg3=atmosphere/package3\nkip1=cfw/mods/mods_extra/*\nkip1=cfw/mods/mods_extra/single/extra.kip\n\n# Note:\n# The above can be used with any pkg3 entry. Like the ones above.\n# You can even override atmosphere (pkg3) kips with this.\n# The wildcard '*' like above can be used to load all kips from a selected directory.\n\n\n{-- Custom Firmwares Old methods --}\n[CFW PKG3 extra kips & patches]\npkg3=atmosphere/package3\nkip1patch=name_of_patch\nkip1=cfw/mods/mods_extra/*\nkip1=cfw/mods/mods_extra/single/extra.kip\n\n# Note:\n# Both options for kip1 can be used. Wildcard and single.\n#  You can override kips loaded from PKG3/FSS0 if you define them after the pkg3 key.\n# If kip1 patch resides in patches.ini and that file OR the patch for\n#  current HOS version does not exist, it will error out.\n\n\n\n[CFW KIPs method]\nsecmon=cfw/mods/exosphere.bin\nwarmboot=cfw/mods/lp0fw.bin\nkip1=cfw/mods/loader.kip\nkip1=cfw/mods/boot.kip\nkip1=cfw/mods/spl.kip\nkip1=cfw/mods/sm.kip\nkip1=cfw/mods/pm.kip\nkip1=cfw/mods/ams_mitm.kip\natmosphere=1\n\n# Note:\n# All kips defined method. This can be changed to what is below also.\n# atmosphere=1 key is IMPORTANT when no PKG3/FSS0 is defined.\n\n\n\n[CFW KIPs method with wildcard]\nsecmon=cfw/mods/exosphere.bin\nwarmboot=cfw/mods/lp0fw.bin\nkip1=cfw/mods/*\nkip1=cfw/mods/extra/extra.kip\natmosphere=1\n\n# Note:\n# All kips parsed from a directory, plus extra added.\n\n\n\n{------- Tools -------}\n[Lockpick RCM]\npayload=bootloader/payloads/Lockpick_RCM.bin\n\n\n\n# hekate - CTCaer mod v5.8.0 .ini template\n#\n# All entries in this template can have these stylistic keys:\n#  like logopath= key which is for bootlogo and icon= key for Nyx icon.\n# Other than these, there many other keys to choose from, like the exosphere configuration keys.\n# All of them are descibed in the main README.\n#\n# You can disable a key in a boot entry by using ; in front of it\n#  Do not use # because that will break it.\n#\n# Do not use newline between keys or spaces before and after a key name/var.\n# That will break the boot entry of config entry.\n#\n# NOT TO BE USED AS IS!\n#  Pick [config] and then only the needed [sections]. # or { } lines can be ommited.\n#  If [config] is not copied, hekate will create one with defaults.\n#  If wanted, only the changed [config] defaults can be set. The rest will be created automatically.\n#\n# Note: The keys in a section are parsed sequentially.\n#  This is important for override order of keys (if any double or matching functionality).\n\n# Disclaimer: There are many combos, that allow hekate to basically boot everything NATIVELY.\n#  hekate will ALWAYS do what YOU tell it to do. If you get an error,\n#  that means that hekate_ipl.ini was wrongly made or files are missing/corrupt/etc!\n"
  },
  {
    "path": "res/patches_template.ini",
    "content": "# ASCII non-extended\n# A KIP section is [kip1_name:sha256_hex_8bytes]\n# A patchset is .patch_name=kip_section_dec:offset_hex_0x:length_hex_0x:src_data_hex,dst_data_hex\n#\n# _dec: 1 char decimal | _hex_0x: max u32 prefixed with 0x | _hex: hex array.\n# Kip1 section decimals: TEXT: 0, RODATA: 1, DATA: 2.\n# \n# Careful when editing this, otherwise it will fail to be parsed.\n#\n# Note: the below patches is an obsolete method that was used\n#  to install homebrew for a qlaunch icon or 3.5GB RAM access.\n#  This is useless nowadays, because title override or custom qlaunch are a more proper solution.\n\n#FS Patches for 1.0.0\n[FS:de9fdda4085dd5fe]\n.nosigchk=0:0x194A0:0x4:BA090094,E0031F2A\n.nosigchk=0:0x3A79C:0x4:E0060036,1F2003D5\n\n#FS Patches for 1.0.0  exfat\n[FS:fc3e80991dca1796]\n.nosigchk=0:0x194A0:0x4:BA090094,E0031F2A\n.nosigchk=0:0x3A79C:0x4:E0060036,1F2003D5\n\n"
  },
  {
    "path": "tools/bin2c/Makefile",
    "content": "NATIVE_CC ?= gcc\n\nifeq (, $(shell which $(NATIVE_CC) 2>/dev/null))\n$(error \"Native GCC is missing. Please install it first. If it's path is custom, set it with export NATIVE_CC=<path to native gcc toolchain>\")\nendif\n\n.PHONY: all clean\n\nall: bin2c\n\t@echo > /dev/null\n\nclean:\n\t@rm -f bin2c\n\nbin2c: bin2c.c\n\t@$(NATIVE_CC) -o $@ bin2c.c\n"
  },
  {
    "path": "tools/bin2c/bin2c.c",
    "content": "/*\n * This is bin2c program, which allows you to convert binary file to\n * C language array, for use as embedded resource, for instance you can\n * embed graphics or audio file directly into your program.\n * This is public domain software, use it on your own risk.\n * Contact Serge Fukanchik at fuxx@mail.ru  if you have any questions.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <ctype.h>\n#include <unistd.h>\n\n/* Replace . with _ */\nchar*\nmake_ident ( char* name )\n{\n  char* ret;\n  char* p;\n\n  ret = strdup ( name );\n\n  for ( p = ret; p[0]; p++ )\n  {\n    if ( !isalnum ( p[0] ) ) p[0] = '_';\n  }\n  return ret;\n}\n\nint\nmain ( int argc, char* argv[] )\n{\n  unsigned char buf[BUFSIZ];\n  char* ident;\n  FILE *fd;\n  size_t size, i, total, blksize = BUFSIZ;\n  int need_comma = 0;\n\n  if ( argc != 2 )\n  {\n    fprintf ( stderr, \"Usage: %s binary_file > output_file\\n\", argv[0] );\n    return -1;\n  }\n\n  fd = fopen ( argv[1], \"rb\" );\n  if ( fd == NULL )\n  {\n    fprintf ( stderr, \"%s: can't open %s for reading\\n\", argv[0], argv[1] );\n    return -1;\n  }\n\n  fseek(fd, 0, SEEK_END);\n  size = ftell(fd);\n  rewind(fd);\n\n  ident = make_ident ( argv[1] );\n\n  printf ( \"static const unsigned char __attribute__((section (\\\"._%s\\\"))) %s[] = {\", ident, ident );\n  for ( total = 0; total < size; )\n  {\n    if ( size - total < blksize ) blksize = size - total;\n    if ( fread ( buf, 1, blksize, fd ) != blksize )\n    {\n      fprintf ( stderr, \"%s: file read error\\n\", argv[0] );\n      return -1;\n    }\n    for ( i = 0; i < blksize; i++ )\n    {\n      if ( need_comma ) printf ( \", \" );\n      else need_comma = 1;\n      if ( ( total % 11 ) == 0 ) printf ( \"\\n\\t\" );\n      printf ( \"0x%.2x\", buf[i] );\n      total++;\n    }\n  }\n  printf ( \"\\n};\\n\" );\n\n  fclose ( fd );\n  free ( ident );\n\n  return 0;\n}\n"
  },
  {
    "path": "tools/emc.def",
    "content": "EMC_DBG                                                 8\nEMC_CFG                                                 C\nEMC_CONFIG_SAMPLE_DELAY                                 5f0\nEMC_CFG_UPDATE                                          5f4\nEMC_ADR_CFG                                             10\nEMC_REFCTRL                                             20\nEMC_PIN                                                 24\nEMC_TIMING_CONTROL                                      28\nEMC_RC                                                  2c\nEMC_RFC                                                 30\nEMC_RFCPB                                               590\nEMC_RAS                                                 34\nEMC_RP                                                  38\nEMC_R2W                                                 3c\nEMC_W2R                                                 40\nEMC_R2P                                                 44\nEMC_W2P                                                 48\nEMC_CCDMW                                               5c0\nEMC_RD_RCD                                              4c\nEMC_WR_RCD                                              50\nEMC_RRD                                                 54\nEMC_REXT                                                58\nEMC_WDV                                                 5c\nEMC_QUSE                                                60\nEMC_QRST                                                64\nEMC_ISSUE_QRST                                          428\nEMC_QSAFE                                               68\nEMC_RDV                                                 6c\nEMC_REFRESH                                             70\nEMC_BURST_REFRESH_NUM                                   74\nEMC_PDEX2WR                                             78\nEMC_PDEX2RD                                             7c\nEMC_PDEX2CKE                                            118\nEMC_PCHG2PDEN                                           80\nEMC_ACT2PDEN                                            84\nEMC_AR2PDEN                                             88\nEMC_RW2PDEN                                             8c\nEMC_CKE2PDEN                                            11c\nEMC_TXSR                                                90\nEMC_TCKE                                                94\nEMC_TFAW                                                98\nEMC_TRPAB                                               9c\nEMC_TCLKSTABLE                                          a0\nEMC_TCLKSTOP                                            a4\nEMC_TREFBW                                              a8\nEMC_TPPD                                                ac\nEMC_PDEX2MRR                                            b4\nEMC_ODT_WRITE                                           b0\nEMC_WEXT                                                b8\nEMC_RFC_SLR                                             c0\nEMC_MRS_WAIT_CNT2                                       c4\nEMC_MRS_WAIT_CNT                                        c8\nEMC_MRS                                                 cc\nEMC_EMRS                                                d0\nEMC_REF                                                 d4\nEMC_PRE                                                 d8\nEMC_NOP                                                 dc\nEMC_SELF_REF                                            e0\nEMC_DPD                                                 e4\nEMC_MRW                                                 e8\nEMC_MRR                                                 ec\nEMC_CMDQ                                                f0\nEMC_MC2EMCQ                                             f4\nEMC_FBIO_SPARE                                          100\nEMC_FBIO_CFG5                                           104\nEMC_CFG_RSV                                             120\nEMC_ACPD_CONTROL                                        124\nEMC_MPC                                                 128\nEMC_EMRS2                                               12c\nEMC_EMRS3                                               130\nEMC_MRW2                                                134\nEMC_MRW3                                                138\nEMC_MRW4                                                13c\nEMC_MRW5                                                4a0\nEMC_MRW6                                                4a4\nEMC_MRW7                                                4a8\nEMC_MRW8                                                4ac\nEMC_MRW9                                                4b0\nEMC_MRW10                                               4b4\nEMC_MRW11                                               4b8\nEMC_MRW12                                               4bc\nEMC_MRW13                                               4c0\nEMC_MRW14                                               4c4\nEMC_MRW15                                               4d0\nEMC_CFG_SYNC                                            4d4\nEMC_CLKEN_OVERRIDE                                      140\nEMC_R2R                                                 144\nEMC_W2W                                                 148\nEMC_EINPUT                                              14c\nEMC_EINPUT_DURATION                                     150\nEMC_PUTERM_EXTRA                                        154\nEMC_TCKESR                                              158\nEMC_TPD                                                 15c\nEMC_STAT_CONTROL                                        160\nEMC_STAT_STATUS                                         164\nEMC_STAT_DRAM_CLOCK_LIMIT_LO                            19c\nEMC_STAT_DRAM_CLOCK_LIMIT_HI                            1a0\nEMC_STAT_DRAM_CLOCKS_LO                                 1a4\nEMC_STAT_DRAM_CLOCKS_HI                                 1a8\nEMC_STAT_DRAM_DEV0_ACTIVATE_CNT_LO                      1ac\nEMC_STAT_DRAM_DEV0_ACTIVATE_CNT_HI                      1b0\nEMC_STAT_DRAM_DEV0_READ_CNT_LO                          1b4\nEMC_STAT_DRAM_DEV0_READ_CNT_HI                          1b8\nEMC_STAT_DRAM_DEV0_READ8_CNT_LO                         1bc\nEMC_STAT_DRAM_DEV0_READ8_CNT_HI                         1c0\nEMC_STAT_DRAM_DEV0_WRITE_CNT_LO                         1c4\nEMC_STAT_DRAM_DEV0_WRITE_CNT_HI                         1c8\nEMC_STAT_DRAM_DEV0_WRITE8_CNT_LO                        1cc\nEMC_STAT_DRAM_DEV0_WRITE8_CNT_HI                        1d0\nEMC_STAT_DRAM_DEV0_REF_CNT_LO                           1d4\nEMC_STAT_DRAM_DEV0_REF_CNT_HI                           1d8\nEMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 1dc\nEMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 1e0\nEMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 1e4\nEMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 1e8\nEMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 1ec\nEMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 1f0\nEMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 1f4\nEMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 1f8\nEMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 1fc\nEMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 200\nEMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 204\nEMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 208\nEMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 20c\nEMC_STAT_DRAM_DEV0_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 210\nEMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 214\nEMC_STAT_DRAM_DEV0_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 218\nEMC_STAT_DRAM_DEV0_SR_CKE_EQ0_CLKS_LO                   21c\nEMC_STAT_DRAM_DEV0_SR_CKE_EQ0_CLKS_HI                   220\nEMC_STAT_DRAM_DEV0_DSR                                  224\nEMC_STAT_DRAM_DEV1_ACTIVATE_CNT_LO                      228\nEMC_STAT_DRAM_DEV1_ACTIVATE_CNT_HI                      22c\nEMC_STAT_DRAM_DEV1_READ_CNT_LO                          230\nEMC_STAT_DRAM_DEV1_READ_CNT_HI                          234\nEMC_STAT_DRAM_DEV1_READ8_CNT_LO                         238\nEMC_STAT_DRAM_DEV1_READ8_CNT_HI                         23c\nEMC_STAT_DRAM_DEV1_WRITE_CNT_LO                         240\nEMC_STAT_DRAM_DEV1_WRITE_CNT_HI                         244\nEMC_STAT_DRAM_DEV1_WRITE8_CNT_LO                        248\nEMC_STAT_DRAM_DEV1_WRITE8_CNT_HI                        24c\nEMC_STAT_DRAM_DEV1_REF_CNT_LO                           250\nEMC_STAT_DRAM_DEV1_REF_CNT_HI                           254\nEMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 258\nEMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 25c\nEMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO 260\nEMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI 264\nEMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 268\nEMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 26c\nEMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO 270\nEMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI 274\nEMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 278\nEMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 27c\nEMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO 280\nEMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI 284\nEMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 288\nEMC_STAT_DRAM_DEV1_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 28c\nEMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO 290\nEMC_STAT_DRAM_DEV1_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI 294\nEMC_STAT_DRAM_DEV1_SR_CKE_EQ0_CLKS_LO                   298\nEMC_STAT_DRAM_DEV1_SR_CKE_EQ0_CLKS_HI                   29c\nEMC_STAT_DRAM_DEV1_DSR                                  2a0\nEMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO c8c\nEMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI c90\nEMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_LO c94\nEMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_NO_BANKS_ACTIVE_CLKS_HI c98\nEMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO c9c\nEMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI ca0\nEMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_LO ca4\nEMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_NO_BANKS_ACTIVE_CLKS_HI ca8\nEMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO cac\nEMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI cb0\nEMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_LO cb4\nEMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ0_SOME_BANKS_ACTIVE_CLKS_HI cb8\nEMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO cbc\nEMC_STAT_DRAM_IO_EXTCLKS_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI cc0\nEMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_LO cc4\nEMC_STAT_DRAM_IO_CLKSTOP_CKE_EQ1_SOME_BANKS_ACTIVE_CLKS_HI cc8\nEMC_STAT_DRAM_IO_SR_CKE_EQ0_CLKS_LO                     ccc\nEMC_STAT_DRAM_IO_SR_CKE_EQ0_CLKS_HI                     cd0\nEMC_STAT_DRAM_IO_DSR                                    cd4\nEMC_AUTO_CAL_CONFIG                                     2a4\nEMC_AUTO_CAL_CONFIG2                                    458\nEMC_AUTO_CAL_CONFIG3                                    45c\nEMC_AUTO_CAL_CONFIG4                                    5b0\nEMC_AUTO_CAL_CONFIG5                                    5b4\nEMC_AUTO_CAL_CONFIG6                                    5cc\nEMC_AUTO_CAL_CONFIG7                                    574\nEMC_AUTO_CAL_CONFIG8                                    2dc\nEMC_AUTO_CAL_VREF_SEL_0                                 2f8\nEMC_AUTO_CAL_VREF_SEL_1                                 300\nEMC_AUTO_CAL_INTERVAL                                   2a8\nEMC_AUTO_CAL_STATUS                                     2ac\nEMC_AUTO_CAL_STATUS2                                    3d4\nEMC_AUTO_CAL_CHANNEL                                    464\nEMC_PMACRO_RX_TERM                                      c48\nEMC_PMACRO_DQ_TX_DRV                                    c70\nEMC_PMACRO_CA_TX_DRV                                    c74\nEMC_PMACRO_CMD_TX_DRV                                   c4c\nEMC_PMACRO_AUTOCAL_CFG_0                                700\nEMC_PMACRO_AUTOCAL_CFG_1                                704\nEMC_PMACRO_AUTOCAL_CFG_2                                708\nEMC_PMACRO_AUTOCAL_CFG_COMMON                           c78\nEMC_PMACRO_ZCTRL                                        c44\nEMC_XM2COMPPADCTRL                                      30c\nEMC_XM2COMPPADCTRL2                                     578\nEMC_XM2COMPPADCTRL3                                     2f4\nEMC_COMP_PAD_SW_CTRL                                    57c\nEMC_REQ_CTRL                                            2b0\nEMC_EMC_STATUS                                          2b4\nEMC_CFG_2                                               2b8\nEMC_CFG_DIG_DLL                                         2bc\nEMC_CFG_DIG_DLL_PERIOD                                  2c0\nEMC_DIG_DLL_STATUS                                      2c4\nEMC_CFG_DIG_DLL_1                                       2c8\nEMC_RDV_MASK                                            2cc\nEMC_WDV_MASK                                            2d0\nEMC_RDV_EARLY_MASK                                      2d4\nEMC_RDV_EARLY                                           2d8\nEMC_WDV_CHK                                             4e0\nEMC_ZCAL_INTERVAL                                       2e0\nEMC_ZCAL_WAIT_CNT                                       2e4\nEMC_ZCAL_MRW_CMD                                        2e8\nEMC_ZQ_CAL                                              2ec\nEMC_SCRATCH0                                            324\nEMC_STALL_THEN_EXE_BEFORE_CLKCHANGE                     3c8\nEMC_STALL_THEN_EXE_AFTER_CLKCHANGE                      3cc\nEMC_UNSTALL_RW_AFTER_CLKCHANGE                          3d0\nEMC_FDPD_CTRL_CMD_NO_RAMP                               4d8\nEMC_SEL_DPD_CTRL                                        3d8\nEMC_FDPD_CTRL_DQ                                        310\nEMC_FDPD_CTRL_CMD                                       314\nEMC_PRE_REFRESH_REQ_CNT                                 3dc\nEMC_REFCTRL2                                            580\nEMC_FBIO_CFG7                                           584\nEMC_DATA_BRLSHFT_0                                      588\nEMC_DATA_BRLSHFT_1                                      58c\nEMC_DQS_BRLSHFT_0                                       594\nEMC_DQS_BRLSHFT_1                                       598\nEMC_CMD_BRLSHFT_0                                       59c\nEMC_CMD_BRLSHFT_1                                       5a0\nEMC_CMD_BRLSHFT_2                                       5a4\nEMC_CMD_BRLSHFT_3                                       5a8\nEMC_QUSE_BRLSHFT_0                                      5ac\nEMC_QUSE_BRLSHFT_1                                      5b8\nEMC_QUSE_BRLSHFT_2                                      5bc\nEMC_QUSE_BRLSHFT_3                                      5c4\nEMC_FBIO_CFG8                                           5c8\nEMC_CMD_MAPPING_CMD0_0                                  380\nEMC_CMD_MAPPING_CMD0_1                                  384\nEMC_CMD_MAPPING_CMD0_2                                  388\nEMC_CMD_MAPPING_CMD1_0                                  38c\nEMC_CMD_MAPPING_CMD1_1                                  390\nEMC_CMD_MAPPING_CMD1_2                                  394\nEMC_CMD_MAPPING_CMD2_0                                  398\nEMC_CMD_MAPPING_CMD2_1                                  39c\nEMC_CMD_MAPPING_CMD2_2                                  3a0\nEMC_CMD_MAPPING_CMD3_0                                  3a4\nEMC_CMD_MAPPING_CMD3_1                                  3a8\nEMC_CMD_MAPPING_CMD3_2                                  3ac\nEMC_CMD_MAPPING_BYTE                                    3b0\nEMC_DYN_SELF_REF_CONTROL                                3e0\nEMC_TXSRDLL                                             3e4\nEMC_CCFIFO_ADDR                                         3e8\nEMC_CCFIFO_DATA                                         3ec\nEMC_CCFIFO_STATUS                                       3f0\nEMC_SWIZZLE_RANK0_BYTE0                                 404\nEMC_SWIZZLE_RANK0_BYTE1                                 408\nEMC_SWIZZLE_RANK0_BYTE2                                 40c\nEMC_SWIZZLE_RANK0_BYTE3                                 410\nEMC_SWIZZLE_RANK1_BYTE0                                 418\nEMC_SWIZZLE_RANK1_BYTE1                                 41c\nEMC_SWIZZLE_RANK1_BYTE2                                 420\nEMC_SWIZZLE_RANK1_BYTE3                                 424\nEMC_TR_TIMING_0                                         3b4\nEMC_TR_CTRL_0                                           3b8\nEMC_TR_CTRL_1                                           3bc\nEMC_TR_DVFS                                             460\nEMC_SWITCH_BACK_CTRL                                    3c0\nEMC_TR_RDV                                              3c4\nEMC_TR_QPOP                                             3f4\nEMC_TR_RDV_MASK                                         3f8\nEMC_TR_QSAFE                                            3fc\nEMC_TR_QRST                                             400\nEMC_IBDLY                                               468\nEMC_OBDLY                                               46c\nEMC_TXDSRVTTGEN                                         480\nEMC_WE_DURATION                                         48c\nEMC_WS_DURATION                                         490\nEMC_WEV                                                 494\nEMC_WSV                                                 498\nEMC_CFG_3                                               49c\nEMC_CFG_PIPE_2                                          554\nEMC_CFG_PIPE_CLK                                        558\nEMC_CFG_PIPE_1                                          55c\nEMC_CFG_PIPE                                            560\nEMC_QPOP                                                564\nEMC_QUSE_WIDTH                                          568\nEMC_PUTERM_WIDTH                                        56c\nEMC_PROTOBIST_CONFIG_ADR_1                              5d0\nEMC_PROTOBIST_CONFIG_ADR_2                              5d4\nEMC_PROTOBIST_MISC                                      5d8\nEMC_PROTOBIST_WDATA_LOWER                               5dc\nEMC_PROTOBIST_WDATA_UPPER                               5e0\nEMC_PROTOBIST_RDATA                                     5ec\nEMC_DLL_CFG_0                                           5e4\nEMC_DLL_CFG_1                                           5e8\nEMC_TRAINING_CMD                                        e00\nEMC_TRAINING_CTRL                                       e04\nEMC_TRAINING_STATUS                                     e08\nEMC_TRAINING_QUSE_CORS_CTRL                             e0c\nEMC_TRAINING_QUSE_FINE_CTRL                             e10\nEMC_TRAINING_QUSE_CTRL_MISC                             e14\nEMC_TRAINING_WRITE_FINE_CTRL                            e18\nEMC_TRAINING_WRITE_CTRL_MISC                            e1c\nEMC_TRAINING_WRITE_VREF_CTRL                            e20\nEMC_TRAINING_READ_FINE_CTRL                             e24\nEMC_TRAINING_READ_CTRL_MISC                             e28\nEMC_TRAINING_READ_VREF_CTRL                             e2c\nEMC_TRAINING_CA_FINE_CTRL                               e30\nEMC_TRAINING_CA_CTRL_MISC                               e34\nEMC_TRAINING_CA_CTRL_MISC1                              e38\nEMC_TRAINING_CA_VREF_CTRL                               e3c\nEMC_TRAINING_CA_TADR_CTRL                               e40\nEMC_TRAINING_SETTLE                                     e44\nEMC_TRAINING_DEBUG_CTRL                                 e48\nEMC_TRAINING_DEBUG_DQ0                                  e4c\nEMC_TRAINING_DEBUG_DQ1                                  e50\nEMC_TRAINING_DEBUG_DQ2                                  e54\nEMC_TRAINING_DEBUG_DQ3                                  e58\nEMC_TRAINING_MPC                                        e5c\nEMC_TRAINING_PATRAM_CTRL                                e60\nEMC_TRAINING_PATRAM_DQ                                  e64\nEMC_TRAINING_PATRAM_DMI                                 e68\nEMC_TRAINING_VREF_SETTLE                                e6c\nEMC_TRAINING_RW_EYE_CENTER_IB_BYTE0                     e70\nEMC_TRAINING_RW_EYE_CENTER_IB_BYTE1                     e74\nEMC_TRAINING_RW_EYE_CENTER_IB_BYTE2                     e78\nEMC_TRAINING_RW_EYE_CENTER_IB_BYTE3                     e7c\nEMC_TRAINING_RW_EYE_CENTER_IB_MISC                      e80\nEMC_TRAINING_RW_EYE_CENTER_OB_BYTE0                     e84\nEMC_TRAINING_RW_EYE_CENTER_OB_BYTE1                     e88\nEMC_TRAINING_RW_EYE_CENTER_OB_BYTE2                     e8c\nEMC_TRAINING_RW_EYE_CENTER_OB_BYTE3                     e90\nEMC_TRAINING_RW_EYE_CENTER_OB_MISC                      e94\nEMC_TRAINING_RW_OFFSET_IB_BYTE0                         e98\nEMC_TRAINING_RW_OFFSET_IB_BYTE1                         e9c\nEMC_TRAINING_RW_OFFSET_IB_BYTE2                         ea0\nEMC_TRAINING_RW_OFFSET_IB_BYTE3                         ea4\nEMC_TRAINING_RW_OFFSET_IB_MISC                          ea8\nEMC_TRAINING_RW_OFFSET_OB_BYTE0                         eac\nEMC_TRAINING_RW_OFFSET_OB_BYTE1                         eb0\nEMC_TRAINING_RW_OFFSET_OB_BYTE2                         eb4\nEMC_TRAINING_RW_OFFSET_OB_BYTE3                         eb8\nEMC_TRAINING_RW_OFFSET_OB_MISC                          ebc\nEMC_TRAINING_OPT_CA_VREF                                ec0\nEMC_TRAINING_OPT_DQ_OB_VREF                             ec4\nEMC_TRAINING_OPT_DQ_IB_VREF_RANK0                       ec8\nEMC_TRAINING_OPT_DQ_IB_VREF_RANK1                       ecc\nEMC_TRAINING_QUSE_VREF_CTRL                             ed0\nEMC_TRAINING_OPT_DQS_IB_VREF_RANK0                      ed4\nEMC_TRAINING_OPT_DQS_IB_VREF_RANK1                      ed8\nEMC_TRAINING_DRAMC_TIMING                               edc\nEMC_PMACRO_QUSE_DDLL_RANK0_0                            600\nEMC_PMACRO_QUSE_DDLL_RANK0_1                            604\nEMC_PMACRO_QUSE_DDLL_RANK0_2                            608\nEMC_PMACRO_QUSE_DDLL_RANK0_3                            60c\nEMC_PMACRO_QUSE_DDLL_RANK0_4                            610\nEMC_PMACRO_QUSE_DDLL_RANK0_5                            614\nEMC_PMACRO_QUSE_DDLL_RANK1_0                            620\nEMC_PMACRO_QUSE_DDLL_RANK1_1                            624\nEMC_PMACRO_QUSE_DDLL_RANK1_2                            628\nEMC_PMACRO_QUSE_DDLL_RANK1_3                            62c\nEMC_PMACRO_QUSE_DDLL_RANK1_4                            630\nEMC_PMACRO_QUSE_DDLL_RANK1_5                            634\nEMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0                      640\nEMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1                      644\nEMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2                      648\nEMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3                      64c\nEMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4                      650\nEMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5                      654\nEMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0                      660\nEMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1                      664\nEMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2                      668\nEMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3                      66c\nEMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4                      670\nEMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5                      674\nEMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0                     680\nEMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1                     684\nEMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2                     688\nEMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3                     68c\nEMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4                     690\nEMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5                     694\nEMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0                     6a0\nEMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1                     6a4\nEMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2                     6a8\nEMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3                     6ac\nEMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4                     6b0\nEMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5                     6b4\nEMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0                     6c0\nEMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1                     6c4\nEMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2                     6c8\nEMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3                     6cc\nEMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_4                     6d0\nEMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_5                     6d4\nEMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0                     6e0\nEMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1                     6e4\nEMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2                     6e8\nEMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3                     6ec\nEMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_4                     6f0\nEMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_5                     6f4\nEMC_PMACRO_TX_PWRD_0                                    720\nEMC_PMACRO_TX_PWRD_1                                    724\nEMC_PMACRO_TX_PWRD_2                                    728\nEMC_PMACRO_TX_PWRD_3                                    72c\nEMC_PMACRO_TX_PWRD_4                                    730\nEMC_PMACRO_TX_PWRD_5                                    734\nEMC_PMACRO_TX_SEL_CLK_SRC_0                             740\nEMC_PMACRO_TX_SEL_CLK_SRC_1                             744\nEMC_PMACRO_TX_SEL_CLK_SRC_3                             74c\nEMC_PMACRO_TX_SEL_CLK_SRC_2                             748\nEMC_PMACRO_TX_SEL_CLK_SRC_4                             750\nEMC_PMACRO_TX_SEL_CLK_SRC_5                             754\nEMC_PMACRO_DDLL_BYPASS                                  760\nEMC_PMACRO_DDLL_PWRD_0                                  770\nEMC_PMACRO_DDLL_PWRD_1                                  774\nEMC_PMACRO_DDLL_PWRD_2                                  778\nEMC_PMACRO_CMD_CTRL_0                                   780\nEMC_PMACRO_CMD_CTRL_1                                   784\nEMC_PMACRO_CMD_CTRL_2                                   788\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0               800\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1               804\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2               808\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_3               80c\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0               810\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1               814\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2               818\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_3               81c\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0               820\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1               824\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2               828\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_3               82c\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0               830\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1               834\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2               838\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_3               83c\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0               840\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1               844\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2               848\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_3               84c\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0               850\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1               854\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2               858\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_3               85c\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0               860\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1               864\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2               868\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_3               86c\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0               870\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1               874\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2               878\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_3               87c\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0                880\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1                884\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2                888\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_3                88c\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0                890\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1                894\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2                898\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_3                89c\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0                8a0\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1                8a4\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2                8a8\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_3                8ac\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0                8b0\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1                8b4\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2                8b8\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_3                8bc\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0               900\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1               904\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2               908\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_3               90c\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0               910\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1               914\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2               918\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_3               91c\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0               920\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1               924\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2               928\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_3               92c\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0               930\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1               934\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2               938\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_3               93c\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0               940\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1               944\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2               948\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_3               94c\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0               950\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1               954\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2               958\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_3               95c\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0               960\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1               964\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2               968\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_3               96c\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0               970\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1               974\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2               978\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_3               97c\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_0                980\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_1                984\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_2                988\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_3                98c\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_0                990\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_1                994\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_2                998\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_3                99c\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_0                9a0\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_1                9a4\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_2                9a8\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_3                9ac\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_0                9b0\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_1                9b4\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_2                9b8\nEMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_3                9bc\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0               a00\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1               a04\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2               a08\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0               a10\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1               a14\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2               a18\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0               a20\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1               a24\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2               a28\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0               a30\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1               a34\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2               a38\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0               a40\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1               a44\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2               a48\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0               a50\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1               a54\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2               a58\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0               a60\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1               a64\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2               a68\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0               a70\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1               a74\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2               a78\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_0                a80\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_1                a84\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD0_2                a88\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_0                a90\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_1                a94\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD1_2                a98\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_0                aa0\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_1                aa4\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD2_2                aa8\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_0                ab0\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_1                ab4\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_CMD3_2                ab8\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0               b00\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1               b04\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2               b08\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0               b10\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1               b14\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2               b18\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0               b20\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1               b24\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2               b28\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0               b30\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1               b34\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2               b38\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0               b40\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1               b44\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2               b48\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0               b50\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1               b54\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2               b58\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0               b60\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1               b64\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2               b68\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0               b70\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1               b74\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2               b78\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_0                b80\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_1                b84\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD0_2                b88\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_0                b90\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_1                b94\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD1_2                b98\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_0                ba0\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_1                ba4\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD2_2                ba8\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_0                bb0\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_1                bb4\nEMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_CMD3_2                bb8\nEMC_PMACRO_IB_VREF_DQ_0                                 be0\nEMC_PMACRO_IB_VREF_DQ_1                                 be4\nEMC_PMACRO_IB_VREF_DQ_2                                 be8\nEMC_PMACRO_IB_VREF_DQS_0                                bf0\nEMC_PMACRO_IB_VREF_DQS_1                                bf4\nEMC_PMACRO_IB_VREF_DQS_2                                bf8\nEMC_PMACRO_IB_RXRT                                      cf4\nEMC_PMACRO_DDLL_LONG_CMD_0                              c00\nEMC_PMACRO_DDLL_LONG_CMD_1                              c04\nEMC_PMACRO_DDLL_LONG_CMD_2                              c08\nEMC_PMACRO_DDLL_LONG_CMD_3                              c0c\nEMC_PMACRO_DDLL_LONG_CMD_4                              c10\nEMC_PMACRO_DDLL_LONG_CMD_5                              c14\nEMC_PMACRO_DDLL_SHORT_CMD_0                             c20\nEMC_PMACRO_DDLL_SHORT_CMD_1                             c24\nEMC_PMACRO_DDLL_SHORT_CMD_2                             c28\nEMC_PMACRO_CFG_PM_GLOBAL_0                              c30\nEMC_PMACRO_VTTGEN_CTRL_0                                c34\nEMC_PMACRO_VTTGEN_CTRL_1                                c38\nEMC_PMACRO_VTTGEN_CTRL_2                                cf0\nEMC_PMACRO_BG_BIAS_CTRL_0                               c3c\nEMC_PMACRO_PAD_CFG_CTRL                                 c40\nEMC_PMACRO_CMD_PAD_RX_CTRL                              c50\nEMC_PMACRO_DATA_PAD_RX_CTRL                             c54\nEMC_PMACRO_CMD_RX_TERM_MODE                             c58\nEMC_PMACRO_DATA_RX_TERM_MODE                            c5c\nEMC_PMACRO_CMD_PAD_TX_CTRL                              c60\nEMC_PMACRO_DATA_PAD_TX_CTRL                             c64\nEMC_PMACRO_COMMON_PAD_TX_CTRL                           c68\nEMC_PMACRO_BRICK_MAPPING_0                              c80\nEMC_PMACRO_BRICK_MAPPING_1                              c84\nEMC_PMACRO_BRICK_MAPPING_2                              c88\nEMC_PMACRO_DDLLCAL_CAL                                  ce0\nEMC_PMACRO_DDLL_OFFSET                                  ce4\nEMC_PMACRO_DDLL_PERIODIC_OFFSET                         ce8\nEMC_PMACRO_BRICK_CTRL_RFU1                              330\nEMC_PMACRO_BRICK_CTRL_RFU2                              334\nEMC_PMACRO_CMD_BRICK_CTRL_FDPD                          318\nEMC_PMACRO_DATA_BRICK_CTRL_FDPD                         31c\nEMC_PMACRO_TRAINING_CTRL_0                              cf8\nEMC_PMACRO_TRAINING_CTRL_1                              cfc\nEMC_PMC_SCRATCH1                                        440\nEMC_PMC_SCRATCH2                                        444\nEMC_PMC_SCRATCH3                                        448\n"
  },
  {
    "path": "tools/fix_regs.py",
    "content": "import re\nimport sys\n\ndef parse_defs(fname):\n\tf = open(fname, \"r\")\n\tlines = f.readlines()\n\tf.close()\n\tres = {}\n\tfor l in lines:\n\t\tp = [str(_.strip()) for _ in l.strip().split(\" \", 1)]\n\t\tres[int(p[1], 16)] = p[0]\n\treturn res\n\nmc = parse_defs(\"mc.def\")\nemc = parse_defs(\"emc.def\")\n\nf = open(sys.argv[1], \"r\")\nbuf = f.read()\nf.close()\n\ndef fix(m):\n\twhat = m.groups()[0]\n\toff = int(m.groups()[1], 16)\n\tif what == \"MC\":\n\t\tif off in mc:\n\t\t\treturn \"MC({0})\".format(mc[off])\n\telif what == \"EMC\":\n\t\tif off in emc:\n\t\t\treturn \"EMC({0})\".format(emc[off])\n\treturn \"{0}(0x{1:X})\".format(what, off)\n\nbuf = re.sub(r'([A-Z]+)\\(0x([0-9a-fA-F]+)\\)', fix, buf)\n\nf = open(sys.argv[2], \"w\")\nf.write(buf)\nf.close()\n"
  },
  {
    "path": "tools/lz/Makefile",
    "content": "NATIVE_CC ?= gcc\n\nifeq (, $(shell which $(NATIVE_CC) 2>/dev/null))\n$(error \"Native GCC is missing. Please install it first. If it's path is custom, set it with export NATIVE_CC=<path to native gcc toolchain>\")\nendif\n\n.PHONY: all clean\n\nall: lz77\n\t@echo > /dev/null\n\nclean:\n\t@rm -f lz77\n\nlz77: lz.c lz77.c\n\t@$(NATIVE_CC) -o $@ lz.c lz77.c\n"
  },
  {
    "path": "tools/lz/lz.c",
    "content": "//\n// Name:        lz.c\n// Author:      Marcus Geelnard\n// Description: LZ77 coder/decoder implementation.\n// Reentrant:   Yes\n// $ATH_LICENSE_NULL$\n//\n// The LZ77 compression scheme is a substitutional compression scheme\n// proposed by Abraham Lempel and Jakob Ziv in 1977. It is very simple in\n// its design, and uses no fancy bit level compression.\n//\n// This is my first attempt at an implementation of a LZ77 code/decoder.\n//\n// The principle of the LZ77 compression algorithm is to store repeated\n// occurrences of strings as references to previous occurrences of the same\n// string. The point is that the reference consumes less space than the\n// string itself, provided that the string is long enough (in this\n// implementation, the string has to be at least 4 bytes long, since the\n// minimum coded reference is 3 bytes long). Also note that the term\n// \"string\" refers to any kind of byte sequence (it does not have to be\n// an ASCII string, for instance).\n//\n// The coder uses a brute force approach to finding string matches in the\n// history buffer (or \"sliding window\", if you wish), which is very, very\n// slow. I recon the complexity is somewhere between O(n^2) and O(n^3),\n// depending on the input data.\n//\n// There is also a faster implementation that uses a large working buffer\n// in which a \"jump table\" is stored, which is used to quickly find\n// possible string matches (see the source code for LZ_CompressFast() for\n// more information). The faster method is an order of magnitude faster,\n// but still quite slow compared to other compression methods.\n//\n// The upside is that decompression is very fast, and the compression ratio\n// is often very good.\n//\n// The reference to a string is coded as a (length,offset) pair, where the\n// length indicates the length of the string, and the offset gives the\n// offset from the current data position. To distinguish between string\n// references and literal strings (uncompressed bytes), a string reference\n// is preceded by a marker byte, which is chosen as the least common byte\n// symbol in the input data stream (this marker byte is stored in the\n// output stream as the first byte).\n//\n// Occurrences of the marker byte in the stream are encoded as the marker\n// byte followed by a zero byte, which means that occurrences of the marker\n// byte have to be coded with two bytes.\n//\n// The lengths and offsets are coded in a variable length fashion, allowing\n// values of any magnitude (up to 4294967295 in this implementation).\n//\n// With this compression scheme, the worst case compression result is\n// (257/256)*insize + 1.\n//\n//------------------------------------------------------------------------\n// Copyright (c) 2003-2006 Marcus Geelnard\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//    claim that you wrote the original software. If you use this software\n//    in a product, an acknowledgment in the product documentation would\n//    be appreciated but is not required.\n//\n// 2. Altered source versions must be plainly marked as such, and must not\n//    be misrepresented as being the original software.\n//\n// 3. This notice may not be removed or altered from any source\n//    distribution.\n//\n// Marcus Geelnard\n// marcus.geelnard at home.se\n//\n\n//\n// This file has been altered from the original version.\n//\n\n/*************************************************************************\n* Constants used for LZ77 coding\n*************************************************************************/\n\n/* Maximum offset (can be any size < 2^31). Lower values give faster\n   compression, while higher values gives better compression. The default\n   value of 100000 is quite high. Experiment to see what works best for\n   you. */\n#define LZ_MAX_OFFSET 100000\n\n\n\n/*************************************************************************\n*                           INTERNAL FUNCTIONS                           *\n*************************************************************************/\n\n\n/*************************************************************************\n* _LZ_StringCompare() - Return maximum length string match.\n*************************************************************************/\n\nstatic unsigned int _LZ_StringCompare( unsigned char * str1,\n  unsigned char * str2, unsigned int minlen, unsigned int maxlen )\n{\n    unsigned int len;\n\n    for( len = minlen; (len < maxlen) && (str1[len] == str2[len]); ++ len );\n\n    return len;\n}\n\n\n/*************************************************************************\n* _LZ_WriteVarSize() - Write unsigned integer with variable number of\n* bytes depending on value.\n*************************************************************************/\n\nstatic int _LZ_WriteVarSize( unsigned int x, unsigned char * buf )\n{\n    unsigned int y;\n    int num_bytes, i, b;\n\n    /* Determine number of bytes needed to store the number x */\n    y = x >> 3;\n    for( num_bytes = 5; num_bytes >= 2; -- num_bytes )\n    {\n        if( y & 0xfe000000 ) break;\n        y <<= 7;\n    }\n\n    /* Write all bytes, seven bits in each, with 8:th bit set for all */\n    /* but the last byte. */\n    for( i = num_bytes-1; i >= 0; -- i )\n    {\n        b = (x >> (i*7)) & 0x0000007f;\n        if( i > 0 )\n        {\n            b |= 0x00000080;\n        }\n        *buf ++ = (unsigned char) b;\n    }\n\n    /* Return number of bytes written */\n    return num_bytes;\n}\n\n\n/*************************************************************************\n* _LZ_ReadVarSize() - Read unsigned integer with variable number of\n* bytes depending on value.\n*************************************************************************/\n\nstatic int _LZ_ReadVarSize( unsigned int * x, unsigned char * buf )\n{\n    unsigned int y, b, num_bytes;\n\n    /* Read complete value (stop when byte contains zero in 8:th bit) */\n    y = 0;\n    num_bytes = 0;\n    do\n    {\n        b = (unsigned int) (*buf ++);\n        y = (y << 7) | (b & 0x0000007f);\n        ++ num_bytes;\n    }\n    while( b & 0x00000080 );\n\n    /* Store value in x */\n    *x = y;\n\n    /* Return number of bytes read */\n    return num_bytes;\n}\n\n\n\n/*************************************************************************\n*                            PUBLIC FUNCTIONS                            *\n*************************************************************************/\n\n\n/*************************************************************************\n* LZ_Compress() - Compress a block of data using an LZ77 coder.\n*  in     - Input (uncompressed) buffer.\n*  out    - Output (compressed) buffer. This buffer must be 0.4% larger\n*           than the input buffer, plus one byte.\n*  insize - Number of input bytes.\n* The function returns the size of the compressed data.\n*************************************************************************/\n\nint LZ_Compress( unsigned char *in, unsigned char *out,\n    unsigned int insize )\n{\n    unsigned char marker, symbol;\n    unsigned int  inpos, outpos, bytesleft, i;\n    unsigned int  maxoffset, offset, bestoffset;\n    unsigned int  maxlength, length, bestlength;\n    unsigned int  histogram[ 256 ];\n    unsigned char *ptr1, *ptr2;\n\n    /* Do we have anything to compress? */\n    if( insize < 1 )\n    {\n        return 0;\n    }\n\n    /* Create histogram */\n    for( i = 0; i < 256; ++ i )\n    {\n        histogram[ i ] = 0;\n    }\n    for( i = 0; i < insize; ++ i )\n    {\n        ++ histogram[ in[ i ] ];\n    }\n\n    /* Find the least common byte, and use it as the marker symbol */\n    marker = 0;\n    for( i = 1; i < 256; ++ i )\n    {\n        if( histogram[ i ] < histogram[ marker ] )\n        {\n            marker = i;\n        }\n    }\n\n    /* Remember the marker symbol for the decoder */\n    out[ 0 ] = marker;\n\n    /* Start of compression */\n    inpos = 0;\n    outpos = 1;\n\n    /* Main compression loop */\n    bytesleft = insize;\n    do\n    {\n        /* Determine most distant position */\n        if( inpos > LZ_MAX_OFFSET ) maxoffset = LZ_MAX_OFFSET;\n        else                        maxoffset = inpos;\n\n        /* Get pointer to current position */\n        ptr1 = &in[ inpos ];\n\n        /* Search history window for maximum length string match */\n        bestlength = 3;\n        bestoffset = 0;\n        for( offset = 3; offset <= maxoffset; ++ offset )\n        {\n            /* Get pointer to candidate string */\n            ptr2 = &ptr1[ -(int)offset ];\n\n            /* Quickly determine if this is a candidate (for speed) */\n            if( (ptr1[ 0 ] == ptr2[ 0 ]) &&\n                (ptr1[ bestlength ] == ptr2[ bestlength ]) )\n            {\n                /* Determine maximum length for this offset */\n                maxlength = (bytesleft < offset ? bytesleft : offset);\n\n                /* Count maximum length match at this offset */\n                length = _LZ_StringCompare( ptr1, ptr2, 0, maxlength );\n\n                /* Better match than any previous match? */\n                if( length > bestlength )\n                {\n                    bestlength = length;\n                    bestoffset = offset;\n                }\n            }\n        }\n\n        /* Was there a good enough match? */\n        if( (bestlength >= 8) ||\n            ((bestlength == 4) && (bestoffset <= 0x0000007f)) ||\n            ((bestlength == 5) && (bestoffset <= 0x00003fff)) ||\n            ((bestlength == 6) && (bestoffset <= 0x001fffff)) ||\n            ((bestlength == 7) && (bestoffset <= 0x0fffffff)) )\n        {\n            out[ outpos ++ ] = (unsigned char) marker;\n            outpos += _LZ_WriteVarSize( bestlength, &out[ outpos ] );\n            outpos += _LZ_WriteVarSize( bestoffset, &out[ outpos ] );\n            inpos += bestlength;\n            bytesleft -= bestlength;\n        }\n        else\n        {\n            /* Output single byte (or two bytes if marker byte) */\n            symbol = in[ inpos ++ ];\n            out[ outpos ++ ] = symbol;\n            if( symbol == marker )\n            {\n                out[ outpos ++ ] = 0;\n            }\n            -- bytesleft;\n        }\n    }\n    while( bytesleft > 3 );\n\n    /* Dump remaining bytes, if any */\n    while( inpos < insize )\n    {\n        if( in[ inpos ] == marker )\n        {\n            out[ outpos ++ ] = marker;\n            out[ outpos ++ ] = 0;\n        }\n        else\n        {\n            out[ outpos ++ ] = in[ inpos ];\n        }\n        ++ inpos;\n    }\n\n    return outpos;\n}\n\n\n/*************************************************************************\n* LZ_CompressFast() - Compress a block of data using an LZ77 coder.\n*  in     - Input (uncompressed) buffer.\n*  out    - Output (compressed) buffer. This buffer must be 0.4% larger\n*           than the input buffer, plus one byte.\n*  insize - Number of input bytes.\n*  work   - Pointer to a temporary buffer (internal working buffer), which\n*           must be able to hold (insize+65536) unsigned integers.\n* The function returns the size of the compressed data.\n*************************************************************************/\n\nint LZ_CompressFast( unsigned char *in, unsigned char *out,\n    unsigned int insize, unsigned int *work )\n{\n    unsigned char marker, symbol;\n    unsigned int  inpos, outpos, bytesleft, i, index, symbols;\n    unsigned int  offset, bestoffset;\n    unsigned int  maxlength, length, bestlength;\n    unsigned int  histogram[ 256 ], *lastindex, *jumptable;\n    unsigned char *ptr1, *ptr2;\n\n    /* Do we have anything to compress? */\n    if( insize < 1 )\n    {\n        return 0;\n    }\n\n    /* Assign arrays to the working area */\n    lastindex = work;\n    jumptable = &work[ 65536 ];\n\n    /* Build a \"jump table\". Here is how the jump table works:\n       jumptable[i] points to the nearest previous occurrence of the same\n       symbol pair as in[i]:in[i+1], so in[i] == in[jumptable[i]] and\n       in[i+1] == in[jumptable[i]+1], and so on... Following the jump table\n       gives a dramatic boost for the string search'n'match loop compared\n       to doing a brute force search. The jump table is built in O(n) time,\n       so it is a cheap operation in terms of time, but it is expensice in\n       terms of memory consumption. */\n    for( i = 0; i < 65536; ++ i )\n    {\n        lastindex[ i ] = 0xffffffff;\n    }\n    for( i = 0; i < insize-1; ++ i )\n    {\n        symbols = (((unsigned int)in[i]) << 8) | ((unsigned int)in[i+1]);\n        index = lastindex[ symbols ];\n        lastindex[ symbols ] = i;\n        jumptable[ i ] = index;\n    }\n    jumptable[ insize-1 ] = 0xffffffff;\n\n    /* Create histogram */\n    for( i = 0; i < 256; ++ i )\n    {\n        histogram[ i ] = 0;\n    }\n    for( i = 0; i < insize; ++ i )\n    {\n        ++ histogram[ in[ i ] ];\n    }\n\n    /* Find the least common byte, and use it as the marker symbol */\n    marker = 0;\n    for( i = 1; i < 256; ++ i )\n    {\n        if( histogram[ i ] < histogram[ marker ] )\n        {\n            marker = i;\n        }\n    }\n\n    /* Remember the marker symbol for the decoder */\n    out[ 0 ] = marker;\n\n    /* Start of compression */\n    inpos = 0;\n    outpos = 1;\n\n    /* Main compression loop */\n    bytesleft = insize;\n    do\n    {\n        /* Get pointer to current position */\n        ptr1 = &in[ inpos ];\n\n        /* Search history window for maximum length string match */\n        bestlength = 3;\n        bestoffset = 0;\n        index = jumptable[ inpos ];\n        while( (index != 0xffffffff) && ((inpos - index) < LZ_MAX_OFFSET) )\n        {\n            /* Get pointer to candidate string */\n            ptr2 = &in[ index ];\n\n            /* Quickly determine if this is a candidate (for speed) */\n            if( ptr2[ bestlength ] == ptr1[ bestlength ] )\n            {\n                /* Determine maximum length for this offset */\n                offset = inpos - index;\n                maxlength = (bytesleft < offset ? bytesleft : offset);\n\n                /* Count maximum length match at this offset */\n                length = _LZ_StringCompare( ptr1, ptr2, 2, maxlength );\n\n                /* Better match than any previous match? */\n                if( length > bestlength )\n                {\n                    bestlength = length;\n                    bestoffset = offset;\n                }\n            }\n\n            /* Get next possible index from jump table */\n            index = jumptable[ index ];\n        }\n\n        /* Was there a good enough match? */\n        if( (bestlength >= 8) ||\n            ((bestlength == 4) && (bestoffset <= 0x0000007f)) ||\n            ((bestlength == 5) && (bestoffset <= 0x00003fff)) ||\n            ((bestlength == 6) && (bestoffset <= 0x001fffff)) ||\n            ((bestlength == 7) && (bestoffset <= 0x0fffffff)) )\n        {\n            out[ outpos ++ ] = (unsigned char) marker;\n            outpos += _LZ_WriteVarSize( bestlength, &out[ outpos ] );\n            outpos += _LZ_WriteVarSize( bestoffset, &out[ outpos ] );\n            inpos += bestlength;\n            bytesleft -= bestlength;\n        }\n        else\n        {\n            /* Output single byte (or two bytes if marker byte) */\n            symbol = in[ inpos ++ ];\n            out[ outpos ++ ] = symbol;\n            if( symbol == marker )\n            {\n                out[ outpos ++ ] = 0;\n            }\n            -- bytesleft;\n        }\n    }\n    while( bytesleft > 3 );\n\n    /* Dump remaining bytes, if any */\n    while( inpos < insize )\n    {\n        if( in[ inpos ] == marker )\n        {\n            out[ outpos ++ ] = marker;\n            out[ outpos ++ ] = 0;\n        }\n        else\n        {\n            out[ outpos ++ ] = in[ inpos ];\n        }\n        ++ inpos;\n    }\n\n    return outpos;\n}\n\n\n/*************************************************************************\n* LZ_Uncompress() - Uncompress a block of data using an LZ77 decoder.\n*  in      - Input (compressed) buffer.\n*  out     - Output (uncompressed) buffer. This buffer must be large\n*            enough to hold the uncompressed data.\n*  insize  - Number of input bytes.\n*************************************************************************/\n\nint LZ_Uncompress( unsigned char *in, unsigned char *out,\n    unsigned int insize )\n{\n    unsigned char marker, symbol;\n    unsigned int  i, inpos, outpos, length, offset;\n\n    /* Do we have anything to uncompress? */\n    if( insize < 1 )\n    {\n        return 0;\n    }\n\n    /* Get marker symbol from input stream */\n    marker = in[ 0 ];\n    inpos = 1;\n\n    /* Main decompression loop */\n    outpos = 0;\n    do\n    {\n        symbol = in[ inpos ++ ];\n        if( symbol == marker )\n        {\n            /* We had a marker byte */\n            if( in[ inpos ] == 0 )\n            {\n                /* It was a single occurrence of the marker byte */\n                out[ outpos ++ ] = marker;\n                ++ inpos;\n            }\n            else\n            {\n                /* Extract true length and offset */\n                inpos += _LZ_ReadVarSize( &length, &in[ inpos ] );\n                inpos += _LZ_ReadVarSize( &offset, &in[ inpos ] );\n\n                /* Copy corresponding data from history window */\n                for( i = 0; i < length; ++ i )\n                {\n                    out[ outpos ] = out[ outpos - offset ];\n                    ++ outpos;\n                }\n            }\n        }\n        else\n        {\n            /* No marker, plain copy */\n            out[ outpos ++ ] = symbol;\n        }\n    }\n    while( inpos < insize );\n\n    return outpos;\n}\n"
  },
  {
    "path": "tools/lz/lz.h",
    "content": "// \n// Name:        lz.h\n// Author:      Marcus Geelnard\n// Description: LZ77 coder/decoder interface.\n// Reentrant:   Yes\n// ------------------------------------------------------------------------\n// $ATH_LICENSE_NULL$\n// Copyright (c) 2003-2006 Marcus Geelnard\n// \n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n// \n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n// \n// 1. The origin of this software must not be misrepresented; you must not\n//    claim that you wrote the original software. If you use this software\n//    in a product, an acknowledgment in the product documentation would\n//    be appreciated but is not required.\n// \n// 2. Altered source versions must be plainly marked as such, and must not\n//    be misrepresented as being the original software.\n// \n// 3. This notice may not be removed or altered from any source\n//    distribution.\n// \n// Marcus Geelnard\n// marcus.geelnard at home.se\n// \n\n//\n// This file has been altered from the original version.\n//\n\n#ifndef _lz_h_\n#define _lz_h_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n/*************************************************************************\n* Function prototypes\n*************************************************************************/\n\nint LZ_Compress( unsigned char *in, unsigned char *out,\n                 unsigned int insize );\nint LZ_CompressFast( unsigned char *in, unsigned char *out,\n                     unsigned int insize, unsigned int *work );\nint LZ_Uncompress( unsigned char *in, unsigned char *out,\n                    unsigned int insize );\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _lz_h_ */\n"
  },
  {
    "path": "tools/lz/lz77.c",
    "content": "/*\n * Copyright (c) 2019 CTCaer\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n#include <sys/stat.h>\n#include \"lz.h\"\n\nchar filename[1024];\n\nint main(int argc, char *argv[])\n{\n\tint nbytes;\n\tint filename_len;\n\tstruct stat statbuf;\n\tFILE *in_file, *out_file;\n\n\tif(stat(argv[1], &statbuf))\n\t\tgoto error;\n\n\tif((in_file=fopen(argv[1], \"rb\")) == NULL)\n\t\tgoto error;\n\n\tstrcpy(filename, argv[1]);\n\tfilename_len = strlen(filename);\n\n\tuint32_t in_size = statbuf.st_size;\n\tuint8_t *in_buf  = (uint8_t *)malloc(in_size);\n\n\tuint32_t out_size = statbuf.st_size + 257;\n\tuint8_t *out_buf = (uint8_t *)malloc(out_size);\n\n\tif(!(in_buf && out_buf))\n\t\tgoto error;\n\n\tif(fread(in_buf, 1, in_size, in_file) != in_size)\n\t\tgoto error;\n\n\tfclose(in_file);\n\n\tuint32_t *work = (uint32_t*)malloc(sizeof(uint32_t) * (in_size + 65536));\n\tfor (int i = 0; i < 2; i++)\n\t{\n\t\tuint32_t in_size_tmp;\n\t\tif (!i)\n\t\t{\n\t\t\tin_size_tmp = in_size / 2;\n\t\t\tstrcpy(filename + filename_len, \".00.lz\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tin_size_tmp = in_size - (in_size / 2);\n\t\t\tstrcpy(filename + filename_len, \".01.lz\");\n\t\t}\n\n\t\tif (work)\n\t\t\tnbytes = LZ_CompressFast(in_buf + (in_size / 2) * i, out_buf, in_size_tmp, work);\n\t\telse\n\t\t\tgoto error;\n\n\t\tif (nbytes > out_size)\n\t\t\tgoto error;\n\n\t\tif((out_file = fopen(filename,\"wb\")) == NULL)\n\t\t\tgoto error;\n\n\t\tif (fwrite(out_buf, 1, nbytes, out_file) != nbytes)\n\t\t\tgoto error;\n\n\t\tfclose(out_file);\n\t}\n\n\treturn 0;\n\nerror:\n\tfprintf(stderr, \"Failed to compress: %s\\n\", argv[1]);\n\texit(1);\n}\n"
  },
  {
    "path": "tools/mc.def",
    "content": "MC_INTSTATUS                                            0\nMC_INTMASK                                              4\nMC_ERR_STATUS                                           8\nMC_ERR_ADR                                              c\nMC_PCFIFO_CLIENT_CONFIG0                                dd0\nMC_PCFIFO_CLIENT_CONFIG1                                dd4\nMC_PCFIFO_CLIENT_CONFIG2                                dd8\nMC_PCFIFO_CLIENT_CONFIG3                                ddc\nMC_PCFIFO_CLIENT_CONFIG4                                de0\nMC_EMEM_CFG                                             50\nMC_EMEM_ADR_CFG                                         54\nMC_EMEM_ADR_CFG_DEV0                                    58\nMC_EMEM_ADR_CFG_DEV1                                    5c\nMC_EMEM_ADR_CFG_CHANNEL_MASK                            60\nMC_EMEM_ADR_CFG_BANK_MASK_0                             64\nMC_EMEM_ADR_CFG_BANK_MASK_1                             68\nMC_EMEM_ADR_CFG_BANK_MASK_2                             6c\nMC_SECURITY_CFG0                                        70\nMC_SECURITY_CFG1                                        74\nMC_SECURITY_CFG3                                        9bc\nMC_SECURITY_RSV                                         7c\nMC_EMEM_ARB_CFG                                         90\nMC_EMEM_ARB_OUTSTANDING_REQ                             94\nMC_EMEM_ARB_TIMING_RCD                                  98\nMC_EMEM_ARB_TIMING_RP                                   9c\nMC_EMEM_ARB_TIMING_RC                                   a0\nMC_EMEM_ARB_TIMING_RAS                                  a4\nMC_EMEM_ARB_TIMING_FAW                                  a8\nMC_EMEM_ARB_TIMING_RRD                                  ac\nMC_EMEM_ARB_TIMING_RAP2PRE                              b0\nMC_EMEM_ARB_TIMING_WAP2PRE                              b4\nMC_EMEM_ARB_TIMING_R2R                                  b8\nMC_EMEM_ARB_TIMING_W2W                                  bc\nMC_EMEM_ARB_TIMING_R2W                                  c0\nMC_EMEM_ARB_TIMING_W2R                                  c4\nMC_EMEM_ARB_TIMING_RFCPB                                6c0\nMC_EMEM_ARB_TIMING_CCDMW                                6c4\nMC_EMEM_ARB_REFPB_HP_CTRL                               6f0\nMC_EMEM_ARB_REFPB_BANK_CTRL                             6f4\nMC_EMEM_ARB_DA_TURNS                                    d0\nMC_EMEM_ARB_DA_COVERS                                   d4\nMC_EMEM_ARB_MISC0                                       d8\nMC_EMEM_ARB_MISC1                                       dc\nMC_EMEM_ARB_MISC2                                       c8\nMC_EMEM_ARB_RING1_THROTTLE                              e0\nMC_EMEM_ARB_RING3_THROTTLE                              e4\nMC_EMEM_ARB_NISO_THROTTLE                               6b0\nMC_EMEM_ARB_OVERRIDE                                    e8\nMC_EMEM_ARB_RSV                                         ec\nMC_CLKEN_OVERRIDE                                       f4\nMC_TIMING_CONTROL_DBG                                   f8\nMC_TIMING_CONTROL                                       fc\nMC_STAT_CONTROL                                         100\nMC_STAT_STATUS                                          104\nMC_STAT_EMC_CLOCK_LIMIT                                 108\nMC_STAT_EMC_CLOCK_LIMIT_MSBS                            10c\nMC_STAT_EMC_CLOCKS                                      110\nMC_STAT_EMC_CLOCKS_MSBS                                 114\nMC_STAT_EMC_FILTER_SET0_ADR_LIMIT_LO                    118\nMC_STAT_EMC_FILTER_SET1_ADR_LIMIT_LO                    158\nMC_STAT_EMC_FILTER_SET0_ADR_LIMIT_HI                    11c\nMC_STAT_EMC_FILTER_SET1_ADR_LIMIT_HI                    15c\nMC_STAT_EMC_FILTER_SET0_ADR_LIMIT_UPPER                 a20\nMC_STAT_EMC_FILTER_SET1_ADR_LIMIT_UPPER                 a24\nMC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_LO            198\nMC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_LO            1a8\nMC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_HI            19c\nMC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_HI            1ac\nMC_STAT_EMC_FILTER_SET0_VIRTUAL_ADR_LIMIT_UPPER         a28\nMC_STAT_EMC_FILTER_SET1_VIRTUAL_ADR_LIMIT_UPPER         a2c\nMC_STAT_EMC_FILTER_SET0_ASID                            1a0\nMC_STAT_EMC_FILTER_SET1_ASID                            1b0\nMC_STAT_EMC_FILTER_SET0_SLACK_LIMIT                     120\nMC_STAT_EMC_FILTER_SET1_SLACK_LIMIT                     160\nMC_STAT_EMC_FILTER_SET0_CLIENT_0                        128\nMC_STAT_EMC_FILTER_SET1_CLIENT_0                        168\nMC_STAT_EMC_FILTER_SET0_CLIENT_1                        12c\nMC_STAT_EMC_FILTER_SET1_CLIENT_1                        16c\nMC_STAT_EMC_FILTER_SET0_CLIENT_2                        130\nMC_STAT_EMC_FILTER_SET1_CLIENT_2                        170\nMC_STAT_EMC_FILTER_SET0_CLIENT_3                        134\nMC_STAT_EMC_FILTER_SET0_CLIENT_4                        b88\nMC_STAT_EMC_FILTER_SET1_CLIENT_3                        174\nMC_STAT_EMC_FILTER_SET1_CLIENT_4                        b8c\nMC_STAT_EMC_SET0_COUNT                                  138\nMC_STAT_EMC_SET0_COUNT_MSBS                             13c\nMC_STAT_EMC_SET1_COUNT                                  178\nMC_STAT_EMC_SET1_COUNT_MSBS                             17c\nMC_STAT_EMC_SET0_SLACK_ACCUM                            140\nMC_STAT_EMC_SET0_SLACK_ACCUM_MSBS                       144\nMC_STAT_EMC_SET1_SLACK_ACCUM                            180\nMC_STAT_EMC_SET1_SLACK_ACCUM_MSBS                       184\nMC_STAT_EMC_SET0_HISTO_COUNT                            148\nMC_STAT_EMC_SET0_HISTO_COUNT_MSBS                       14c\nMC_STAT_EMC_SET1_HISTO_COUNT                            188\nMC_STAT_EMC_SET1_HISTO_COUNT_MSBS                       18c\nMC_STAT_EMC_SET0_MINIMUM_SLACK_OBSERVED                 150\nMC_STAT_EMC_SET1_MINIMUM_SLACK_OBSERVED                 190\nMC_STAT_EMC_SET0_IDLE_CYCLE_COUNT                       1b8\nMC_STAT_EMC_SET0_IDLE_CYCL_COUNT_MSBS                   1bc\nMC_STAT_EMC_SET1_IDLE_CYCLE_COUNT                       1c8\nMC_STAT_EMC_SET1_IDLE_CYCL_COUNT_MSBS                   1cc\nMC_STAT_EMC_SET0_IDLE_CYCLE_PARTITION_SELECT            1c0\nMC_STAT_EMC_SET1_IDLE_CYCLE_PARTITION_SELECT            1d0\nMC_CLIENT_HOTRESET_CTRL                                 200\nMC_CLIENT_HOTRESET_CTRL_1                               970\nMC_CLIENT_HOTRESET_STATUS                               204\nMC_CLIENT_HOTRESET_STATUS_1                             974\nMC_EMEM_ARB_ISOCHRONOUS_0                               208\nMC_EMEM_ARB_ISOCHRONOUS_1                               20c\nMC_EMEM_ARB_ISOCHRONOUS_2                               210\nMC_EMEM_ARB_ISOCHRONOUS_3                               214\nMC_EMEM_ARB_ISOCHRONOUS_4                               b94\nMC_EMEM_ARB_HYSTERESIS_0                                218\nMC_EMEM_ARB_HYSTERESIS_1                                21c\nMC_EMEM_ARB_HYSTERESIS_2                                220\nMC_EMEM_ARB_HYSTERESIS_3                                224\nMC_EMEM_ARB_HYSTERESIS_4                                b84\nMC_EMEM_ARB_DHYSTERESIS_0                               bb0\nMC_EMEM_ARB_DHYSTERESIS_1                               bb4\nMC_EMEM_ARB_DHYSTERESIS_2                               bb8\nMC_EMEM_ARB_DHYSTERESIS_3                               bbc\nMC_EMEM_ARB_DHYSTERESIS_4                               bc0\nMC_EMEM_ARB_DHYST_CTRL                                  bcc\nMC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0                        bd0\nMC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1                        bd4\nMC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2                        bd8\nMC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3                        bdc\nMC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4                        be0\nMC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5                        be4\nMC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6                        be8\nMC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7                        bec\nMC_RESERVED_RSV                                         3fc\nMC_DISB_EXTRA_SNAP_LEVELS                               408\nMC_APB_EXTRA_SNAP_LEVELS                                2a4\nMC_AHB_EXTRA_SNAP_LEVELS                                2a0\nMC_USBD_EXTRA_SNAP_LEVELS                               a18\nMC_ISP_EXTRA_SNAP_LEVELS                                a08\nMC_AUD_EXTRA_SNAP_LEVELS                                a10\nMC_MSE_EXTRA_SNAP_LEVELS                                40c\nMC_GK2_EXTRA_SNAP_LEVELS                                a40\nMC_A9AVPPC_EXTRA_SNAP_LEVELS                            414\nMC_FTOP_EXTRA_SNAP_LEVELS                               2bc\nMC_JPG_EXTRA_SNAP_LEVELS                                a3c\nMC_HOST_EXTRA_SNAP_LEVELS                               a14\nMC_SAX_EXTRA_SNAP_LEVELS                                2c0\nMC_DIS_EXTRA_SNAP_LEVELS                                2ac\nMC_VICPC_EXTRA_SNAP_LEVELS                              a1c\nMC_HDAPC_EXTRA_SNAP_LEVELS                              a48\nMC_AVP_EXTRA_SNAP_LEVELS                                2a8\nMC_USBX_EXTRA_SNAP_LEVELS                               404\nMC_PCX_EXTRA_SNAP_LEVELS                                2b8\nMC_SD_EXTRA_SNAP_LEVELS                                 a04\nMC_DFD_EXTRA_SNAP_LEVELS                                a4c\nMC_VE_EXTRA_SNAP_LEVELS                                 2d8\nMC_GK_EXTRA_SNAP_LEVELS                                 a00\nMC_VE2_EXTRA_SNAP_LEVELS                                410\nMC_SDM_EXTRA_SNAP_LEVELS                                a44\nMC_VIDEO_PROTECT_BOM                                    648\nMC_VIDEO_PROTECT_SIZE_MB                                64c\nMC_VIDEO_PROTECT_BOM_ADR_HI                             978\nMC_VIDEO_PROTECT_REG_CTRL                               650\nMC_ERR_VPR_STATUS                                       654\nMC_ERR_VPR_ADR                                          658\nMC_VIDEO_PROTECT_VPR_OVERRIDE                           418\nMC_VIDEO_PROTECT_VPR_OVERRIDE1                          590\nMC_IRAM_BOM                                             65c\nMC_IRAM_TOM                                             660\nMC_IRAM_ADR_HI                                          980\nMC_IRAM_REG_CTRL                                        964\nMC_EMEM_CFG_ACCESS_CTRL                                 664\nMC_TZ_SECURITY_CTRL                                     668\nMC_EMEM_ARB_OUTSTANDING_REQ_RING3                       66c\nMC_EMEM_ARB_OUTSTANDING_REQ_NISO                        6b4\nMC_EMEM_ARB_RING0_THROTTLE_MASK                         6bc\nMC_EMEM_ARB_NISO_THROTTLE_MASK                          6b8\nMC_EMEM_ARB_NISO_THROTTLE_MASK_1                        b80\nMC_SEC_CARVEOUT_BOM                                     670\nMC_SEC_CARVEOUT_SIZE_MB                                 674\nMC_SEC_CARVEOUT_ADR_HI                                  9d4\nMC_SEC_CARVEOUT_REG_CTRL                                678\nMC_ERR_SEC_STATUS                                       67c\nMC_ERR_SEC_ADR                                          680\nMC_PC_IDLE_CLOCK_GATE_CONFIG                            684\nMC_STUTTER_CONTROL                                      688\nMC_RESERVED_RSV_1                                       958\nMC_DVFS_PIPE_SELECT                                     95c\nMC_AHB_PTSA_MIN                                         4e0\nMC_AUD_PTSA_MIN                                         54c\nMC_MLL_MPCORER_PTSA_RATE                                44c\nMC_RING2_PTSA_RATE                                      440\nMC_USBD_PTSA_RATE                                       530\nMC_USBX_PTSA_MIN                                        528\nMC_USBD_PTSA_MIN                                        534\nMC_APB_PTSA_MAX                                         4f0\nMC_JPG_PTSA_RATE                                        584\nMC_DIS_PTSA_MIN                                         420\nMC_AVP_PTSA_MAX                                         4fc\nMC_AVP_PTSA_RATE                                        4f4\nMC_RING1_PTSA_MIN                                       480\nMC_DIS_PTSA_MAX                                         424\nMC_SD_PTSA_MAX                                          4d8\nMC_MSE_PTSA_RATE                                        4c4\nMC_VICPC_PTSA_MIN                                       558\nMC_PCX_PTSA_MAX                                         4b4\nMC_ISP_PTSA_RATE                                        4a0\nMC_A9AVPPC_PTSA_MIN                                     48c\nMC_RING2_PTSA_MAX                                       448\nMC_AUD_PTSA_RATE                                        548\nMC_HOST_PTSA_MIN                                        51c\nMC_MLL_MPCORER_PTSA_MAX                                 454\nMC_SD_PTSA_MIN                                          4d4\nMC_RING1_PTSA_RATE                                      47c\nMC_JPG_PTSA_MIN                                         588\nMC_HDAPC_PTSA_MIN                                       62c\nMC_AVP_PTSA_MIN                                         4f8\nMC_JPG_PTSA_MAX                                         58c\nMC_VE_PTSA_MAX                                          43c\nMC_DFD_PTSA_MAX                                         63c\nMC_VICPC_PTSA_RATE                                      554\nMC_GK_PTSA_MAX                                          544\nMC_VICPC_PTSA_MAX                                       55c\nMC_SDM_PTSA_MAX                                         624\nMC_SAX_PTSA_RATE                                        4b8\nMC_PCX_PTSA_MIN                                         4b0\nMC_APB_PTSA_MIN                                         4ec\nMC_GK2_PTSA_MIN                                         614\nMC_PCX_PTSA_RATE                                        4ac\nMC_RING1_PTSA_MAX                                       484\nMC_HDAPC_PTSA_RATE                                      628\nMC_MLL_MPCORER_PTSA_MIN                                 450\nMC_GK2_PTSA_MAX                                         618\nMC_AUD_PTSA_MAX                                         550\nMC_GK2_PTSA_RATE                                        610\nMC_ISP_PTSA_MAX                                         4a8\nMC_DISB_PTSA_RATE                                       428\nMC_VE2_PTSA_MAX                                         49c\nMC_DFD_PTSA_MIN                                         638\nMC_FTOP_PTSA_RATE                                       50c\nMC_A9AVPPC_PTSA_RATE                                    488\nMC_VE2_PTSA_MIN                                         498\nMC_USBX_PTSA_MAX                                        52c\nMC_DIS_PTSA_RATE                                        41c\nMC_USBD_PTSA_MAX                                        538\nMC_A9AVPPC_PTSA_MAX                                     490\nMC_USBX_PTSA_RATE                                       524\nMC_FTOP_PTSA_MAX                                        514\nMC_HDAPC_PTSA_MAX                                       630\nMC_SD_PTSA_RATE                                         4d0\nMC_DFD_PTSA_RATE                                        634\nMC_FTOP_PTSA_MIN                                        510\nMC_SDM_PTSA_RATE                                        61c\nMC_AHB_PTSA_RATE                                        4dc\nMC_SMMU_SMMU_PTSA_MAX                                   460\nMC_RING2_PTSA_MIN                                       444\nMC_SDM_PTSA_MIN                                         620\nMC_APB_PTSA_RATE                                        4e8\nMC_MSE_PTSA_MIN                                         4c8\nMC_HOST_PTSA_RATE                                       518\nMC_VE_PTSA_RATE                                         434\nMC_AHB_PTSA_MAX                                         4e4\nMC_SAX_PTSA_MIN                                         4bc\nMC_SMMU_SMMU_PTSA_MIN                                   45c\nMC_ISP_PTSA_MIN                                         4a4\nMC_HOST_PTSA_MAX                                        520\nMC_SAX_PTSA_MAX                                         4c0\nMC_VE_PTSA_MIN                                          438\nMC_GK_PTSA_MIN                                          540\nMC_MSE_PTSA_MAX                                         4cc\nMC_DISB_PTSA_MAX                                        430\nMC_DISB_PTSA_MIN                                        42c\nMC_SMMU_SMMU_PTSA_RATE                                  458\nMC_VE2_PTSA_RATE                                        494\nMC_GK_PTSA_RATE                                         53c\nMC_PTSA_GRANT_DECREMENT                                 960\nMC_LATENCY_ALLOWANCE_AVPC_0                             2e4\nMC_LATENCY_ALLOWANCE_AXIAP_0                            3a0\nMC_LATENCY_ALLOWANCE_XUSB_1                             380\nMC_LATENCY_ALLOWANCE_ISP2B_0                            384\nMC_LATENCY_ALLOWANCE_SDMMCAA_0                          3bc\nMC_LATENCY_ALLOWANCE_SDMMCA_0                           3b8\nMC_LATENCY_ALLOWANCE_ISP2_0                             370\nMC_LATENCY_ALLOWANCE_SE_0                               3e0\nMC_LATENCY_ALLOWANCE_ISP2_1                             374\nMC_LATENCY_ALLOWANCE_DC_0                               2e8\nMC_LATENCY_ALLOWANCE_VIC_0                              394\nMC_LATENCY_ALLOWANCE_DCB_1                              2f8\nMC_LATENCY_ALLOWANCE_NVDEC_0                            3d8\nMC_LATENCY_ALLOWANCE_DCB_2                              2fc\nMC_LATENCY_ALLOWANCE_TSEC_0                             390\nMC_LATENCY_ALLOWANCE_DC_2                               2f0\nMC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB                  694\nMC_LATENCY_ALLOWANCE_PPCS_1                             348\nMC_LATENCY_ALLOWANCE_XUSB_0                             37c\nMC_LATENCY_ALLOWANCE_PPCS_0                             344\nMC_LATENCY_ALLOWANCE_TSECB_0                            3f0\nMC_LATENCY_ALLOWANCE_AFI_0                              2e0\nMC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B                   698\nMC_LATENCY_ALLOWANCE_DC_1                               2ec\nMC_LATENCY_ALLOWANCE_APE_0                              3dc\nMC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C                   6a0\nMC_LATENCY_ALLOWANCE_A9AVP_0                            3a4\nMC_LATENCY_ALLOWANCE_GPU2_0                             3e8\nMC_LATENCY_ALLOWANCE_DCB_0                              2f4\nMC_LATENCY_ALLOWANCE_HC_1                               314\nMC_LATENCY_ALLOWANCE_SDMMC_0                            3c0\nMC_LATENCY_ALLOWANCE_NVJPG_0                            3e4\nMC_LATENCY_ALLOWANCE_PTC_0                              34c\nMC_LATENCY_ALLOWANCE_ETR_0                              3ec\nMC_LATENCY_ALLOWANCE_MPCORE_0                           320\nMC_LATENCY_ALLOWANCE_VI2_0                              398\nMC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB                  69c\nMC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB                  6a4\nMC_LATENCY_ALLOWANCE_SATA_0                             350\nMC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A                   690\nMC_LATENCY_ALLOWANCE_HC_0                               310\nMC_LATENCY_ALLOWANCE_DC_3                               3c8\nMC_LATENCY_ALLOWANCE_GPU_0                              3ac\nMC_LATENCY_ALLOWANCE_SDMMCAB_0                          3c4\nMC_LATENCY_ALLOWANCE_ISP2B_1                            388\nMC_LATENCY_ALLOWANCE_NVENC_0                            328\nMC_LATENCY_ALLOWANCE_HDA_0                              318\nMC_MIN_LENGTH_APE_0                                     b34\nMC_MIN_LENGTH_DCB_2                                     8a8\nMC_MIN_LENGTH_A9AVP_0                                   950\nMC_MIN_LENGTH_TSEC_0                                    93c\nMC_MIN_LENGTH_DC_1                                      898\nMC_MIN_LENGTH_AXIAP_0                                   94c\nMC_MIN_LENGTH_ISP2B_0                                   930\nMC_MIN_LENGTH_VI2_0                                     944\nMC_MIN_LENGTH_DCB_0                                     8a0\nMC_MIN_LENGTH_DCB_1                                     8a4\nMC_MIN_LENGTH_PPCS_1                                    8f4\nMC_MIN_LENGTH_NVJPG_0                                   b3c\nMC_MIN_LENGTH_HDA_0                                     8c4\nMC_MIN_LENGTH_NVENC_0                                   8d4\nMC_MIN_LENGTH_SDMMC_0                                   b18\nMC_MIN_LENGTH_ISP2B_1                                   934\nMC_MIN_LENGTH_HC_1                                      8c0\nMC_MIN_LENGTH_DC_3                                      b20\nMC_MIN_LENGTH_AVPC_0                                    890\nMC_MIN_LENGTH_VIC_0                                     940\nMC_MIN_LENGTH_ISP2_0                                    91c\nMC_MIN_LENGTH_HC_0                                      8bc\nMC_MIN_LENGTH_SE_0                                      b38\nMC_MIN_LENGTH_NVDEC_0                                   b30\nMC_MIN_LENGTH_SATA_0                                    8fc\nMC_MIN_LENGTH_DC_0                                      894\nMC_MIN_LENGTH_XUSB_1                                    92c\nMC_MIN_LENGTH_DC_2                                      89c\nMC_MIN_LENGTH_SDMMCAA_0                                 b14\nMC_MIN_LENGTH_GPU_0                                     b04\nMC_MIN_LENGTH_ETR_0                                     b44\nMC_MIN_LENGTH_AFI_0                                     88c\nMC_MIN_LENGTH_PPCS_0                                    8f0\nMC_MIN_LENGTH_ISP2_1                                    920\nMC_MIN_LENGTH_XUSB_0                                    928\nMC_MIN_LENGTH_MPCORE_0                                  8cc\nMC_MIN_LENGTH_TSECB_0                                   b48\nMC_MIN_LENGTH_SDMMCA_0                                  b10\nMC_MIN_LENGTH_GPU2_0                                    b40\nMC_MIN_LENGTH_SDMMCAB_0                                 b1c\nMC_MIN_LENGTH_PTC_0                                     8f8\nMC_EMEM_ARB_OVERRIDE_1                                  968\nMC_VIDEO_PROTECT_GPU_OVERRIDE_0                         984\nMC_VIDEO_PROTECT_GPU_OVERRIDE_1                         988\nMC_EMEM_ARB_STATS_0                                     990\nMC_EMEM_ARB_STATS_1                                     994\nMC_MTS_CARVEOUT_BOM                                     9a0\nMC_MTS_CARVEOUT_SIZE_MB                                 9a4\nMC_MTS_CARVEOUT_ADR_HI                                  9a8\nMC_MTS_CARVEOUT_REG_CTRL                                9ac\nMC_ERR_MTS_STATUS                                       9b0\nMC_ERR_MTS_ADR                                          9b4\nMC_ERR_GENERALIZED_CARVEOUT_STATUS                      c00\nMC_ERR_GENERALIZED_CARVEOUT_ADR                         c04\nMC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2     d74\nMC_SECURITY_CARVEOUT4_CFG0                              cf8\nMC_SECURITY_CARVEOUT4_CLIENT_ACCESS2                    d10\nMC_SECURITY_CARVEOUT4_SIZE_128KB                        d04\nMC_SECURITY_CARVEOUT1_CLIENT_ACCESS4                    c28\nMC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1     c30\nMC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4     c8c\nMC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0     d1c\nMC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1     d70\nMC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0     c2c\nMC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4     d7c\nMC_SECURITY_CARVEOUT3_SIZE_128KB                        cb4\nMC_SECURITY_CARVEOUT2_CFG0                              c58\nMC_SECURITY_CARVEOUT1_CFG0                              c08\nMC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2     c84\nMC_SECURITY_CARVEOUT2_CLIENT_ACCESS0                    c68\nMC_SECURITY_CARVEOUT3_BOM                               cac\nMC_SECURITY_CARVEOUT2_CLIENT_ACCESS2                    c70\nMC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3     d78\nMC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0     c7c\nMC_SECURITY_CARVEOUT4_CLIENT_ACCESS4                    d18\nMC_SECURITY_CARVEOUT3_CLIENT_ACCESS1                    cbc\nMC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3     c38\nMC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2     c34\nMC_SECURITY_CARVEOUT3_CLIENT_ACCESS2                    cc0\nMC_SECURITY_CARVEOUT5_CLIENT_ACCESS2                    d60\nMC_SECURITY_CARVEOUT3_CFG0                              ca8\nMC_SECURITY_CARVEOUT3_CLIENT_ACCESS0                    cb8\nMC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3     c88\nMC_SECURITY_CARVEOUT2_SIZE_128KB                        c64\nMC_SECURITY_CARVEOUT5_BOM_HI                            d50\nMC_SECURITY_CARVEOUT1_SIZE_128KB                        c14\nMC_SECURITY_CARVEOUT4_CLIENT_ACCESS3                    d14\nMC_SECURITY_CARVEOUT1_BOM                               c0c\nMC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4     d2c\nMC_SECURITY_CARVEOUT5_CLIENT_ACCESS4                    d68\nMC_SECURITY_CARVEOUT3_CLIENT_ACCESS4                    cc8\nMC_SECURITY_CARVEOUT5_CLIENT_ACCESS0                    d58\nMC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2     d24\nMC_SECURITY_CARVEOUT3_CLIENT_ACCESS3                    cc4\nMC_SECURITY_CARVEOUT2_CLIENT_ACCESS4                    c78\nMC_SECURITY_CARVEOUT1_CLIENT_ACCESS1                    c1c\nMC_SECURITY_CARVEOUT1_CLIENT_ACCESS0                    c18\nMC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3     d28\nMC_SECURITY_CARVEOUT5_CLIENT_ACCESS1                    d5c\nMC_SECURITY_CARVEOUT3_BOM_HI                            cb0\nMC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3     cd8\nMC_SECURITY_CARVEOUT2_BOM_HI                            c60\nMC_SECURITY_CARVEOUT4_BOM_HI                            d00\nMC_SECURITY_CARVEOUT5_CLIENT_ACCESS3                    d64\nMC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4     cdc\nMC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1     c80\nMC_SECURITY_CARVEOUT5_SIZE_128KB                        d54\nMC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1     d20\nMC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2     cd4\nMC_SECURITY_CARVEOUT4_CLIENT_ACCESS1                    d0c\nMC_SECURITY_CARVEOUT2_CLIENT_ACCESS3                    c74\nMC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0     ccc\nMC_SECURITY_CARVEOUT4_BOM                               cfc\nMC_SECURITY_CARVEOUT5_CFG0                              d48\nMC_SECURITY_CARVEOUT2_BOM                               c5c\nMC_SECURITY_CARVEOUT5_BOM                               d4c\nMC_SECURITY_CARVEOUT1_CLIENT_ACCESS3                    c24\nMC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0     d6c\nMC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1     cd0\nMC_SECURITY_CARVEOUT1_BOM_HI                            c10\nMC_SECURITY_CARVEOUT1_CLIENT_ACCESS2                    c20\nMC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4     c3c\nMC_SECURITY_CARVEOUT2_CLIENT_ACCESS1                    c6c\nMC_SECURITY_CARVEOUT4_CLIENT_ACCESS0                    d08\nMC_ERR_APB_ASID_UPDATE_STATUS                           9d0\nMC_DA_CONFIG0                                           9dc\n"
  },
  {
    "path": "tools/smmu_payload.py",
    "content": "'''\nCopyright (c) 2018 balika011\n\nThis program is free software; you can redistribute it and/or modify it\nunder the terms and conditions of the GNU General Public License,\nversion 2, as published by the Free Software Foundation.\n\nThis program is distributed in the hope it will be useful, but WITHOUT\nANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\nFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\nmore details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program. If not, see <http://www.gnu.org/licenses/>.\n'''\n\nfrom keystone import *\n\nCODE = b'''\n\tLDR\tX1, =0x70019010\n\tMOV X0, #0x1\n\tSTR W0, [X1]\n\nloop:\n\tIC\tIALLUIS\n\tDSB ISH\n\tB loop\n\tMOV X0, #0x0\n\tSTR W0, [X1]\n\tLDR\tX0, =0x4002B000\n\tBR\tX0\n'''\ntry:\n\tks = Ks(KS_ARCH_ARM64, KS_MODE_LITTLE_ENDIAN)\n\tencoding, count = ks.asm(CODE, 0x0)\n\tprint(\"%s = %s (number of statements: %u)\" %(CODE, ', '.join([('0x%02x' % (x)) for x in encoding]), count))\nexcept KsError as e:\n\tprint(\"ERROR: %s\" %e)"
  }
]